如何在自定义小部件中的 vi 运算符挂起模式后移动 zsh 光标?

如何在自定义小部件中的 vi 运算符挂起模式后移动 zsh 光标?

我开发了一个zsh 插件这是 vi 模拟模式下 zsh 的 vim-easymotion 的端口。由于 zsh 行编辑器具有多行支持,因此我添加了对行运动(jk)的支持。该插件还应该适用于 vi 运算符挂起模式(例如在删除模式下),因此我使用zsh 的MARKCURSOR变量将用户选择扩展到完整行(因此行运动将始终删除或更改整行,而不仅仅是部分行)其中)。这是 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 时该怎么办。

相关内容