egorius: (Default)
egorius ([personal profile] egorius) wrote2009-11-21 03:15 pm

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)

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

[identity profile] hardsign.livejournal.com 2009-11-21 08:21 pm (UTC)(link)
Хм, оно¤ того® точно стóит?

[identity profile] egorius.livejournal.com 2009-11-22 09:23 am (UTC)(link)
А чёрт его знает. Но мне нравится.
Вот ещё приделаю свою оракловую приблубу, и будет полное щастье.