emacsclient --eval有时能把窗口切换到emacs有时不能?

昨天在翻the art of command line的时候偶然看到贡献者里面有熟悉的@xuchunyang 同学的头像,就点进去翻了一下,发现了这篇博客,通过emacsclinet --eval来把当前shell的上下文放到emacs中继续浏览。

问题是:博主是通过mac下的open切换到emacs的,我实验后发现博客里的magit是会直接跳到emacs的,dired则不能(windows+cygwin),这个区别是什么原因呢?(虽然我通过autohotkey实现了切换的功能,但是能修改eval的elisp来切换的话更好)


附上我自己加入的两段脚本,很简单,如果有和我一样shell和emacs刚入门的同学可以参考:

  • windows下使用autohotkey实现切换窗口(在autohotkey安装目录下生成一个switch-to-emacs.ahk文件,然后执行它。我翻了好久没找到AutoHotkey.exe怎么执行inline的脚本,也没找到怎么在shell下不生成文件就把stdin给AutoHotkey这样只接受文件名的命令):
open-emacs() {
    local exepath=`which AutoHotkey`
    # must quote exepath in case there's space in it
    local ahkpath=$(cygpath -m '"'exepath'"' | sed 's/AutoHotkey\(\\.exe\)\?//g')
    echo 'WinActivate, ahk_class Emacs' > $ahkpath'switch-to-emacs.ahk'
    AutoHotkey $ahkpath'switch-to-emacs.ahk'
}
  • 在emacs中生成一条cd命令给shell,末尾带个换行符,抄袭自spacemacs/show-and-copy-buffer-filename
  (defun make-cd-for-terminal ()
    "make a cd command for terminal, targeting current buffer file's dir"
    (interactive)
    (let ((file-name (buffer-file-name)))
      (if file-name
          (message (kill-new (format "cd %s \n" (file-name-directory file-name))))
        (error "Buffer not visiting a file"))))
1 个赞

听起来确实挺奇怪的,dired 和 magit 并没有什么不同,都只是让 Emacs 执行的命令而已,或许这不是问题的根源,你可以试试随便别的什么命令,比如 (emacs-version) 等,看看是否正常。


从 Shell 中(终端中)切换到 Emacs 窗口,Mac 下最简单,Windows 下楼主也提了,Linux 下,我是用 xdotool 实现的,在 Ubuntu 16.04 默认的 Unity 下有效,但有可能不适用于其它的发行版/窗口管理器

xdotool windowactivate --sync $( xdotool search --class Emacs | tail -1 )

目前我把相关的设置都放到了一个单独的文件里了,有些命令直接用的是 emacs --eval

其中的有些命令虽然不常用,但是第一次想到感觉挺有意思的

# calc 支持任意大的数(?)比如 2**10000
calc ()
{
    emacs -Q --batch --eval "(message \"%s\" (calc-eval \"$1\"))"
}

elisp_repl ()
{
    emacs --batch --eval '(while t (message "%s" (eval (read (read-string "> ")))))'
}

随便(emacs-version)或者(message ...)一下是不会切换窗口的,emacsclient打开文件是会切换窗口的,似乎跟它认为你需要在哪里观察命令结果有关。dired和magit的区别是,执行前emacs里有一个window的话,dired会在这个window里打开,magit会开第二个window。。

哦,我明白你什么意思了。其实原来

emacsclient --eval '(magit-status)'

是不会切换到 Emacs 窗口的,不然我压根就用不着用 open 了,刚刚我试了下,现在是可以直接就切换了。不过我也不清楚 magit-status 是如何做到的,有时间再看看它的代码。

找到了,是用 select-frame-set-input-focus 实现了

这样的话,就用不着自己想办法用外部程序打开 Emacs 窗口了

(defun open-emacs-window ()
  "打开 Emacs 窗口."
  (select-frame-set-input-focus (selected-frame)))

~$ emacsclient --eval '(dired ".")' --eval '(open-emacs-window)'

~$ emacsclient --eval '(org-agenda-list)' --eval '(open-emacs-window)'
2 个赞