2010-04-21 11 views
6

Copia elementi da buffer di output in codice C++ su cui sto lavorando in vim. Spesso questa uscita si blocca nelle stringhe. Sarebbe bello poter sfuggire automaticamente tutti i caratteri di controllo piuttosto che tornare indietro e modificare manualmente il frammento incollato.Escape characters during paste in vim

A titolo di esempio, potrei copiare qualcosa di simile:

error in file "foo.dat" 

e la necessità di mettere in qualcosa di simile

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

Sto pensando che potrebbe essere possibile applicare una funzione di sostituzione al corpo dell'ultima incolla usando i segni di inizio e fine dell'ultima incolla, ma non sono sicuro di come farlo volare.

UPDATE:

Joey Mazzarelli sugested utilizzando

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

dopo una pasta.

Poiché nessuna spiegazione è stata data per quello che stava e inizialmente ho trovato un po 'laconico, ma difficile da spiegare nei commenti ho pensato di mettere una spiegazione di quello che penso che fa qui:

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

Questo sembra un buon approccio, ma gestisce solo un carattere, ", mi piacerebbe che gestisse newline, schede e altre cose che potrebbero cadere nel testo. (Probabilmente non è unicode generale) I capire che potrebbe non essere stato chiaro nella definizione del problema

+0

Non dovrebbe essere questo il superuser? – zmbush

+0

@zipcodeman Penso che SO sia OK poiché utilizza in modo specifico vim per un'attività di codifica. Probabilmente userò SU se fosse per l'utilizzo di vim per un'attività di sys-admin. –

risposta

5

Ecco coppia delle funzioni di vimscript che dovrebbero fare ciò che vuoi.

  • EscapeText() trasforma il testo arbitrario l'equivalente C-sfuggito. Converte newline in \n, scheda in \t, Control + G in \a, ecc. E genera escape ottali (come \o032) per caratteri speciali che non hanno un nome descrittivo.

  • PasteEscapedRegister() fugge il contenuto del registro denominato da v:register, quindi lo inserisce nel buffer corrente. (Il registro viene ripristinato quando la funzione ritorna, in modo che la funzione può essere chiamata più volte senza sfuggire il contenuto del registro più volte.)

Ci sono anche un paio di mappatura dei tasti incluso per rendere PasteEscapedRegister() facile da usare in modo interattivo. Le paste <Leader>P sono sfuggite al contenuto del registro prima della posizione del cursore e dopo le paste <Leader>p. Entrambi possono essere preceduti da una specifica del registro, come "a\P per incollare il contenuto di escape del registro a.

Ecco il codice:

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

Non l'ho ancora provato, ma sembra perfetto (e si legge anche bene ... il vimscript può sembrare simile a perl;)) –

1

Questo potrebbe almeno iniziare ...

Dopo aver incollato in:

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

È possibile, ovviamente, mappare che a qualcosa di più facile da digitare.

+0

Questo sembra un buon approccio, ma gestisce solo un carattere, ", mi piacerebbe che gestisse newline, schede e altre cose che potrebbero cadere nel testo (probabilmente non unicode generale). Capisco che potrebbe non essere stato chiaro nella definizione del problema: –

0

Mentre Joeys soluzione sembra che potrebbe essere estensibile per coprire tutti i casi che ho bisogno, ho pensato di condividere la mia soluzione parziale utilizzando VIMS integrazione python (Dal momento che sono più familiari al pitone di script di 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))) 

Poi nel mio Vimrc o un altro file conf posso mettere

# 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 

sarebbe bello se potessi la prima funzione di lavorare in modo che "un \ P incollato il contenuto trasformata del" un "registrati, e presumo che sia fattibile usando v: registrati in qualche modo, ma mi sfugge.

Una versione di questo che funziona nello stesso modo come soluzione Joeys potrebbe essere realizzato come

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

Riconoscimento: Questo utilizza il codice dalla Can you access registers from python functions in vim per interagire con i registri da VIMS pitone