User:Ans/vim

From Wikiversity

ระหว่างนั่งไล่ code js ยาวมากๆ ของ web คนอื่น, ก็ได้เขียน comment ลงไปใน code ว่า func ที่ call นี้ code มันอยู่บรรทัดไหน ต้องไปอ่าน code ของ func นี้ที่บรรทัดไหน. ก็เลยอยากหาวิธีที่เลื่อน cursor ไปชี้ที่เลขบรรทัดที่เขียนไว้ใน comment นั้น แล้วกด hot key ให้มันกระโดดไปที่บรรทัดนั้นได้เลย. ใช้ vim ก็สามารถทำเป็น macro ได้ โดยบันทึกคำสั่งเป็น macro ตามนี้้,

  1. กด qg เพื่อเริ่มการบันทึก macro ไว้ใน register g
  2. กด g* เพื่อให้มัน search ตัวเลขที่อยู่ใต้ cursor, มันก็จะเก็บตัวเลขไว้ใน register @/
    1. (หลังกด g* ให้กด ctrl-o ครั้งนึง เพื่อเลื่อน cursor กลับที่เดิม (ไม่ต้องทำก็ได้, ที่ทำก็แค่เพื่อลบ cursor history ที่ไม่จำเป็นออก))
  3. จากนั้นสั่ง :let @l=@/+0 กด enter, เพื่อเก็บตัวเลขใน register @l
  4. เสร็จแล้วกด @lgg เพื่อกระโดดไปบรรทัดตามที่เก็บใน register @l
  5. กด q เพื่อจบการบันทึก macro

เวลาจะใช้ macro นี้ก็เลื่อน cursor ไปบนตัวเลขที่ต้องการ แล้วกด @g มันก็จะกระโดดไปที่เลขบรรทัดตามตัวเลขนั้น --Ans (talk) 07:21, 16 July 2021 (UTC)

ปรับปรุุง version ล่าสุด,

  1. ใช้ func call แทน เพื่อลดจำนวน register ที่ใช้ (ไม่ต้องใช้ @l แล้ว)
  2. match regex ด้วย matchstr() เพื่อตัด case ที่เป็นเลข 0 ออก
  3. กรณีคำแรกใต้ cursor ไม่ใช่ตัวเลข, ก็ใช้ search regex เพื่อหาตัวเลขแรกหลัง cursor นั้นแทน
  4. ทำไมไม่ใช้ search regex อย่างเดียว, จะ search ด้วยคำสั่ง * ด้วยทำไม? เพราะทำยากกรณี cursor อยู่ตรงกลางของตัวเลข เช่น 123[cursor]456. ถอยหลังไป match 123 จะยาก, แต่ถ้าใช้คำสั่ง * มันถอยไป match ให้. แต่คำสั่ง * อย่างเดียวมันอาจ match คำที่ไม่ใช่ตัวเลข ก็เลยต้อง regex match เพิ่มด้วย
let @g='*'.nr2char(15).':call execute("normal ".(matchstr(@/.strpart(getline("."),col(".")-1),''[1-9]\d*''))."gg")'.nr2char(10)

--Ans (talk) 05:28, 19 July 2021 (UTC)

แก้ค่า register @/ ซึ่งเก็บคำค้นล่าสุด ให้เป็นตัวเลขบรรทัดที่เพิ่ง jump, มันจะได้ highlight คำค้นที่เป็นตัวเลขนั้นแทน,

let @g='*'.nr2char(15).':let @/=(matchstr(@/.strpart(getline("."),col(".")-1),"[1-9]\\d*"))|call execute("normal ".@/."gg")|let @/="\\<".@/."\\>"'.nr2char(10)

ตอนหลังเพิ่งรู้ว่ามีคำสั่ง :exe ที่ทำเหมือน func execute() เลยปรับ code และใช้ \n \x0f แทน nr2char() เพื่อให้ code สั้นลง,

let @g="*\x0f:let @/=(matchstr(@/.strpart(getline('.'),col('.')-1),'[1-9]\\d*'))|exe 'norm '.@/.'gg'|let @/='\\<'.@/.'\\>'\n"

--Ans (talk) 13:15, 22 July 2021 (UTC)

use :keepj to preserve jumplist,

let @g="m`*:keepj norm ``\n:let @/=(matchstr(@/.strpart(getline('.'),col('.')-1),'[1-9]\\d*'))|exe 'keepj norm '.@/.'gg'|let @/='\\<'.@/.'\\>'\n"
" place cursor on number of previous line
let @g="m`*:keepj norm ``\n:let @/=(matchstr(@/.strpart(getline('.'),col('.')-1),'[1-9]\\d*'))|exe 'let @/=''\\%'.@/.'l\\<'.line('.').'\\>''|keepj norm '.@/.'gg$n'\n"
" use cursor() to place cursor, instead
let @g="m`*:keepj norm ``\n:let @/=(matchstr(@/.strpart(getline('.'),col('.')-1),'[1-9]\\d*'))\n:call cursor(@/,max([match(getline(@/),'\\<'.line('.').'\\>')+1,1]))\n:let @/='\\<'.@/.'\\>'\n"
" handle when no line number
let @g="m`*:keepj norm ``\n:let @/=(matchstr(@/.strpart(getline('.'),col('.')-1),'[1-9]\\d*'))\n:call cursor(@/,max([match(getline(@/),'\\<'.line('.').'\\>')+1,1]))\n:if @/!=''|let @/='\\<'.@/.'\\>'|el|let @/='\\<'.line('.').'\\>'|en\n"

--Ans (talk) 05:04, 23 July 2021 (UTC)