แทนที่ชุดสัญลักษณ์แสดงหัวข้อย่อยของเครื่องหมายดอกจันด้วยรายการหมายเลข


16

ลองนึกภาพฉันมีข้อความต่อไปนี้:

some random stuff
* asdf
* foo
* bar
some other random stuff

ฉันต้องการแทนที่สัญลักษณ์ดอกจันด้วยตัวเลขเช่น:

some random stuff
1. asdf
2. foo
3. bar
some other random stuff

สิ่งนี้สามารถทำได้ในกลุ่ม?


ทำไมคุณไม่ลองปลั๊กอิน สิ่งที่คล้ายกันคือ increment.vim ใน Github
SibiCoder

มันยอดเยี่ยมมากและยอดเยี่ยมที่ทุกคนตอบคำถามของพวกเขาเพิ่มจำนวน แต่เนื่องจาก Markdown จะให้หมายเลขพวกเขาสำหรับคุณทำไมไม่เพียง แต่ทำให้พวกเขาทั้งหมด1.? ดังนั้น:%s/^* /1. /จะทำมัน ดูเหมือนว่าจะทำงานน้อยลง
ลูกไก่

คำตอบ:


14

คุณสามารถลองคำสั่งต่อไปนี้:

:let c=0 | g/^* /let c+=1 | s//\=c.'. '

ก่อนอื่นมันจะเริ่มต้นตัวแปรc( let c=0) จากนั้นมันจะรันคำสั่งโกลบอลgซึ่งมองหารูปแบบ^*(จุดเริ่มต้นของบรรทัดตามด้วยเครื่องหมายดอกจันและเว้นวรรค)

เมื่อใดก็ตามที่พบบรรทัดที่มีรูปแบบนี้คำสั่งโกลบอลจะเรียกใช้งานคำสั่ง:
let c+=1 | s//\=c.'. '
เพิ่มค่าของตัวแปรc( let c+=1) จากนั้น ( |) แทนที่ด้วย ( s) รูปแบบการค้นหาก่อนหน้า ( //) ด้วยการประเมินผลของนิพจน์ ( \=):
เนื้อหาของตัวแปรที่cต่อกัน ( .) ด้วยสตริง'. '


หากคุณไม่ต้องการแก้ไขบรรทัดทั้งหมดจากบัฟเฟอร์ แต่เฉพาะย่อหน้าที่เฉพาะเจาะจงคุณสามารถส่งช่วงไปยังคำสั่งโกลบอลได้ ตัวอย่างเช่นหากต้องการแก้ไขเฉพาะบรรทัดที่มีหมายเลขอยู่ระหว่าง 5 ถึง 10:

:let c=0 | 5,10g/^* /let c+=1 | s//\=c.'. '

หากคุณมีไฟล์ที่มีรายการที่คล้ายกันหลายรายการซึ่งคุณต้องการแปลงตัวอย่างเช่นสิ่งนี้:

some random stuff                 some random stuff                      
* foo                             1. foo                                 
* bar                             2. bar                                 
* baz                             3. baz                                 
some other random stuff           some other random stuff                
                           ==>                                                
some random stuff                 some random stuff                      
* foo                             1. foo                                 
* bar                             2. bar                                 
* baz                             3. baz                                 
* qux                             4. qux                                 
some other random stuff           some other random stuff                

คุณสามารถทำได้ด้วยคำสั่งต่อไปนี้:

:let [c,d]=[0,0] | g/^* /let [c,d]=[line('.')==d+1 ? c+1 : 1, line('.')] | s//\=c.'. '

มันเป็นเพียงตัวแปรของคำสั่งก่อนหน้าซึ่งจะรีเซ็ตตัวแปรcเมื่อคุณเปลี่ยนเป็นรายการอื่น เพื่อตรวจสอบว่าคุณอยู่ในรายการอื่นหรือไม่ตัวแปรdจะถูกใช้เพื่อเก็บหมายเลขของบรรทัดสุดท้ายที่มีการแทนที่
คำสั่งเปรียบเทียบระดับโลกจำนวนบรรทัดปัจจุบัน ( line('.')) d+1ด้วย หากพวกเขาเหมือนกันก็หมายความว่าเราอยู่ในรายการเดียวกันเหมือนก่อนที่cจะเพิ่มขึ้น ( c+1) มิฉะนั้นก็หมายความว่าเราอยู่ในรายการที่แตกต่างกันดังนั้นจึงcถูกรีเซ็ต ( 1)

ภายในฟังก์ชั่นคำสั่งlet [c,d]=[line('.')==d+1 ? c+1 : 1, line('.')]สามารถเขียนใหม่ได้เช่นนี้

let c = line('.') == d+1 ? c+1 : 1
let d = line('.')

หรือเช่นนี้

if line('.') == d+1
    let c = c+1
else
    let c = 1
endif
let d = line('.')

ในการบันทึกการกดแป้นบางตัวคุณสามารถกำหนดคำสั่งที่กำหนดเอง:NumberedListsซึ่งยอมรับช่วงที่ค่าเริ่มต้นคือ1,$( -range=%):

command! -range=% NumberedLists let [c,d]=[0,0] | <line1>,<line2>g/^* /let [c,d]=[line('.')==d+1 ? c+1 : 1, line('.')] | s//\=c.'. '

เมื่อ:NumberedListsใดจะถูกดำเนินการ<line1>และ<line2>จะถูกแทนที่โดยอัตโนมัติด้วยช่วงที่คุณใช้

ดังนั้นหากต้องการแปลงรายการทั้งหมดในบัฟเฟอร์คุณจะต้องพิมพ์: :NumberedLists

เฉพาะรายการระหว่างบรรทัด 10 และ 20: :10,20NumberedLists

เฉพาะการเลือกภาพ: :'<,'>NumberedLists


สำหรับข้อมูลเพิ่มเติมดู:

:help :range
:help :global
:help :substitute
:help sub-replace-expression
:help list-identity    (section list unpack)
:help expr1
:help :command

9

ใช้งานได้เฉพาะกับ Vim เวอร์ชันล่าสุด (ที่มี:h v_g_CTRL-A):

  1. บล็อกเลือกกระสุนรายการ ( *) และแทนที่ด้วย0(เคอร์เซอร์เป็นครั้งแรก):* Ctrl-v j j r 0
  2. เลือกบล็อกก่อนหน้าและเพิ่มด้วยตัวนับซ้ำ :gv g Ctrl-a

... และนั่นคือมัน :)


(ถ้าคุณต้องการที่จะมีจุดหลังจากที่แต่ละหมายเลขเปลี่ยนขั้นตอนที่ 1: Ctrl-v j j s 0 . Esc)


9

มองเห็นเส้นและเรียกใช้คำสั่งการแทนที่นี้ด้วยสายตา:

:'<,'>s/*/\=line('.') - line("'<") + 1 . '.'

ดู:help sub-replace-expression, และ:help line():help '<

เพื่อหลีกเลี่ยงการเลือกบรรทัดคุณสามารถใช้การค้นหาย้อนหลังและไปข้างหน้าด้วยออฟเซ็ตเพื่อระบุช่วงการทดแทนดังนี้:

:?^[^*]?+1,/^[^*]/-1s/*/\=line('.') - search('^[^[:digit:]]', 'bn') . '.'

ดู :help cmdline-ranges



0

คุณสามารถกำหนดโอเปอเรเตอร์ที่กำหนดเองได้

คุณสามารถแม็พกับลำดับที่สำคัญและ'* '#เครื่องหมาย*และ#ไม่มีอยู่ดังนั้นคุณจะไม่แทนที่ฟังก์ชันการทำงานเริ่มต้นใด ๆ เหตุผลที่เลือก'เป็นคำนำหน้าคือเพื่อให้ได้ความจำบางอย่าง คุณกำลังเพิ่มเครื่องหมาย / เครื่องหมายไว้ข้างหน้าบางบรรทัด 'และมักจะไปทำเครื่องหมายที่คุณใช้คำนำหน้า

fu! s:op_list_bullet(...) abort range

    if a:0
        let [lnum1, lnum2] = [line("'["), line("']")]
    else
        let [lnum1, lnum2] = [line("'<"), line("'>")]
    endif

    if !empty(matchstr(getline(lnum1), '^\s*\d\s*\.'))
        let pattern     = '\d\s*\.\s\?'
        let replacement = '* '

    elseif count(['-', '*'], matchstr(getline(lnum1), '\S'))
        let pattern     = '\v\S\s*'
        let replacement = ''

    else
        let pattern     = '\v\ze\S'
        let replacement = '* '
    endif

    let cmd = 'keepj keepp %s,%s s/%s/%s'

    sil exe printf(cmd, lnum1, lnum2, pattern, replacement)
endfu

fu! s:op_list_digit(...) abort range
    let l:c = 0

    if a:0
        let [lnum1, lnum2] = [line("'["), line("']")]
    else
        let [lnum1, lnum2] = [a:firstline, a:lastline]
    endif

    if count(['-', '*'], matchstr(getline(lnum1), '\S'))
        let pattern     = '\S\s*'
        let replacement = '\=l:c.". "'

    elseif !empty(matchstr(getline(lnum1), '^\s*\d\s*\.'))
        let pattern     = '\d\s*\.\s\?'
        let replacement = ''

    else
        let pattern     = '\v^\s*\zs\ze\S'
        let replacement = '\=l:c.". "'
    endif

    let cmd = 'keepj keepp %s,%s g/%s/let l:c = line(".") == line("'']")+1 ?
                                                \ l:c+1 : 1 |
                                                \ keepj keepp s/%s/%s'

    sil exe printf(cmd, lnum1, lnum2, pattern, pattern, replacement)
endfu

nno <silent> '*     :<C-U>set opfunc=<SID>op_list_bullet<CR>g@
nno <silent> '**    :<C-U>set opfunc=<SID>op_list_bullet
                    \<Bar>exe 'norm! ' . v:count1 . 'g@_'<CR>
xno <silent> '*     :call <SID>op_list_bullet()<CR>

nno <silent> '#     :<C-U>set opfunc=<SID>op_list_digit<CR>g@
nno <silent> '##    :<C-U>set opfunc=<SID>op_list_digit
                    \<Bar>exe 'norm! ' . v:count1 . 'g@_'<CR>
xno <silent> '#     :call <SID>op_list_digit()<CR>

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

'*ipตัวอย่างเช่นคุณสามารถสลับรายการนำหน้าด้วยเครื่องหมายดอกจันหรือเครื่องหมายลบภายในวรรคปัจจุบันโดยการกดปุ่ม นี่'*คือโอเปอเรเตอร์และipเป็น text-object ที่ใช้งานได้

และทำสิ่งเดียวกันสำหรับรายการนำหน้าด้วยตัวเลขใน 10 '#10jบรรทัดถัดไปโดยการกดปุ่ม นี่'#คือโอเปอเรเตอร์อื่นและ10jเป็นภาพเคลื่อนไหวที่ครอบคลุมบรรทัดที่โอเปอเรเตอร์ทำงาน

ประโยชน์อื่น ๆ ของการใช้ตัวดำเนินการแบบกำหนดเองคือคุณสามารถทำซ้ำฉบับล่าสุดด้วยคำสั่ง dot

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

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