前几天发布了帖子:使用 Emacs 作为万能粘合剂 介绍了,最近编写的几个 emacs 工具。其中,Global Interactive Emacs 适合单独拿出来讨论一下。
以这篇文章 作为基础,实现的类似 lauchbar 或者 Alfred 应用启动工具,能够快速的进行应用启动、链接跳转、常用工作流的快捷操作。
核心逻辑是: hack completing-read-function
方法,让外部工具(choose /rofi )去处理 completing-read
的输入输出。
当前我已经用它替代了日常使用 lauchbar 的需求。
目前实现的功能有:
global-interactive-select-from-clipboard: 从 kill-ring and clipboard 选择文本。
global-interactive-run-app: 启动 MaOS 安装的 app 。
global-interactive-open-url: 使用浏览器打开预定义的网址。
global-interactive-leetcode: 交互性查询并显示 leetcode 问题。
global-interactive-kubectl: 交互式查询并打开 K8S 资源配置。
global-interactive-youdao-dictionary: 由有道字典翻译单词。
global-interactive-web-search: 使用浏览器通过预定义的搜索引擎查询信息。
global-interactive-send-request: 使用 chrome cookie 发送 http 请求,并解析它的 json 响应。
global-interactive-find-file: 在系统中查找文件并对此文件执行一些操作。
global-interactive-chrome-bookmarks: 查询 Chrome 书签。
global-interactive-chrome-history: 查询 Chrome 历史。
这个工具的主要优点:
免费: 不管是 Lauchbar 还是 Alfred,你都需要付费才能舒适有效地使用它。这个工具只需要 Emacs 和一些可以免费使用的开源软件。
一致性: 您可以在 Emacs 内部或外部使用相同的特性,并有类似的体验。
简单配置: 如果您熟悉 Emacs,您可以轻松地使用 Emacs-lisp 配置它,而不必重新学习其他工具的语言和工作流。
可扩展: 可以编写自己的交互式函数并将它们嵌入到工具中,或者使用其他人开发的 Emacs 插件,提取交互式函数并将它们插入到工具中。
示例:
global-interactive-select-from-clipboard
global-interactive-run-app
global-interactive-open-url
global-interactive-kubectl
global-interactive-leetcode
global-interactive-youdao-dictionary
global-interactive-web-search
global-interactive-send-request
global-interactive-find-file
global-interactive-chrome-bookmarks
lobal-interactive-chrome-history
不足与改进
这个工具没有 lauchbar 或者 Alfred 那么强大。目前它只对我自己的需要有用。我会根据自己的需要不断改进,欢迎任何人来帮助我改进。如果大家有什么使用lauchbar/Alfred 过程中积累的比较便捷的工具流,欢迎提出建议。
目前使用外部工具不能完全支持所有Emacs交互函数,例如execute-extended-command
它运行 completing-read
的入参是一个函数而不是一个候选列表,目前我还没有办法让外部工具来处理这种情况。
我尝试进行另一种尝试:并不是使用外部工具来进行交互,而是创建一个Emacs frame,它只包含交互的部分,而不是整个Emacs窗口。
posframe 是一个很好的参考。无奈 posframe 当前创建的是当前 frame 的一个子frame。因此我想到了一个比较 tricky 的方法:
创建一个透明的、全屏的 frame
然后在这个 frame 下,调用posframe (直接使用vertico-posframe )
适当的时机(我还没找到这个适当是什么时候)删除创建的透明frame
问题:
是否这样的思路合适,感觉这样,整个流程只是比在Emacs内部使用,少了一个切换到Emacs的过程。
不知道在哪个时刻删除预先创建的 frame 比较合适,因为运行的过程中,可能会有异步的运行,需要等待一段时间弹出候选窗口。(目前我是没有自动的删除 frame 的逻辑,是运行 C-g 时,删除所有创建的透明 frame)
其他问题:
elisp 程序该怎么编写单元测试或者集成测试?
欢迎大家使用,积极的提供意见,无比感谢。
10 个赞
为什么一定要用posframe创建child frame呢?直接创建一个frame不行吗?
因为简单。
最好是直接创建一个frame。只是这样相当与要重新实现一个类似 vertico-posframe 的功能。如果直接使用 vertico-posframe,那么只需要处理什么时候创建主 frame 和怎么删掉它就行了。
不过,直接创建 frame 应该是最终的解决方法。
不用切换到 Emacs 主 frame 就可以运行 Emacs 的交互函数。
如果vertico-posframe 作为一个单独 frame 运行,那就可以把弹出vertico-posframe 绑定到某个快捷键上,如图,在不用切换到 Emacs 的情况下,快速的运行一些既定的 Emacs 函数。
局限性太大了,这样还必须依赖于vertico、posframe和vertico-posframe。就是最底层的make-frame不行吗?
rua
2022 年8 月 1 日 06:42
10
尝试使用 GitHub - SebastienWae/app-launcher: Launch application from Emacs
(defun eat/emacs-app-launcher ()
""
(interactive)
(let ((default-frame-alist '((undecorated . t)
(vertical-scroll-bars)
(scroll-bar-mode . 0)
(menu-bar-lines . 0)
(tool-bar-lines . 0))))
(with-selected-frame
(make-frame
'((name . "emacs-app-launcher")
(minibuffer . only)
(width . 120)
(height . 11)))
(unwind-protect
(app-launcher-run-app)
(delete-frame)))))
但是运行 emacsclient -e "(eat/emacs-app-launcher)"
会 Error:
*ERROR*: Unknown terminal type
不太会 elisp, 暂时不知道如何进行
行是行,只是直接 make-frame 的话,许多 vertico、posframe 踩过的坑,估计还得踩。要好用的话,估计还得慢慢开发。如果有现有的工具的话,还是希望可以复用的。
嗯嗯,我看看。看起来核心就是make-frame 创建一个只有 minibuffer 的 frame。
感觉不太靠谱,不过如果下面的函数返回的是 (x . y), 创建的就是普通 frame,这个功能是为 exwm 设计的,因为窗口遮挡问题。
(defcustom vertico-posframe-refposhandler #'vertico-posframe-refposhandler-default
"The refposhandler used by vertico-posframe.
NOTE: This variable is very useful to EXWM users."
:type 'function)
(defun vertico-posframe-refposhandler-default (&optional frame)
"The default posframe refposhandler used by vertico-posframe.
Optional argument FRAME ."
(cond
;; EXWM environment
((bound-and-true-p exwm--connection)
(or (ignore-errors
(let ((info (elt exwm-workspace--workareas
exwm-workspace-current-index)))
(cons (elt info 0)
(elt info 1))))
;; Need user install xwininfo.
(ignore-errors
(posframe-refposhandler-xwininfo frame))
;; Fallback, this value will incorrect sometime, for example: user
;; have panel.
(cons 0 0)))
(t nil)))
你指的UI是?emacs 外部使用的是 choose ,内部是 vertico-posframe
1 个赞
yibie
2022 年8 月 1 日 13:47
18
我用的浏览器不是Chrome,而是Brave,安装 GIE 的时候出现如下出错提示:
目前访问浏览器 History 只支持 Chrome,把 (require 'global-interactive-chrome-bookmarks)
(require 'global-interactive-chrome-history) 这两个引入去掉吧。
按照提示,尝试用 vertico-posframe 创建一个独立的 frame 用于交互。但并没有成功。vertico-posframe 的焦点处理让它还是集中与原来 Emacs frame。
现在 Global Interactive Emacs 提供了三种交互形式:
直接在Emacs内部运行。
创建一个透明的 Frame,在这个 Frame 中运行 vertico-posframe
使用 Choose 进行交互。
经过最近一段事件的使用。使用 Choose 进行交互已经可以满足大部分的需求。但是有一些复杂的Emacs命令还无法支持。
而使用一个透明的 Frame,在这个 Frame 中运行 vertico-posframe,可以支持更多的 Emacs 命令。目前遇到的唯一缺陷时,当退出 Frame 时,没法自动聚焦到上一次访问的app。(Choose 目前最大的优势就在于,使用完之后,聚焦到上一次的应用当中。)