整合iTerm2与Emacs
Emacs中的终端体验又慢有难用,因此我都是用iTerm2作为我的主要终端来用的. 我创建了三个emacs-lisp函数,这些函数会调用AppleScript,使得我可以快速在iTerm和spacemacs之间相互切换.
这个函数返回当前打开文件所在的目录. 若当前buffer为 *scratch*
或类似的buffer,则会返回home目录.
(defun get-file-dir-or-home () "If inside a file buffer, return the directory, else return home" (interactive) (let ((filename (buffer-file-name))) (if (not (and filename (file-exists-p filename))) "~/" (file-name-directory filename))))
这个函数让我cd到当前编辑文件所在的目录. 若我处于类似 *scratch*
buffer中则会cd到 $HOME
目录. 然后进入iTerm2应用.
(defun iterm-goto-filedir-or-home () "Go to present working dir and focus iterm" (interactive) (do-applescript (concat " tell application \"iTerm2\"\n" " tell the current session of current window\n" (format " write text \"cd %s\" \n" (get-file-dir-or-home)) " end tell\n" " end tell\n" " do shell script \"open -a iTerm\"\n" )) )
EDIT: 2016-09-05 我接受Steve Purcell的建议. Emacs已经有了一个名为 default-directory
的变量. 它的值就是当前编辑buffer所在的目录,若当前buffer没有对应的文件,则其值为nil. 因此 (or default-directory "
")~ 也能起到相同的作用.
为了防止目录名中包含类似unicode字符或空格这样的特殊字符, 我们需要在将其传递到shell前将其引用起来. 这可以用 shell-quote-argument
来实现.
不过,由于我们需要把这些引用之后的特殊字符作为参数传递到applescript语句中. 因此引用符可能会看起来比较乱.
下面这个函数即使当处于类似 “~/Users/me/Google Drive/pâte à pizza/” 这样的目录中时也能正常工作.
(defun sam--iterm-goto-filedir-or-home () "Go to present working dir and focus iterm" (interactive) (do-applescript (concat " tell application \"iTerm2\"\n" " tell the current session of current window\n" (format " write text \"cd %s\" \n" ;; string escaping madness for applescript (replace-regexp-in-string "\\\\" "\\\\\\\\" (shell-quote-argument (or default-directory "~")))) " end tell\n" " end tell\n" " do shell script \"open -a iTerm\"\n" )) )
最后这个函数仅仅是进入iTerm2应用而不会修改工作目录.
(defun iterm-focus () (interactive) (do-applescript " do shell script \"open -a iTerm\"\n" ))
最后,我用general.el来将这两个函数的快捷键分别设置为SPC '以及SPC ?.
(general-define-key :states '(normal visual insert emacs) :prefix "SPC" "'" '(iterm-focus :which-key "focus iterm") "?" '(iterm-goto-filedir-or-home :which-key "focus iterm - goto dir") )