làm cho chế độ nhắc zsh của tôi hiển thị ở chế độ vi


44

Tôi sử dụng bindkey -v(đối với bash-ers set -o vitôi nghĩ rằng nó cũng hoạt động ở chế độ zsh) hoặc vi (m). nhưng điều đó làm tôi bực mình rằng tôi không có bất kỳ dấu hiệu trực quan nào để cho tôi biết tôi đang ở chế độ chèn hay chế độ lệnh. Có ai biết làm thế nào tôi có thể làm cho lời nhắc của tôi hiển thị chế độ?

Câu trả lời:


25

Tôi tìm thấy điều này thông qua SU . Đây là ví dụ cơ bản, mặc dù tôi vẫn đang tùy chỉnh nó cho chính mình:

function zle-line-init zle-keymap-select {
    RPS1="${${KEYMAP/vicmd/-- NORMAL --}/(main|viins)/-- INSERT --}"
    RPS2=$RPS1
    zle reset-prompt
}

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

Tôi sẽ giải thích nó ngoại trừ tôi chưa thực sự hiểu nó


1
Tôi đã thử phương pháp này nhưng tìm thấy một vấn đề. Nếu bạn làm một cái gì đó giống như CTRL+Ckhi ở chế độ vi-lệnh, lời nhắc sẽ đặt lại, nhưng cho biết bạn đang ở chế độ lệnh khi bạn thực sự ở chế độ chèn. zle-line-initphải luôn luôn thay đổi chỉ báo sang chế độ chèn. Vì một số lý do $KEYMAPkhông được cập nhật đúng khi zle-line-init được gọi.
Patrick

2
zle reset-promptsẽ xóa 1 (hoặc nhiều hơn) dòng trên dấu nhắc (nếu lời nhắc của bạn là đa dòng) khi vẽ lại :( Đây là một showstopper cho tôi.
Paweł Gościcki

@ PawełGościcki dường như là một vấn đề khi bạn có hai hoặc nhiều dòng PS1.
Metaphox

@Metaphox Tôi biết, đó là lý do tại sao tôi đã nói "(nếu lời nhắc của bạn là đa dòng)". Bất kỳ sửa chữa cho điều đó?
Paweł Gościcki

@ PawełGościcki aww xin lỗi tôi bằng cách nào đó đã bỏ qua các từ trong ngoặc đơn, thói quen xấu. Không, tôi đã không tìm thấy một sửa chữa cho điều đó. Bạn đang ở trên nền tảng nào? Đã tự hỏi nếu đây là OS X cụ thể.
Metaphox

18

Bạn đã tìm thấy zle-keymap-selectđược thực thi bất cứ khi nào chế độ thay đổi. Bạn có thể sử dụng nó để đặt một số chỉ báo trực quan khác ngoài lời nhắc, tùy thuộc vào thiết bị đầu cuối của bạn hỗ trợ nó (và sở thích của bạn trong hiển thị chỉ báo chế độ, tất nhiên).

Có một khả năng terminfo tiêu chuẩn để thay đổi hình dạng của con trỏ. Tuy nhiên, một số thiết bị đầu cuối hiển thị cùng một con trỏ trong cả hai chế độ. Khái niệm của Xterm về một con trỏ ít nhìn thấy hơn là làm cho nó nhấp nháy (và điều này phải được kích hoạt với -bcđối số hoặc cursorBlinktài nguyên dòng lệnh ).

zle-keymap-select () {
  case $KEYMAP in
    vicmd) print -rn -- $terminfo[cvvis];; # block cursor
    viins|main) print -rn -- $terminfo[cnorm];; # less visible cursor
  esac
}

Với một số thiết bị đầu cuối, bạn cũng có thể thay đổi màu con trỏ bằng print -n '\e]12;pink\a'(theo tên màu) hoặc print -n '\e]12;#abcdef\a'(theo thông số RGB). Các trình tự này được mô tả trong tài liệu xterm, trong ctlseqstệp; trình giả lập thiết bị đầu cuối hiện đại thường mô phỏng xterm, mặc dù chúng có thể không hỗ trợ tất cả các tính năng của nó.


Đối với một số lý do tôi nhận được maincho KEYMAPthay viins, không chắc chắn lý do tại sao.
Graeme

1
@Graeme mainlà một bí danh cho viinshoặc emacstùy thuộc vào việc zsh có nghĩ rằng trình soạn thảo yêu thích của bạn là vi hay không khi nó bắt đầu. Tôi nghĩ rằng nó sẽ sử dụng viinskhi chuyển đổi chế độ từ đó vicmd, nhưng có vẻ như nó sử dụng mainthay thế. Đã cập nhật.
Gilles 'SO- ngừng trở nên xấu xa'

1
Bạn vẫn cần tăng gấp đôi với zle-line-init(hoặc bất kỳ thay thế nào) vì zle-keymap-selectkhông được gọi nếu nhấn enter sẽ thay đổi sơ đồ bàn phím.
Graeme

9

Đối với những người gặp vấn đề khi sử dụng dấu nhắc đặt lại với lời nhắc đa dòng, cách này hiệu quả với tôi: http://zeitlens.com/posts/2014-06-29-howto-zsh-vi-style.html Kết hợp với https: // stackoverflow.com/questions/3622943/zsh-vi-mode-status-line Tôi đã kết thúc việc làm:

terminfo_down_sc=$terminfo[cud1]$terminfo[cuu1]$terminfo[sc]$terminfo[cud1]

function insert-mode () { echo "-- INSERT --" }
function normal-mode () { echo "-- NORMAL --" }

precmd () {
    # yes, I actually like to have a new line, then some stuff and then 
    # the input line
    print -rP "
[%D{%a, %d %b %Y, %H:%M:%S}] %n %{$fg[blue]%}%m%{$reset_color%}"

    # this is required for initial prompt and a problem I had with Ctrl+C or
    # Enter when in normal mode (a new line would come up in insert mode,
    # but normal mode would be indicated)
    PS1="%{$terminfo_down_sc$(insert-mode)$terminfo[rc]%}%~ $ "
}
function set-prompt () {
    case ${KEYMAP} in
      (vicmd)      VI_MODE="$(normal-mode)" ;;
      (main|viins) VI_MODE="$(insert-mode)" ;;
      (*)          VI_MODE="$(insert-mode)" ;;
    esac
    PS1="%{$terminfo_down_sc$VI_MODE$terminfo[rc]%}%~ $ "
}

function zle-line-init zle-keymap-select {
    set-prompt
    zle reset-prompt
}
preexec () { print -rn -- $terminfo[el]; }

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

5

bạn có thể thử VimMode


4
Tôi đã hy vọng cho một cái gì đó ít liên kết hơn và một chút giải thích. Tôi muốn biết làm thế nào mọi thứ hoạt động.
xenoterracide

1
Thật ra nó là tất cả. Nhìn vào các bình luận các chức năng và cách chúng bị ràng buộc với các sự kiện thay đổi chế độ.
Martin

5

Đây là những gì tôi sử dụng để thay đổi con trỏ giữa hình dạng 'Chặn' và 'Chùm' trong zsh:

(Đã thử nghiệm với Mối , gnome-terminalmate-terminal )

# vim mode config
# ---------------

# Activate vim mode.
bindkey -v

# Remove mode switching delay.
KEYTIMEOUT=5

# Change cursor shape for different vi modes.
function zle-keymap-select {
  if [[ ${KEYMAP} == vicmd ]] ||
     [[ $1 = 'block' ]]; then
    echo -ne '\e[1 q'

  elif [[ ${KEYMAP} == main ]] ||
       [[ ${KEYMAP} == viins ]] ||
       [[ ${KEYMAP} = '' ]] ||
       [[ $1 = 'beam' ]]; then
    echo -ne '\e[5 q'
  fi
}
zle -N zle-keymap-select

# Use beam shape cursor on startup.
echo -ne '\e[5 q'

# Use beam shape cursor for each new prompt.
preexec() {
   echo -ne '\e[5 q'
}

Điều này sẽ chỉ hoạt động trên các thiết bị đầu cuối và trình giả lập thiết bị đầu cuối hiểu được DECSCUSR.
JdeBP

1
Tôi thích điều này. Tôi lo lắng rằng văn bản cho tương tác sức preexec với tập quán khác, vì vậy tôi sửa đổi nó một chút để sử dụng add-zsh-hooknhư sau: gist.github.com/MatrixManAtYrService/...
MatrixManAtYrService

4

Một giải pháp khác để thay đổi hình dạng con trỏ giữa I-tia và khối (đối với dấu gạch dưới, sử dụng \033[4 q). Thêm phần này vào bạn ~/.zshrc.

zle-keymap-select () {
if [ $KEYMAP = vicmd ]; then
    printf "\033[2 q"
else
    printf "\033[6 q"
fi
}
zle -N zle-keymap-select
zle-line-init () {
zle -K viins
printf "\033[6 q"
}
zle -N zle-line-init
bindkey -v

Được sửa đổi từ https://bbs.archlinux.org/viewtopic.php?id=95078 . Đã thử nghiệm trong gnome-terminal 3.22.


Cập nhật

Một giải pháp khác để thay đổi hình dạng con trỏ có thể được tìm thấy ở đây . Cái này rõ ràng hoạt động cho iTerm2, cái mà tôi không có phương tiện để kiểm tra, nhưng thêm nó vào đây trong trường hợp nó hữu ích cho người khác. Sự bổ sung cuối cùng cho bạn ~/.zshrcsẽ là

function zle-keymap-select zle-line-init
{
    # change cursor shape in iTerm2
    case $KEYMAP in
        vicmd)      print -n -- "\E]50;CursorShape=0\C-G";;  # block cursor
        viins|main) print -n -- "\E]50;CursorShape=1\C-G";;  # line cursor
    esac

    zle reset-prompt
    zle -R
}

function zle-line-finish
{
    print -n -- "\E]50;CursorShape=0\C-G"  # block cursor
}

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

1
Tôi xác nhận rằng tập lệnh cập nhật cho iTerm2 thực sự đã hoạt động.
Jason Denney

Kịch bản đầu tiên sẽ chỉ hoạt động trên các thiết bị đầu cuối và trình giả lập thiết bị đầu cuối hiểu được DECSCUSR.
JdeBP

Đây là một giải pháp thực sự tao nhã mà không làm mất vỏ của tôi
tsturzl

3

Tôi hiện đang sử dụng Zsh với chủ đề Bullet Train . Theo ví dụ được đưa ra bởi câu trả lời của Sebastian Blask , tôi đã kết thúc với mã dưới đây

bindkey -v
KEYTIMEOUT=1

function zle-line-init zle-keymap-select {
    case ${KEYMAP} in
        (vicmd)      BULLETTRAIN_PROMPT_CHAR="N" ;;
        (main|viins) BULLETTRAIN_PROMPT_CHAR="I" ;;
        (*)          BULLETTRAIN_PROMPT_CHAR="I" ;;
    esac
    zle reset-prompt
}

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

Điều này sẽ chỉ thay đổi de mặc định $ thành chữ N thành chế độ bình thường và tôi sang chế độ chèn.

Hình ảnh này là một ví dụ khi ở chế độ bình thường tôi nhấn Ctrl+ C:

nhập mô tả hình ảnh ở đây


2

Đây là một phiên bản khác, dựa trên bài viết của Sebastian Blask . Điều này được dự định là không xâm phạm nhất có thể, vì tất cả các giải pháp khác tôi có thể tìm thấy đã sử dụng thêm dòng, trạng thái ở bên phải hoặc thêm ký tự.

Điều này chỉ đơn giản là thay đổi màu $từ trắng sang đỏ khi bật chế độ bình thường. Chỉnh sửa lời nhắc theo ý thích của bạn

bindkey -v
function zle-line-init zle-keymap-select {
    case ${KEYMAP} in
        (vicmd)      PROMPT=$'%{\e[0;32m%}%~%{\e[0m%} %{\e[0;31m%}$%{\e[0m%} ' ;;
        (main|viins) PROMPT=$'%{\e[0;32m%}%~%{\e[0m%} $ ' ;;
        (*)          PROMPT=$'%{\e[0;32m%}%~%{\e[0m%} $ ' ;;
    esac
    zle reset-prompt
}

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

2

Một phiên bản cho oh-my-zshngười dùng

Có một plugin để oh-my-zshgọi vi-modecó thể được tìm thấy ở đây:

robbyrussell / oh-my-zsh / plugin / vi-mode

Tôi sử dụng Antigen để quản lý các plugin của mình, vì vậy việc bao gồm nó cũng đơn giản như việc thêm nó vào .zshrc:

antigen bundle vi-mode

1

Các zsh-vim-mode plugin là có thể hiển thị một chỉ báo cho chèn, lệnh, tìm kiếm, thay thế, và phương thức thị giác. Nó sử dụng kỹ thuật cơ bản của các câu trả lời khác để nối vào các móc ZLE khác nhau (zle-keymap-select, zle-isearch-update, v.v.). Nó kiểm tra [[ $ZLE_STATE = *overwrite* ]]chế độ thay thế. Nó kiểm tra $REGION_ACTIVEđể xác định chế độ trực quan.

Logic rất phức tạp bởi một số câu hỏi về cách ZSH kích hoạt các sự kiện khi rời khỏi chế độ isearch.

Một tính năng hay khác của mô-đun là khả năng thay đổi hình dạng và màu sắc con trỏ dựa trên chế độ. Ví dụ: bạn có thể sử dụng thanh dọc trong chế độ INSERT và gạch chân nhấp nháy trong chế độ TÌM KIẾM.


Plugin này rất tuyệt.
jdhao
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.