整合 readline 的 kill-ring 和 X11 剪贴板

15

在我的.zshrc文件中,我使用以下代码片段将shell剪贴板和我的主要X11剪贴板集成起来。由于这种集成,我可以在不使用鼠标的情况下在emacs、firefox和终端之间剪切和粘贴文本。

kill-line() { zle .kill-line ; echo -n $CUTBUFFER | xclip -i }
zle -N kill-line # bound on C-k

yank() { LBUFFER=$LBUFFER$(xclip -o) }
zle -N yank # bound on C-y

注意:我在Mac OS X上也使用这种技巧(使用pbcopy/pbpaste代替xclip),并且感谢Synergy让我的两台电脑共享一个剪贴板。很棒。但它无法与readline一起使用。我经常发现自己需要使用readline,例如在(i)python、gdb、ncftp中。

因此,我的问题来了:有没有一种方法将readline的剪贴板与其他地方集成?

当然,我在想一些.inputrc黑科技,但任何见解/想法都会受到欢迎。


我不确定你真正想要什么,但我找到了另一个类似xclip的工具XSEL - http://www.vergenet.net/~conrad/software/xsel/,它似乎更强大。 - jitter
谢谢分享。实际上,我想要的是一种自动从 readline 程序(例如 bash)调用类似 XSEL 的程序的方法,当我按下 Ctrl-K / Ctrl-Y 时。我猜这归结为将 shell 命令绑定到 readline 键组合... - Gyom
我建议你将echo -n改为上面的print -rn --(或printf %s)。 - Stephane Chazelas
4个回答

15

Bash 4.0引入了一些新功能:

NEWS

使用`bind -x'分配给键序列的命令现在会在执行的命令环境中设置两个新变量: READLINE_LINE_BUFFERREADLINE_POINT。命令可以通过修改READLINE_LINE_BUFFERREADLINE_POINT来更改当前的readline行和光标位置。

NEWS文件似乎不准确;其他地方记录的是READLINE_LINE(没有_BUFFER),并且实际有效。

以下将模拟Bash现有的Ctrl+(U|K|Y)的行为,但影响X选择,尽管我使用Meta/Esc因为我不喜欢覆盖现有的功能。

_xdiscard() {
    echo -n "${READLINE_LINE:0:$READLINE_POINT}" | xclip
    READLINE_LINE="${READLINE_LINE:$READLINE_POINT}"
    READLINE_POINT=0
}
_xkill() {
    echo -n "${READLINE_LINE:$READLINE_POINT}" | xclip
    READLINE_LINE="${READLINE_LINE:0:$READLINE_POINT}"
}
_xyank() {
    READLINE_LINE="${READLINE_LINE:0:$READLINE_POINT}$(xclip -o)${READLINE_LINE:$READLINE_POINT}"
}
bind -m emacs -x '"\eu": _xdiscard'
bind -m emacs -x '"\ek": _xkill'
bind -m emacs -x '"\ey": _xyank'

我仍然更喜欢使用screen,但这个回答更好地回答了你的问题—只要你关心的readline应用程序是Bash。


谢谢,这确实是我想要的东西。不幸的是,我正在使用zsh作为shell,所以当我使用readline时,它通常是与_bash_之外的其他程序一起使用的 :-) 我想我必须习惯screen了。 - Gyom
1
这在我的Bash 4.2.37下无法工作。那些变量实际上不包含任何值。 - Forethinker
我点赞了这个答案和用户@Wei_Hu下面的修改。请看那里。 - user1404316

5

我想基于ephemient的答案提出以下_xyank()函数:

_xyank() {
    CLIP=$(xclip -o)
    COUNT=$(echo -n "$CLIP" | wc -c)
    READLINE_LINE="${READLINE_LINE:0:$READLINE_POINT}${CLIP}${READLINE_LINE:$READLINE_POINT}"
    READLINE_POINT=$(($READLINE_POINT + $COUNT))
}

这个命令会将光标移动到被复制的文本结尾处,使其与其他内置命令更加一致。

1
谢谢,但是我再次强调,我的问题是针对非Bash Readline应用程序的 :-) - Gyom

5
个人而言,我在GNU screen中运行所有内容。这为我提供了跨所有基于终端的程序的大量功能,而不仅仅是基于readline的程序。它有自己的剪贴板(s),这些剪贴板在当前会话中的所有屏幕之间共享,并且可以读/写交换文件(可配置为bufferfile)。
  • 使用Ctrl+A[、<movement>、Space、<movement>进行屏幕选择;
  • 使用Enter复制到剪贴板;
  • 使用Ctrl+A]粘贴;
  • 使用Ctrl+A<替换为交换文件的内容;
  • 并使用Ctrl+A>将其写入交换文件。
然后,您只需要一些小助手来同步/tmp/screen-exchange和X选择。这样简单的东西就可以工作了。
# ~/.screenrc (or entered at C-a : command prompt)
bind '{' exec sh -c 'xclip -o>~/.screen_exchange'
bind '}' exec sh -c 'xclip -i ~/.screen_exchange'

当然,更好的绑定和宏会让生活更轻松(这需要使用 C-a { C-a < C-a ] 将 X 选择粘贴到终端),但这完全由你决定。

0

正如我在这里所写的,我发现将填充X剪贴板的键绑定分开可能更好,因为我经常在Readline中使用“kill”进行文本操作,而我不希望每次都清除剪贴板。

当Readline具有触发与X交互的键绑定功能时,我建议将^Xw和^Xy绑定到复制和粘贴。

我知道这并没有解决你的问题,但我没有足够的声望在评论中说出来。

至于扩展Readline以绑定键到命令的能力,我在Readline邮件列表上提出了这个问题,我们将看看Chet会说什么:

https://lists.gnu.org/archive/html/bug-readline/2016-05/msg00002.html


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接