diff --git a/runtime/doc/editing.txt b/runtime/doc/editing.txt index 0448cd52ae..687963e238 100644 --- a/runtime/doc/editing.txt +++ b/runtime/doc/editing.txt @@ -996,11 +996,13 @@ slower (but safer). WRITING WITH MULTIPLE BUFFERS *buffer-write* *:wa* *:wall* -:wa[ll] Write all changed buffers. Buffers without a file +:wa[ll] [++opt] Write all changed buffers. Buffers without a file name cause an error message. Buffers which are readonly are not written. + For ++opt see |++opt|, but only ++p is effective, and + applies to each written file. -:wa[ll]! Write all changed buffers, even the ones that are +:wa[ll]! [++opt] Write all changed buffers, even the ones that are readonly. Buffers without a file name are not written and cause an error message. diff --git a/runtime/doc/news.txt b/runtime/doc/news.txt index 71c8ee0239..cb2621354a 100644 --- a/runtime/doc/news.txt +++ b/runtime/doc/news.txt @@ -197,6 +197,8 @@ EDITOR • |gx| in help buffers opens the online documentation for the tag under the cursor. • |:Undotree| for visually navigating the |undo-tree| +• |:wall| permits a |++p| option for creating parent directories when writing + changed buffers. EVENTS diff --git a/src/nvim/ex_cmds.c b/src/nvim/ex_cmds.c index ed19458d61..8211b59063 100644 --- a/src/nvim/ex_cmds.c +++ b/src/nvim/ex_cmds.c @@ -1806,6 +1806,15 @@ static int check_writable(const char *fname) } #endif +static int handle_mkdir_p_arg(exarg_T *eap, char *fname) +{ + if (eap->mkdir_p && os_file_mkdir(fname, 0755) < 0) { + return FAIL; + } + + return OK; +} + /// Write current buffer to file "eap->arg". /// If "eap->append" is true, append to the file. /// @@ -1943,11 +1952,9 @@ int do_write(exarg_T *eap) fname = curbuf->b_sfname; } - if (eap->mkdir_p) { - if (os_file_mkdir(fname, 0755) < 0) { - retval = FAIL; - goto theend; - } + if (handle_mkdir_p_arg(eap, fname) == FAIL) { + retval = FAIL; + goto theend; } int name_was_missing = curbuf->b_ffname == NULL; @@ -2123,7 +2130,8 @@ void do_wqall(exarg_T *eap) } else { bufref_T bufref; set_bufref(&bufref, buf); - if (buf_write_all(buf, eap->forceit) == FAIL) { + if (handle_mkdir_p_arg(eap, buf->b_fname) == FAIL + || buf_write_all(buf, eap->forceit) == FAIL) { error++; } // An autocommand may have deleted the buffer. diff --git a/src/nvim/ex_cmds.lua b/src/nvim/ex_cmds.lua index 790bf9e22a..e7d9c45aff 100644 --- a/src/nvim/ex_cmds.lua +++ b/src/nvim/ex_cmds.lua @@ -3187,7 +3187,7 @@ M.cmds = { }, { command = 'wall', - flags = bit.bor(BANG, TRLBAR, CMDWIN, LOCK_OK), + flags = bit.bor(BANG, TRLBAR, CMDWIN, LOCK_OK, ARGOPT), addr_type = 'ADDR_NONE', func = 'do_wqall', }, diff --git a/test/functional/ex_cmds/write_spec.lua b/test/functional/ex_cmds/write_spec.lua index 668fc3ecf4..8997198837 100644 --- a/test/functional/ex_cmds/write_spec.lua +++ b/test/functional/ex_cmds/write_spec.lua @@ -23,6 +23,9 @@ describe(':write', function() os.remove('test_fifo') os.remove('test/write/p_opt.txt') os.remove('test/write') + os.remove('test/write2/p_opt.txt') + os.remove('test/write2/p_opt2.txt') + os.remove('test/write2') os.remove('test') os.remove(fname) os.remove(fname_bak) @@ -111,6 +114,21 @@ describe(':write', function() command('write ++p test/write/p_opt.txt') eq(1, eval("filereadable('test/write/p_opt.txt')")) + eq(0, eval("filereadable('test/write2/p_opt.txt')")) + eq(0, eval("filereadable('test/write2/p_opt2.txt')")) + eq(0, eval("filereadable('test/write3/p_opt3.txt')")) + command('file test/write2/p_opt.txt') + command('set modified') + command('sp test/write2/p_opt2.txt') + command('set modified') + command('sp test/write3/p_opt3.txt') + -- don't set p_opt3.txt modified - assert it isn't written + -- and that write3/ isn't created + command('wall ++p') + eq(1, eval("filereadable('test/write2/p_opt.txt')")) + eq(1, eval("filereadable('test/write2/p_opt2.txt')")) + eq(0, eval("filereadable('test/write3/p_opt3.txt')")) + eq('Vim(write):E32: No file name', pcall_err(command, 'write ++p test_write/')) if not is_os('win') then eq(