0

我在 Vi 模式下使用 Zsh。


$KEYMAP == vicmd(即command-mode)时,我想按退格键将光标向左移动一个字符,而不删除任何内容。[在职的]

$KEYMAP == viins && $ZLE_STATE == *insert*(即insert-mode)时,我想按退格键将光标向左移动一个字符,删除该行上紧接的前一个字符。[在职的]

$KEYMAP == viins && $ZLE_STATE == *overwrite*(即覆盖模式/替换模式)时,我想按退格键将光标向左移动一个字符,将行上的前一个字符恢复为进入覆盖模式之前最初存在的字符. [不工作]


这是一个例子:

# [COMMAND MODE] We start with the following string on the command line:
$ Hello, world!
     ^
     cursor position

# [REPLACE MODE] Now, I hit "R" to enter replace-mode and I type "stuff".
$ Helstufforld!
          ^
          cursor position

# [REPLACE MODE] Finally, I hit backspace 3 times.
$ Helst, world!
       ^
       cursor position


上面的例子显示了当我在覆盖模式下 按退格键时我想要发生的事情;但是,真正发生的情况如下:

# [COMMAND MODE] We start with the following string on the command line:
$ Hello, world!
     ^
     cursor position

# [REPLACE MODE] Now, I hit "R" to enter replace-mode and I type "stuff".
$ Helstufforld!
          ^
          cursor position

# [REPLACE MODE] Finally, I hit backspace 3 times.
$ Helstworld!
       ^
       cursor position


请注意,在第二个示例中按下退格键时,不是恢复刚刚被覆盖的原始 3 个字符(即", w"),而是删除了替换这些字符的最后 3 个字符(即"uff"),以及光标右侧的字符被移到了左边。


如何获得我想要的行为?

4

1 回答 1

0

好的,所以我最终找到了解决我遇到的问题的方法,我会在这里发布,以防其他人遇到同样的问题。


解决方案

把它放在你的.zshrc中:

readonly ZLE_VI_MODE_CMD=0
readonly ZLE_VI_MODE_INS=1
readonly ZLE_VI_MODE_REP=2
readonly ZLE_VI_MODE_OTH=3

function zle-vi-mode {
    if [[ $KEYMAP == vicmd ]]; then
        echo -n $ZLE_VI_MODE_CMD
    elif [[ $KEYMAP == (viins|main) ]] && [[ $ZLE_STATE == *insert* ]]; then
        echo -n $ZLE_VI_MODE_INS
    elif [[ $KEYMAP == (viins|main) ]] && [[ $ZLE_STATE == *overwrite* ]]; then
        echo -n $ZLE_VI_MODE_REP
    else
        echo -n $ZLE_VI_MODE_OTH
    fi
}

function zle-backward-delete-char-fix {
    case "$(zle-vi-mode)" in
        $ZLE_VI_MODE_REP)
            if [[ $CURSOR -le $MARK ]]; then
                CURSOR=$(( $(($CURSOR-1)) > 0 ? $(($CURSOR-1)) : 0 ))
                MARK=$CURSOR
            else
                zle undo
            fi
            ;;
        *)
            zle backward-delete-char
            ;;
    esac
}

zle -N zle-backward-delete-char-fix

## Change cursor shape according to the current Vi-mode.
function zle-line-init zle-keymap-select {
    case "$(zle-vi-mode)" in
        $ZLE_VI_MODE_CMD) echo -ne '\e[2 q' ;; # cursor -> block
        $ZLE_VI_MODE_INS) echo -ne '\e[6 q' ;; # cursor -> vertical bar
        $ZLE_VI_MODE_REP)
            echo -ne '\e[4 q' # cursor -> underline
            MARK=$CURSOR
            ;;
        *)
            ;;
    esac
}

zle -N zle-line-init
zle -N zle-keymap-select

bindkey -v

bindkey '^?' zle-backward-delete-char-fix
bindkey '^h' zle-backward-delete-char-fix


此外,上面的代码会导致光标形状根据您当前所处的 vi 模式而改变(即,因为这是我的.zshrc的复制/粘贴,这就是我喜欢的)。如果您不想要这个,而只是想要简单的修复,请将zle-init-line/zle-keymap-select函数替换为以下内容:

function zle-line-init zle-keymap-select {
    case "$(zle-vi-mode)" in
        $ZLE_VI_MODE_REP)
            MARK=$CURSOR
            ;;
        *)
            ;;
    esac
}
于 2019-08-23T06:36:39.440 回答