ทำให้โหมดแสดงพรอมต์ zsh ของฉันในโหมด vi


44

ฉันใช้bindkey -v(สำหรับ bash-ers set -o viฉันคิดว่ามันใช้งานได้ในโหมด zsh ด้วย) หรือโหมด vi (m) แต่มันทำให้ฉันสับสนว่าฉันไม่มีคิวภาพใด ๆ ที่จะบอกฉันว่าฉันอยู่ในโหมดแทรกหรือโหมดคำสั่ง ไม่มีใครรู้ว่าฉันจะทำให้โหมดการแสดงพร้อมท์ของฉันปรากฏขึ้นได้อย่างไร?

คำตอบ:


25

ผมพบว่านี้ผ่านSU นี่คือตัวอย่างพื้นฐานแม้ว่าฉันจะยังคงปรับแต่งมันเอง:

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

ฉันจะอธิบายมันยกเว้นฉันยังไม่เข้าใจจริงๆ


1
ฉันลองใช้วิธีนี้ แต่พบปัญหาหนึ่งอย่าง หากคุณทำสิ่งที่ชอบCTRL+Cในขณะที่อยู่ในโหมดคำสั่ง vi พร้อมท์จะรีเซ็ต แต่ระบุว่าคุณอยู่ในโหมดคำสั่งเมื่อคุณอยู่ในโหมดแทรกจริงๆ zle-line-initควรเปลี่ยนตัวบ่งชี้เป็นโหมดแทรก ด้วยเหตุผลบางอย่าง$KEYMAPไม่ได้รับการอัพเดตอย่างถูกต้องเมื่อเรียก zle-line-init
แพทริค

2
zle reset-promptจะลบ 1 (หรือมากกว่า) บรรทัดด้านบนพรอมต์ (หากพรอมต์ของคุณคือหลายบรรทัด) เมื่อวาดใหม่ :( นี่คือ showstopper สำหรับฉัน
PawełGościcki

@ PawełGościckiดูเหมือนว่าจะมีปัญหาเมื่อคุณมี PS1 สองบรรทัดขึ้นไป
Metaphox

@ Metaphox ฉันรู้ว่าทำไมฉันถึงพูดว่า "(หากพรอมต์ของคุณเป็นหลายบรรทัด)" การแก้ไขใด ๆ ที่?
PawełGościcki

@ PawełGościcki aww ขอโทษฉันข้ามคำในวงเล็บนิสัยไม่ดี ไม่ฉันไม่พบวิธีแก้ไขสำหรับสิ่งนั้น คุณอยู่บนแพลตฟอร์มใด สงสัยว่านี่เป็น OS X เฉพาะหรือไม่
Metaphox

18

คุณพบแล้วzle-keymap-selectซึ่งจะถูกดำเนินการเมื่อใดก็ตามที่มีการเปลี่ยนแปลงโหมด คุณสามารถใช้มันเพื่อตั้งค่าตัวบ่งชี้ภาพอื่น ๆ กว่าการแจ้งเตือนขึ้นอยู่กับสิ่งที่เทอร์มินัลของคุณรองรับ

มีความสามารถ terminfoมาตรฐานเพื่อเปลี่ยนรูปร่างของเคอร์เซอร์ อย่างไรก็ตามเทอร์มินัลบางตัวแสดงเคอร์เซอร์เดียวกันในทั้งสองโหมด ความคิดของ Xterm เกี่ยวกับเคอร์เซอร์ที่มองเห็นได้น้อยคือการทำให้มันกระพริบ (และสิ่งนี้จะต้องเปิดใช้งานด้วย-bcอาร์กิวเมนต์บรรทัดคำสั่งหรือcursorBlinkทรัพยากร)

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

สำหรับเทอร์มินัลบางตัวคุณสามารถเปลี่ยนสีเคอร์เซอร์ด้วยprint -n '\e]12;pink\a'(ตามชื่อสี) หรือprint -n '\e]12;#abcdef\a'(ตามข้อกำหนด RGB) ลำดับเหล่านี้อธิบายไว้ในเอกสาร xterm ในctlseqsไฟล์; เทอร์มินัลอีมูเลเตอร์สมัยใหม่มักเลียนแบบ xterm แม้ว่าพวกเขาอาจจะไม่รองรับคุณสมบัติทั้งหมดของมัน


ด้วยเหตุผลบางอย่างที่ฉันได้รับmainสำหรับการKEYMAPแทนviinsไม่แน่ใจว่าทำไม
แกรม

1
@Graeme mainเป็นชื่อแทนviinsหรือemacsขึ้นอยู่กับว่าzsh คิดว่าตัวแก้ไขที่คุณชื่นชอบคือ vi หรือไม่เมื่อเริ่มต้น ฉันคิดว่ามันจะใช้viinsเมื่อเปลี่ยนโหมดกลับจากvicmdแต่ดูเหมือนว่าจะใช้mainแทน Updated
Gilles 'หยุดความชั่วร้าย'

1
คุณยังต้องเพิ่มเป็นสองเท่าด้วยzle-line-init(หรือสิ่งอื่นใด) เนื่องจากzle-keymap-selectจะไม่ถูกเรียกถ้ากดปุ่ม Enter เพื่อเปลี่ยนคีย์แมป
แกรม

9

สำหรับผู้ที่มีปัญหาในการใช้ reset-prompt พร้อมกับ multiline prompt สิ่งนี้ใช้ได้กับฉัน: http://zeitlens.com/posts/2014-06-29-howto-zsh-vi-style.htmlร่วมกับhttps: // stackoverflow.com/questions/3622943/zsh-vi-mode-status-lineฉันสิ้นสุดที่ทำ:

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

คุณสามารถลองVimMode


4
ฉันหวังว่าจะมีบางสิ่งที่เชื่อมโยงน้อยลงและอธิบายเพิ่มเติมอีกเล็กน้อย ฉันชอบที่จะรู้ว่าสิ่งต่าง ๆ ทำงานอย่างไร
xenoterracide

1
จริงๆแล้วมันมีทั้งหมด ดูความคิดเห็นฟังก์ชั่นและวิธีการที่พวกเขาจะผูกพันกับเหตุการณ์การเปลี่ยนแปลงโหมด
Martin

5

นี่คือสิ่งที่ฉันใช้เพื่อเปลี่ยนเคอร์เซอร์ระหว่างรูปร่าง 'Block' และ 'Beam' ใน zsh:

(ทดสอบด้วยปลวก , gnome-terminalและmate-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'
}

สิ่งนี้จะทำงานกับเทอร์มินัลและเทอร์มินัลอีมูเลเตอร์ที่เข้าใจ DECSCUSR
JdeBP

1
ฉันชอบสิ่งนี้. ฉันกังวลว่าการเขียน preexec อาจโต้ตอบกับประเพณีอื่น ๆ ดังนั้นฉันจึงปรับเปลี่ยนเล็กน้อยเพื่อใช้add-zsh-hookเช่น: gist.github.com/MatrixManAtYrService/
MatrixManAtYrService

4

อีกวิธีหนึ่งในการเปลี่ยนรูปร่างเคอร์เซอร์ระหว่าง I-beam และ block (สำหรับขีดล่างใช้\033[4 q) ~/.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

ดัดแปลงจากhttps://bbs.archlinux.org/viewtopic.php?id=95078 ทดสอบใน gnome-terminal 3.22


ปรับปรุง

แต่การแก้ปัญหาอีกครั้งเพื่อให้การเปลี่ยนแปลงรูปร่างเคอร์เซอร์สามารถพบได้ที่นี่ เห็นได้ชัดว่าอันนี้ใช้งานได้กับ iTerm2 ซึ่งฉันไม่มีวิธีทดสอบ แต่เพิ่มไว้ที่นี่ในกรณีที่มันมีประโยชน์สำหรับคนอื่น นอกจากนี้สุดท้ายของคุณ~/.zshrcจะเป็น

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
ฉันยืนยันว่าสคริปต์ที่อัปเดตสำหรับ iTerm2 นั้นใช้งานได้จริง
Jason Denney

สคริปต์แรกจะทำงานเฉพาะกับเทอร์มินัลและเทอร์มินัลอีมูเลเตอร์ที่เข้าใจ DECSCUSR
JdeBP

นี่เป็นทางออกที่ยอดเยี่ยมจริงๆที่ไม่ทำให้เปลือกของฉันยุ่งเหยิง
tsturzl

3

ฉันกำลังใช้ Zsh ด้วยธีมรถไฟหัวกระสุน ตามตัวอย่างที่ได้รับจากคำตอบของ Sebastian Blaskฉันลงเอยด้วยรหัสตะโกน

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

สิ่งนี้จะเปลี่ยนค่าเริ่มต้น$เป็นตัวอักษรNเป็นโหมดปกติและฉันจะแทรกโหมด

ภาพนี้เป็นตัวอย่างเมื่ออยู่ในโหมดปกติฉันกดCtrl+ C:

ป้อนคำอธิบายรูปภาพที่นี่


2

ที่นี่ยังอีกรุ่นตามมาจากการโพสต์ของเซบาสเตียน Blask นี่เป็นจุดประสงค์ที่จะไม่เป็นการล่วงล้ำเท่าที่จะทำได้เช่นเดียวกับโซลูชันอื่น ๆ ทั้งหมดที่ฉันสามารถหาได้ใช้บรรทัดพิเศษสถานะทางด้านขวาหรืออักขระที่เพิ่มเข้ามา

สิ่งนี้จะเปลี่ยนสี$จากสีขาวเป็นสีแดงเมื่อเปิดใช้งานโหมดปกติ แก้ไขข้อความที่คุณชอบ

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

รุ่นสำหรับoh-my-zshผู้ใช้

มีปลั๊กอินสำหรับoh-my-zshเรียกvi-modeที่สามารถพบได้ที่นี่:

robbyrussell / โอ้-zsh ของฉัน / ปลั๊กอิน / vi โหมด

ฉันใช้ Antigen เพื่อจัดการปลั๊กอินของฉันดังนั้นการรวมมันก็ง่ายเหมือนการเพิ่มลงในของฉัน.zshrc:

antigen bundle vi-mode

1

zsh-เป็นกลุ่มโหมดปลั๊กอินสามารถแสดงตัวบ่งชี้สำหรับการแทรกคำสั่ง, การค้นหา, แทนที่และโหมดภาพ มันใช้เทคนิคพื้นฐานของคำตอบอื่น ๆ เพื่อขอเกี่ยวกับ hooks ZLE ต่างๆ (zle-keymap-select, zle-isearch-update, ฯลฯ ) มันจะตรวจสอบ[[ $ZLE_STATE = *overwrite* ]]โหมดแทนที่ มันตรวจสอบ$REGION_ACTIVEเพื่อระบุโหมดภาพ

ตรรกะมีความซับซ้อนโดยนิสัยใจคอบางอย่างของวิธี ZSH ยิงเหตุการณ์เมื่อออกจากโหมด isearch

อีกคุณสมบัติที่ดีของโมดูลคือความสามารถในการเปลี่ยนรูปร่างเคอร์เซอร์และสีตามโหมด ตัวอย่างเช่นคุณสามารถใช้แถบแนวตั้งในโหมด INSERT และขีดเส้นใต้กระพริบในโหมด SEARCH


ปลั๊กอินนี้ดีมาก
jdhao
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.