ฉันจะบันทึกไฟล์ในไดเรกทอรีที่ยังไม่มีอยู่ได้อย่างไร?


35

สมมติว่าฉันเริ่มเป็นกลุ่มเพื่อแก้ไขไฟล์ใหม่ในไดเรกทอรีที่ยังไม่ได้สร้าง:

vim nonExisitingDirectory/newFile.txt

Vim จะแสดงบัฟเฟอร์ว่างให้ฉันอย่างมีความสุขและฉันสามารถเริ่มเขียนไฟล์ใหม่ของฉันได้ แต่เมื่อฉันต้องการเขียนไฟล์ลงดิสก์ฉันได้รับข้อผิดพลาดนี้:

E212: Can't Open file for writing.

ฉันคิดว่านี่เป็นเพราะไดเรกทอรียังไม่มีอยู่ มีวิธีบังคับให้ Vim สร้างไดเรกทอรีให้ฉันหรือไม่?

คำตอบ:


37

เท่าที่ฉันรู้ว่าไม่มีการตั้งค่าหรือบางอย่างเช่นการทำเช่นนี้ แต่ไม่ทั้งหมดหายไปแน่นอนเราสามารถใช้การเติมข้อความ BufWritePreอัตโนมัติได้
สิ่งนี้ถูกดำเนินการก่อนที่บัฟเฟอร์จะถูกเขียนไปยังดิสก์ ดังนั้นเราสามารถสร้างไดเรกทอรีที่นั่นถ้ามันยังไม่มี

ตัวอย่างเช่น:

augroup Mkdir
  autocmd!
  autocmd BufWritePre *
    \ if !isdirectory(expand("<afile>:p:h")) |
        \ call mkdir(expand("<afile>:p:h"), "p") |
    \ endif
augroup END
  • ก่อนอื่นเราตรวจสอบว่ามีไดเรกทอรีอยู่ด้วยisdirectoryมิฉะนั้นmkdirจะทำให้เกิดข้อผิดพลาด
  • <afile>หมายถึงไฟล์ที่เราพยายามบันทึก :pเป็นตัวดัดแปลงเพื่อขยายเป็นชื่อพา ธ แบบเต็ม (แทนที่จะเป็นแบบสัมพัทธ์) และ:hลบส่วนประกอบพา ธ สุดท้าย (ไฟล์)
  • จากนั้นเราโทรmkdir()ถ้าจำเป็น เราจำเป็นต้องpธงmkdir()เพื่อให้ทุกไดเรกทอรีพ่อแม่ (ie. nonexistent/more_nonexisting/fileในกรณีของ

แน่นอนคุณสามารถเรียกใช้mkdir()คำสั่งจาก commandline Vim หรือผูกกับ keybind เช่น:

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

ที่นี่ฉันใช้%แทน<afile>เนื่องจากใช้ได้เฉพาะจากภายใน autocommand ( %หมายถึงบัฟเฟอร์ที่ใช้งานอยู่ในปัจจุบันซึ่งจะไม่ทำงานด้วย:waเช่น<afile>อ้างถึงชื่อไฟล์ของบัฟเฟอร์ที่เรียก autocmd)

คุณยังสามารถขอคำยืนยันก่อนที่จะเขียนไดเรกทอรีถ้าคุณต้องการ ดูคำถามนี้สำหรับรายละเอียดเพิ่มเติม: ฉันจะหยุด Vim จากการเขียนไฟล์ใน Autocommand ของ BufWritePre ได้อย่างไร


ตัวอย่างด้านบนจะสร้างไดเรกทอรีในการเขียนครั้งแรก ( :w) คุณสามารถถ้าคุณต้องการยังสร้างไดเรกทอรีเมื่อคุณเปิด (เช่นหลังการพิมพ์vim ...) โดยใช้BufNewFileautocmd BufWritePreแทน


นอกจากนี้ยังมีปลั๊กอินที่เรียกว่าauto_mkdirซึ่งมีประสิทธิภาพเหมือนข้างต้น

ในหน้านี้ มีข้อมูลโค้ดที่ขยายออกเล็กน้อยซึ่งจะถามคุณว่าคุณต้องการสร้างไดเรกทอรีก่อนหรือไม่ซึ่งบางอันอาจถือว่ามีประโยชน์ นอกจากนี้ยังมีการแปลงชื่อไฟล์ของการเข้ารหัสก่อนที่จะเขียน:

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

ฉันไม่แน่ใจว่าจำเป็นต้องใช้สิ่งนี้จริงหรือไม่ แต่ถ้าคุณผสมการเข้ารหัสจำนวนมากและรับชื่อไฟล์แปลก ๆ คุณสามารถลองได้


ฉันใส่ทุกอย่างไว้ในauto_mkdir2.vimปลั๊กอินเพื่อการติดตั้งง่ายขึ้น


3

ฉันสามารถแนะนำ vim plugin จาก Tim Pope ที่เรียกว่าvim-eunuchซึ่งกำหนดคำสั่งที่มีประโยชน์มากมายเมื่อคุณทำงานกับ UNIX / Linux ด้วย Vim (ลองดูฟีเจอร์ของมัน !)

สมมติว่าคุณเปิดเป็นกลุ่มด้วยvim this/is/a/testและไม่มีไดเรกทอรีเหล่านี้มาก่อน เพียงแค่เรียกใช้:Mkdir!<CR>แล้ว vim-eunuch สร้างไฟล์เหล่านั้นให้คุณ (ด้วยmkdir -p) ดังนั้นตอนนี้คุณสามารถบันทึกไฟล์ของคุณ:w<CR>ได้แล้ว


2

ใช้:Wเพื่อสร้างไฟล์และไดเรกทอรีหลัก:

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

(เพิ่มในของคุณvimrcขึ้นอยู่กับการรวมคำตอบของ ZyxและคำตอบของDamien Pollet )


1

อีกทางด้วย vanilla Vim (ไม่มี conf หรือปลั๊กอินพิเศษ) ในกลุ่ม:

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

หรือ

$ 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

ฉันหวังว่าจะสนับสนุนรุ่นที่สร้างขึ้นจากคำตอบข้างต้นเพื่อปรับปรุงขั้นตอนการทำงานให้ดียิ่งขึ้น ฉันมักจะสร้างไฟล์ใหม่ภายในโครงสร้างโครงการที่หลากหลาย การบิดนี้จะช่วยฉันในเวลาที่มั่นคง

มีสองการพึ่งพาที่ฉันสามารถคิด:

  1. ฉันตั้งค่าautochdirเนื่องจากวิธีการทำงานกับ<C-x><C-f>คำสั่งการนำเข้าของฉัน
  2. saveas"ใบที่อยู่เบื้องหลัง" (ถ้าคุณจะ) บัฟเฟอร์ที่ซ่อนอยู่ในส่วนท้ายของรายการบัฟเฟอร์ ฉันไม่แน่ใจว่าเป็นพฤติกรรมของรัฐที่อินสแตนซ์ vim / nvim ทั้งหมดสนุกหรือไม่
  3. FYI อื่น ๆ : ฉันใช้ NVIM ใน 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
    
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.