Побег персонажей во время вставки в VIM - PullRequest
7 голосов
/ 21 апреля 2010

Я копирую материал из выходных буферов в код C ++, над которым я работаю в vim. Часто этот вывод застревает в строках. И было бы неплохо иметь возможность автоматически экранировать все управляющие символы, а не возвращаться назад и вручную редактировать вставленный фрагмент.

В качестве примера я мог бы скопировать что-то вроде этого:

error in file "foo.dat"

И нужно поместить это во что-то вроде этого

std::string expected_error = "error in file \"foo.dat\""

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

UPDATE

Джои Мадзарелли предложил использовать

`[v`]h:%s/\%V"/\\"/g

после пасты.

Поскольку не было дано никакого объяснения тому, что это происходило, и я сначала нашел это немного лаконичным, но трудно объяснить в комментариях, я подумал, что я бы объяснил, что, по моему мнению, здесь происходит:

`[  : Move to start of last paste
v   : Start visual mode
`]  : Move to end of last paste
h   : adjust cursor one position left
:%  : apply on the lines of the selection
s/  : replace
\%V : within the visual area
"   : "
/   : with
\\" : \"
/g  : all occurrences

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

Ответы [ 3 ]

5 голосов
/ 24 апреля 2010

Вот пара функций vimscript, которые должны делать то, что вы хотите.

  • EscapeText() преобразует произвольный текст в C-экранированный эквивалент. Он преобразует перевод строки в \n, табуляцию в \t, Control + G в \a и т. Д. И генерирует восьмеричные экранированные символы (например, \o032) для специальных символов, которые не имеют понятного имени.

  • PasteEscapedRegister() экранирует содержимое регистра, названного v:register, а затем вставляет его в текущий буфер. (Регистр восстанавливается при возврате функции, поэтому функцию можно вызывать повторно без многократного экранирования содержимого регистра.)

Также имеется пара сопоставлений клавиш, которые упрощают интерактивное использование PasteEscapedRegister(). <Leader>P вставляет экранированное содержимое регистра перед позицией курсора, а <Leader>p вставляет после. Оба могут иметь префикс с указанием регистра, например "a\P, чтобы вставить экранированное содержимое регистра a.

Вот код:

function! EscapeText(text)

    let l:escaped_text = a:text

    " Map characters to named C backslash escapes. Normally, single-quoted
    " strings don't require double-backslashing, but these are necessary
    " to make the substitute() call below work properly.
    "
    let l:charmap = {
    \   '"'     : '\\"',
    \   "'"     : '\\''',
    \   "\n"    : '\\n',
    \   "\r"    : '\\r',
    \   "\b"    : '\\b',
    \   "\t"    : '\\t',
    \   "\x07"  : '\\a',
    \   "\x0B"  : '\\v',
    \   "\f"    : '\\f',
    \   }

    " Escape any existing backslashes in the text first, before
    " generating new ones. (Vim dictionaries iterate in arbitrary order,
    " so this step can't be combined with the items() loop below.)
    "
    let l:escaped_text = substitute(l:escaped_text, "\\", '\\\', 'g')

    " Replace actual returns, newlines, tabs, etc., with their escaped
    " representations.
    "
    for [original, escaped] in items(charmap)
        let l:escaped_text = substitute(l:escaped_text, original, escaped, 'g')
    endfor

    " Replace any other character that isn't a letter, number,
    " punctuation, or space with a 3-digit octal escape sequence. (Octal
    " is used instead of hex, since octal escapes terminate after 3
    " digits. C allows hex escapes of any length, so it's possible for
    " them to run up against subsequent characters that might be valid
    " hex digits.)
    "
    let l:escaped_text = substitute(l:escaped_text,
    \   '\([^[:alnum:][:punct:] ]\)',
    \   '\="\\o" . printf("%03o",char2nr(submatch(1)))',
    \   'g')

    return l:escaped_text

endfunction


function! PasteEscapedRegister(where)

    " Remember current register name, contents, and type,
    " so they can be restored once we're done.
    "
    let l:save_reg_name     = v:register
    let l:save_reg_contents = getreg(l:save_reg_name, 1)
    let l:save_reg_type     = getregtype(l:save_reg_name)

    echo "register: [" . l:save_reg_name . "] type: [" . l:save_reg_type . "]"

    " Replace the contents of the register with the escaped text, and set the
    " type to characterwise (so pasting into an existing double-quoted string,
    " for example, will work as expected).
    " 
    call setreg(l:save_reg_name, EscapeText(getreg(l:save_reg_name)), "c")

    " Build the appropriate normal-mode paste command.
    " 
    let l:cmd = 'normal "' . l:save_reg_name . (a:where == "before" ? "P" : "p")

    " Insert the escaped register contents.
    "
    exec l:cmd

    " Restore the register to its original value and type.
    " 
    call setreg(l:save_reg_name, l:save_reg_contents, l:save_reg_type)

endfunction

" Define keymaps to paste escaped text before or after the cursor.
"
nmap <Leader>P :call PasteEscapedRegister("before")<cr>
nmap <Leader>p :call PasteEscapedRegister("after")<cr>
1 голос
/ 23 апреля 2010

Это, по крайней мере, может помочь вам начать ...

После вставки в:

`[v`]h:%s/\%V"/\\"/g

Вы, очевидно, можете сопоставить это с чем-то более простым для ввода.

0 голосов
/ 23 апреля 2010

Хотя решение Joeys выглядит так, что оно может быть расширяемым, чтобы охватить все случаи, в которых я нуждаюсь, я подумал, что поделюсь своим частичным решением, используя интеграцию с vims python (поскольку я больше знаком с python, чем с vim script)

# FILE : tocstring.py
import vim
def setRegister(reg, value):
  vim.command( "let @%s='%s'" % (reg, value.replace("'","''") ) )

def getRegister(reg):
  return vim.eval("@%s" % reg )

def transformChar( map, c):
  if c in map:
    return map[c]
  return c

def transformText( map, text ):
  return ''.join( [ transformChar(map,c) for c in text ] )

cmap={}
cmap["\\"]="\\\\"
cmap["\n"]="\\n" 
cmap["\t"]=r"\\t"
cmap['"']="\\\""

def convertToCString( inregister, outregister ):
  setRegister(outregister, transformText( cmap, getRegister(inregister) ) )

Тогда в моем .vimrc или другом conf-файле я могу поместить

# FILE cpp.vim
python import tocstring
# C-Escape and paste the currently yanked content
nmap <Leader>P :python tocstring.convertToCString("@","z")<CR>"zP
# C-Escape and paste the current visual selection
vmap <Leader>P "zd:python tocstring.convertToCString("z","z")<CR>"zP

Было бы неплохо, если бы я мог сработать первой функцией, чтобы "a \ P вставил преобразованное содержимое регистра" a ", и я предполагаю, что это выполнимо с помощью v: register, но это ускользает от меня.

Версия, которая работает так же, как решение Joeys, может быть обработана как

nmap <Leader>P `[v`]"zd:python tocstring.convertToCString("z","z")<CR>"zP

Подтверждение: используется код из Можно ли получить доступ к регистрам из функций python в vim для взаимодействия с регистрами из vims python

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