From 2c20e459fafbf7f571833ce9a26143878c4f5902 Mon Sep 17 00:00:00 2001 From: Tom Ryder Date: Fri, 31 May 2019 22:02:49 +1200 Subject: Handle :cd then buffer write of non-existent path --- autoload/write_mkpath.vim | 52 +++++++++++++++++++++++++++++++++++++++++------ plugin/write_mkpath.vim | 4 +++- 2 files changed, 49 insertions(+), 7 deletions(-) diff --git a/autoload/write_mkpath.vim b/autoload/write_mkpath.vim index 0d3e357..aca49f1 100644 --- a/autoload/write_mkpath.vim +++ b/autoload/write_mkpath.vim @@ -1,13 +1,42 @@ -function! write_mkpath#(path) abort +" Handle a buffer created for a new file; anchor its filename to be absolute +" if it's relative and the directory path doesn't yet exist; this stops Vim +" trying to save in the wrong place if the user changes directory before +" writing the buffer +function! write_mkpath#New(path) abort - " Path exists, we don't need to do anything - if isdirectory(a:path) + " We don't have fnameescape(); this old Vim < v7.1.299 is likely too buggy + " to handle the buffer renaming for paths safely, so better not to mess with + " it and instead to stick with suboptimal but consistent behaviour + if !exists('*fnameescape') return endif - " If :write! was issued, we'll try to create the path; failing that, if - " 'confirm' is enabled, and the user responds affirmatively to the prompt, - " that will do, too. Otherwise, we will allow the write to fail. + " Path exists, or is absolute; we don't need to do anything + if isdirectory(fnamemodify(a:path, ':h')) + \ || s:Absolute(a:path) + return + endif + + " Set filename to absolute path using :file {name} + execute 'file '.fnameescape(getcwd().'/'.a:path) + +endfunction + +" Handle a :write operation; prompt for directory creation if needed with +" 'confirm', force it with :write! +function! write_mkpath#Write(path) abort + + " Get all directory elements leading up to directory + let dir = fnamemodify(a:path, ':h') + + " Directory exists, we don't need to do anything + if isdirectory(dir) + return + endif + + " If :write! was issued, we'll try to create the missing path; failing that, + " if 'confirm' is enabled, and the user responds affirmatively to the + " prompt, that will do, too. Otherwise, we will allow the write to fail. if v:cmdbang let mkpath = 1 elseif &confirm @@ -22,3 +51,14 @@ function! write_mkpath#(path) abort endif endfunction + +" Clumsy and probably wrong helper function to check if a path is absolute +function! s:Absolute(path) abort + if has('unix') + return a:path =~# '^/' " Leading slash on Unix + elseif has('win32') || has('win64') + return a:path =~# '^\u:' " e.g. C: -- I'm not sure this is right + else + echoerr 'Unrecognised operating system' + endif +endfunction diff --git a/plugin/write_mkpath.vim b/plugin/write_mkpath.vim index 334f24e..c7c9543 100644 --- a/plugin/write_mkpath.vim +++ b/plugin/write_mkpath.vim @@ -12,6 +12,8 @@ endif " Check path to every file before it's saved augroup write_mkpath autocmd! + autocmd BufNewFile * + \ call write_mkpath#New(expand('')) autocmd BufWritePre * - \ call write_mkpath#(expand(':p:h')) + \ call write_mkpath#Write(expand('')) augroup END -- cgit v1.2.3