【技巧分享】 在 Emacs mini buffer 中选择并打开其他 App【macOS only】

找到一段几年前的旧代码,稍微修改了一下就能用了。

UPDATE 2022-12-25 14:22:57 +0800

  1. 使用 app bundle id 定位 app

  2. 根据 hsingko 大佬的指点,修好了原有的 bug,现在能正确处理 app 名称中有空格这种情况了。

(defun mac-launchpad/string-ends-with (s ending)
  "Return non-nil if string S ends with ENDING."
  (cond ((>= (length s) (length ending))
         (let ((elength (length ending)))
           (string= (substring s (- 0 elength)) ending)))
        (t nil)))

(defun mac-launchpad/find-mac-apps (folder)
  (let* ((files (directory-files folder))
         (without-dots (cl-delete-if (lambda (f) (or (string= "." f) (string= ".." f))) files))
         (all-files (mapcar (lambda (f) (file-name-as-directory (concat (file-name-as-directory folder) f))) without-dots))
         (result (cl-delete-if-not (lambda (s) (mac-launchpad/string-ends-with s ".app/")) all-files)))
    result))

(defun mac-launchpad ()
  (interactive)
  (let* ((apps (mac-launchpad/find-mac-apps "/Applications"))
         (to-launch (completing-read "launch: " apps)))
    (shell-command (format "defaults read \"%s\"Contents/Info.plist CFBundleIdentifier | xargs open -b" to-launch))))

由 vertico+pyim+posframe 强力驱动 :stuck_out_tongue_closed_eyes:

2 个赞

有点 bug:

没办法打开名称中有空格的 app; 已修复

微信.app 只能通过 WeChat 搜索到。

Update

修改了下 shell-command 用查找 app bundle id 的方式打开,命令还是会在空格前加一个逗号导致运行失败。

2022-12-24 20:54:55.563 defaults[64299:10005023] 
The domain/default pair of (/Applications/MarginNote, 3.app/Contents/Info.plist) does not exist

有没有大佬帮忙排下错啊,感谢感谢 :pray:

(defun mac-launchpad/string-ends-with (s ending)
  "Return non-nil if string S ends with ENDING."
  (cond ((>= (length s) (length ending))
         (let ((elength (length ending)))
           (string= (substring s (- 0 elength)) ending)))
        (t nil)))

(defun mac-launchpad/find-mac-apps (folder)
  (let* ((files (directory-files folder))
         (without-dots (cl-delete-if (lambda (f) (or (string= "." f) (string= ".." f))) files))
         (all-files (mapcar (lambda (f) (file-name-as-directory (concat (file-name-as-directory folder) f))) without-dots))
         (result (cl-delete-if-not (lambda (s) (mac-launchpad/string-ends-with s ".app/")) all-files)))
    result))

(defun mac-launchpad ()
  (interactive)
  (let* ((apps (mac-launchpad/find-mac-apps "/Applications"))
         (to-launch (completing-read "launch: " apps)))
    (shell-command (format "defaults read %sContents/Info.plist CFBundleIdentifier | xargs open -b" to-launch))))

用名称带有多个空格的 app 试了下。

搞不明白为什么文件路径被截断了,这个逗号是什么时候被添加进来的。

测试 App:DB Browser for SQLite.app

2022-12-24 21:19:50.031 defaults[65130:10026474] 
The domain/default pair of (/Applications/DB, Browser) does not exist

虽然但是,这个和用mac自带的command+space然后搜索比有什么优势吗?

除了可以不占用快捷键,没有优势。

你可以和你选择是两个问题。

刚才打开聚焦搜索试了一下,dy 搜索不到抖音.app,不知道这算不算优势,哈哈哈。

试试用双引号括住:

    (shell-command (format "open \"%s\"" to-launch))
1 个赞

奇奇怪怪的东西又增加了。拿走了。

:smiling_face_with_three_hearts: 感谢感谢,能正确处理带多个空格的 app 名称了。

我去把修改推给上游。

记得这个好像就是干这事的:GitHub - d12frosted/counsel-osx-app: Launch OSX applications via ivy interface 。 helm也有类似的package。

嗯,本质上是一样的,不过它用的 open -a 我用的 open -b,最关键是没有外部依赖(除了 macOS :laughing:)。

-b 真的好吗?我见过没有 info.plist 的 app(

主要是自己用,就不考虑边界情况了,我能力还不够写一个场景全覆盖的 launcher :rofl: