Merge #15433 defaults: auto-create backup dir

This commit is contained in:
Justin M. Keyes 2021-08-27 18:08:20 -07:00 committed by GitHub
commit ff7f7dd26b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 72 additions and 34 deletions

View File

@ -824,12 +824,12 @@ A jump table for the options with a short description can be found at |Q_op|.
again not rename the file.
*'backupdir'* *'bdir'*
'backupdir' 'bdir' string (default ".,$XDG_DATA_HOME/nvim/backup")
'backupdir' 'bdir' string (default ".,$XDG_DATA_HOME/nvim/backup//")
global
List of directories for the backup file, separated with commas.
- The backup file will be created in the first directory in the list
where this is possible. The directory must exist, Vim will not
create it for you.
where this is possible. If none of the directories exist Nvim will
attempt to create the last directory in the list.
- Empty means that no backup file will be created ('patchmode' is
impossible!). Writing may fail because of this.
- A directory "." means to put the backup file in the same directory
@ -6533,17 +6533,17 @@ A jump table for the options with a short description can be found at |Q_op|.
'ttyfast' 'tf' Removed. |vim-differences|
*'undodir'* *'udir'* *E5003*
'undodir' 'udir' string (default "$XDG_DATA_HOME/nvim/undo")
'undodir' 'udir' string (default "$XDG_DATA_HOME/nvim/undo//")
global
List of directory names for undo files, separated with commas.
See |'backupdir'| for details of the format.
See 'backupdir' for details of the format.
"." means using the directory of the file. The undo file name for
"file.txt" is ".file.txt.un~".
For other directories the file name is the full path of the edited
file, with path separators replaced with "%".
When writing: The first directory that exists is used. "." always
works, no directories after "." will be used for writing. If none of
the directories exist Neovim will attempt to create last directory in
works, no directories after "." will be used for writing. If none of
the directories exist Nvim will attempt to create the last directory in
the list.
When reading all entries are tried to find an undo file. The first
undo file that exists is used. When it cannot be read an error is
@ -6552,6 +6552,10 @@ A jump table for the options with a short description can be found at |Q_op|.
This option cannot be set from a |modeline| or in the |sandbox|, for
security reasons.
Note that unlike 'directory' and 'backupdir', 'undodir' always acts as
though the trailing slashes are present (see 'backupdir' for what this
means).
*'undofile'* *'noundofile'* *'udf'* *'noudf'*
'undofile' 'udf' boolean (default off)
local to buffer
@ -6692,7 +6696,7 @@ A jump table for the options with a short description can be found at |Q_op|.
displayed when 'verbosefile' is set.
*'viewdir'* *'vdir'*
'viewdir' 'vdir' string (default: "$XDG_DATA_HOME/nvim/view")
'viewdir' 'vdir' string (default: "$XDG_DATA_HOME/nvim/view//")
global
Name of the directory where to store files for |:mkview|.
This option cannot be set from a |modeline| or in the |sandbox|, for

View File

@ -30,7 +30,7 @@ the differences.
- 'autoread' is enabled
- 'background' defaults to "dark" (unless set automatically by the terminal/UI)
- 'backspace' defaults to "indent,eol,start"
- 'backupdir' defaults to .,~/.local/share/nvim/backup (|xdg|)
- 'backupdir' defaults to .,~/.local/share/nvim/backup// (|xdg|), auto-created
- 'belloff' defaults to "all"
- 'compatible' is always disabled
- 'complete' excludes "i"
@ -63,7 +63,7 @@ the differences.
- 'tags' defaults to "./tags;,tags"
- 'ttimeoutlen' defaults to 50
- 'ttyfast' is always set
- 'undodir' defaults to ~/.local/share/nvim/undo (|xdg|), auto-created
- 'undodir' defaults to ~/.local/share/nvim/undo// (|xdg|), auto-created
- 'viewoptions' includes "unix,slash", excludes "options"
- 'viminfo' includes "!"
- 'wildmenu' is enabled

View File

@ -2688,9 +2688,22 @@ buf_write(
/*
* Isolate one directory name, using an entry in 'bdir'.
*/
(void)copy_option_part(&dirp, IObuff, IOSIZE, ",");
p = IObuff + STRLEN(IObuff);
if (after_pathsep((char *)IObuff, (char *)p) && p[-1] == p[-2]) {
size_t dir_len = copy_option_part(&dirp, IObuff, IOSIZE, ",");
p = IObuff + dir_len;
bool trailing_pathseps = after_pathsep((char *)IObuff, (char *)p) && p[-1] == p[-2];
if (trailing_pathseps) {
IObuff[dir_len - 2] = NUL;
}
if (*dirp == NUL && !os_isdir(IObuff)) {
int ret;
char *failed_dir;
if ((ret = os_mkdir_recurse((char *)IObuff, 0755, &failed_dir)) != 0) {
EMSG3(_("E303: Unable to create directory \"%s\" for backup file: %s"),
failed_dir, os_strerror(ret));
xfree(failed_dir);
}
}
if (trailing_pathseps) {
// Ends with '//', Use Full path
if ((p = (char_u *)make_percent_swname((char *)IObuff, (char *)fname))
!= NULL) {
@ -2840,9 +2853,22 @@ nobackup:
/*
* Isolate one directory name and make the backup file name.
*/
(void)copy_option_part(&dirp, IObuff, IOSIZE, ",");
p = IObuff + STRLEN(IObuff);
if (after_pathsep((char *)IObuff, (char *)p) && p[-1] == p[-2]) {
size_t dir_len = copy_option_part(&dirp, IObuff, IOSIZE, ",");
p = IObuff + dir_len;
bool trailing_pathseps = after_pathsep((char *)IObuff, (char *)p) && p[-1] == p[-2];
if (trailing_pathseps) {
IObuff[dir_len - 2] = NUL;
}
if (*dirp == NUL && !os_isdir(IObuff)) {
int ret;
char *failed_dir;
if ((ret = os_mkdir_recurse((char *)IObuff, 0755, &failed_dir)) != 0) {
EMSG3(_("E303: Unable to create directory \"%s\" for backup file: %s"),
failed_dir, os_strerror(ret));
xfree(failed_dir);
}
}
if (trailing_pathseps) {
// path ends with '//', use full path
if ((p = (char_u *)make_percent_swname((char *)IObuff, (char *)fname))
!= NULL) {

View File

@ -1442,7 +1442,7 @@ recover_names (
* Append the full path to name with path separators made into percent
* signs, to dir. An unnamed buffer is handled as "" (<currentdir>/"")
*/
char *make_percent_swname(const char *dir, char *name)
char *make_percent_swname(const char *dir, const char *name)
FUNC_ATTR_NONNULL_ARG(1)
{
char *d = NULL;

View File

@ -483,17 +483,17 @@ void set_init_1(bool clean_arg)
#endif
false);
char *backupdir = stdpaths_user_data_subpath("backup", 0, true);
char *backupdir = stdpaths_user_data_subpath("backup", 2, true);
const size_t backupdir_len = strlen(backupdir);
backupdir = xrealloc(backupdir, backupdir_len + 3);
memmove(backupdir + 2, backupdir, backupdir_len + 1);
memmove(backupdir, ".,", 2);
set_string_default("viewdir", stdpaths_user_data_subpath("view", 0, true),
true);
set_string_default("backupdir", backupdir, true);
set_string_default("viewdir", stdpaths_user_data_subpath("view", 2, true),
true);
set_string_default("directory", stdpaths_user_data_subpath("swap", 2, true),
true);
set_string_default("undodir", stdpaths_user_data_subpath("undo", 0, true),
set_string_default("undodir", stdpaths_user_data_subpath("undo", 2, true),
true);
// Set default for &runtimepath. All necessary expansions are performed in
// this function.

View File

@ -672,6 +672,7 @@ char *u_get_undo_file_name(const char *const buf_ffname, const bool reading)
#ifdef HAVE_READLINK
char fname_buf[MAXPATHL];
#endif
char *p;
if (ffname == NULL) {
return NULL;
@ -704,6 +705,13 @@ char *u_get_undo_file_name(const char *const buf_ffname, const bool reading)
memmove(tail + tail_len + 1, ".un~", sizeof(".un~"));
} else {
dir_name[dir_len] = NUL;
// Remove trailing pathseps from directory name
p = &dir_name[dir_len - 1];
while (vim_ispathsep(*p)) {
*p-- = NUL;
}
bool has_directory = os_isdir((char_u *)dir_name);
if (!has_directory && *dirp == NUL && !reading) {
// Last directory in the list does not exist, create it.
@ -720,7 +728,7 @@ char *u_get_undo_file_name(const char *const buf_ffname, const bool reading)
if (has_directory) {
if (munged_name == NULL) {
munged_name = xstrdup(ffname);
for (char *p = munged_name; *p != NUL; MB_PTR_ADV(p)) {
for (p = munged_name; *p != NUL; MB_PTR_ADV(p)) {
if (vim_ispathsep(*p)) {
*p = '%';
}

View File

@ -354,13 +354,13 @@ describe('XDG-based defaults', function()
.. ',' .. root_path .. ('/a'):rep(2048) .. '/nvim/after'
.. ',' .. root_path .. ('/x'):rep(4096) .. '/nvim/after'
):gsub('\\', '/')), (meths.get_option('runtimepath')):gsub('\\', '/'))
eq('.,' .. root_path .. ('/X'):rep(4096).. '/' .. data_dir .. '/backup',
eq('.,' .. root_path .. ('/X'):rep(4096).. '/' .. data_dir .. '/backup//',
(meths.get_option('backupdir'):gsub('\\', '/')))
eq(root_path .. ('/X'):rep(4096) .. '/' .. data_dir .. '/swap//',
(meths.get_option('directory')):gsub('\\', '/'))
eq(root_path .. ('/X'):rep(4096) .. '/' .. data_dir .. '/undo',
eq(root_path .. ('/X'):rep(4096) .. '/' .. data_dir .. '/undo//',
(meths.get_option('undodir')):gsub('\\', '/'))
eq(root_path .. ('/X'):rep(4096) .. '/' .. data_dir .. '/view',
eq(root_path .. ('/X'):rep(4096) .. '/' .. data_dir .. '/view//',
(meths.get_option('viewdir')):gsub('\\', '/'))
end)
end)
@ -404,13 +404,13 @@ describe('XDG-based defaults', function()
.. ',$XDG_DATA_DIRS/nvim/after'
.. ',$XDG_DATA_HOME/nvim/after'
):gsub('\\', '/')), (meths.get_option('runtimepath')):gsub('\\', '/'))
eq(('.,$XDG_CONFIG_HOME/' .. data_dir .. '/backup'),
eq(('.,$XDG_CONFIG_HOME/' .. data_dir .. '/backup//'),
meths.get_option('backupdir'):gsub('\\', '/'))
eq(('$XDG_CONFIG_HOME/' .. data_dir .. '/swap//'),
meths.get_option('directory'):gsub('\\', '/'))
eq(('$XDG_CONFIG_HOME/' .. data_dir .. '/undo'),
eq(('$XDG_CONFIG_HOME/' .. data_dir .. '/undo//'),
meths.get_option('undodir'):gsub('\\', '/'))
eq(('$XDG_CONFIG_HOME/' .. data_dir .. '/view'),
eq(('$XDG_CONFIG_HOME/' .. data_dir .. '/view//'),
meths.get_option('viewdir'):gsub('\\', '/'))
meths.command('set all&')
eq(('$XDG_DATA_HOME/nvim'
@ -424,13 +424,13 @@ describe('XDG-based defaults', function()
.. ',$XDG_DATA_DIRS/nvim/after'
.. ',$XDG_DATA_HOME/nvim/after'
):gsub('\\', '/'), (meths.get_option('runtimepath')):gsub('\\', '/'))
eq(('.,$XDG_CONFIG_HOME/' .. data_dir .. '/backup'),
eq(('.,$XDG_CONFIG_HOME/' .. data_dir .. '/backup//'),
meths.get_option('backupdir'):gsub('\\', '/'))
eq(('$XDG_CONFIG_HOME/' .. data_dir .. '/swap//'),
meths.get_option('directory'):gsub('\\', '/'))
eq(('$XDG_CONFIG_HOME/' .. data_dir .. '/undo'),
eq(('$XDG_CONFIG_HOME/' .. data_dir .. '/undo//'),
meths.get_option('undodir'):gsub('\\', '/'))
eq(('$XDG_CONFIG_HOME/' .. data_dir .. '/view'),
eq(('$XDG_CONFIG_HOME/' .. data_dir .. '/view//'),
meths.get_option('viewdir'):gsub('\\', '/'))
end)
end)
@ -483,13 +483,13 @@ describe('XDG-based defaults', function()
.. ',\\,-\\,-\\,' .. path_sep ..'nvim' .. path_sep ..'after'
.. ',\\, \\, \\,' .. path_sep ..'nvim' .. path_sep ..'after'
), meths.get_option('runtimepath'))
eq('.,\\,=\\,=\\,' .. path_sep .. data_dir .. '' .. path_sep ..'backup',
eq('.,\\,=\\,=\\,' .. path_sep .. data_dir .. '' .. path_sep ..'backup' .. (path_sep):rep(2),
meths.get_option('backupdir'))
eq('\\,=\\,=\\,' .. path_sep ..'' .. data_dir .. '' .. path_sep ..'swap' .. (path_sep):rep(2),
meths.get_option('directory'))
eq('\\,=\\,=\\,' .. path_sep ..'' .. data_dir .. '' .. path_sep ..'undo',
eq('\\,=\\,=\\,' .. path_sep ..'' .. data_dir .. '' .. path_sep ..'undo' .. (path_sep):rep(2),
meths.get_option('undodir'))
eq('\\,=\\,=\\,' .. path_sep ..'' .. data_dir .. '' .. path_sep ..'view',
eq('\\,=\\,=\\,' .. path_sep ..'' .. data_dir .. '' .. path_sep ..'view' .. (path_sep):rep(2),
meths.get_option('viewdir'))
end)
end)