2010-04-04 13 views
7

Cuando uso:%! para ejecutar el contenido de un archivo a través de un filtro y el filtro falla (devuelve otro código que 0) e imprime un mensaje de error a stderr obtengo mi archivo reemplazado con este mensaje de error. ¿Hay alguna manera de decirle a vim que omita el filtrado si el filtro devuelve un código de estado que indica un error y/o ignora la salida que el programa de filtro escribe en stderr?vim filters y stdout/stderr

Hay casos en los que desea que su archivo se sustituya por la salida del filtro, pero la mayoría de las veces este comportamiento es incorrecto. Por supuesto, puedo deshacer el filtrado con una sola pulsación de tecla pero no es óptimo.

También tengo un problema similar al escribir una secuencia de comandos vim personalizada para hacer el filtrado. Tengo una secuencia de comandos que llama a un programa de filtro con system() y reemplaza el archivo en el búfer con su salida, pero no parece haber una manera de detectar si las líneas devueltas por system() fueron escritas en stdout o stderr . ¿Hay alguna manera de distinguirlos en el script vim?

Respuesta

3

Puede utilizar Python para distinguir entre stdout y 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

¡Por supuesto! Con cada lenguaje de script "real" no es un problema en absoluto. No pensé en eso. Aunque preferiría el script vim si fuera posible porque no quiero tener más dependencias en mi script de lo necesario. – ahe

+1

Sólo sé de otra manera: use 'system()', redireccione stderr a un archivo temporal (o '/ dev/null'), guarde stdout en alguna variable y use' v: shell_error' para determinar si un comando falló antes sobrescribiendo buffer Tenga en cuenta que los filtros ':!' Reemplazan «!» Por el comando anterior y «%» con el nombre de archivo actual, mientras que 'system()' no lo hace. – ZyX

3

:!{cmd} Ejecuta {cmd} con la cáscara y establece v:shell_error.

Si por casualidad realizar asignaciones para llamar a sus filtros, se puede hacer algo como lo siguiente:

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

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

Buen truco :). En realidad, esperaba un colgante sensible a errores para la sintaxis:! {Cmd} que acababa de pasar por alto. Pero cada vez más me temo que no existe tal sintaxis alternativa. – ahe

1

Una alternativa sería la de ejecutar el comando de filtro como se modifica el archivo en el disco.

Por ejemplo, para gofmt (www.golang.org) Tengo estas asignaciones en su lugar:

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

Explicación: : w - guardar archivo : silent - evitar presionar entrar en el extremo % - pasa el archivo a gofmt w = true - indica gofmt volver a escribir en el archivo : e - dice vim para recargar modificado archivo

0

Esto es lo que terminé haciendo:

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. 

se puede ver el código completo en http://vim.wikia.com/wiki/Perl_compatible_regular_expressions

Es complicado, pero funciona y cuando se usa, es bastante transparente y elegante. Espero que ayude de cualquier manera!