【问题标题】:Get POSIX path of active Finder window with JXA AppleScript使用 JXA AppleScript 获取活动 Finder 窗口的 POSIX 路径
【发布时间】:2018-01-07 15:16:06
【问题描述】:

我想要这个 AppleScript sn-p 的 JXA 等效项:

tell application "Finder"

    # Get path
    set currentTarget to target of window 1
    set posixPath to (POSIX path of (currentTarget as alias))

    # Show dialog
    display dialog posixPath buttons {"OK"}

end tell

我得到的最接近的是使用url 属性来初始化Foundation NSURL 对象并访问它的fileSystemRepresentation 属性,如下所示:

// Get path
var finder = Application('Finder')
var currentTarget = finder.finderWindows[0].target()
var fileURLString = currentTarget.url()

// I'd like to get rid of this step
var fileURL = $.NSURL.alloc.initWithString(fileURLString)
var posixPath = fileURL.fileSystemRepresentation

// Show dialog
finder.includeStandardAdditions = true
finder.displayAlert('', {buttons: ['Ok'], message: posixPath})

但这似乎不必要地复杂。是否有更好的方法可以在不使用 Foundation API 或手动字符串处理的情况下访问 POSIX 路径?

如果我天真地尝试这个:

finder.finderWindows[0].target().posixPath()

我收到此错误:

app.startupDisk.folders.byName("Users").folders.byName("kymer").folders.byName("Desktop").posixPath()
        --> Error -1728: Can't get object.

这个SO answer 似乎相关,但我似乎无法调整它以满足我的需要:

App = Application.currentApplication()
App.includeStandardAdditions = true
SystemEvents = Application('System Events')

var pathToMe = App.pathTo(this)
var containerPOSIXPath = SystemEvents.files[pathToMe.toString()].container().posixPath()

任何帮助将不胜感激!

【问题讨论】:

  • Cocoa API 有什么问题?它比发送 Apple 事件要快得多。
  • @vadian:这是一个简单的脚本任务,它应该有一个简单的JXA-only解决方案,类似于(相当)简单的AppleScript - 唯一的解决方案。在这种简单的情况下,要求脚本编写者诉诸 基础 API(在这种情况下是 Foundation,而不是 Cocoa,顺便说一句)是一种不必要的负担,代表了可以避免的飞跃在必要的知识方面。
  • @mklement0 我知道它是基金会,我只是引用了问题中的一句话。但是,您也建议在答案中使用NSURL
  • @vadian:我am 建议NSURL,因为它是考虑到情况 最简单、最可靠的解决方案,但是,绝对是明确:这不应该是必要的。我在回答中已经更清楚地说明了这一点。
  • 关于 NSURL 是 Foundation 而不是 Cocoa 的一部分的好处。编辑了问题。使用它没有任何错误,但我希望它没有必要。由于 mklement0 提到的原因,我更喜欢纯 JXA 解决方案(不诉诸手动字符串操作)。

标签: applescript macos-sierra finder javascript-automation


【解决方案1】:

@Kymer,你说:

但这似乎不必要地复杂。有没有更好的方法可以到达 不使用 Cocoa API 或手动字符串整理的 POSIX 路径?

你在正确的轨道上。这是我所知道的最好的方法。如果有更好的,我也想知道它们。但是,这似乎运行得很快,并且适用于文件和文件夹。

var finderApp = Application("Finder");
var itemList  = finderApp.selection();
var oItem      = itemList[0];
var oItemPaths  = getPathInfo(oItem);

/* --- oItemPaths Object Keys ---
  oItemPaths.itemClass
  oItemPaths.fullPath
  oItemPaths.parentPath
  oItemPaths.itemName
*/

console.log(JSON.stringify(oItemPaths, undefined, 4))

function getPathInfo(pFinderItem) {

  var itemClass  = pFinderItem.class();  // returns "folder" if item is a folder.
  var itemURL = pFinderItem.url();
  var fullPath  = decodeURI(itemURL).slice(7);

  //--- Remove Trailing "/", if any, to handle folder item ---
  var pathElem  = fullPath.replace(/\/$/,"").split('/')

  var  itemName   = pathElem.pop();
  var parentPath = pathElem.join('/');

  return {
    itemClass:   itemClass,
    fullPath:    fullPath,
    parentPath:  parentPath,
    itemName:    itemName
    };

}

【讨论】:

  • 感谢您花时间回答。我知道我可以手动 wrangle 路径字符串,但这是我真正想要避免的。希望能够以某种方式获取posixPath 属性。
【解决方案2】:

理论上你会这样写:

finder.finderWindows[0].target({as:"alias"})

但这不起作用,文档中没有任何内容表明它受支持。但这是 JXA 的 SOP,与 Apple 早期的 Scripting Bridge 一样,它存在许多设计缺陷和遗漏,这些缺陷和遗漏从未(也可能永远不会)得到修复。 [1]

FWIW,这是您在 Node.js 中使用NodeAutomation 的方法:

$ node
> Object.assign(this,require('nodeautomation'));undefined
> const fn = app('Finder')
> var file = fn.FinderWindows[0].target({asType:k.alias}) // returns File object
> file.toString() // converts File object to POSIX path string
'/Users/jsmith/dev/nodeautomation'

(请注意,NodeAutomation 对我来说是一个非常低优先级的项目,因为 Mac 自动化在 Apple 看起来几乎处于最后阶段。警告购买者等。对于非平凡的脚本,我强烈建议坚持使用 AppleScript因为它是唯一真正有效的官方支持的解决方案。)


[1] 例如,另一个 JXA 限制是大多数应用程序的 moveduplicate 命令严重受损,因为 JXA 的作者忘记实现 insertion reference forms。 (顺便说一句,我什至在 JXA 发布之前就报告了所有这些问题,而 appscript 在十年前就已经解决了所有这些问题,所以他们也没有理由不做对。)

【讨论】:

  • @JMichaelTX:如果那是您的反对意见,请为 OP 的利益服务,而不是您的个人议程。
  • 投反对票绝对不值得。如果是为了给其他答案更多的可见性,那确实是非常琐碎的。不幸的是,我的用例不能依赖外部依赖,但您的回答仍然很有帮助。您似乎对自动化非常了解。你考虑过在 Github 上托管你的 repo 吗?可能会获得更多的知名度,我肯定会在那里加注/关注他们:)
  • 关于可见性:编写 NodeAutomation 更多的是为了证明一个观点,而不是为 Mac 自动化建立一个新平台。那些关注的人的意见是,AppleScript 和 Apple event IPC 在经过多年的管理不善之后终于在 Apple 退出,所以我现在不鼓励任何人加入 xAutomation 的潮流。去过那里,做到了,并为他们的麻烦烧毁了 1000 多个appscript 用户。如果其他人想使用 [Swift/Node]Automation 并与他们一起运行,欢迎尝试;就个人而言,我只是将它们作为一个有用的观点。
【解决方案3】:

这是一个相当简单的示例函数,它只抓取窗口的target,然后从其url 中剥离前导file://

/*
pathToFrontWindow()
returns path to front Finder window
*/
function pathToFrontWindow() {
    if ( finder.windows.length ) {
        return decodeURI( finder.windows[0].target().url().slice(7) )
    } else {
        return ""
    }
}

【讨论】:

  • 虽然这可能会回答问题,但也请添加简短说明您的代码实际做了什么以及为什么它解决了最初的问题。
  • 对字符串进行切片和切块是我真正想避免的事情。希望以某种方式直接获得posixPath 属性。
  • 问题是Finder的window类的target属性返回了类folder的说明符,它没有posixPath属性。您需要一个alias 对象才能获得posixPath,据我所知,在JXA 中无法将folder 转换为alias
【解决方案4】:

如此简单的一段 AppleScript 代码没有直接的 JXA 翻译这一事实证明了基于 OSA 脚本的 JXA 和 macOS 自动化的糟糕状态

正如您自己的示例所表明的那样,在两种垂死的自动化脚本语言中,AppleScript(尽管有很多缺点)是更成熟、更可靠的选择


为了解决您在 JXA 中的问题,您似乎自己想出了最好的方法。 让我把它打包成一个辅助函数,或许可以在一定程度上减轻痛苦 - 明确一点:这样的辅助函数不应该是必需的

// Helper function: Given a Finder window, returns its folder's POSIX path.
// Note: No need for an ObjC.import() statement, because NSURL is 
//       a Foundation class, and all Foundation classes are implicitly
//       available.
function posixPath(finderWin) {
  return $.NSURL.alloc.initWithString(finderWin.target.url()).fileSystemRepresentation
}

// Get POSIX path of Finder's frontmost window:
posixPath(Application('Finder').finderWindows[0])

【讨论】:

  • 关于您在此处链接的自动化状态的有趣博客文章。哦,感谢有关不必要导入的提示!
【解决方案5】:
(() => {

    // getFinderDirectory :: () -> String
    const getFinderDirectory = () =>
        Application('Finder')
        .insertionLocation()
        .url()
        .slice(7);

    return getFinderDirectory();
})();

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2010-11-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多