我开发了一个zsh 插件这是 vi 模拟模式下 zsh 的 vim-easymotion 的端口。由于 zsh 行编辑器具有多行支持,因此我添加了对行运动(j
和k
)的支持。该插件还应该适用于 vi 运算符挂起模式(例如在删除模式下),因此我使用zsh 的MARK
和CURSOR
变量将用户选择扩展到完整行(因此行运动将始终删除或更改整行,而不仅仅是部分行)其中)。这是 vim 用户所期望的行为。然而,更改/删除操作后的光标位置是错误的。光标应位于下一行的第一个单词上后删除的行块。相反,光标位于最后一行的末尾前行块。我看不到在操作员挂起模式后更改光标的可能性,因为任何光标更改都将成为所选操作员区域的一部分。
所以我的问题是:有谁知道如何在 zsh 自定义小部件中更改光标位置后vi 操作符被执行?
更新:
为了使问题易于理解,我尝试创建一个最小的问题示例:
这个 zsh 小脚本的来源是:
function test-widget () {
MARK=3
CURSOR=6
}
zle -N test-widget
bindkey -M vicmd ' ' test-widget
如果您处于 zsh 的 vicmd/正常模式(bindkey -v
激活 vi 模拟并<esc>
进入命令模式),您现在可以按 将<space>
光标设置到当前编辑缓冲区中的第六个字符。如果您输入 vi 运算符(如d
后跟 )<space>
,则从第三个字符到第六个字符的所有内容都将被删除(由于变量的设置MARK
)。
删除示例:考虑您的编辑缓冲区是(光标位置用 标记[]
):
[a]bc def ghi
然后你按d<space>
,你会得到:
abc[f] ghi
但是,我想在同一个小部件调用中进行删除操作后更改光标的位置,例如:
abcf [g]hi
我不知道这怎么可能,因为所有更改都会CURSOR
影响已删除文本的范围。
如何实现删除操作+光标定位?
答案1
在我看来,您必须重新定义采取动作的小部件,例如绑定到d
, c
, y
, gu
, gU
, g~
...的小部件
就像是:
test-widget () {
MARK=3
CURSOR=6
MOVE_AFTER_MOTION=2
}
zle -N test-widget
bindkey -M vicmd ' ' test-widget
for widget in vi-{delete,change,yank,{down,oper-swap,up}-case}; do
$widget () {
local ret
zle ".$WIDGET"; ret=$?
if (($+MOVE_AFTER_MOTION)); then
(( CURSOR += MOVE_AFTER_MOTION ))
unset MOVE_AFTER_MOTION
fi
return "$ret"
}
zle -N $widget
done
您可能还必须考虑当$NUMERIC
不为 1 时该怎么办。