Vim: Tạo thư mục mẹ khi lưu


122

Nếu tôi gọi vim foo/bar/somefilenhưng foo/barchưa tồn tại, Vim sẽ từ chối lưu.

Tôi biết tôi có thể chuyển sang trình bao hoặc làm :!mkdir foo/bartừ Vim nhưng tôi lười :) Có cách nào để Vim làm điều đó tự động khi nó lưu bộ đệm không?


13
mkdir -p %:htốt hơn vì nó hoạt động cho các đường dẫn không tồn tại lồng nhau, không gây ra lỗi khi đường dẫn đã tồn tại và %:hlà đường dẫn đầy đủ của tệp hiện tại. Tuy nhiên, tôi không biết làm thế nào để gọi nó tự động. Thông thường, điều này được thực hiện với các lệnh tự động nhưng BufWritePresự kiện dường như không hoạt động ở đây.
Konrad Rudolph

Xác định một chức năng mà kiểm tra nếu tập tin tồn tại và gọi dựng sẵn writevà gọi hệ thống để mkdir -ptrên dirnamebằng cách khác, bản đồ nó đến W... Tôi quá lười biếng để tìm kiếm các cú pháp và gửi nó như một câu trả lời ... Xin lỗi
Khachik

1
Tôi đoán tôi có thể kết hợp cả hai đề xuất và bí danh của bạn :wđể mkdir -p %:htiếp theo là builting:write
Damien Pollet

Câu trả lời:


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

Lưu ý các điều kiện: expand("<afile>")!~#'^\w\+:/'sẽ ngăn vim tạo thư mục cho các tệp như ftp://*!isdirectorysẽ ngăn cuộc gọi mkdir tốn kém.

Cập nhật : giải pháp sắp xếp tốt hơn cũng kiểm tra buftype không trống và sử dụng 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
Cảm ơn, dường như nhiều bụi hơn những gì tôi đoán-hack :)
Damien Pollet

11
call mkdir(expand('%:h'), 'p')có thể di động hơn.
Marius Gedminas

1
@MariusGedminas Tôi muốn xem mã hoàn chỉnh với thay đổi đó. Bạn có thể vui lòng đăng nó như một câu trả lời / tải nó lên ở đâu đó được không?
kikito

@kikito Xem câu trả lời của tôi. Nó đã được chỉnh sửa vài giờ sau nhận xét đó.
ZyX

@Zyx cảm ơn! Tôi đã kết thúc việc làm một cái gì đó ngắn hơn một chút (câu trả lời của tôi hiện là câu cuối cùng) nhưng nó có vẻ thực hiện thủ thuật một cách độc đáo.
kikito

20

Dựa trên các gợi ý cho câu hỏi của tôi, đây là những gì tôi đã kết thúc:

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

Điều này xác định :Wlệnh. Lý tưởng nhất, tôi muốn có tất cả :w!, :wq, :wq!, :wallvv làm việc như nhau, nhưng tôi không chắc chắn nếu nó có thể không có cơ bản reimplementing tất cả chúng với chức năng tùy chỉnh.


2
Tôi đã thử cùng lệnh này và mỗi khi sử dụng :W, màn hình của tôi gần như trống rỗng. Tôi sẽ thử xóa các tùy chọn trước đây của mình và đưa ra phản hồi.
moebius_eye

6

Tôi đã thêm cái này vào ~ / .vimrc của tôi

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

Nếu tôi cần tạo thư mục mà tôi đang ở, tôi nhập :mk.và nó thay thế thư mục đó bằng "! Mkdir -p / path / to / my / file /" và cho phép tôi xem lại lệnh trước khi gọi nó.



3

này sẽ nhắc bạn tạo thư mục bằng :whoặc chỉ thực hiện với :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

Tôi nghĩ rằng tôi đã quản lý để làm điều này trong ba dòng, kết hợp những gì người khác đang nói về câu trả lời này.

Điều này dường như thực hiện thủ thuật:

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

Nó cố gắng tạo thư mục tự động khi lưu bộ đệm. Nếu bất kỳ điều gì xấu xảy ra (tức là các vấn đề về quyền), nó sẽ chỉ đóng cửa và để tệp ghi không thành công.

Nếu bất kỳ ai nhìn thấy bất kỳ sai sót rõ ràng, xin vui lòng gửi một bình luận. Tôi không thành thạo vimscript.

CHỈNH SỬA: Ghi chú nhờ ZyX

  • Điều này sẽ không hoạt động nếu các thư mục của bạn có khoảng trống trên chúng (dường như chúng không được thoát đúng cách hoặc một cái gì đó)
  • Hoặc nếu bạn đang làm các tệp giả.
  • Hoặc nếu bạn đang tìm nguồn vimrc của mình.
  • Nhưng con trai, nó ngắn.

1
Không bao giờ sử dụng %trong các tập lệnh như vậy. Vim sẽ không thoát khỏi bất kỳ biểu tượng đặc biệt: ví dụ, nếu bạn đang chỉnh sửa một file có tên /mnt/windows/Documents and Settings/User/_vimrcbạn sẽ kết thúc có bốn thư mục mới: /mnt/windows/Documents, ./and, ./Settings./Settings/User. Và, nhân tiện, bạn không cần :executeở đây.
ZyX

1
system()chức năng cho các cuộc gọi shell hoàn toàn im lặng, nhưng bạn không cần cả hai :execute%:p:h: :silent !mkdir -p %:p:hhoạt động chính xác như những gì bạn đã viết (mặc dù :redraw!cuối cùng bạn có thể cần , trong trường hợp :executenày là hữu ích), nhưng tốt hơn là nên sử dụng call system('mkdir -p '.shellescape(expand('%:p:h'))). Sử dụng :execute '!command' shellescape(arg, 1)(với đối số thứ hai cho shellescape) nếu bạn phải sử dụng bangs thay vì system(). Sử dụng bangs nếu đối số thoát chứa dòng mới.
ZyX

Và bạn sẽ không tránh khỏi những rắc rối khác mà tôi đang tránh trong đoạn mã đầu tiên của mình: khởi chạy shell một lần nữa sau mỗi lần tìm nguồn vimrc (giả sử bạn lấy các bản cập nhật vimrc bằng cách thực hiện :source ~/.vimrc) (đây là cái augroupautocmd!dành cho), chế độ xem bị loại bỏ sau khi khởi chạy shell (đó là những gì redraw!dành cho), tạo thư mục rác trong trường hợp sử dụng tệp giả (trong đoạn mã đầu tiên được cắt, nó được kiểm tra bằng cách chỉ khớp tên tệp với một mẫu, nhưng trong lần thứ hai, tôi cũng kiểm tra &buftype) và lệnh gọi shell vô ích trong thư mục trường hợp tồn tại (isdirectory() điều kiện).
ZyX

1
@ZyX Cảm ơn phản hồi của bạn. Tôi không muốn giải quyết những vấn đề mà tôi không có. Tôi không bao giờ sử dụng các ký tự đặc biệt (tức là dấu cách) trên các thư mục của mình, vì vậy%: p: h phù hợp với tôi. Tôi không bao giờ mã nguồn vimrc (thay vào đó tôi giết và mở lại vim) và tôi thậm chí không biết các tập tin giả là gì. vẽ lại! dường như không làm gì cả với tôi. Nhưng tôi thích đề xuất của bạn về loại bỏ thực thi để làm cho mọi thứ ngắn hơn. Chúc mừng!
kikito

1
Không quan trọng bạn có ký tự đặc biệt hay không, đó là điều bạn nên quan tâm. Có quá nhiều vấn đề với %việc mở rộng có thể đề xuất sử dụng nó cho bất kỳ ai. Các tệp giả được sử dụng trong một loạt các plugin (ví dụ như fugitive hoặc my aurum), do đó chúng đáng quan tâm. Nguồn cung ứng vimrc cũng là một thực tế phổ biến. Bạn có thể có bất cứ thứ gì bạn muốn trong vimrc, chỉ cần không đề xuất nó như một câu trả lời. Sử dụng :silent! call mkdir(expand('%:p:h'), 'p')biến thể giải quyết được hai trong số những điểm tôi đã đề cập và thứ ba tôi không đề cập: !mkdirsẽ không hoạt động trên windows.
ZyX
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.