feat: ":wall ++p" creates parent dirs for each buf #36121

`:wall ++p` will create parent directories if they do not exist, for
each modified buffer
This commit is contained in:
Rob Pilling
2025-10-11 16:27:58 +01:00
committed by GitHub
parent f0b9232ad8
commit ce27423132
5 changed files with 39 additions and 9 deletions

View File

@@ -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.

View File

@@ -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

View File

@@ -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.

View File

@@ -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',
},

View File

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