Vim: Membuat direktori induk saat menyimpan

122

Jika saya memanggil vim foo/bar/somefiletetapi foo/barbelum ada, Vim menolak untuk menyimpan.

Saya tahu saya dapat beralih ke shell atau melakukan :!mkdir foo/bardari Vim tetapi saya malas :) Apakah ada cara untuk membuat Vim melakukan itu secara otomatis ketika itu menyimpan buffer?

Damien Pollet
sumber
13
mkdir -p %:hlebih baik karena berfungsi untuk jalur yang tidak ada bersarang, tidak menimbulkan kesalahan saat jalur sudah ada, dan %:hmerupakan jalur lengkap dari file saat ini. Namun, saya tidak tahu cara mengaktifkannya secara otomatis. Biasanya, ini dilakukan dengan perintah otomatis tetapi BufWritePreacara tersebut tampaknya tidak berfungsi di sini.
Konrad Rudolph
Tentukan fungsi yang memeriksa apakah file tersebut ada dan memanggil bawaan writedan memanggil sistem ke mkdir -pon dirnamejika tidak, petakan ke W... Saya terlalu malas untuk mencari sintaks dan mempostingnya sebagai jawaban ... Maaf
khachik
1
Saya kira saya bisa menggabungkan saran dan alias Anda :wuntuk mkdir -p %:hdiikuti oleh builting:write
Damien Pollet

Jawaban:

91
augroup BWCCreateDir
    autocmd!
    autocmd BufWritePre * if expand("<afile>")!~#'^\w\+:/' && !isdirectory(expand("%:h")) | execute "silent! !mkdir -p ".shellescape(expand('%:h'), 1) | redraw! | endif
augroup END

Perhatikan kondisi: expand("<afile>")!~#'^\w\+:/'akan mencegah vim membuat direktori untuk file seperti ftp://*dan !isdirectoryakan mencegah panggilan mkdir yang mahal.

Perbarui : solusi yang lebih baik yang juga memeriksa buftype dan penggunaan yang tidak kosong mkdir():

function s:MkNonExDir(file, buf)
    if empty(getbufvar(a:buf, '&buftype')) && a:file!~#'\v^\w+\:\/'
        let dir=fnamemodify(a:file, ':h')
        if !isdirectory(dir)
            call mkdir(dir, 'p')
        endif
    endif
endfunction
augroup BWCCreateDir
    autocmd!
    autocmd BufWritePre * :call s:MkNonExDir(expand('<afile>'), +expand('<abuf>'))
augroup END
ZyX
sumber
1
Terima kasih, tampaknya jauh lebih bersih daripada yang saya kira-diretas :)
Damien Pollet
11
call mkdir(expand('%:h'), 'p')mungkin lebih portabel.
Marius Gedminas
1
@MariusGedminas Saya ingin melihat kode lengkap dengan perubahan itu. Bisakah Anda mempostingnya sebagai jawaban / mengunggahnya di suatu tempat?
kikito
@kikito Lihat jawaban saya. Itu diedit beberapa jam setelah komentar itu.
ZyX
@Zyx terima kasih! Saya akhirnya melakukan sesuatu yang sedikit lebih pendek (jawaban saya saat ini adalah yang terakhir) tetapi tampaknya melakukan trik dengan baik.
kikito
20

Berdasarkan saran untuk pertanyaan saya, inilah yang akhirnya saya dapatkan:

function WriteCreatingDirs()
    execute ':silent !mkdir -p %:h'
    write
endfunction
command W call WriteCreatingDirs()

Ini mendefinisikan :Wperintah. Idealnya, saya ingin memiliki semua :w!, :wq, :wq!, :walldll bekerja sama, tapi aku tidak yakin apakah itu mungkin tanpa dasarnya reimplementing mereka semua dengan fungsi kustom.

Damien Pollet
sumber
2
Saya sudah mencoba perintah yang sama ini dan setiap kali saya gunakan :W, layar saya menjadi hampir kosong. Saya akan mencoba dan menghapus opsi saya sebelumnya dan memberikan umpan balik.
moebius_eye
6

Saya menambahkan ini ke ~ / .vimrc saya

cnoremap mk. !mkdir -p <c-r>=expand("%:h")<cr>/

Jika saya perlu membuat direktori tempat saya berada, saya mengetik :mk.dan itu menggantikannya dengan "! Mkdir -p / path / to / my / file /" dan mengizinkan saya untuk meninjau perintah sebelum saya memanggilnya.

Asa Ayers
sumber
3

Kode ini akan meminta Anda untuk membuat direktori dengan :w, atau lakukan saja dengan :w!:

augroup vimrc-auto-mkdir
  autocmd!
  autocmd BufWritePre * call s:auto_mkdir(expand('<afile>:p:h'), v:cmdbang)
  function! s:auto_mkdir(dir, force)
    if !isdirectory(a:dir)
          \   && (a:force
          \       || input("'" . a:dir . "' does not exist. Create? [y/N]") =~? '^y\%[es]$')
      call mkdir(iconv(a:dir, &encoding, &termencoding), 'p')
    endif
  endfunction
augroup END
Tom Hale
sumber
1

Saya pikir saya berhasil melakukan ini dalam tiga baris, menggabungkan apa yang dikatakan orang lain tentang jawaban ini.

Ini sepertinya berhasil:

if has("autocmd")
  autocmd BufWritePre * :silent !mkdir -p %:p:h
end

Ia mencoba untuk membuat folder secara otomatis saat menyimpan buffer. Jika sesuatu yang buruk terjadi (yaitu masalah izin), itu hanya akan menutup dan membiarkan file menulis gagal.

Jika ada yang melihat kekurangan yang jelas, silakan kirim komentar. Saya tidak terlalu ahli dalam vimscript.

EDIT: Catatan berkat ZyX

  • Ini tidak akan berfungsi jika folder Anda memiliki spasi di dalamnya (tampaknya mereka tidak di-escape dengan benar atau semacamnya)
  • Atau jika Anda melakukan pseudo file.
  • Atau jika Anda mencari vimrc Anda.
  • Tapi nak, itu pendek.
kikito
sumber
1
Jangan pernah gunakan %dalam skrip seperti itu. Vim tidak akan melarikan diri setiap simbol khusus: misalnya, jika Anda mengedit sebuah file bernama /mnt/windows/Documents and Settings/User/_vimrcAnda akan berakhir memiliki empat direktori baru: /mnt/windows/Documents, ./and, ./Settingsdan ./Settings/User. Dan, omong-omong, Anda tidak perlu di :executesini.
ZyX
1
Ada system()fungsi untuk panggilan shell yang senyap, tetapi Anda tidak memerlukan keduanya :executedan %:p:h: :silent !mkdir -p %:p:hberfungsi persis seperti yang telah Anda tulis (meskipun Anda mungkin perlu :redraw!di bagian akhir, dalam hal ini akan :executeberguna), tetapi lebih baik digunakan call system('mkdir -p '.shellescape(expand('%:p:h'))). Gunakan :execute '!command' shellescape(arg, 1)(dengan argumen kedua untuk shellescape) jika Anda harus menggunakan poni, bukan system(). Gunakan poni jika argumen lolos berisi baris baru.
ZyX
Dan Anda tidak menghindari masalah lain yang saya hindari dalam cuplikan kode pertama saya: meluncurkan shell satu kali lagi setelah setiap sumber vimrc (misalkan Anda menarik pembaruan vimrc dengan melakukan :source ~/.vimrc) (ini untuk apa augroupdan autocmd!untuk), membatalkan tampilan setelah meluncurkan shell perintah (untuk apa redraw!), membuat direktori sampah jika menggunakan pseudo-file (dalam kode pertama yang dipotong itu diperiksa hanya dengan mencocokkan nama file dengan pola, tetapi di yang kedua saya juga memeriksa &buftype) dan panggilan shell yang tidak berguna dalam direktori kasus ada ( isdirectory()kondisi).
ZyX
1
@ZyX Terima kasih atas tanggapan Anda. Saya tidak ingin menyelesaikan masalah yang tidak saya miliki. Saya tidak pernah menggunakan karakter khusus (yaitu spasi) pada folder saya, jadi%: p: h tidak masalah bagi saya. Saya tidak pernah mencari vimrc (saya membunuh dan membuka kembali vim sebagai gantinya) dan saya bahkan tidak tahu apa itu pseudofiles. menggambar ulang! sepertinya tidak melakukan apa-apa padaku. Tapi saya suka saran Anda untuk menghapus eksekusi untuk membuat semuanya lebih pendek. Bersulang!
kikito
1
Tidak masalah apakah Anda memiliki karakter khusus atau tidak, itu adalah hal yang harus Anda pedulikan. Ada terlalu banyak masalah dengan %ekspansi yang tidak pernah disarankan untuk digunakan oleh siapa pun. File pseudo digunakan dalam banyak plugin (misalnya buronan atau aurum saya), oleh karena itu mereka layak untuk diperhatikan. Sumber daya vimrc juga merupakan praktik umum. Anda dapat memiliki apa pun yang Anda inginkan di vimrc, hanya saja jangan menyarankannya sebagai jawaban. Menggunakan :silent! call mkdir(expand('%:p:h'), 'p')varian memecahkan dua poin yang saya sebutkan dan ketiga saya tidak menyebutkan: !mkdirtidak akan berfungsi di windows.
ZyX