2010-04-21 44 views
6

Copio cosas de los almacenamientos intermedios de salida en el código de C++ en el que estoy trabajando en vim. A menudo, esta salida se atasca en cadenas. Y sería bueno poder escapar de todos los personajes de control automáticamente en lugar de retroceder y editar manualmente el fragmento pegado.Escape de caracteres durante pegar en vim

Como ejemplo podría copiar algo como esto:

error in file "foo.dat" 

y la necesidad de ponerlo en algo como esto

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

estoy pensando que podría ser posible aplicar una función de reemplazar al cuerpo de la última pasta usando las marcas de inicio y fin de la última pasta, pero no estoy seguro de cómo hacerlo volar.

ACTUALIZACIÓN:

Joey Mazzarelli sugested usando

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

después de una pasta.

Puesto que ninguna explicación fue dada por lo que estaba pasando y al principio pareció un poco escueta, pero difícil de explicar en los comentarios que pensé que había puesto una explicación de lo que creo que hace aquí:

`[ : 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 

Esto parece un buen enfoque, pero solo maneja el carácter único ", me gustaría que maneje líneas nuevas, pestañas y otras cosas que podrían esperarse que caigan en el texto. (Probablemente no sea unicode general) Entiendo que puede no haber sido claro en la definición del problema.

+0

No debería estar en superusuario? – zmbush

+0

@zipcodeman Creo que SO está bien ya que está usando vim específicamente para una tarea de codificación. Probablemente usaría SU si fuera por usar vim para una tarea sys-admin. –

Respuesta

5

Aquí hay un par de funciones vimscript que deberían hacer lo que quieras.

  • EscapeText() transforma texto arbitrario al equivalente C-escapado. Convierte newline a \n, tabula a \t, Control + G a \a, etc., y genera escapes octales (como \o032) para caracteres especiales que no tienen un nombre descriptivo.

  • PasteEscapedRegister() escapa el contenido del registro llamado por v:register, luego lo inserta en el búfer en uso. (El registro se restablece cuando vuelve la función, por lo que la función se pueden llamar varias veces sin escapar el contenido del registro varias veces.)

También hay un par de asignaciones de teclas incluye para hacer PasteEscapedRegister() fácil de usar de forma interactiva. <Leader>P las pastas escaparon el contenido del registro antes de la posición del cursor, y <Leader>p pegaron después. Ambos pueden tener un prefijo con una especificación de registro, como "a\P para pegar los contenidos escapados del registro a.

Aquí está el código:

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> 
+0

Todavía no lo he probado pero se ve perfecto (e incluso lee bien ... vimscript puede terminar pareciéndose a perl;)) –

1

Esto podría al menos comenzar ...

Después de pegar en:

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

Puede obviamente mapa que le sea más fácil para escribir.

+0

Esto parece un buen enfoque, pero solo maneja el carácter ", me gustaría que maneje líneas nuevas, pestañas y otras cosas que podrían esperarse que caigan en el texto. (Probablemente no sea unicode general) Entiendo que puede no haber sido claro en la definición del problema. –

0

Mientras Joeys solución parece que podría ser extensible para cubrir todos los casos que necesito, yo pensé en compartir mi solución parcial mediante la integración VIMS pitón (Ya que estoy más familiarizado al pitón de script de Vim)

# 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))) 

Luego, en mi .vimrc u otro archivo de conf puedo poner

# 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 

sería bueno si pudiera la primera función de trabajar para que "un \ P pegar el contenido transformadas de la" una "registrarse, y supongo que esto es factible usando v: registrar de alguna manera, pero se me escapa.

Una versión de este que funciona de la misma manera como solución Joeys podría ser elaborado como

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

Agradecimiento: Este utiliza el código de Can you access registers from python functions in vim para interactuar con los registros de VIMS pitón

Cuestiones relacionadas