Vim: Створення батьківських каталогів при збереженні


122

Якщо я посилаюсь, vim foo/bar/somefileале її foo/barще не існує, Vim відмовляється зберігати.

Я знаю, що я міг би перейти на оболонку або зробити :!mkdir foo/barз Vim, але я лінивий :) Чи є спосіб зробити так, щоб Vim робив це автоматично, коли він зберігає буфер?


13
mkdir -p %:hкраще, оскільки він працює для вкладених неіснуючих шляхів, не викликає помилки, коли шлях вже існує, і %:hє повним шляхом поточного файлу. Однак я не знаю, як викликати це автоматично. Як правило, це робиться з автоматичними командами, але BufWritePreподія, здається, не працює тут.
Конрад Рудольф

Визначте функцію, яка перевіряє, чи існує файл, і викликає вбудований writeі закликає систему в іншому випадку, mkdir -pdirnameW
нанесіть

1
Напевно, я міг би поєднати як ваші пропозиції, так і псевдонім, :wщоб mkdir -p %:hслідувати нарощуванню:write
Дамієн

Відповіді:


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

Зверніть увагу на умови: expand("<afile>")!~#'^\w\+:/'заважатиме vim створювати каталоги для таких файлів, як ftp://*і !isdirectoryзапобігає дорогому виклику mkdir.

Оновлення : плавно краще рішення, яке також перевіряє наявність непустого типу та використовує 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

1
Дякую, здається, набагато чистіше, ніж те, що я гадаю, зламане :)
Дамієн Поллет

11
call mkdir(expand('%:h'), 'p')може бути більш портативним.
Маріус Гедмінас

1
@MariusGedminas Я хотів би побачити повний код із цією зміною. Чи можете ви опублікувати його як відповідь / завантажити десь?
кікіто

@kikito Дивіться мою відповідь. Він був відредагований через кілька годин після цього коментаря.
ZyX

@Zyx дякую! Я в кінцевому підсумку робив щось трохи коротше (моя відповідь наразі остання), але, здається, добре робила трюк.
кікіто

20

На основі пропозицій до мого запитання, ось що я закінчив:

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

Це визначає :Wкоманду. В ідеалі я хотів би мати все :w!, :wq, :wq!, і :wallт.д. працюю так само, але я не впевнений , якщо це можливо без в основному реалізувавши їх всі призначені для користувача функції.


2
Я спробував цю ж команду, і кожен раз, коли я використовую :W, мій екран стає майже порожнім. Я спробую видалити свої попередні варіанти та надати відгуки.
moebius_eye

6

Я додав це до свого ~ / .vimrc

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

Якщо мені потрібно створити каталог, в якому я вписую, :mk.він замінює його на "! Mkdir -p / path / to / my / file /" і дозволяє мені переглянути команду перед тим, як викликати її.



3

Цей код запропонує вам створити каталог :wабо просто зробити це за допомогою :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

1

Я думаю, що мені вдалося це зробити в три рядки, поєднуючи те, що інші говорять у цій відповіді.

Це, здається, робить трюк:

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

Він намагається створити папку автоматично під час збереження буфера. Якщо трапиться щось погане (тобто проблеми з дозволом), воно просто закриється і не дозволить записати файл.

Якщо хтось бачить явні недоліки, будь ласка, опублікуйте коментар. Я не дуже розбираюся в vimscript.

EDIT: Примітки завдяки ZyX

  • Це не спрацює, якщо у ваших папках є пробіли (мабуть, вони неправильно відображені чи щось)
  • Або якщо ви робите псевдофайли.
  • Або якщо ви шукаєте свій vimrc.
  • Але сину, це коротко.

1
Ніколи не використовуйте %в таких сценаріях. Vim не збирається тікати які - або спеціальні символи, наприклад, якщо ви редагуєте файл з ім'ям /mnt/windows/Documents and Settings/User/_vimrcви будете в кінцевому підсумку, чотири нових каталогів: /mnt/windows/Documents, ./and, ./Settingsі ./Settings/User. І, до речі, тут вам не потрібно :execute.
ZyX

1
Існує system()функція для абсолютно безшумних викликів оболонки, але вам не потрібно і те, :executeі інше %:p:h: :silent !mkdir -p %:p:hпрацює саме так, як ви написали (хоча вам, можливо, знадобиться :redraw!в кінці, в цьому випадку :executeстане в нагоді), але краще використовувати call system('mkdir -p '.shellescape(expand('%:p:h'))). Скористайтеся :execute '!command' shellescape(arg, 1)(з другим аргументом для shellescape), якщо вам доведеться використовувати чубок замість system(). Використовуйте чубку, якщо аргумент, що вийшов, містить нові рядки.
ZyX

І ви не уникаєте інших неприємностей, яких я уникаю в своєму першому фрагменті коду: запускайте оболонку ще один раз після кожного пошуку vimrc (припустимо, ви робите оновлення vimrc, роблячи :source ~/.vimrc) (це те, що augroupі autocmd!для чого), скраптований вигляд після запуску оболонки команди (саме redraw!для цього), створення каталогів сміття у разі використання псевдофайлів (у першому фрагменті коду це перевіряється лише відповідним іменем файлу відповідно до шаблону, а в другому я також перевіряю &buftype) та марним викликом оболонки у каталозі випадку існує ( isdirectory()умова).
ZyX

1
@ZyX Дякуємо за ваш відгук. Я не хочу вирішувати проблем, яких у мене немає. Я ніколи не використовую спеціальних символів (тобто пробілів) у своїх папках, тому%: p: h для мене просто чудово. Я ніколи не створюю vimrc (замість цього я вбиваю і повторюю vim), і навіть не знаю, що таке псевдофайли. перемалювати! начебто нічого не робить для мене взагалі. Але мені подобається ваша пропозиція про видалення Execute, щоб зробити все коротшим. Ура!
кікіто

1
Не має значення, чи є у вас спеціальні персонажі чи ні, це те, про що ви повинні піклуватися. Існує надто багато проблем із %розширенням, щоб коли-небудь запропонувати використовувати його комусь. Псевдофайли використовуються у великій купі плагінів (наприклад, втікач чи мій аурум), тому їх варто дбати. Ресурсування vimrc також є поширеною практикою. У vimrc ви можете мати все, що завгодно, просто не пропонуйте це як відповідь. Використання :silent! call mkdir(expand('%:p:h'), 'p')варіанту вирішує два згадані мною моменти, а третій я не згадував: !mkdirне буде працювати над Windows.
ZyX
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.