ฉันจะทำให้โหมด vi ของ zsh ทำงานเหมือนโหมด vi ของ bash ได้อย่างไร


24

ฉันชอบความเร็วทั่วไปของ zsh มาก แต่สองสิ่งที่ทำให้ฉันรำคาญ

  1. ผมต้องตีรอสักครู่ระหว่างการกดปุ่มหลบหนีและกดทับที่จะได้รับการค้นหาประวัติศาสตร์ (ถ้ามันตีเฉือนเร็วเกินไปที่จะกล่าวว่าzsh: do you wish to see all 514 possibilities (172 lines))
  2. หลังจากเข้าสู่โหมดแทรกเนื่องจากมีการกดปุ่มaหรือAฉันไม่สามารถถอยถอยหลังผ่านจุดที่ฉันเข้าสู่โหมดแทรกได้

ฉันรู้ว่า 2 เหมือนคลาสสิค vi แต่ฉันชอบสไตล์ที่ดีกว่า


หากทุกคนกำลังประสบปัญหาการหลบหนีซ้ำซ้อนที่น่ารำคาญอย่างมากซึ่งทำให้คุณต้องกดiสองครั้งเพื่อกลับไปที่โหมดแทรกฉันจะขอแนะนำการแก้ไขนี้ !
cchamberlain

นอกจากนี้ยังมีบทสรุปที่ดีที่นี่: dougblack.io/words/zsh-vi-mode.html
jackcogdill

คำตอบ:


22

(1) ด้วยเหตุผลบางอย่างผิดปกติพฤติกรรม bindkey เมื่อมันมาถึง "/": <esc>อย่างรวดเร็วตามถูกตีความว่าเป็น/ <esc-/>(ฉันสังเกตพฤติกรรมนี้เมื่อวันก่อนไม่แน่ใจว่าอะไรเป็นสาเหตุ) ฉันไม่รู้ว่านี่เป็นข้อผิดพลาดหรือคุณลักษณะและหากเป็นคุณลักษณะที่สามารถปิดใช้งานได้ แต่คุณสามารถแก้ไขได้อย่างง่ายดาย .

คำสั่งผสมคีย์นี้อาจถูกผูกไว้กับ_history-complete-olderซึ่งกำลังสร้างผลลัพธ์ที่ไม่พึงประสงค์ - คุณสามารถใช้bindkey -Lเพื่อดูว่าเป็นกรณีนี้หรือไม่

ในอัตราใด ๆ ถ้าคุณไม่คิดเสียสละที่เกิดขึ้นจริง <esc-/> (กดเข้าด้วยกันเป็นคอร์ด) ผูกพันคุณสามารถ re-ผูกกับ VI-โหมดคำสั่งประวัติการค้นหาเพื่อการพิมพ์ที่<esc>ตามมา/จะเป็นสิ่งเดียวกันที่พิมพ์ใด ๆ ความเร็ว. =)

เนื่องจากสิ่งนี้จะได้รับการปฏิบัติเหมือนเป็นคอร์ดมันจะไม่มีผลต่อการเข้าสู่โหมดคำสั่งแรกของ vi ดังนั้นเราจะต้องตรวจสอบให้แน่ใจก่อนว่าเกิดขึ้นก่อน ก่อนอื่นคุณต้องกำหนดฟังก์ชั่น วางไว้ที่อื่นในของคุณfpathถ้าคุณใช้หรือใส่ไว้ใน. zshrc ของคุณ

vi-search-fix() {
zle vi-cmd-mode
zle .vi-history-search-backward
}

ส่วนที่เหลือไปใน. zshrc ของคุณด้วยวิธีใดวิธีหนึ่ง:

autoload vi-search-fix
zle -N vi-search-fix
bindkey -M viins '\e/' vi-search-fix

ควรจะไปดี

(2) คุณสามารถแก้ไขคีย์ backspace ได้ดังนี้:

`bindkey "^?" backward-delete-char`

นอกจากนี้หากคุณต้องการพฤติกรรมที่คล้ายกันสำหรับคำสั่งสไตล์ vi อื่น ๆ :

bindkey "^W" backward-kill-word 
bindkey "^H" backward-delete-char      # Control-h also deletes the previous char
bindkey "^U" backward-kill-line            

มัน^[/ไม่ได้อยู่ภายใต้\e/แต่มีทั้งสองวิธีที่ถูกต้องในการพูดว่าหลบหนี การเปลี่ยนแปลงทำงานได้อย่างสมบูรณ์แบบ ตอนนี้ฉันกำลังเล่นกับมันอย่างสมบูรณ์ยิ่งขึ้นดูเหมือนว่าโหมด vi ของ zsh จะแย่เมื่อเทียบกับทุบตี (หรืออย่างน้อยก็ไม่ได้กำหนดค่าโดยสมบูรณ์) ตัวอย่างหนึ่งคือความจริงที่ว่ามันทำให้คุณเข้าสู่โหมดแทรกหลังจากประวัติการค้นหา ฉันต้องกลับไปที่โหมดคำสั่งเพื่อกด n เพื่อค้นหารายการค้นหาถัดไป
Chas Owens

1
ดีฉันไม่ทราบว่าคุณมีตัวอย่างอื่น ๆ แต่คนที่คุณพูดถึงเป็นความผิดของฉันไม่ใช่ของ zsh =) สิ่งที่เกิดขึ้นคือฉันได้ผูกคำสั่งแก้ไขโหมด vi-cmd ในโหมดแทรก vi - คำสั่งคาดว่าเชลล์จะอยู่ในโหมด cmd แล้วและทำงานตามนั้น เราจำเป็นต้องเขียนคำสั่งแก้ไขซึ่งเป็นครั้งแรกเรียกว่า "คำสั่งเข้าสู่โหมด cmd" และแล้ว.vi-history-search-backwardรัน ฉันจะเขียนและแก้ไขคำตอบของฉัน - ตรวจสอบอีกครั้งในวันนี้
Marshall Eubanks

ตกลงฉันอัปเดตคำตอบของฉัน ลองดู
Marshall Eubanks

ด้วยการไปถึง (2) เมื่อฉันทำbindkey | grep <searchterm>สำหรับเงื่อนไขใด ๆ vi-ที่พวกเขากำลังทั้งหมดที่นำหน้าด้วย ฉันจำเป็นต้องตั้งค่าbindkeyคำสั่งที่ไม่ได้ขึ้นต้นด้วยvi-หรือไม่?
adam_0

1
ขอขอบคุณ. แฮ็กเหล่านี้ (และของ wjv ด้านล่างเช่นกัน) ทำให้โหมด vi ของ zsh เปลี่ยนจากการใช้งานไม่ได้ไปเป็นเลิศ ฉันสร้างบัญชีผู้ใช้ขั้นสูงเพื่อให้ฉันสามารถลงคะแนนคุณได้ :-)
ctrueden

14

ฉันกำลังจะตอบคำถามเท่านั้น (1)

ปัญหาของคุณคือ KEYTIMEOUT ฉันพูดจาก zshzle (1):

เมื่อ ZLE กำลังอ่านคำสั่งจากเทอร์มินัลมันอาจอ่านลำดับที่ถูกผูกไว้กับบางคำสั่งและยังเป็นคำนำหน้าของสตริงที่ถูกผูกไว้อีกต่อไป ในกรณีนี้ ZLE จะรอสักครู่เพื่อดูว่ามีการพิมพ์อักขระเพิ่มเติมหรือไม่และ (หรือไม่ตรงกับสตริงอื่น ๆ ) จะดำเนินการเชื่อมโยง การหมดเวลานี้กำหนดโดยพารามิเตอร์ KEYTIMEOUT ค่าเริ่มต้นคือ 0.4 วินาที ไม่มีการหมดเวลาหากสตริงส่วนนำหน้าไม่ถูกผูกเข้ากับคำสั่ง

นั่นคือความล่าช้าที่คุณประสบหลังจากกดปุ่ม ESC 0.4 วินาที การแก้ไขคือการตั้งค่า KEYTIMEOUT ลงไปที่ 0.01s ในหนึ่งในไฟล์เริ่มต้นเชลล์:

export KEYTIMEOUT=1

น่าเสียดายที่สิ่งนี้มีผลกระทบแบบน็อคออน: สิ่งอื่น ๆ เริ่มผิดพลาด ...

ประการแรกตอนนี้มีปัญหาในโหมดคำสั่ง vi: การพิมพ์ ESC ทำให้เคอร์เซอร์ค้างและจากนั้นอักขระใดก็ตามที่คุณพิมพ์ต่อไปจะถูกกลืน นี่เป็นเพราะ ESC ไม่ได้ถูกผูกไว้กับสิ่งใดโดยปริยายในโหมดคำสั่ง vi แต่มีวิดเจ็ตหลายตัวที่ขึ้นต้นด้วย ESC (ปุ่มลูกศร!) ดังนั้นเมื่อคุณกดปุ่ม ESC ZLE จะรอตัวละครตัวต่อไปแล้วกินมัน

การแก้ไขคือการผูก ESC กับบางสิ่งในโหมดคำสั่งดังนั้นจึงมั่นใจได้ว่าสิ่งที่ได้รับผ่านไปยัง ZLE หลังจาก $ KEYTIMEOUT centiseconds ตอนนี้เราสามารถทำการผูกให้เริ่มต้นด้วย ESC ในโหมดคำสั่งโดยไม่มีผลกระทบที่เลวร้ายเหล่านี้ ฉันผูก ESC กับตัวละครระฆังซึ่งฉันคิดว่าน่ารำคาญน้อยกว่าการใส่ตัวเอง (และกระสุนของฉันเงียบ):

bindkey -sM vicmd '^[' '^G'

อัปเดต 2017:

ฉันได้พบวิธีที่ดียิ่งขึ้นสำหรับการผูก ESC - undefined-keyวิดเจ็ต ฉันไม่แน่ใจว่าวิดเจ็ตนี้มีให้ใน zsh หรือไม่เมื่อฉันเขียนคำตอบนี้

bindkey -M vicmd '^[' undefined-key

ปัญหาถัดไป: โดยปกติแล้ววิดเจ็ตสองปุ่มบางตัวจะเริ่มใน ^ X ในโหมดแทรก vi สิ่งเหล่านี้ใช้ไม่ได้หาก $ KEYTIMEOUT ตั้งค่าจนสุด สิ่งที่ฉันทำคือยกเลิกการผูก ^ X ในโหมดแทรก vi (มันแทรกตัวเองตามค่าเริ่มต้น); สิ่งนี้อนุญาตให้วิดเจ็ตสองคีย์เหล่านั้นทำงานต่อไปได้

bindkey -rM viins '^X'

คุณสูญเสียการผูกสำหรับการแทรกตัวเอง แต่คุณสามารถผูกไว้กับสิ่งอื่นได้แน่นอน (ฉันไม่ได้เนื่องจากฉันไม่ได้ใช้มัน)

ปัญหาล่าสุด (ฉันได้พบจนถึง): มีการผูกคีย์เริ่มต้นที่เหลืออยู่ที่เรา "เสีย" เนื่องจากการตั้งค่า $ KEYTIMEOUT ขวาลงเพื่อปัญญา: ผู้ที่เริ่มต้นด้วย ESC ในโหมดแทรก vi ซึ่งไม่ใช่ปุ่มเคอร์เซอร์ โดยส่วนตัวแล้วพวกเขาจะเริ่มต้นด้วย ^ X แทน:

bindkey -M viins '^X,' _history-complete-newer \
                 '^X/' _history-complete-older \
                 '^X`' _bash_complete-word

อัปเดต 2018:

ปรากฎว่าส่วนทั้งหมดข้างต้น (หลังจาก“ อัปเดต 2017”) ไม่จำเป็นต้องมี เป็นไปได้ที่จะตั้งค่าปุ่ม META ให้เทียบเท่ากับ ESC ในการจับคู่แป้นพิมพ์โดยใช้:

bindkey -mv

ดังนั้นจึงเป็นไปไม่ได้จะยกเลิกการผูก ^ X และเข้าถึงการเชื่อมโยงคีย์ที่เริ่มต้นใน ESC โดยการกด META ในฐานะผู้นำแทน (ALT หรือ OPT บนแป้นพิมพ์ที่ทันสมัย)

หากคุณมีสิทธิ์เข้าถึงหนังสือจาก Bash ถึง Z Shellโดย Kiddle et al. ความสมดุลของ ESC และ META ใน keybindings ถูกกล่าวถึงในบทที่ 4 แถบด้านข้างในหน้า 78–79


ขอขอบคุณ. แฮ็กเหล่านี้ (และของ marshaul ด้านบนด้วย) ทำให้โหมด vi ของ zsh เปลี่ยนจากใกล้เข้าไม่ได้เป็นเลิศ ฉันสร้างบัญชีผู้ใช้ขั้นสูงเพื่อให้ฉันสามารถลงคะแนนคุณได้ :-)
ctrueden

1
ขอบคุณ! ฉันคิดว่ามันน่ากังวลนิดหน่อยว่าหลังจากนี้เรายังคงต้องการแฮ็คและวิธีแก้ปัญหาเพื่อให้ฟังก์ชัน zsh บิตใช้งานได้!
wjv
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.