Come faccio a rendere vim un set di directory per un file, se non esiste nella directory corrente?


9

Quando voglio modificare il mio zshrc, devo solo digitare:

vim .zshrc

Senza specificare il percorso completo ( ~/.zshrc), se mi trovo in una directory diversa, verrà invece avviato un nuovo file. Questo è molto fastidioso, dato che ne ho solo uno .zshrc, dentro ~e solo uno vimrc, dentro ~/.vim/. Quindi, come faccio ad aprire Vim ~/.zshrco ~/.vim/vimrcquando lo faccio vim .zshrco vim vimrcin un'altra directory?


Mentre creare una configurazione per ogni singolo file è un modo, stavo pensando a qualcosa sulla falsariga di CDPATH. CDPATHè una variabile in alcune shell che contiene un elenco di percorsi in cui cdcercare una directory. Ad esempio, se avessi CDPATH=:/home/muru, ed ero in una directory che non contiene una directory denominata Desktop, potrei fare cd Desktope raggiungere /home/muru/Desktop. Semplice, elegante, flessibile. Se vimavesse un posto VIMPATHdove cercare i file da modificare, sarebbe l'opzione migliore.

Risposte:


6

L' 'path'opzione di Vim ti consente di specificare le directory che comandano gfe :findcercheranno un file.

Se si desidera che questa funzionalità si attivi solo per un set specifico di file, è possibile utilizzare un autocmd per "reindirizzare" automaticamente il :editcomando sul file in una delle 'path'directory.

set path+=~/
function! FindInPath(name)
    let found = findfile(a:name)
    if !empty(found)
        exe 'silent keepalt file '. fnameescape(found)
        edit
    endif
endfunction
autocmd BufNewFile .vimrc,.zshrc nested call FindInPath(expand('<afile>'))

Questo utilizza BufNewFileautocmd come trigger per file not found, so try to find it somewhere else. Quando viene rilevata tale situazione, utilizzare findfile()per provare a trovare il file nelle 'path'directory. Se viene trovato, modifica il nome del buffer corrente in quel file e modifica nuovamente il buffer, altrimenti continua a utilizzare il nuovo buffer.

Il nestedqualificatore è richiesto qui poiché gli autocmds normalmente non si annidano. In questo caso, si desidera che i tipici autocmds si attivino quando il :editcomando apre il file.

Si noti che ciò creerà comunque un buffer aggiuntivo rispetto alla semplice modifica manuale del file. Quando BufNewFileviene eseguito, il buffer per il nome file specificato in origine è già stato creato. L'uso :fileper modificare il nome di un buffer crea un nuovo buffer non caricato con il nome originale.

Se vuoi sempre cercare 'path', allora autocmd può essere semplicemente modificato per utilizzare il *modello di file piuttosto che specificare determinati file.


Ecco una versione aggiornata che dovrebbe soddisfare meglio le tue esigenze. Usa :findper aprire direttamente il file invece di impostare il nome del buffer in base al risultato di findfile().

function! FindInPath(name)
    let path=&path
    " Add any extra directories to the normal search path
    set path+=~,~/.vim,/etc
    " If :find finds a file, then wipeout the buffer that was created for the "new" file
    setlocal bufhidden=wipe
    exe 'silent! keepalt find '. fnameescape(a:name)
    " Restore 'path' and 'bufhidden' to their normal values
    let &path=path
    set bufhidden<
endfunction
autocmd BufNewFile * nested call FindInPath(expand('<afile>'))

Questo risolve il problema nella funzione precedente in cui Vim si lamentava quando tentava di salvare il :filebuffer con nome.


Hmm. keepalt fileha lo stesso inconveniente dell'assegnazione a vim.current.buffer.name- vim ti avverte che il file esiste già quando provi a salvare le tue modifiche.
Muru,

Dopo aver utilizzato questo per quasi un anno, ho alcuni suggerimenti: avvolgo in if expand('%') !~ '^[.~]\?/'... endifin modo che explicilty specificato percorsi relativi o assoluti ottengono saltato; e usa silentinvece di silent!, perché se apri vim vimrcin due terminali, il secondo attenderà l'input al solito avviso "il file è aperto altrove", ma l'utente non ha idea di cosa stia aspettando. Non lo sto ancora modificando, per vedere se hai modi migliori per affrontarli.
Muru,

3

L'alternativa è rendere alcuni comandi che renderanno questo più semplice:

command! Evimrc e ~/.vimrc
command! Svimrc sp ~/.vimrc

Sto usando il modello E/ Sche utilizza rails.vim / projectionist.vim .

Per ulteriori informazioni, consultare:

:h :command
:h :e
:h :sp

3

Questa non è una soluzione, ma è quello che faccio per avere un facile accesso a .vimrce .zshrc. Personalmente penso che sia abbastanza pulito:

map <leader>ev :e ~/.vim/vimrc<cr>
map <leader>ez :e ~/.zshrc<cr>

1

Nello spirito di CDPATH, ho scritto una funzione basata su Python per farlo (con l' aiuto di Matt Boehm ):

function LookupFiles ()
    python <<EOF
from os.path import *
from vim import *
current_file = eval ('expand("%")')
current_index = str (current.buffer.number)
PATHS = ['~', '~/.vim', '/etc']

if current_file != '' and  not isfile (current_file):
    for p in map (expanduser, PATHS):
        f = join (p, current_file)
        if isfile (f):          
            command ('bad ' + f)
            command ('bd ' + current_index)
            break
EOF
endfunction

autocmd BufWinEnter * nested call LookupFiles() 
  • Ho usato BufWinEnterinvece BufNewFileperché quest'ultimo non sembrava comportarsi in modo affidabile quando sono stati dati più nomi di file.
  • Dopo un po 'di tentativi ed errori, ho optato badper bdun modo affidabile per chiudere il buffer aperto per il file inutilizzato. Questo non funziona ancora quando lo faccio :tabe some-file(nessuna nuova scheda è aperta). Tuttavia, questa è una domanda per un altro giorno.
  • Come con CDPATH, posso facilmente aggiungere più directory modificando PATHSo trasformandolo in una variabile di livello Vim e modificandolo.

Quello che manca alle altre risposte, IMO, è che non voglio creare la configurazione per ciascun file , ma per ogni directory . Non mi importa se sto aprendo fstabo vimrc, volevo solo che Vim cercasse i file in un set di directory se non esistesse nella directory corrente. +1 a tutti loro per gli sforzi specifici del file, però.


La semplice modifica della mia risposta da utilizzare *per il modello di file, piuttosto che per file specifici, dovrebbe raggiungere la stessa cosa ed evitare il tuo problema :tabe.
Jamessan,

@Jamessan Devo ammettere di aver visto l'autocmd originale e di aver suddiviso in zone. Su una nota non correlata: fnameescape potrebbe essere la soluzione a un'altra domanda qui, su gvim e remote send.
muru,

1

Con 'user-commands'e 'Dictionary', possiamo modificare i file senza creare un buffer per sovrascrivere il file che vogliamo modificare nel buffer.

com -nargs=* E call Editfile(<q-args>)
let s:fileLocation = {'vimrc':'~/.vim/', '.zshrc':'~/'}
function Editfile(filename)
    if has_key(s:fileLocation, a:filename)
        exe "e " . fnameescape(s:fileLocation[a:filename].a:filename)
    else
        exe "e " . fnameescape(a:filename)
    endif
endfunction 

Si noti che la funzione Editfilenon tenta di verificare il suo argomento. Facciamo in modo che vim gestisca tutti gli errori come altri normali comandi Ex. Se l'argomento è corretto, allora vim inizia a modificare il file e, se non è corretto, vim segnalerà errori.

A mio avviso, non è necessario creare un buffer. Ha due inconvenienti principali.

  1. La 'not-edited'bandiera sarebbe stata impostata. Come Jamessan sottolinea nella sua risposta , se impostiamo il nome del file corrente con il :filecomando e proviamo a scrivere il file, incontreremo il messaggio di errore E13: File exists (use ! to override)Questo perché Vim contrassegna il file come "non modificato" quando cambiamo il nome del file con :filecomando.
  2. Dobbiamo provare a mantenere il nome del file alternativo con il :keepaltcomando. Quando proviamo a modificare vimrc durante la modifica di 'foo.bar', ci aspettiamo che il nome del file alternativo dovrebbe essere 'foo.bar'. Ma se creiamo un buffer e cambiamo il nome, il nome del file alternativo non diventa "foo.bar" ma il vecchio nome del buffer "vimrc". Ancora peggio, il vecchio buffer verrà lasciato come unlisted-buffero inactive-buffer. Ecco perché dovremmo usare il :keepaltcomando per mantenere il nome del file alternativo come previsto e impostare l' bufhiddenopzione wipeper cancellare il vecchio buffer.

Se la lettera maiuscola nel nome del comando (tutti i comandi definiti dall'utente devono iniziare con la lettera maiuscola) non ci riguarda, sarebbe meglio usarla. Poiché non crea un buffer, non abbiamo alcun onere per la gestione del buffer. Basta passare il nome del file per vim e vedere come vim lo gestisce.

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.