将 Emacs 作为 X 剪切板管理器
一直以来,我都是使用 clipit(parcellite 的克隆版本) 作为 X 环境下的剪切板管理器(X clipboard manager)。 但是我发现当有一个剪切板管理器运行时,Emacs 会出现一个 bug , 这逼着我去寻找 clipit 的替代品。
我如愿以偿地找到了一个名为 clipmon 的 package, 它工作的相对还不错,但是美中不足的是,它也有一个 bug 。
而且,看起来在 Emacs 中监测 X 剪切板的唯一方式似乎只能由 Emacs 主动去检查 X 剪切板中的内容。 我不是很喜欢这种每隔一两秒就由 Emacs 检查一次 X 剪切板的方案。 我的替代方案是将检查剪切板的动作移出 Emacs,由 shell 脚本来完成。
#!/bin/sh
occ=$(xclip -sel clip -o | sed 's/[\"]/\\&/g')
while sleep 2; do
ncc=$(xclip -sel clip -o | sed 's/[\"]/\\&/g')
if [ "${occ}" != "${ncc}" ]; then
emacsclient -e "(kill-new \"${ncc}\")"
occ=${ncc}
fi
done
这是一个简单而有效的解决方案,但是它依然要不断的探测剪切板的内容。 若能有一个事件驱动的解决方案就好了。 我的 Emacs 经历让我有股冲动去为 X 试着写一个 on-clipboard-change hook, 但这个工作量就太大了。
一般来讲, 除了 Emacs 之外,我只用另外两个应用(一个 web 浏览器,一个终端模拟器),而且这两款应用都是可定制的。
这使得每次我从这些应用中拷贝东西到 X 剪切板时都可以同时再将剪切板中的内容拷贝到 Emacs 的 kill ring 中去。我用的浏览器是 Conkeror,我将下面这段配置添加到它的初始化文件中去了。
function ekr (cc) {
if (typeof cc `=` 'undefined') { cc = read_from_clipboard(); }
cc = cc.replace(/([^\\]*)\\([^\\]*)/g, "$1\\\\$2");
cc = cc.replace('"', '\\"', "g");
cc = cc.replace("'", "'\\''", "g");
var ecc = "emacsclient -e '(kill-new \"" + cc + "\")' > /dev/null";
shell_command_blind(ecc);
}
interactive(
"ekr_cmd_copy",
"Copy the selection to the clipboard and the Emacs kill ring",
function (I) {
call_builtin_command(I.window, "cmd_copy", true);
ekr();
}
);
undefine_key(caret_keymap,"M-w");
define_key(caret_keymap,"M-w", "ekr_cmd_copy");
undefine_key(content_buffer_normal_keymap,"M-w");
define_key(content_buffer_normal_keymap,"M-w", "ekr_cmd_copy");
undefine_key(special_buffer_keymap,"M-w");
define_key(special_buffer_keymap,"M-w", "ekr_cmd_copy");
undefine_key(text_keymap,"M-w");
define_key(text_keymap,"M-w", "ekr_cmd_copy");
我还在 modules/commands.js
中的 kill-region
和 kill-ring-save
的命令以及 modules/content-buffer-input.js
中的 cut-to-end-of-line
命令后添加了对 ekr()
的调用。在 modules/elements.js
中的 copy_text
函数最后添加了对 ekr(text)
的调用.
第二个常用的非 Emacs 应用是 urxvt/tmux。 为了完成跟上面一样的效果,我将下面这行配置加入到 ~/.tmux.conf
中。
bind-key -temacs-copy M-w copy-pipe 'c2e -r'
下面是 c2e 脚本的源代码。
#!/bin/sh
# c2e: Copy text to the Emacs kill ring.
#
# With no arguments, send the contents of the X clipboard to the Emacs kill ring.
# With -r, first set the clipboard to the contents read from standard input.
# With -s, instead send X primary selection to the Emacs kill ring.
if [ "${1}" = '-r' ]; then
exec xclip -sel clip -i -f | \
emacsclient -e "(kill-new \"$(sed 's/[\"]/\\&/g')\")"
elif [ "${1}" = '-s' ]; then
exec xclip -o | \
emacsclient -e "(kill-new \"$(sed 's/[\"]/\\&/g')\")"
else
exec xclip -sel clip -o | \
emacsclient -e "(kill-new \"$(sed 's/[\"]/\\&/g')\")"
fi
为了使这个新剪切板管理器(即 Emacs 的 kill ring) 更容易使用,我为 StumpWM 添加了一个新的命令和相应的快捷键。
(defcommand eaacm () ()
"Emacs as a clipboard manager."
(run-or-raise "emacsclient -nc" '(:class "Emacs"))
(run-shell-command "emacsclient -n -e '(let ((helm-full-frame t)) \
(save-window-excursion (delete-other-windows) (helm-show-kill-ring)))'"))
(define-key *root-map* (kbd "c") "eaacm")
现在不管我正在使用哪个应用,只需要按下 C-t c
就会有一个 helm 界面让我选择 kill ring 中的内容。 在 Helm 中甚至有一项功能可以将当前 entry 移动到 kill ring 的顶端同时将该 entry 的内容拷贝到 X 剪切板中。 该功能的默认快捷键是 C-c C-k
。
偶尔我也会需要在其他应用中拷贝内容到剪切板中,因此我还创建了两个简单的 StumpWM 命令来调用 c2e 脚本,并分别分配了快捷键。
(defcommand c2e () ()
"Copy the X clipboard contents to the Emacs kill ring."
(run-shell-command "c2e"))
(defcommand s2e () ()
"Copy the X selection contents to the Emacs kill ring."
(run-shell-command "c2e -s"))
(define-key *root-map* (kbd "C") "c2e")
(define-key *root-map* (kbd "s") "s2e")
仅仅过了几天而已,Emacs 就变成了一个很不错的 X 剪切板管理器了。
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论