?

Log in

No account? Create an account

Сб, 21 ноя, 2009, 15:15
Vim: удалить и вставить

Одна из сил vimа в том, что называется {motion}, то есть некое движение. Например, нажимая w, я перемещаюсь к началу следующего слова. А 3w перескочит к началу третьего слова. Ну, этим никого не удивишь: в обычном редакторе можно нажать Ctrl и стрелку вправо. Три раза.

Ну а как насчет такого: нажимая %, я двигаюсь от открывающей круглой скобке к соответствующей закрывающей, и наоборот. В обычном редакторе придётся искать закрывающую скобку глазами, ничего не поделаешь. А потом к ней ползти.

Но основная сила в том, что {motion} может комбинироваться с операторами. Если я жму yw, то оператор y (yank = copy) копирует текст от сих и до начала следующего слова. А если y% (например, на вызове функции), то от сих и до закрывающей круглой скобки (то есть весь вызов целиком, вместе со всеми вложенными скобками). А если yi" (i = inner), находясь где-нибудь внутри строки, ограниченной кавычками, то всё содержимое этой строки. Ну и так далее.

Идём дальше. Допустим, есть такой код:

if (check_err(errhp, OCIParamGet(stmtp, OCI_HTYPE_STMT, errhp, (dvoid**)&parmp, i) )) {

И захотел я заменить в нём выделенный вызов функции на другой, который предварительно скопировал (с помощью %, конечно). Встав на начало вызова (в начале строки для этого достаточно fO, что переместит нас к первой букве O), приходится сначала удалить ненужный вызов: d% (d = delete), а затем вставить скопированное. Но поскольку d сам по себе копирует удалённое (то есть работает как cut), то скопированное ранее надо извлечь из специального регистра "0: "0P (P = put, то есть paste).

Посчитаем нажатия: d%"0P, 5 штук. Много. Хочется такой оператор, чтобы удалял {motion} и сразу вставлял на его место скопированный текст. А такого почему-то нет. Хотя подобную операцию приходится проделывать довольно часто.

К счастью, у нас есть help :map-operator, а в хелпе есть прекрасные примеры, с помощью которых можно шаманить, даже не до конца всё понимая. В итоге рисуется такая функция:

function! PutInstead(type, ...)
  let sel_save = &selection
  let &selection = "inclusive"

  if a:0
    silent exe "normal! `<" . a:type . "`>d\"0P"
  elseif a:type == 'line'
    silent exe "normal! '[V']d\"0P"
  elseif a:type == 'block'
    silent exe "normal! `[\<C-V>`]d\"0P"
  else
    silent exe "normal! `[v`]d\"0P"
  endif

  let &selection = sel_save
endfunction

Она маппится на запятую:

nmap <silent> , :set opfunc=PutInsteadg@
vmap <silent> , :<C-U>call PutInstead(visualmode(), 1)

После этого вся процедура требует двух нажатий: ,%. Почему запятая? Ну просто все клавиши уже напичканы функциями, а запятая среди них самая ненужная.

Сб, 21 ноя, 2009 17:09 (UTC)
pigdeon

А где "P.S. Этот пост был набран в редакторе vim?"

Вс, 22 ноя, 2009 09:21 (UTC)
egorius

P.S. Этот пост был набран в веб-интерфейсе ЖЖ.
P.P.S. Этот код был набран в редакторе vim.

Сб, 21 ноя, 2009 20:21 (UTC)
hardsign

Хм, оно¤ того® точно стóит?

Вс, 22 ноя, 2009 09:23 (UTC)
egorius

А чёрт его знает. Но мне нравится.
Вот ещё приделаю свою оракловую приблубу, и будет полное щастье.

Ср, 30 дек, 2009 22:58 (UTC)
_pk_sly

хе ;)
в vim есть режим visual select, активируется кнопочкой v
можно в нём выбрать фрагмент и нажать p, произойдёт именно замена ;)
к сожалению, регистр загадится выделенным куском, но дальше можно и спользовать 0p и т.д.

насчёт выделения - попробуй команды:
iw ow
iW oW
i) o)
i] o]
i" o"

Пт, 1 янв, 2010 19:03 (UTC)
egorius

Насчёт visual — это мысль, спасибо! Хотя мой вариант мне всё-таки больше нравится :)