Come eseguire il file che sto modificando in Vi (m)


101

Come eseguire il file che sto modificando in Vi (m) e ottenere l'output nella finestra divisa (come in SciTE)?

Ovviamente potrei eseguirlo in questo modo:

:!scriptname

Ma è possibile evitare di scrivere il nome dello script e come ottenere l'output nella finestra divisa invece nella parte inferiore dello schermo?


21
:!% ti permetterà di evitare di scrivere "nome script". Le soluzioni seguenti sono migliori, ma ho pensato di menzionarlo nel caso in cui decidessi:!% È abbastanza buono.
overthink

11
Un'altra nota, puoi usare%: p (invece di solo%) per fare riferimento al percorso assoluto del file corrente. Questo potrebbe essere necessario se la tua directory corrente è da qualche altra parte.
andy

4
per eseguire script ruby:! ruby% farà il trucco
Alexis Perrier

1
@andy:!%: p risolve anche che la directory non si trova in $ PATH
MayTheSForceBeWithYou

2
E :!"%:p"per far fronte agli spazi bianchi.
OJFord

Risposte:


109

C'è il makecomando. Esegue il comando impostato makeprgnell'opzione. Usa %come segnaposto per il nome del file corrente. Ad esempio, se stavi modificando uno script Python:

:set makeprg=python\ %

Sì, devi fuggire dallo spazio. Dopo questo puoi semplicemente eseguire:

:make

Se lo desideri, puoi impostare il file autowrite opzione e verrà salvata automaticamente prima di eseguire makeprg:

:set autowrite

Questo risolve la parte di esecuzione. Non conosco alcun modo per ottenere quell'output in una finestra divisa che non implichi il reindirizzamento al file.


5
In realtà, la tua soluzione ottiene l'output in una finestra divisa. Utilizzare :copenper aprire la "lista errori" prodotta eseguendo. :makeNella sua finestra. Sfortunatamente, per fare in modo che l'output sia formattato correttamente, sono necessarie alcune rifiniture errorformatdell'opzione. Altrimenti si presume che l'output sia nel formato che gcc mette in uscita.
Conspicuous Compiler

2
Sei dannatamente sicuro del formato di errore "finagling". Sembra un codice Perl che ho visto ...
R. Martinho Fernandes

1
Questa funzionalità è disponibile per il 'make' del progetto da vim (fornisce a vim la capacità di IDE). La soluzione di Brian Carper ( :let f=expand("%")|vnew|execute '.!ruby "' . f . '"') sebbene sembri criptica, funziona esattamente come chiesto dall'autore della domanda.
AjayKumarBasuthkar

29

Per accedere al nome del file del buffer corrente, utilizzare %. Per inserirlo in una variabile puoi usare la expand()funzione. Per aprire una nuova finestra con un nuovo buffer, utilizzare :newo :vnew. Per reindirizzare l'output di un comando nel buffer corrente, utilizzare :.!. Mettere tutto insieme:

:let f=expand("%")|vnew|execute '.!ruby "' . f . '"'

ovviamente sostituendolo rubycon qualsiasi comando tu voglia. L'ho usato in executemodo da poter racchiudere il nome del file tra virgolette, quindi funzionerà se il nome del file contiene spazi.


3
@baboonWorksFine Usa :command! R let f=expand("%")|vnew|execute '.!ruby "' . f . '"'per essere in grado di usare solo :Rper eseguire il suo comando
xorpaul

Sarebbe possibile farlo funzionare anche con script che richiedono l'input dell'utente durante l'esecuzione?
ilstam

23

Vim ha il !comando ("bang") che esegue il comando della shell direttamente dalla finestra VIM. Inoltre permette di lanciare sequenze di comandi che sono collegati con pipe e leggono stdout.

Per esempio:

! node %

è equivalente all'apertura della finestra del prompt dei comandi e all'avvio dei comandi:

cd my_current_directory 
node my_current_file

Vedere "Suggerimenti per Vim: lavorare con comandi esterni" per i dettagli.


11

Ho una scorciatoia per questo nel mio vimrc:

nmap <F6> :w<CR>:silent !chmod 755 %<CR>:silent !./% > .tmp.xyz<CR>
     \ :tabnew<CR>:r .tmp.xyz<CR>:silent !rm .tmp.xyz<CR>:redraw!<CR>

Questo scrive il buffer corrente, rende eseguibile il file corrente (solo unix), lo esegue (solo unix) e reindirizza l'output a .tmp.xyz, quindi crea una nuova scheda, legge il file e quindi lo elimina.

Abbattendolo:

:w<CR>                             write current buffer
:silent !chmod 755 %<CR>           make file executable
:silent !./% > .tmp.xyz<CR>        execute file, redirect output
:tabnew<CR>                        new tab
:r .tmp.xyz<CR>                    read file in new tab
:silent !rm .tmp.xyz<CR>           remove file
:redraw!<CR>                       in terminal mode, vim get scrambled
                                   this fixes it

2
Mi è piaciuta molto la tua soluzione e, dopo averla utilizzata, ho sentito che poteva essere migliorata. Quindi ecco la mia opinione: :w<CR>:silent !chmod +x %:p<CR>:silent !%:p 2>&1 | tee ~/.vim/output<CR>:split ~/.vim/output<CR>:redraw!<CR>- questo reindirizza sia lo stdout che lo stderr al file temporaneo, e prima di farlo, stampa tutto su stdout, quindi se uno script impiega molto tempo per essere eseguito, lo vedi effettivamente funzionare. Inoltre, è indipendente dalla directory (ricevevo errori durante l'apertura dei file tramite il loro percorso assoluto). Tuttavia, non esegue script in modo interattivo e non ho trovato un modo per farlo.
Kirill G

1
fyi - sulla soluzione di @Cyril, ho dovuto evitare il simbolo del tubo: | -> \ |
mpettis


3

Vim 8 ha un terminale interattivo integrato. Per eseguire lo script bash corrente in un riquadro diviso:

:terminal bash %

o in breve

:ter bash %

% si espande nel nome del file corrente.

Da :help terminal:

The terminal feature is optional, use this to check if your Vim has it:
    echo has('terminal')
If the result is "1" you have it.

1

Uso un meccanismo leggermente più invadente attraverso le mappe:

map ;e :w<CR>:exe ":!python " . getreg("%") . "" <CR>

Fa solo in modo che non debba salvare, quindi vado. Vai e basta.


1
Se imposti l'opzione autowrite, puoi eseguire: make and it ... auto save before.
R. Martinho Fernandes

1

Puoi usare il plugin bexec di vim . Per quanto ne so, l'ultima versione è la 0.5.

Poi:

$ mkdir -p ~/.vim/plugin
$ mv bexec-0.5.vba ~/.vim/plugin
$ vim ~/.vim/plugin/bexec-0.5.vba

All'interno di vim stesso durante la modifica del file .vba fare:

:so %

Alcuni output verranno visualizzati per farti sapere che bexec.vim è stato scritto così come la documentazione, ecc.

Ora puoi testarlo aprendo il tuo (qualunque linguaggio script che abbia un interprete #! Che funziona correttamente) in vim ed esegui

:Bexec 

Nota: volevo che la divisione fosse verticale anziché orizzontale, quindi ho fatto:

$ grep -i -n split ~/.vim/plugin/bexec.vim | grep -i hor
102:    let bexec_splitdir = "hor" " hor|ver
261:        exec {"ver":"vsp", "hor":"sp"}[g:bexec_splitdir]

e cambiato il valore di da "hor" a "ver" ..

So che è una vecchia domanda, ma spero che questo possa aiutare qualcuno là fuori. Mi sono imbattuto nello stesso numero durante il corso Startup Engineering di Coursera dove il professor Palaji usa Emacs e non mi piace Emacs ..


Dovresti modificare le impostazioni relative alle preferenze nel tuo .vimrc locale. bexec offre l'impostazione "let bexec_splitdir = 'hor'" che può farlo senza modificare il codice del plugin.
Saurabh Hirani

0

Sulla base delle risposte di @SethKriticos e @Cyril, ora utilizzo quanto segue:

function! Setup_ExecNDisplay()
  execute "w"
  execute "silent !chmod +x %:p"
  let n=expand('%:t')
  execute "silent !%:p 2>&1 | tee ~/.vim/output_".n
  " I prefer vsplit
  "execute "split ~/.vim/output_".n
  execute "vsplit ~/.vim/output_".n
  execute "redraw!"
  set autoread
endfunction

function! ExecNDisplay()
  execute "w"
  let n=expand('%:t')
  execute "silent !%:p 2>&1 | tee ~/.vim/output_".n
  " I use set autoread
  "execute "1 . 'wincmd e'"
endfunction

:nmap <F9> :call Setup_ExecNDisplay()<CR>
:nmap <F2> :call ExecNDisplay()<CR>

Usa F9 per impostare la nuova finestra e F2 per eseguire lo script e tee nel file di output.

Ho anche aggiunto il nome dello script al nome del file di output, in modo da poterlo utilizzare per più script contemporaneamente.


0

Nel tuo .vimrcpuoi incollare questa funzione

function! s:ExecuteInShell(command)
  let command = join(map(split(a:command), 'expand(v:val)'))
  let winnr = bufwinnr('^' . command . '$')
  silent! execute ':w'
  silent! execute  winnr < 0 ? 'vnew ' . fnameescape(command) : winnr . 'wincmd w'
  setlocal buftype=nowrite bufhidden=wipe nobuflisted noswapfile nowrap number
  silent! execute 'silent %!'. command
  silent! redraw
  silent! execute 'au BufUnload <buffer> execute bufwinnr(' . bufnr('#') . ') . ''wincmd w'''
  silent! execute 'nnoremap <silent> <buffer> <LocalLeader>r :call <SID>ExecuteInShell(''' . command . ''')<CR>'
  silent! execute 'wincmd w'
  " echo 'Shell command ' . command . ' executed.'
endfunction
command! -complete=shellcmd -nargs=+ Shell call s:ExecuteInShell(<q-args>)
cabbrev shell Shell

Dopodiché, nel vimcomando run :shell python ~/p.pycome esempio. E otterrai l'output nella finestra divisa. + Dopo le modifiche p.pynell'esempio, eseguirai di nuovo lo stesso comando, questa funzione non creerà più una nuova finestra, visualizzerà il risultato nella precedente (stessa) finestra divisa.


È fantastico, grazie! Come potresti cambiarlo per rieseguirlo quando il buffer viene riscritto?
elzi

0

@xorpaul

Stavo cercando questo script (python / Windows) da un po 'di tempo. Dato che non c'è il "tee" in Windows, l'ho cambiato in:

function! Setup_ExecNDisplay()
  execute "w"
  let n=expand('%:t')
  execute "silent ! python % > d:\\temp\\output_".n ." 2>&1"
  execute "vsplit d:\\temp\\output_".n
  execute "redraw!"
  set autoread
endfunction

function! ExecNDisplay()
  execute "w"
  let n=expand('%:t')
  execute "silent ! python % > d:\\temp\\output_".n . " 2>&1"
endfunction

:nmap <F9> :call Setup_ExecNDisplay()<CR>
:nmap <F2> :call ExecNDisplay()<CR>

0

Usa semplicemente i due punti e il punto esclamativo come mostrato di seguito

:! <nome_script>


0

Consiglierei il plugin quickrun . È veloce e semplice da configurare. Ecco una piccola dimostrazione: inserisci qui la descrizione dell'immagine

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.