2010-04-04 19 views
7

Quando utilizzo:%! per eseguire il contenuto di un file attraverso un filtro e il filtro non riesce (restituisce un altro codice diverso da 0) e stampa un messaggio di errore su stderr I file vengono sostituiti con questo messaggio di errore. C'è un modo per dire a vim di saltare il filtro se il filtro restituisce un codice di stato che indica un errore e/o ignora l'output che il programma di filtro scrive su stderr?filtri vim e stdout/stderr

In alcuni casi è possibile sostituire il file con l'output del filtro, ma molto spesso questo comportamento è sbagliato. Ovviamente posso semplicemente annullare il filtro con un solo tasto ma non è ottimale.

Inoltre, ho un problema simile quando si scrive uno script Vim personalizzato per fare il filtro. Ho uno script che chiama un programma di filtro con system() e sostituisce il file nel buffer con il suo output ma non sembra essere un modo per rilevare se le righe restituite da system() dove sono scritte su stdout o su stderr . C'è un modo per distinguerli in vim script?

risposta

3

È possibile utilizzare Python per distinguere tra stdout e stderr:

python import vim, subprocess 
python b=vim.current.buffer 
python line=vim.current.range.start 
python p=subprocess.Popen(["command", "argument", ...], stdout=subprocess.PIPE, stderr=subprocess.PIPE, close_fds=True) 
python returncode=p.poll() 
python if not returncode: b.append(("STDOUT:\n"+p.stdout.read()+"\nSTDERR:\n"+p.stderr.read()).split("\n"), line) 
+0

Naturalmente! Con ogni linguaggio di scripting "reale" non è affatto un problema. Non ci ho pensato. Anche se preferirei script vim se possibile, perché non voglio avere più dipendenze sul mio script del necessario. – ahe

+1

Conosco solo un altro modo: usa 'system()', reindirizza lo stderr in un file temporaneo (o '/ dev/null'), salva stdout su qualche variabile e usa' v: shell_error' per determinare se un comando ha fallito prima buffer di sovrascrittura. Nota che i filtri ':!' Sostituiscono «!» Con il comando precedente e «%» con il nome file corrente mentre 'system()' no. – ZyX

3

:!{cmd} Esegue {cmd} con il guscio e imposta v:shell_error.

Se vi capita di impostare assegnazioni per chiamare i filtri, si potrebbe fare qualcosa di simile al seguente:

function! UndoIfShellError() 
    if v:shell_error 
     undo 
    endif 
endfuntion 

nmap <leader>filter :%!/path/to/filter<CR>:call UndoIfShellError()<CR> 
+0

Bel trucco :). In realtà speravo in un pendente sensibile agli errori per la sintassi:! {Cmd} che ho appena trascurato. Ma sempre più temo che non esista alcuna sintassi alternativa. – ahe

1

Un'alternativa potrebbe essere quella di eseguire il comando di filtro, come si modifica il file su disco.

Ad esempio, per gofmt (www.golang.org) Ho questi mapping sul posto:

map <f9> :w<CR>:silent !gofmt -w=true %<CR>:e<CR> 
imap <f9> <ESC>:w<CR>:silent !gofmt -w=true %<CR>:e<CR> 

Spiegazione: : w - salvare il file : silenzioso - evitare di premere invio alla fine % - passa il file al gofmt w = true - dice a gofmt di scrivere al file : e - dice a Vim di ricaricare modificato file di

0

Questo è quello che ho finito per fare:

function MakeItAFunction(line1, line2, args) 
    let l:results=system() " call filter via system or systemlist 
    if v:shell_error 
    "no changes were ever actually made! 
    echom "Error with etc etc" 
    echom results 
    endif 
    "process results if anything needed? 

    " delete lines but don't put in register: 
    execute a:line1.",".a:line2." normal \"_dd" 
    call append(a:line1-1, l:result) " add lines 
    call cursor(a:line1, 1) " back to starting place 
    " echom any messages 
endfunction 
command -range <command keys> MakeItAFunction(<line1>,<line2>,<q-args>) 
"           or <f-args>, etc. 

Si può vedere il mio codice completo a http://vim.wikia.com/wiki/Perl_compatible_regular_expressions

E 'complicato, ma funziona e quando viene utilizzato, è abbastanza trasparente e grazioso. Spero che ti aiuti in qualsiasi modo!