Замініть серію точок кулі зірочок нумерованим списком


16

Уявіть, у мене є такий текст:

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

Я хочу замінити позначення зірочок цифрами на зразок:

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

Як це можна зробити в vim?


Чому ви не підете на плагіни? Схожий є increment.vim у Github
SibiCoder

Це настільки дивовижно і класно, що всі свої відповіді збільшували цифри, але оскільки Маркдаун пронумерує їх для вас, чому б просто не зробити їх усі 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

... і це все :)


(Якщо ви хочете мати крапку після кожного числа, змініть перший крок на 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є текстовим об'єктом, над яким він працює.

І те ж саме зробіть для списку з префіксом цифр у наступних 10 рядках, натискаючи '#10j. Тут '#є ще один оператор і 10jце рух, що охоплює лінії, над якими працює оператор.

Інша перевага використання користувацького оператора полягає в тому, що ви можете повторити останнє видання за допомогою команди dot.

введіть тут опис зображення

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.