Comment faire pour que vim regarde dans un ensemble de répertoires pour un fichier, s'il n'existe pas dans le répertoire courant?

9

Lorsque je souhaite modifier mon zshrc, je tape simplement:

vim .zshrc

Sans spécifier le chemin complet ( ~/.zshrc), si je suis dans un répertoire différent, cela va plutôt démarrer un nouveau fichier. C'est très ennuyeux, car je n'en ai qu'un .zshrc, en ~, et un seul vimrc, en ~/.vim/. Alors, comment puis-je faire ouvrir vim ~/.zshrcou ~/.vim/vimrcquand je le fais vim .zshrcou vim vimrcdans un autre répertoire?


Bien que la création d'une configuration pour chaque fichier individuel soit une façon, je pensais à quelque chose dans le sens de CDPATH. CDPATHest une variable dans certains shells qui contient une liste de chemins où cdrecherchera un répertoire. Par exemple, si j'avais CDPATH=:/home/muru, et j'étais dans n'importe quel répertoire qui ne contient pas de répertoire nommé Desktop, je pourrais le faire cd Desktopet l'atteindre /home/muru/Desktop. Simple, élégant, flexible. S'il y vimavait un VIMPATHendroit où il chercherait des fichiers à modifier, ce serait la meilleure option.

muru
la source

Réponses:

6

L' 'path'option de Vim vous permet de spécifier les répertoires que les commandes aiment gfet :findrechercheront un fichier.

Si vous souhaitez uniquement que cette fonctionnalité se déclenche pour un ensemble spécifique de fichiers, vous pouvez utiliser un autocmd pour "rediriger" automatiquement votre :editcommande vers le fichier dans l'un des 'path'répertoires.

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

Cela utilise l' BufNewFileautocmd comme déclencheur pour file not found, so try to find it somewhere else. Lorsque cette situation est détectée, utilisez findfile()pour essayer de trouver le fichier dans les 'path'répertoires. S'il est trouvé, changez le nom du tampon actuel en ce fichier et rééditez le tampon, sinon continuez simplement à utiliser le nouveau tampon.

Le nestedqualificatif est requis ici car les autocmds ne s'emboîtent pas normalement. Dans ce cas, vous souhaitez que les autocmds typiques se déclenchent lorsque la :editcommande ouvre votre fichier.

Notez que cela créera toujours un tampon supplémentaire par rapport à la simple modification manuelle du fichier. Au moment de l' BufNewFileexécution, le tampon du nom de fichier spécifié à l'origine est déjà créé. L'utilisation de :filepour modifier le nom d'un tampon crée un nouveau tampon non chargé avec le nom d'origine.

Si vous souhaitez toujours rechercher 'path', alors l'autocmd peut simplement être modifié pour utiliser le *modèle de fichier plutôt que de spécifier certains fichiers.


Voici une version mise à jour qui devrait mieux correspondre à vos besoins. Il utilise :findpour ouvrir directement le fichier au lieu de définir le nom du tampon en fonction du résultat de 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>'))

Cela résout le problème dans la fonction précédente où Vim se plaindrait en essayant de sauvegarder le :filetampon nommé.

jamessan
la source
Hmm. keepalt filea le même inconvénient que l'attribution à vim.current.buffer.name- vim vous avertit que le fichier existe déjà lorsque vous essayez d'enregistrer vos modifications.
muru
Après avoir utilisé cela pendant près d'un an, j'ai quelques suggestions: enveloppez-le if expand('%') !~ '^[.~]\?/'... endifpour que les chemins relatifs ou absolus spécifiés soient ignorés; et utilisez à la silentplace de silent!, car si vous ouvrez vim vimrcdans deux terminaux, le second attendra l'entrée dans l'avertissement habituel "le fichier est ouvert ailleurs", mais l'utilisateur n'a aucune idée de ce qu'il attend. Je ne le modifie pas encore, pour voir si vous avez de meilleures façons de vous attaquer non plus.
muru
3

L'alternative est de rendre certaines commandes qui faciliteront cela:

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

J'utilise le modèle E/ Sque rails.vim / projectionist.vim utilise.

Pour plus d'aide, voir:

:h :command
:h :e
:h :sp
Peter Rincker
la source
3

Ce n'est pas une solution, mais c'est ce que je fais pour avoir un accès facile à .vimrcet .zshrc. Personnellement, je pense que c'est plutôt bien:

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

Dans l'esprit de CDPATH, j'ai écrit une fonction basée sur Python pour ce faire (avec l' aide de 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() 
  • J'ai utilisé à la BufWinEnterplace de BufNewFileparce que ce dernier ne semblait pas se comporter de manière fiable lorsque plusieurs noms de fichiers étaient fournis.
  • Après un peu d'essais et d'erreurs, je me suis installé, badpuis bdcomme un moyen fiable de fermer le tampon ouvert pour le fichier inutilisé. Cela ne fonctionne toujours pas quand je le fais :tabe some-file(aucun nouvel onglet n'est ouvert). Cependant, c'est une question pour un autre jour.
  • Comme avec CDPATH, je peux facilement ajouter plus de répertoires en éditant PATHS, ou en faisant une variable de niveau Vim et en la modifiant.

Ce que les autres réponses manquent, IMO, c'est que je ne veux pas créer de configuration pour chaque fichier , mais pour chaque répertoire . Peu m'importe si j'ouvre fstabou vimrc, je voulais juste que Vim recherche des fichiers dans un ensemble de répertoires s'il n'existait pas dans le répertoire courant. +1 à tous pour les efforts spécifiques au fichier, cependant.

muru
la source
Changer simplement ma réponse à utiliser *pour le modèle de fichier, plutôt que des fichiers spécifiques, devrait réaliser la même chose et éviter votre problème :tabe.
jamessan
@jamessan J'avoue avoir vu l'autocmd d'origine et zoné. Sur une note sans rapport: le fnameescape pourrait être la solution à une autre question ici, à propos de gvim et de l'envoi à distance.
muru
1

Avec 'user-commands'et 'Dictionary', nous pouvons éditer les fichiers sans créer de tampon pour remplacer le fichier que nous voulons éditer sur le tampon.

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 

Notez que la fonction Editfilen'essaie pas de vérifier son argument. Faisons en sorte que vim gère toutes les erreurs comme les autres commandes Ex normales. Si l'argument est correct, vim commence à éditer le fichier et s'il n'est pas correct, vim signalera des erreurs.

À mon avis, nous n'avons pas besoin de créer un tampon. Il présente deux inconvénients principaux.

  1. Le 'not-edited'drapeau serait mis. Comme le souligne jamessan dans sa réponse , si nous définissons le nom du fichier actuel avec la :filecommande et essayons d'écrire le fichier, nous rencontrerons le message d'erreur. E13: File exists (use ! to override)C'est parce que vim marque le fichier comme "non modifié" lorsque nous changeons le nom du fichier avec :filecommande.
  2. Nous devons essayer de conserver le nom de fichier alternatif avec la :keepaltcommande. Lorsque nous essayons de modifier vimrc lors de l'édition de 'foo.bar', nous nous attendons à ce que le nom de fichier alternatif soit 'foo.bar'. Mais si nous créons un tampon et changeons le nom, le nom de fichier alternatif ne devient pas le "foo.bar" mais l'ancien nom du tampon 'vimrc'. Pire encore, l'ancien tampon restera comme unlisted-bufferou inactive-buffer. C'est pourquoi nous devrions utiliser la :keepaltcommande afin de conserver le nom de fichier alternatif comme nous l'attendons et définir l' bufhiddenoption wipepour effacer l'ancien tampon.

Si la majuscule du nom de la commande (toutes les commandes définies par l'utilisateur doivent commencer par une majuscule) ne nous concerne pas, il serait préférable de l'utiliser. Parce qu'il ne crée pas de tampon, nous sommes libres de gérer le tampon. Passez simplement le nom du fichier à vim et voyez comment vim le gère.

MS.Kim
la source