Подстановка совпадения с нулевой шириной в скрипте vim - PullRequest
3 голосов
/ 04 августа 2009

Я написал этот скрипт, который заменяет много пробелов вокруг курсора одним пробелом. Это, однако, не работает, когда я использую его без пробелов вокруг курсора. Мне кажется, что Vim не заменяет совпадение с нулевой шириной.

function JustOneSpace()
    let save_cursor = getpos(".")
    let pos = searchpos(' \+', 'bc')
    s/\s*\%#\s*/ /e
    let save_cursor[2] = pos[1] + 1 
    call setpos('.', save_cursor)
endfunction

nmap <space> :call JustOneSpace()<cr>

Вот несколько примеров (труба | - курсор):

Эта строка

hello     |      world

становится

hello |world

Но эта строка

hello wo|rld

не становится

hello wo |rld

Обновление: Изменяя функцию на следующую, она работает для приведенных выше примеров.

function JustOneSpace()
    let save_cursor = getpos(".")
    let pos = searchpos(' *', 'bc')
    s/\s*\%#\s*/ /e
    let save_cursor[2] = pos[1] + 1 
    call setpos('.', save_cursor)
endfunction

Эта строка

hello |world

становится

hello w|orld

Проблема в том, что курсоры перемещаются к следующему символу. Стоит на том же месте.

Какие-нибудь указатели и / или советы?

Ответы [ 4 ]

4 голосов
/ 04 августа 2009

Я думаю, что единственная проблема с вашим сценарием в том, что сохранение позиции кажется неправильным. По сути, вы можете делать то, что пытаетесь сделать:

:s/\s*\%#\s*/ /e

, что соответствует (правильному) коду в вашем вопросе. Вы можете просто сопоставить это с:

:nmap <space> :s/\s*\%#\s*/ /e<CR>

Если вы хотите сохранить позицию, все становится немного сложнее. Вероятно, лучше всего использовать что-то вроде этого:

function! JustOneSpace()
    " Get the current contents of the current line
    let current_line = getline(".")
    " Get the current cursor position
    let cursor_position = getpos(".")
    " Generate a match using the column number of the current cursor position
    let matchRE = '\(\s*\)\%' . cursor_position[2] . 'c\s*'
    " Find the number of spaces that precede the cursor
    let isolate_preceding_spacesRE = '^.\{-}' . matchRE . '.*$'
    let preceding_spaces = substitute(current_line, isolate_preceding_spacesRE, '\1', "")
    " Modify the line by replacing with one space
    let modified_line = substitute(current_line, matchRE, " ", "")
    " Modify the cursor position to handle the change in string length
    let cursor_position[2] -= len(preceding_spaces) - 1
    " Set the line in the window
    call setline(".", modified_line)
    " Reset the cursor position
    call setpos(".", cursor_position)
endfunction

В основном это комментарии, но главное, что вы смотрите на длину строки до и после замены и соответственно выбираете новую позицию курсора. Вы можете сделать это с помощью вашего метода, сравнив len(getline(".")) до и после, если хотите.

Редактировать

Если вы хотите, чтобы курсор заканчивался после пробела, измените строку:

    let cursor_position[2] -= len(current_line) - len(modified_line)

такой, что выглядит так:

    let cursor_position[2] -= (len(current_line) - len(modified_line)) - 1

Редактировать (2)

Я изменил скрипт выше, чтобы учесть ваши комментарии так, чтобы позиция курсора корректировалась только на количество пробелов перед позицией курсора. Это делается путем создания второго регулярного выражения, которое извлекает из строки пробелы, предшествующие курсору (и ничего больше), а затем корректирует положение курсора по количеству пробелов.

3 голосов
/ 04 августа 2009

Я не использую vim, но если вы хотите найти ноль или более пробелов, разве вы не должны использовать ' *' вместо ' \+'?

РЕДАКТИРОВАТЬ: проблема позиционирования курсора: сейчас вы устанавливаете позицию в начале пробела перед заменой, затем перемещаете ее на одну позицию вперед, чтобы она была после пробела. Попробуйте вместо этого установить end матча, например:

search(' *', 'bce')

Таким образом, любые добавления или удаления будут происходить до позиции курсора. В большинстве редакторов положение курсора автоматически перемещается для отслеживания таких изменений. Вам не нужно делать что-то из этого getpos / setpos.

0 голосов
/ 08 апреля 2011

Этот простой, который я использую, делает почти то же самое:

nnoremap <leader>6 d/\S<CR>

Поместите курсор туда, где вы хотите удалить пробелы, и он удалит все пробелы после курсора и следующего текста.

0 голосов
/ 05 августа 2009

Эта функция основана на Al 's answer .

function JustOneSpace()
    " Get the current contents of the current line
    let current_line = getline(".")

    " Get the current cursor position
    let cursor_position = getpos(".")

    " Generate a match using the column number of the current cursor position
    let matchre = '\s*\%' . cursor_position[2] . 'c\s*'
    let pos = match(current_line, matchre) + 2

    " Modify the line by replacing with one space
    let modified_line = substitute(current_line, matchre, " ", "")

    " Modify the cursor position to handle the change in string length
    let cursor_position[2] = pos

    " Set the line in the window
    call setline(".", modified_line)
    " Reset the cursor position
    call setpos(".", cursor_position)
endfunction

Вместо этого, используя разницу между обычной и измененной строками, я нахожу позицию первого пробела, которая будет соответствовать регулярному выражению подстановки. Затем я устанавливаю позицию курсора в эту позицию + 1.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...