Zastąp serię punktorów z gwiazdką numerowaną listą

16

Wyobraź sobie, że mam następujący tekst:

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

Chcę zastąpić gwiazdki gwiazdkami liczbami, tak jak poniżej:

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

Jak można to zrobić w vimie?

Brennan Vincent
źródło
Dlaczego nie wybierasz wtyczek? Podobny jest increment.vim w Github
SibiCoder 16.04.16
To jest tak niesamowite i fajne, że wszyscy udzielili odpowiedzi, zwiększając liczby, ale skoro Markdown je dla ciebie policzy, dlaczego nie zrobić ich wszystkich 1.? Więc :%s/^* /1. /byłoby to zrobić. To wydaje się znacznie mniej pracy.
pisklęta

Odpowiedzi:

14

Możesz spróbować wykonać następujące polecenie:

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

Najpierw inicjuje zmienną c( let c=0), a następnie wykonuje polecenie globalne, gktóre szuka wzorca ^*(początek linii, a następnie gwiazdka i spacja).

Za każdym razem, gdy zostanie znaleziona linia zawierająca ten wzorzec, polecenie globalne wykonuje polecenie:
let c+=1 | s//\=c.'. '
zwiększa zmienną c( let c+=1), a następnie ( |) zastępuje ( s) poprzednio wyszukiwany wzorzec ( //) oceną wyrażenia ( \=):
zawartość zmiennej cpołączonej ( .) z ciągiem'. '


Jeśli nie chcesz modyfikować wszystkich linii z bufora, ale tylko określony akapit, możesz przekazać zakres do polecenia globalnego. Na przykład, aby zmodyfikować tylko linie, których liczba wynosi od 5 do 10:

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

Jeśli masz plik zawierający kilka podobnych list, które chcesz przekonwertować, na przykład coś takiego:

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                

Możesz to zrobić za pomocą następującego polecenia:

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

Jest to tylko wariant poprzedniego polecenia, które resetuje zmienną cpo przełączeniu na inną listę. Aby wykryć, czy znajdujesz się na innej liście, zmienna dsłuży do przechowywania numeru ostatniego wiersza, w którym dokonano podstawienia.
Komenda globalna porównuje bieżący numer linii ( line('.')) z d+1. Jeśli są takie same, oznacza to, że znajdujemy się na tej samej liście, co poprzednio, więc cjest zwiększana ( c+1), w przeciwnym razie oznacza to, że znajdujemy się na innej liście, więc cjest resetowana ( 1).

Wewnątrz funkcji polecenie let [c,d]=[line('.')==d+1 ? c+1 : 1, line('.')]można przepisać w następujący sposób:

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

Lub tak:

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

Aby zapisać niektóre naciśnięcia klawiszy, możesz również zdefiniować niestandardowe polecenie :NumberedLists, które akceptuje zakres, którego wartością domyślną jest 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.'. '

Kiedy :NumberedListszostanie wykonany <line1>i <line2>zostanie automatycznie zastąpiony użytym zakresem.

Aby przekonwertować wszystkie listy w buforze, wpisz: :NumberedLists

Tylko listy między wierszem 10 a 20: :10,20NumberedLists

Tylko wybór wizualny: :'<,'>NumberedLists


Aby uzyskać więcej informacji, zobacz:

:help :range
:help :global
:help :substitute
:help sub-replace-expression
:help list-identity    (section list unpack)
:help expr1
:help :command
saginaw
źródło
9

Działa to tylko z najnowszą wersją Vima (która ma :h v_g_CTRL-A):

  1. Kostka wybrać kul List ( *) i zastąpić je 0(kursor znajduje się na pierwszej *) Ctrl-v j j r 0.
  2. Wybierz poprzedni blok i przyrost z licznikiem :gv g Ctrl-a

... i to wszystko :)


(Jeśli chcesz mieć kropkę po każdym numerze, zmień 1. krok do: Ctrl-v j j s 0 . Esc)

VanLaser
źródło
9

Wybierz wizualnie linie i wykonaj następujące polecenie podstawiania:

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

Zobacz :help sub-replace-expression, :help line()oraz :help '<.

Aby uniknąć konieczności wybierania linii, można użyć wyszukiwania wstecz i do przodu z przesunięciem w celu określenia zakresu podstawienia w następujący sposób:

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

Widzieć :help cmdline-ranges

djjcast
źródło
2

Inny sposób:

:let n = 1 | g/^* /s//\=printf('%d. ', n)/g | let n = n + 1
Cylian
źródło
0

Możesz także zdefiniować niestandardowe operatory

Możesz zmapować je do kluczowych sekwencji '*i '#. Znaki *i #nie istnieją, więc nie zastąpisz żadnej domyślnej funkcjonalności. Powodem wyboru 'jako prefiksu jest uzyskanie pewnego rodzaju mnemoników. Dodajesz znak / znak przed niektórymi liniami. I zwykle, aby przejść do znaku, używasz prefiksu '.

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>

Działa również z trybu wizualnego.
Polecenia ex są dobre do pisania skryptów, ale do użytku interaktywnego normalny operator jest prawdopodobnie lepszy, ponieważ można go połączyć z dowolnym ruchem lub obiektem tekstowym.

Na przykład możesz przełączyć listę z gwiazdką lub znakiem minus w bieżącym akapicie, naciskając '*ip. Tutaj '*jest operatorem i ipobiektem tekstowym, na którym działa.

I rób to samo dla listy z liczbami w kolejnych 10 wierszach, naciskając '#10j. Tutaj '#jest inny operator i 10jjest to ruch obejmujący linie, na których operator pracuje.

Inną zaletą korzystania z niestandardowego operatora jest to, że możesz powtórzyć swoje ostatnie wydanie za pomocą polecenia kropki.

wprowadź opis zdjęcia tutaj

użytkownik9433424
źródło