Wie lasse ich vim in einer Reihe von Verzeichnissen nach einer Datei suchen, wenn sie im aktuellen Verzeichnis nicht vorhanden ist?

9

Wenn ich meine bearbeiten möchte, tippe zshrcich einfach:

vim .zshrc

~/.zshrcWenn ich mich in einem anderen Verzeichnis befinde, wird ohne Angabe des vollständigen Pfads ( ) stattdessen eine neue Datei gestartet. Das ist sehr ärgerlich, da ich nur einen .zshrcin ~und nur einen vimrcin habe ~/.vim/. Wie kann ich vim öffnen ~/.zshrcoder ~/.vim/vimrcwann vim .zshrcoder vim vimrcin einem anderen Verzeichnis?


Während das Erstellen einer Konfiguration für jede einzelne Datei eine Möglichkeit ist, habe ich mir etwas in der Art von gedacht CDPATH. CDPATHist eine Variable in einigen Shells, die eine Liste von Pfaden enthält, in denen nach einem Verzeichnis gesucht cdwird. Wenn ich zum Beispiel CDPATH=:/home/muruin einem Verzeichnis wäre, das kein Verzeichnis mit dem Namen enthält Desktop, könnte ich dies tun cd Desktopund erreichen /home/muru/Desktop. Einfach, elegant, flexibel. Wenn vimes einen Ort VIMPATHgäbe, an dem nach zu bearbeitenden Dateien gesucht würde, wäre dies die beste Option.

muru
quelle

Antworten:

6

Mit der 'path'Option von Vim können Sie Verzeichnisse angeben, die Befehle mögen gfund :findnach einer Datei suchen.

Wenn Sie möchten, dass diese Funktionalität nur für einen bestimmten Satz von Dateien ausgelöst wird, können Sie mit einem Autocmd Ihren :editBefehl automatisch in die Datei in einem der 'path'Verzeichnisse "umleiten" .

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>'))

Dies verwendet den BufNewFileAutocmd als Auslöser für file not found, so try to find it somewhere else. Wenn diese Situation erkannt wird findfile(), versuchen Sie, die Datei in den 'path'Verzeichnissen zu finden. Wenn es gefunden wird, ändern Sie den Namen des aktuellen Puffers in diese Datei und bearbeiten Sie den Puffer erneut. Andernfalls verwenden Sie einfach den neuen Puffer weiter.

Das nestedQualifikationsmerkmal ist hier erforderlich, da Autocmds normalerweise nicht verschachtelt sind. In diesem Fall möchten Sie, dass die typischen Autocmds ausgelöst werden, wenn der :editBefehl Ihre Datei öffnet.

Beachten Sie, dass dadurch immer noch ein zusätzlicher Puffer erstellt wird, anstatt die Datei nur manuell zu bearbeiten. Zum Zeitpunkt der BufNewFileAusführung ist der Puffer für den ursprünglich angegebenen Dateinamen bereits erstellt. Wenn Sie :fileden Namen eines Puffers ändern, wird ein neuer, entladener Puffer mit dem ursprünglichen Namen erstellt.

Wenn Sie immer suchen 'path'möchten, kann der Autocmd einfach geändert werden, um das Dateimuster zu verwenden *, anstatt bestimmte Dateien anzugeben.


Hier ist eine aktualisierte Version, die Ihren Anforderungen besser entsprechen sollte. Es wird verwendet :find, um die Datei direkt zu öffnen, anstatt den Puffernamen basierend auf dem Ergebnis von festzulegen 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>'))

Dies löst das Problem in der vorherigen Funktion, bei der sich Vim beschwert, wenn versucht wird, den :filebenannten Puffer zu speichern .

Jamessan
quelle
Hmm. keepalt filehat den gleichen Nachteil wie die Zuweisung an vim.current.buffer.name- vim warnt Sie, dass die Datei bereits vorhanden ist, wenn Sie versuchen, Ihre Änderungen zu speichern.
Muru
Nachdem ich dies fast ein Jahr lang verwendet habe, habe ich einige Vorschläge: Wickeln Sie es ein if expand('%') !~ '^[.~]\?/'... endifdamit explizit angegebene relative oder absolute Pfade übersprungen werden; und verwenden Sie silentstattdessen silent!, denn wenn Sie vim vimrcin zwei Terminals öffnen , wartet die zweite auf die Eingabe der üblichen Warnung "Datei ist an anderer Stelle geöffnet", aber der Benutzer hat keine Ahnung, worauf er wartet. Ich bearbeite es noch nicht, um zu sehen, ob Sie auch bessere Möglichkeiten haben, es anzugehen.
Muru
3

Alternativ können Sie einige Befehle ausführen, die dies vereinfachen:

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

Ich verwende das E/ Spattern, das Rails.vim / projectionist.vim verwendet.

Weitere Hilfe finden Sie unter:

:h :command
:h :e
:h :sp
Peter Rincker
quelle
3

Dies ist keine Lösung, aber es ist das, was ich tue, um einen einfachen Zugang zu .vimrcund zu haben .zshrc. Persönlich finde ich das ziemlich ordentlich:

map <leader>ev :e ~/.vim/vimrc<cr>
map <leader>ez :e ~/.zshrc<cr>
Karl Yngve Lervåg
quelle
1

Im Geiste von habe CDPATHich dazu eine Python-basierte Funktion geschrieben (mit Hilfe von 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() 
  • Ich habe BufWinEnterstattdessen verwendet, BufNewFileweil letzteres sich nicht zuverlässig zu verhalten schien, wenn mehrere solcher Dateinamen angegeben wurden.
  • Nach einem bisschen von Versuch und Irrtum, ließ ich mich auf , badgefolgt von bdals zuverlässigem Weg , um den Puffer für die nicht genutzte Datei geöffnet zu schließen. Dies funktioniert immer noch nicht, wenn ich es tue :tabe some-file(es wird kein neuer Tab geöffnet). Das ist jedoch eine Frage für einen anderen Tag.
  • Wie bei CDPATHkann ich einfach weitere Verzeichnisse hinzufügen, indem ich sie bearbeite PATHSoder zu einer Variablen auf Vim-Ebene mache und sie ändere.

Was die anderen Antworten vermissen, IMO, ist, dass ich nicht für jede Datei , sondern für jedes Verzeichnis eine Konfiguration erstellen möchte . Es ist mir egal, ob ich öffne fstaboder vimrc, ich wollte nur, dass Vim in einigen Verzeichnissen nach Dateien sucht, wenn diese nicht im aktuellen Verzeichnis vorhanden sind. +1 an alle für die dateispezifischen Bemühungen.

muru
quelle
Das einfache Ändern meiner Antwort *für das Dateimuster anstelle bestimmter Dateien sollte dasselbe bewirken und Ihr Problem mit vermeiden :tabe.
Jamessan
@ Jamessan Ich gebe zu, ich habe das Original-Autocmd gesehen und es in Zonen aufgeteilt. In einem anderen Zusammenhang: Die fnameescape könnte die Lösung für eine andere Frage sein, die sich mit gvim und Remote Send befasst.
Muru
1

Mit 'user-commands'und 'Dictionary'können wir die Dateien bearbeiten, ohne einen Puffer zum Überschreiben der Datei zu erstellen, die wir im Puffer bearbeiten möchten.

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 

Beachten Sie, dass die Funktion Editfilenicht versucht, ihr Argument zu überprüfen. Lassen Sie vim alle Fehler wie andere normale Ex-Befehle behandeln. Wenn das Argument korrekt ist, beginnt vim mit der Bearbeitung der Datei. Wenn dies nicht korrekt ist, meldet vim Fehler.

Meiner Meinung nach müssen wir keinen Puffer erstellen. Es hat zwei Hauptnachteile.

  1. Die 'not-edited'Flagge würde gesetzt. Wie Jamessan in seiner Antwort betont :file, wird die Fehlermeldung angezeigt , wenn wir den aktuellen Dateinamen mit dem Befehl festlegen und versuchen, die Datei zu schreiben. E13: File exists (use ! to override)Dies liegt daran, dass vim die Datei als "nicht bearbeitet" markiert, wenn wir den Namen der Datei ändern mit :fileBefehl.
  2. Wir müssen versuchen, den alternativen Dateinamen mit dem :keepaltBefehl beizubehalten. Wenn wir versuchen, vimrc während der Bearbeitung von 'foo.bar' zu bearbeiten, erwarten wir, dass der alternative Dateiname 'foo.bar' lautet. Wenn wir jedoch einen Puffer erstellen und den Namen ändern, wird der alternative Dateiname nicht zur "foo.bar", sondern zum alten Namen des Puffers 'vimrc'. Schlimmer noch, der alte Puffer bleibt als unlisted-bufferoder erhalten inactive-buffer. Aus diesem Grund sollten wir den :keepaltBefehl verwenden, um den erwarteten alternativen Dateinamen beizubehalten und die bufhiddenOption so einzustellen , dass wipeder alte Puffer gelöscht wird.

Wenn der Großbuchstabe im Befehlsnamen (alle benutzerdefinierten Befehle sollten mit einem Großbuchstaben beginnen) uns nicht betrifft, ist es besser, ihn zu verwenden. Da kein Puffer erstellt wird, müssen wir den Puffer nicht mehr verwalten. Übergeben Sie einfach den Dateinamen an vim und sehen Sie, wie vim damit umgeht.

MS.Kim
quelle