Comment enregistrer un fichier dans un répertoire qui n'existe pas encore?


35

Supposons que je lance Vim pour éditer un nouveau fichier dans un répertoire qui n'a pas encore été créé:

vim nonExisitingDirectory/newFile.txt

Vim me montrera avec plaisir un tampon vide et je pourrai commencer à écrire mon nouveau fichier. Mais quand je veux écrire le fichier sur le disque, j'obtiens cette erreur:

E212: Can't Open file for writing.

Je présume que c'est parce que le répertoire n'existe pas encore. Existe-t-il un moyen de forcer Vim à créer le répertoire pour moi?

Réponses:


37

Autant que je sache, il n'y a pas de réglage ou quelque chose de ce genre. Mais tout n'est pas perdu, nous pouvons bien sûr utiliser la commande BufWritePreautomatique.
Ceci est exécuté avant que le tampon ne soit écrit sur le disque. Donc, nous pouvons créer le répertoire ici s'il n'existe pas encore.

Par exemple:

augroup Mkdir
  autocmd!
  autocmd BufWritePre *
    \ if !isdirectory(expand("<afile>:p:h")) |
        \ call mkdir(expand("<afile>:p:h"), "p") |
    \ endif
augroup END
  • On vérifie d’abord si le répertoire existe avec isdirectory, sinon on mkdirobtient une erreur.
  • <afile>fait référence au fichier que nous essayons de sauvegarder; :pest un modificateur pour le développer jusqu'au chemin complet (plutôt que relatif), et :hsupprime le dernier composant de chemin (le fichier).
  • Nous appelons ensuite mkdir()si nécessaire. Nous avons besoin du pdrapeau pour mkdir()faire tous les répertoires des parents (c'est-à-dire dans le cas de nonexistent/more_nonexisting/file.

Vous pouvez bien sûr également exécuter la mkdir()commande à partir de la ligne de commande Vim ou la lier à un raccourci clavier, c'est-à-dire:

nnoremap <Leader>m :call mkdir(expand("%:p:h"), "p")<CR>

Ici, j’ai utilisé à la %place de <afile>, puisque cela n’est valable que depuis une autocommande ( %fait référence au tampon actuellement actif, qui ne fonctionnerait pas :wapar exemple; <afile>fait référence au nom de fichier du tampon qui déclenche l’autocmd).

Vous pouvez également demander une confirmation avant d'écrire un répertoire si vous le souhaitez. Voir cette question pour plus de détails: Comment puis-je empêcher Vim d'écrire un fichier dans la commande automatique BufWritePre?


L'extrait ci-dessus créera le répertoire sur le premier write ( :w). Si vous le souhaitez, vous pouvez également créer le répertoire lors de sa première ouverture (c'est-à-dire juste après sa saisie vim ...) en utilisant BufNewFileautocmd à la place de BufWritePre.


Il existe également un plugin appelé auto_mkdir qui est en réalité le même que celui ci-dessus.

Sur cette page , un extrait de code légèrement développé vous demande également si vous souhaitez créer le répertoire en premier, ce que certains jugeront peut-être utile. Il a également converti le nom de fichier de l'encodage avant de l'écrire:

call mkdir(iconv(expand("%:p:h"), &encoding, &termencoding), 'p')

Je ne sais pas si cela est réellement nécessaire, mais si vous mélangez beaucoup les encodages et obtenez des noms de fichiers étranges, vous pouvez l'essayer.


Je mets tout ce qui précède dans un auto_mkdir2.vimplugin pour une installation plus facile.


3

Je peux recommander un plugin vim de Tim Pope appelé vim-eunuch qui définit de nombreuses commandes extrêmement utiles lorsque vous travaillez sous UNIX / Linux avec Vim (découvrez ses fonctionnalités !).

Disons que vous ouvrez vim avec vim this/is/a/testet qu'aucun de ces répertoires n'existait auparavant. Il suffit de courir :Mkdir!<CR>et vim-eunuch les crée pour vous (avec mkdir -p), vous pouvez donc maintenant sauvegarder votre fichier avec :w<CR>.


2

Utilisez :Wpour créer un fichier et ses répertoires parents:

function! s:WriteCreatingDirs()
  let l:file=expand("%")
  if empty(getbufvar(bufname("%"), '&buftype')) && l:file !~# '\v^\w+\:\/'
    let dir=fnamemodify(l:file, ':h')
    if !isdirectory(dir)
      call mkdir(dir, 'p')
    endif
  endif
  write
endfunction
command! W call s:WriteCreatingDirs()

(Ajoutez à votre vimrc. Basé sur une combinaison de la réponse de Zyx et de celle de Damien Pollet ).


1

Une autre façon avec un Vim vanille (sans conf, ni plugins). à Vim:

:!mkdir -p /folder/you/want/
:w  #save file

ou

$ vim /folder/you/want/myfile.conf
$ ctrl+z # switch to the terminal then create the folders
$ mkdir -p /folder/you/want/
$ fg # return to Vim
$ :w  #save file

1

J'espère contribuer à une version qui s'appuie sur les réponses ci-dessus pour rationaliser le flux de travail encore plus. Je crée souvent de nouveaux fichiers dans un large éventail de structures de projet. Ce tweak va me faire économiser beaucoup de temps.

Il y a deux dépendances auxquelles je peux penser:

  1. J'ai défini en autochdirraison de la façon dont cela fonctionne <C-x><C-f>pour mes instructions d'importation.
  2. le saveas"laisse derrière" (si vous voulez) un tampon caché à la fin de la liste de tampons. Je ne sais pas s'il s'agit d'un comportement d'état dont bénéficient toutes les instances de vim / nvim.
  3. Autre information: J'utilise NVIM sur un Mac OS

    " Auto magically Mkdir
    " ====================
    
    autocmd BufWritePre * call MkDir()
    
    function! MkDir()
       if !isdirectory(expand("<afile>:p:h"))
          let confirmation=confirm("Create a new directory?", "&Yes\n&No")
          if confirmation == 1
             call mkdir(expand("<afile>:p:h"), "p")
             lcd %:p:h
             saveas %:t
             echom "Created a new directory:" expand("<afile>:p:h")
             let buf_del = bufnr("$")
             exe "bd" . buf_del
          endif
          redraw
       endif
    endfunction
    
    " Conditionaly create the parent directory when writing to disk
    " <afile> refers to the file we are saving
    " :p is a modifier that expands to full filename
    " :h is a modifier that removes the file from full filename
    " :t is a modifier that generates the filename with extension
    " "p" is the flag that will create all the parent directories
    
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.