mirror of
https://github.com/neovim/neovim.git
synced 2025-10-05 09:26:30 +00:00
Merge pull request #3470 from ZyX-I/pr-3198
XDG base directory specification support
This commit is contained in:
211
src/nvim/main.c
211
src/nvim/main.c
@@ -287,8 +287,8 @@ int main(int argc, char **argv)
|
||||
* Set the default values for the options that use Rows and Columns.
|
||||
*/
|
||||
win_init_size();
|
||||
/* Set the 'diff' option now, so that it can be checked for in a .vimrc
|
||||
* file. There is no buffer yet though. */
|
||||
// Set the 'diff' option now, so that it can be checked for in a vimrc
|
||||
// file. There is no buffer yet though.
|
||||
if (params.diff_mode)
|
||||
diff_win_options(firstwin, FALSE);
|
||||
|
||||
@@ -345,7 +345,7 @@ int main(int argc, char **argv)
|
||||
*/
|
||||
load_plugins();
|
||||
|
||||
/* Decide about window layout for diff mode after reading vimrc. */
|
||||
// Decide about window layout for diff mode after reading vimrc.
|
||||
set_window_layout(¶ms);
|
||||
|
||||
/*
|
||||
@@ -358,10 +358,8 @@ int main(int argc, char **argv)
|
||||
mch_exit(0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Set a few option defaults after reading .vimrc files:
|
||||
* 'title' and 'icon', Unix: 'shellpipe' and 'shellredir'.
|
||||
*/
|
||||
// Set a few option defaults after reading vimrc files:
|
||||
// 'title' and 'icon', Unix: 'shellpipe' and 'shellredir'.
|
||||
set_init_3();
|
||||
TIME_MSG("inits 3");
|
||||
|
||||
@@ -1551,8 +1549,8 @@ static void create_windows(mparm_T *parmp)
|
||||
if (parmp->window_count == 0)
|
||||
parmp->window_count = GARGCOUNT;
|
||||
if (parmp->window_count > 1) {
|
||||
/* Don't change the windows if there was a command in .vimrc that
|
||||
* already split some windows */
|
||||
// Don't change the windows if there was a command in vimrc that
|
||||
// already split some windows
|
||||
if (parmp->window_layout == 0)
|
||||
parmp->window_layout = WIN_HOR;
|
||||
if (parmp->window_layout == WIN_TABS) {
|
||||
@@ -1574,14 +1572,11 @@ static void create_windows(mparm_T *parmp)
|
||||
getout(1);
|
||||
do_modelines(0); /* do modelines */
|
||||
} else {
|
||||
/*
|
||||
* Open a buffer for windows that don't have one yet.
|
||||
* Commands in the .vimrc might have loaded a file or split the window.
|
||||
* Watch out for autocommands that delete a window.
|
||||
*/
|
||||
/*
|
||||
* Don't execute Win/Buf Enter/Leave autocommands here
|
||||
*/
|
||||
// Open a buffer for windows that don't have one yet.
|
||||
// Commands in the vimrc might have loaded a file or split the window.
|
||||
// Watch out for autocommands that delete a window.
|
||||
//
|
||||
// Don't execute Win/Buf Enter/Leave autocommands here
|
||||
++autocmd_no_enter;
|
||||
++autocmd_no_leave;
|
||||
dorewind = TRUE;
|
||||
@@ -1691,8 +1686,8 @@ static void edit_buffers(mparm_T *parmp)
|
||||
}
|
||||
advance = TRUE;
|
||||
|
||||
/* Only open the file if there is no file in this window yet (that can
|
||||
* happen when .vimrc contains ":sall"). */
|
||||
// Only open the file if there is no file in this window yet (that can
|
||||
// happen when vimrc contains ":sall").
|
||||
if (curbuf == firstwin->w_buffer || curbuf->b_ffname == NULL) {
|
||||
curwin->w_arg_idx = arg_idx;
|
||||
/* Edit file from arg list, if there is one. When "Quit" selected
|
||||
@@ -1801,117 +1796,121 @@ static void exe_commands(mparm_T *parmp)
|
||||
TIME_MSG("executing command arguments");
|
||||
}
|
||||
|
||||
/*
|
||||
* Source startup scripts.
|
||||
*/
|
||||
static void source_startup_scripts(mparm_T *parmp)
|
||||
/// Source vimrc or do other user initialization
|
||||
///
|
||||
/// Does one of the following things, stops after whichever succeeds:
|
||||
///
|
||||
/// 1. Execution of VIMINIT environment variable.
|
||||
/// 2. Sourcing user vimrc file ($XDG_CONFIG_HOME/nvim/init.vim).
|
||||
/// 3. Sourcing other vimrc files ($XDG_CONFIG_DIRS[1]/nvim/init.vim, …).
|
||||
/// 4. Execution of EXINIT environment variable.
|
||||
///
|
||||
/// @return True if it is needed to attempt to source exrc file according to
|
||||
/// 'exrc' option definition.
|
||||
static bool do_user_initialization(void)
|
||||
FUNC_ATTR_WARN_UNUSED_RESULT
|
||||
{
|
||||
int i;
|
||||
bool do_exrc = p_exrc;
|
||||
if (process_env("VIMINIT", true) == OK) {
|
||||
return do_exrc;
|
||||
}
|
||||
char_u *user_vimrc = (char_u *)stdpaths_user_conf_subpath("init.vim");
|
||||
if (do_source(user_vimrc, true, DOSO_VIMRC) != FAIL) {
|
||||
if (do_exrc) {
|
||||
do_exrc = (path_full_compare((char_u *)VIMRC_FILE, user_vimrc, false)
|
||||
!= kEqualFiles);
|
||||
}
|
||||
xfree(user_vimrc);
|
||||
return do_exrc;
|
||||
}
|
||||
xfree(user_vimrc);
|
||||
char *const config_dirs = stdpaths_get_xdg_var(kXDGConfigDirs);
|
||||
if (config_dirs != NULL) {
|
||||
const void *iter = NULL;
|
||||
do {
|
||||
const char *dir;
|
||||
size_t dir_len;
|
||||
iter = vim_colon_env_iter(config_dirs, iter, &dir, &dir_len);
|
||||
if (dir == NULL || dir_len == 0) {
|
||||
break;
|
||||
}
|
||||
const char path_tail[] = { 'n', 'v', 'i', 'm', PATHSEP,
|
||||
'i', 'n', 'i', 't', '.', 'v', 'i', 'm', NUL };
|
||||
char *vimrc = xmalloc(dir_len + sizeof(path_tail) + 1);
|
||||
memmove(vimrc, dir, dir_len);
|
||||
vimrc[dir_len] = PATHSEP;
|
||||
memmove(vimrc + dir_len + 1, path_tail, sizeof(path_tail));
|
||||
if (do_source((char_u *) vimrc, true, DOSO_VIMRC) != FAIL) {
|
||||
if (do_exrc) {
|
||||
do_exrc = (path_full_compare((char_u *)VIMRC_FILE, (char_u *)vimrc,
|
||||
false) != kEqualFiles);
|
||||
}
|
||||
xfree(vimrc);
|
||||
xfree(config_dirs);
|
||||
return do_exrc;
|
||||
}
|
||||
xfree(vimrc);
|
||||
} while (iter != NULL);
|
||||
xfree(config_dirs);
|
||||
}
|
||||
if (process_env("EXINIT", false) == OK) {
|
||||
return do_exrc;
|
||||
}
|
||||
return do_exrc;
|
||||
}
|
||||
|
||||
/*
|
||||
* If -u argument given, use only the initializations from that file and
|
||||
* nothing else.
|
||||
*/
|
||||
/// Source startup scripts
|
||||
///
|
||||
/// @param[in]
|
||||
static void source_startup_scripts(const mparm_T *const parmp)
|
||||
FUNC_ATTR_NONNULL_ALL
|
||||
{
|
||||
// If -u argument given, use only the initializations from that file and
|
||||
// nothing else.
|
||||
if (parmp->use_vimrc != NULL) {
|
||||
if (strcmp(parmp->use_vimrc, "NONE") == 0
|
||||
|| strcmp(parmp->use_vimrc, "NORC") == 0) {
|
||||
if (parmp->use_vimrc[2] == 'N')
|
||||
p_lpl = FALSE; // don't load plugins either
|
||||
p_lpl = false; // don't load plugins either
|
||||
} else {
|
||||
if (do_source((char_u *)parmp->use_vimrc, FALSE, DOSO_NONE) != OK)
|
||||
EMSG2(_("E282: Cannot read from \"%s\""), parmp->use_vimrc);
|
||||
}
|
||||
} else if (!silent_mode) {
|
||||
|
||||
/*
|
||||
* Get system wide defaults, if the file name is defined.
|
||||
*/
|
||||
#ifdef SYS_VIMRC_FILE
|
||||
(void)do_source((char_u *)SYS_VIMRC_FILE, FALSE, DOSO_NONE);
|
||||
// Get system wide defaults, if the file name is defined.
|
||||
(void) do_source((char_u *)SYS_VIMRC_FILE, false, DOSO_NONE);
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Try to read initialization commands from the following places:
|
||||
* - environment variable VIMINIT
|
||||
* - user vimrc file (~/.vimrc)
|
||||
* - second user vimrc file ($VIM/.vimrc for Dos)
|
||||
* - environment variable EXINIT
|
||||
* - user exrc file (~/.exrc)
|
||||
* - second user exrc file ($VIM/.exrc for Dos)
|
||||
* The first that exists is used, the rest is ignored.
|
||||
*/
|
||||
if (process_env("VIMINIT", true) != OK) {
|
||||
if (do_source((char_u *)USR_VIMRC_FILE, TRUE, DOSO_VIMRC) == FAIL
|
||||
#ifdef USR_VIMRC_FILE2
|
||||
&& do_source((char_u *)USR_VIMRC_FILE2, TRUE,
|
||||
DOSO_VIMRC) == FAIL
|
||||
#endif
|
||||
#ifdef USR_VIMRC_FILE3
|
||||
&& do_source((char_u *)USR_VIMRC_FILE3, TRUE,
|
||||
DOSO_VIMRC) == FAIL
|
||||
#endif
|
||||
&& process_env("EXINIT", FALSE) == FAIL
|
||||
&& do_source((char_u *)USR_EXRC_FILE, FALSE, DOSO_NONE) == FAIL) {
|
||||
#ifdef USR_EXRC_FILE2
|
||||
(void)do_source((char_u *)USR_EXRC_FILE2, FALSE, DOSO_NONE);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Read initialization commands from ".vimrc" or ".exrc" in current
|
||||
* directory. This is only done if the 'exrc' option is set.
|
||||
* Because of security reasons we disallow shell and write commands
|
||||
* now, except for unix if the file is owned by the user or 'secure'
|
||||
* option has been reset in environment of global ".exrc" or ".vimrc".
|
||||
* Only do this if VIMRC_FILE is not the same as USR_VIMRC_FILE or
|
||||
* SYS_VIMRC_FILE.
|
||||
*/
|
||||
if (p_exrc) {
|
||||
if (do_user_initialization()) {
|
||||
// Read initialization commands from ".vimrc" or ".exrc" in current
|
||||
// directory. This is only done if the 'exrc' option is set.
|
||||
// Because of security reasons we disallow shell and write commands
|
||||
// now, except for unix if the file is owned by the user or 'secure'
|
||||
// option has been reset in environment of global "exrc" or "vimrc".
|
||||
// Only do this if VIMRC_FILE is not the same as vimrc file sourced in
|
||||
// do_user_initialization.
|
||||
#if defined(UNIX)
|
||||
/* If ".vimrc" file is not owned by user, set 'secure' mode. */
|
||||
// If vimrc file is not owned by user, set 'secure' mode.
|
||||
if (!file_owned(VIMRC_FILE))
|
||||
#endif
|
||||
secure = p_secure;
|
||||
|
||||
i = FAIL;
|
||||
if (path_full_compare((char_u *)USR_VIMRC_FILE,
|
||||
(char_u *)VIMRC_FILE, FALSE) != kEqualFiles
|
||||
#ifdef USR_VIMRC_FILE2
|
||||
&& path_full_compare((char_u *)USR_VIMRC_FILE2,
|
||||
(char_u *)VIMRC_FILE, FALSE) != kEqualFiles
|
||||
#endif
|
||||
#ifdef USR_VIMRC_FILE3
|
||||
&& path_full_compare((char_u *)USR_VIMRC_FILE3,
|
||||
(char_u *)VIMRC_FILE, FALSE) != kEqualFiles
|
||||
#endif
|
||||
#ifdef SYS_VIMRC_FILE
|
||||
&& path_full_compare((char_u *)SYS_VIMRC_FILE,
|
||||
(char_u *)VIMRC_FILE, FALSE) != kEqualFiles
|
||||
#endif
|
||||
)
|
||||
i = do_source((char_u *)VIMRC_FILE, TRUE, DOSO_VIMRC);
|
||||
|
||||
if (i == FAIL) {
|
||||
if (do_source((char_u *)VIMRC_FILE, true, DOSO_VIMRC) == FAIL) {
|
||||
#if defined(UNIX)
|
||||
/* if ".exrc" is not owned by user set 'secure' mode */
|
||||
if (!file_owned(EXRC_FILE))
|
||||
// if ".exrc" is not owned by user set 'secure' mode
|
||||
if (!file_owned(EXRC_FILE)) {
|
||||
secure = p_secure;
|
||||
else
|
||||
} else {
|
||||
secure = 0;
|
||||
}
|
||||
#endif
|
||||
if ( path_full_compare((char_u *)USR_EXRC_FILE,
|
||||
(char_u *)EXRC_FILE, FALSE) != kEqualFiles
|
||||
#ifdef USR_EXRC_FILE2
|
||||
&& path_full_compare((char_u *)USR_EXRC_FILE2,
|
||||
(char_u *)EXRC_FILE, FALSE) != kEqualFiles
|
||||
#endif
|
||||
)
|
||||
(void)do_source((char_u *)EXRC_FILE, FALSE, DOSO_NONE);
|
||||
(void)do_source((char_u *)EXRC_FILE, false, DOSO_NONE);
|
||||
}
|
||||
}
|
||||
if (secure == 2)
|
||||
need_wait_return = TRUE;
|
||||
if (secure == 2) {
|
||||
need_wait_return = true;
|
||||
}
|
||||
secure = 0;
|
||||
}
|
||||
did_source_startup_scripts = true;
|
||||
@@ -2042,7 +2041,7 @@ static void usage(void)
|
||||
mch_msg(_(" -r, -L List swap files and exit\n"));
|
||||
mch_msg(_(" -r <file> Recover crashed session\n"));
|
||||
mch_msg(_(" -u <nvimrc> Use <nvimrc> instead of the default\n"));
|
||||
mch_msg(_(" -i <shada> Use <shada> instead of the default " SHADA_FILE "\n")); // NOLINT(whitespace/line_length)
|
||||
mch_msg(_(" -i <shada> Use <shada> instead of the default\n"));
|
||||
mch_msg(_(" --noplugin Don't load plugin scripts\n"));
|
||||
mch_msg(_(" -o[N] Open N windows (default: one for each file)\n"));
|
||||
mch_msg(_(" -O[N] Like -o but split vertically\n"));
|
||||
|
@@ -406,10 +406,12 @@ void ml_setname(buf_T *buf)
|
||||
* Try all directories in the 'directory' option.
|
||||
*/
|
||||
dirp = p_dir;
|
||||
bool found_existing_dir = false;
|
||||
for (;; ) {
|
||||
if (*dirp == NUL) /* tried all directories, fail */
|
||||
break;
|
||||
fname = findswapname(buf, &dirp, mfp->mf_fname);
|
||||
fname = (char_u *)findswapname(buf, (char **)&dirp, (char *)mfp->mf_fname,
|
||||
&found_existing_dir);
|
||||
/* alloc's fname */
|
||||
if (dirp == NULL) /* out of memory */
|
||||
break;
|
||||
@@ -504,13 +506,15 @@ void ml_open_file(buf_T *buf)
|
||||
* Try all directories in 'directory' option.
|
||||
*/
|
||||
dirp = p_dir;
|
||||
bool found_existing_dir = false;
|
||||
for (;; ) {
|
||||
if (*dirp == NUL)
|
||||
break;
|
||||
/* There is a small chance that between choosing the swap file name
|
||||
* and creating it, another Vim creates the file. In that case the
|
||||
* creation will fail and we will use another directory. */
|
||||
fname = findswapname(buf, &dirp, NULL); /* allocates fname */
|
||||
// There is a small chance that between choosing the swap file name
|
||||
// and creating it, another Vim creates the file. In that case the
|
||||
// creation will fail and we will use another directory.
|
||||
fname = (char_u *)findswapname(buf, (char **)&dirp, NULL,
|
||||
&found_existing_dir);
|
||||
if (dirp == NULL)
|
||||
break; /* out of memory */
|
||||
if (fname == NULL)
|
||||
@@ -3222,45 +3226,56 @@ static int do_swapexists(buf_T *buf, char_u *fname)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Find out what name to use for the swap file for buffer 'buf'.
|
||||
*
|
||||
* Several names are tried to find one that does not exist
|
||||
* Returns the name in allocated memory or NULL.
|
||||
* When out of memory "dirp" is set to NULL.
|
||||
*
|
||||
* Note: If BASENAMELEN is not correct, you will get error messages for
|
||||
* not being able to open the swap or undo file
|
||||
* Note: May trigger SwapExists autocmd, pointers may change!
|
||||
*/
|
||||
static char_u *
|
||||
findswapname (
|
||||
buf_T *buf,
|
||||
char_u **dirp, /* pointer to list of directories */
|
||||
char_u *old_fname /* don't give warning for this file name */
|
||||
)
|
||||
/// Find out what name to use for the swap file for buffer 'buf'.
|
||||
///
|
||||
/// Several names are tried to find one that does not exist. Last directory in
|
||||
/// option is automatically created.
|
||||
///
|
||||
/// @note If BASENAMELEN is not correct, you will get error messages for
|
||||
/// not being able to open the swap or undo file.
|
||||
/// @note May trigger SwapExists autocmd, pointers may change!
|
||||
///
|
||||
/// @param[in] buf Buffer for which swap file names needs to be found.
|
||||
/// @param[in,out] dirp Pointer to a list of directories. When out of memory,
|
||||
/// is set to NULL. Is advanced to the next directory in
|
||||
/// the list otherwise.
|
||||
/// @param[in] old_fname Allowed existing swap file name. Except for this
|
||||
/// case, name of the non-existing file is used.
|
||||
/// @param[in,out] found_existing_dir If points to true, then new directory
|
||||
/// for swap file is not created. At first
|
||||
/// findswapname() call this argument must
|
||||
/// point to false. This parameter may only
|
||||
/// be set to true by this function, it is
|
||||
/// never set to false.
|
||||
///
|
||||
/// @return [allocated] Name of the swap file.
|
||||
static char *findswapname(buf_T *buf, char **dirp, char *old_fname,
|
||||
bool *found_existing_dir)
|
||||
FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_NONNULL_ARG(1, 2, 4)
|
||||
{
|
||||
char_u *fname;
|
||||
int n;
|
||||
char_u *dir_name;
|
||||
char_u *buf_fname = buf->b_fname;
|
||||
char *fname;
|
||||
size_t n;
|
||||
char *dir_name;
|
||||
char *buf_fname = (char *) buf->b_fname;
|
||||
|
||||
/*
|
||||
* Isolate a directory name from *dirp and put it in dir_name.
|
||||
* First allocate some memory to put the directory name in.
|
||||
*/
|
||||
dir_name = xmalloc(STRLEN(*dirp) + 1);
|
||||
(void)copy_option_part(dirp, dir_name, 31000, ",");
|
||||
const size_t dir_len = strlen(*dirp);
|
||||
dir_name = xmalloc(dir_len + 1);
|
||||
(void)copy_option_part((char_u **) dirp, (char_u *) dir_name, dir_len, ",");
|
||||
|
||||
/*
|
||||
* we try different names until we find one that does not exist yet
|
||||
*/
|
||||
fname = makeswapname(buf_fname, buf->b_ffname, buf, dir_name);
|
||||
fname = (char *)makeswapname((char_u *)buf_fname, buf->b_ffname, buf,
|
||||
(char_u *)dir_name);
|
||||
|
||||
for (;; ) {
|
||||
if (fname == NULL) /* must be out of memory */
|
||||
break;
|
||||
if ((n = (int)STRLEN(fname)) == 0) { /* safety check */
|
||||
if ((n = strlen(fname)) == 0) { /* safety check */
|
||||
xfree(fname);
|
||||
fname = NULL;
|
||||
break;
|
||||
@@ -3269,7 +3284,7 @@ findswapname (
|
||||
// Extra security check: When a swap file is a symbolic link, this
|
||||
// is most likely a symlink attack.
|
||||
FileInfo file_info;
|
||||
bool file_or_link_found = os_fileinfo_link((char *)fname, &file_info);
|
||||
bool file_or_link_found = os_fileinfo_link(fname, &file_info);
|
||||
if (!file_or_link_found) {
|
||||
break;
|
||||
}
|
||||
@@ -3300,7 +3315,7 @@ findswapname (
|
||||
* Try to read block 0 from the swap file to get the original
|
||||
* file name (and inode number).
|
||||
*/
|
||||
fd = os_open((char *)fname, O_RDONLY, 0);
|
||||
fd = os_open(fname, O_RDONLY, 0);
|
||||
if (fd >= 0) {
|
||||
if (read_eintr(fd, &b0, sizeof(b0)) == sizeof(b0)) {
|
||||
/*
|
||||
@@ -3311,7 +3326,7 @@ findswapname (
|
||||
if (b0.b0_flags & B0_SAME_DIR) {
|
||||
if (fnamecmp(path_tail(buf->b_ffname),
|
||||
path_tail(b0.b0_fname)) != 0
|
||||
|| !same_directory(fname, buf->b_ffname)) {
|
||||
|| !same_directory((char_u *) fname, buf->b_ffname)) {
|
||||
/* Symlinks may point to the same file even
|
||||
* when the name differs, need to check the
|
||||
* inode too. */
|
||||
@@ -3351,12 +3366,12 @@ findswapname (
|
||||
* user anyway.
|
||||
*/
|
||||
if (swap_exists_action != SEA_NONE
|
||||
&& has_autocmd(EVENT_SWAPEXISTS, buf_fname, buf))
|
||||
choice = do_swapexists(buf, fname);
|
||||
&& has_autocmd(EVENT_SWAPEXISTS, (char_u *) buf_fname, buf))
|
||||
choice = do_swapexists(buf, (char_u *) fname);
|
||||
|
||||
if (choice == 0) {
|
||||
/* Show info about the existing swap file. */
|
||||
attention_message(buf, fname);
|
||||
attention_message(buf, (char_u *) fname);
|
||||
|
||||
/* We don't want a 'q' typed at the more-prompt
|
||||
* interrupt loading a file. */
|
||||
@@ -3364,20 +3379,21 @@ findswapname (
|
||||
}
|
||||
|
||||
if (swap_exists_action != SEA_NONE && choice == 0) {
|
||||
char_u *name;
|
||||
char *name;
|
||||
|
||||
name = xmalloc(STRLEN(fname)
|
||||
+ STRLEN(_("Swap file \""))
|
||||
+ STRLEN(_("\" already exists!")) + 5);
|
||||
const size_t fname_len = strlen(fname);
|
||||
name = xmalloc(fname_len
|
||||
+ strlen(_("Swap file \""))
|
||||
+ strlen(_("\" already exists!")) + 5);
|
||||
STRCPY(name, _("Swap file \""));
|
||||
home_replace(NULL, fname, name + STRLEN(name),
|
||||
1000, TRUE);
|
||||
home_replace(NULL, (char_u *) fname, (char_u *)&name[strlen(name)],
|
||||
fname_len, true);
|
||||
STRCAT(name, _("\" already exists!"));
|
||||
choice = do_dialog(VIM_WARNING,
|
||||
(char_u *)_("VIM - ATTENTION"),
|
||||
name == NULL
|
||||
? (char_u *)_("Swap file already exists!")
|
||||
: name,
|
||||
(char_u *)(name == NULL
|
||||
? _("Swap file already exists!")
|
||||
: name),
|
||||
# if defined(UNIX)
|
||||
process_still_running
|
||||
? (char_u *)_(
|
||||
@@ -3409,7 +3425,7 @@ findswapname (
|
||||
swap_exists_action = SEA_RECOVER;
|
||||
break;
|
||||
case 4:
|
||||
os_remove((char *)fname);
|
||||
os_remove(fname);
|
||||
break;
|
||||
case 5:
|
||||
swap_exists_action = SEA_QUIT;
|
||||
@@ -3421,7 +3437,7 @@ findswapname (
|
||||
}
|
||||
|
||||
/* If the file was deleted this fname can be used. */
|
||||
if (!os_file_exists(fname))
|
||||
if (!os_file_exists((char_u *) fname))
|
||||
break;
|
||||
} else
|
||||
{
|
||||
@@ -3454,6 +3470,19 @@ findswapname (
|
||||
--fname[n - 1]; /* ".swo", ".swn", etc. */
|
||||
}
|
||||
|
||||
if (os_isdir((char_u *) dir_name)) {
|
||||
*found_existing_dir = true;
|
||||
} else if (!*found_existing_dir && **dirp == NUL) {
|
||||
int ret;
|
||||
char *failed_dir;
|
||||
if ((ret = os_mkdir_recurse(dir_name, 0755, &failed_dir)) != 0) {
|
||||
EMSG3(_("E303: Unable to create directory \"%s\" for swap file, "
|
||||
"recovery impossible: %s"),
|
||||
failed_dir, os_strerror(ret));
|
||||
xfree(failed_dir);
|
||||
}
|
||||
}
|
||||
|
||||
xfree(dir_name);
|
||||
return fname;
|
||||
}
|
||||
|
@@ -301,6 +301,243 @@ static char *(p_cot_values[]) = {"menu", "menuone", "longest", "preview",
|
||||
# include "option.c.generated.h"
|
||||
#endif
|
||||
|
||||
/// Append string with escaped commas
|
||||
static char *strcpy_comma_escaped(char *dest, const char *src, const size_t len)
|
||||
FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT
|
||||
{
|
||||
size_t shift = 0;
|
||||
for (size_t i = 0; i < len; i++) {
|
||||
if (src[i] == ',') {
|
||||
dest[i + shift++] = '\\';
|
||||
}
|
||||
dest[i + shift] = src[i];
|
||||
}
|
||||
return &dest[len + shift];
|
||||
}
|
||||
|
||||
/// Compute length of a colon-separated value, doubled and with some suffixes
|
||||
///
|
||||
/// @param[in] val Colon-separated array value.
|
||||
/// @param[in] common_suf_len Length of the common suffix which is appended to
|
||||
/// each item in the array, twice.
|
||||
/// @param[in] single_suf_len Length of the suffix which is appended to each
|
||||
/// item in the array once.
|
||||
///
|
||||
/// @return Length of the comma-separated string array that contains each item
|
||||
/// in the original array twice with suffixes with given length
|
||||
/// (common_suf is present after each new item, single_suf is present
|
||||
/// after half of the new items) and with commas after each item, commas
|
||||
/// inside the values are escaped.
|
||||
static inline size_t compute_double_colon_len(const char *const val,
|
||||
const size_t common_suf_len,
|
||||
const size_t single_suf_len)
|
||||
FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_PURE
|
||||
{
|
||||
if (val == NULL && *val) {
|
||||
return 0;
|
||||
}
|
||||
size_t ret = 0;
|
||||
const void *iter = NULL;
|
||||
do {
|
||||
size_t dir_len;
|
||||
const char *dir;
|
||||
iter = vim_colon_env_iter(val, iter, &dir, &dir_len);
|
||||
if (dir != NULL && dir_len > 0) {
|
||||
ret += ((dir_len + memcnt(dir, ',', dir_len) + common_suf_len
|
||||
+ !after_pathsep(dir, dir + dir_len)) * 2
|
||||
+ single_suf_len);
|
||||
}
|
||||
} while (iter != NULL);
|
||||
return ret;
|
||||
}
|
||||
|
||||
#define NVIM_SIZE (sizeof("nvim") - 1)
|
||||
|
||||
/// Add directories to a comma-separated array from a colon-separated one
|
||||
///
|
||||
/// Commas are escaped in process. To each item PATHSEP "nvim" is appended in
|
||||
/// addition to suf1 and suf2.
|
||||
///
|
||||
/// @param[in,out] dest Destination comma-separated array.
|
||||
/// @param[in] val Source colon-separated array.
|
||||
/// @param[in] suf1 If not NULL, suffix appended to destination. Prior to it
|
||||
/// directory separator is appended. Suffix must not contain
|
||||
/// commas.
|
||||
/// @param[in] len1 Length of the suf1.
|
||||
/// @param[in] suf2 If not NULL, another suffix appended to destination. Again
|
||||
/// with directory separator behind. Suffix must not contain
|
||||
/// commas.
|
||||
/// @param[in] len2 Length of the suf2.
|
||||
/// @param[in] forward If true, iterate over val in forward direction.
|
||||
/// Otherwise in reverse.
|
||||
///
|
||||
/// @return (dest + appended_characters_length)
|
||||
static inline char *add_colon_dirs(char *dest, const char *const val,
|
||||
const char *const suf1, const size_t len1,
|
||||
const char *const suf2, const size_t len2,
|
||||
const bool forward)
|
||||
FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_NONNULL_RET FUNC_ATTR_NONNULL_ARG(1)
|
||||
{
|
||||
if (val == NULL && *val) {
|
||||
return dest;
|
||||
}
|
||||
const void *iter = NULL;
|
||||
do {
|
||||
size_t dir_len;
|
||||
const char *dir;
|
||||
iter = (forward ? vim_colon_env_iter : vim_colon_env_iter_rev)(
|
||||
val, iter, &dir, &dir_len);
|
||||
if (dir != NULL && dir_len > 0) {
|
||||
dest = strcpy_comma_escaped(dest, dir, dir_len);
|
||||
if (!after_pathsep(dest - 1, dest)) {
|
||||
*dest++ = PATHSEP;
|
||||
}
|
||||
memmove(dest, "nvim", NVIM_SIZE);
|
||||
dest += NVIM_SIZE;
|
||||
if (suf1 != NULL) {
|
||||
*dest++ = PATHSEP;
|
||||
memmove(dest, suf1, len1);
|
||||
dest += len1;
|
||||
if (suf2 != NULL) {
|
||||
*dest++ = PATHSEP;
|
||||
memmove(dest, suf2, len2);
|
||||
dest += len2;
|
||||
}
|
||||
}
|
||||
*dest++ = ',';
|
||||
}
|
||||
} while (iter != NULL);
|
||||
return dest;
|
||||
}
|
||||
|
||||
/// Add directory to a comma-separated list of directories
|
||||
///
|
||||
/// In the added directory comma is escaped.
|
||||
///
|
||||
/// @param[in,out] dest Destination comma-separated array.
|
||||
/// @param[in] dir Directory to append.
|
||||
/// @param[in] append_nvim If true, append "nvim" as the very first suffix.
|
||||
/// @param[in] suf1 If not NULL, suffix appended to destination. Prior to it
|
||||
/// directory separator is appended. Suffix must not contain
|
||||
/// commas.
|
||||
/// @param[in] len1 Length of the suf1.
|
||||
/// @param[in] suf2 If not NULL, another suffix appended to destination. Again
|
||||
/// with directory separator behind. Suffix must not contain
|
||||
/// commas.
|
||||
/// @param[in] len2 Length of the suf2.
|
||||
/// @param[in] forward If true, iterate over val in forward direction.
|
||||
/// Otherwise in reverse.
|
||||
///
|
||||
/// @return (dest + appended_characters_length)
|
||||
static inline char *add_dir(char *dest, const char *const dir,
|
||||
const size_t dir_len, const bool append_nvim,
|
||||
const char *const suf1, const size_t len1,
|
||||
const char *const suf2, const size_t len2)
|
||||
FUNC_ATTR_NONNULL_RET FUNC_ATTR_NONNULL_ARG(1) FUNC_ATTR_WARN_UNUSED_RESULT
|
||||
{
|
||||
if (dir == NULL && dir_len != 0) {
|
||||
return dest;
|
||||
}
|
||||
dest = strcpy_comma_escaped(dest, dir, dir_len);
|
||||
if (append_nvim) {
|
||||
if (!after_pathsep(dest - 1, dest)) {
|
||||
*dest++ = PATHSEP;
|
||||
}
|
||||
memmove(dest, "nvim", NVIM_SIZE);
|
||||
dest += NVIM_SIZE;
|
||||
if (suf1 != NULL) {
|
||||
*dest++ = PATHSEP;
|
||||
memmove(dest, suf1, len1);
|
||||
dest += len1;
|
||||
if (suf2 != NULL) {
|
||||
*dest++ = PATHSEP;
|
||||
memmove(dest, suf2, len2);
|
||||
dest += len2;
|
||||
}
|
||||
}
|
||||
}
|
||||
*dest++ = ',';
|
||||
return dest;
|
||||
}
|
||||
|
||||
/// Set &runtimepath to default value
|
||||
static void set_runtimepath_default(void)
|
||||
{
|
||||
size_t rtp_size = 0;
|
||||
char *const data_home = stdpaths_get_xdg_var(kXDGDataHome);
|
||||
char *const config_home = stdpaths_get_xdg_var(kXDGConfigHome);
|
||||
char *const vimruntime = vim_getenv("VIMRUNTIME");
|
||||
char *const data_dirs = stdpaths_get_xdg_var(kXDGDataDirs);
|
||||
char *const config_dirs = stdpaths_get_xdg_var(kXDGConfigDirs);
|
||||
#define SITE_SIZE (sizeof("site") - 1)
|
||||
#define AFTER_SIZE (sizeof("after") - 1)
|
||||
size_t data_len = 0;
|
||||
size_t config_len = 0;
|
||||
size_t vimruntime_len = 0;
|
||||
if (data_home != NULL) {
|
||||
data_len = strlen(data_home);
|
||||
if (data_len != 0) {
|
||||
rtp_size += ((data_len + memcnt(data_home, ',', data_len)
|
||||
+ NVIM_SIZE + 1 + SITE_SIZE + 1
|
||||
+ !after_pathsep(data_home, data_home + data_len)) * 2
|
||||
+ AFTER_SIZE + 1);
|
||||
}
|
||||
}
|
||||
if (config_home != NULL) {
|
||||
config_len = strlen(config_home);
|
||||
if (config_len != 0) {
|
||||
rtp_size += ((config_len + memcnt(config_home, ',', config_len)
|
||||
+ NVIM_SIZE + 1
|
||||
+ !after_pathsep(config_home, config_home + config_len)) * 2
|
||||
+ AFTER_SIZE + 1);
|
||||
}
|
||||
}
|
||||
if (vimruntime != NULL) {
|
||||
vimruntime_len = strlen(vimruntime);
|
||||
if (vimruntime_len != 0) {
|
||||
rtp_size += vimruntime_len + memcnt(vimruntime, ',', vimruntime_len) + 1;
|
||||
}
|
||||
}
|
||||
rtp_size += compute_double_colon_len(data_dirs, NVIM_SIZE + 1 + SITE_SIZE + 1,
|
||||
AFTER_SIZE + 1);
|
||||
rtp_size += compute_double_colon_len(config_dirs, NVIM_SIZE + 1,
|
||||
AFTER_SIZE + 1);
|
||||
if (rtp_size == 0) {
|
||||
return;
|
||||
}
|
||||
char *const rtp = xmalloc(rtp_size);
|
||||
char *rtp_cur = rtp;
|
||||
rtp_cur = add_dir(rtp_cur, config_home, config_len, true, NULL, 0, NULL, 0);
|
||||
rtp_cur = add_colon_dirs(rtp_cur, config_dirs, NULL, 0, NULL, 0, true);
|
||||
rtp_cur = add_dir(rtp_cur, data_home, data_len, true, "site", SITE_SIZE,
|
||||
NULL, 0);
|
||||
rtp_cur = add_colon_dirs(rtp_cur, data_dirs, "site", SITE_SIZE, NULL, 0,
|
||||
true);
|
||||
rtp_cur = add_dir(rtp_cur, vimruntime, vimruntime_len, false, NULL, 0,
|
||||
NULL, 0);
|
||||
rtp_cur = add_colon_dirs(rtp_cur, data_dirs, "site", SITE_SIZE,
|
||||
"after", AFTER_SIZE, false);
|
||||
rtp_cur = add_dir(rtp_cur, data_home, data_len, true, "site", SITE_SIZE,
|
||||
"after", AFTER_SIZE);
|
||||
rtp_cur = add_colon_dirs(rtp_cur, config_dirs, "after", AFTER_SIZE, NULL, 0,
|
||||
false);
|
||||
rtp_cur = add_dir(rtp_cur, config_home, config_len, true,
|
||||
"after", AFTER_SIZE, NULL, 0);
|
||||
// Strip trailing comma.
|
||||
rtp_cur[-1] = NUL;
|
||||
assert((size_t) (rtp_cur - rtp) == rtp_size);
|
||||
#undef SITE_SIZE
|
||||
#undef AFTER_SIZE
|
||||
set_string_default("runtimepath", rtp, true);
|
||||
xfree(data_dirs);
|
||||
xfree(config_dirs);
|
||||
xfree(data_home);
|
||||
xfree(config_home);
|
||||
xfree(vimruntime);
|
||||
}
|
||||
|
||||
#undef NVIM_SIZE
|
||||
|
||||
/*
|
||||
* Initialize the options, first part.
|
||||
*
|
||||
@@ -308,7 +545,6 @@ static char *(p_cot_values[]) = {"menu", "menuone", "longest", "preview",
|
||||
*/
|
||||
void set_init_1(void)
|
||||
{
|
||||
char_u *p;
|
||||
int opt_idx;
|
||||
|
||||
langmap_init();
|
||||
@@ -320,8 +556,12 @@ void set_init_1(void)
|
||||
* Find default value for 'shell' option.
|
||||
* Don't use it if it is empty.
|
||||
*/
|
||||
if ((p = (char_u *)os_getenv("SHELL")) != NULL)
|
||||
set_string_default("sh", p);
|
||||
{
|
||||
const char *shell = os_getenv("SHELL");
|
||||
if (shell != NULL) {
|
||||
set_string_default("sh", (char *) shell, false);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Set the default for 'backupskip' to include environment variables for
|
||||
@@ -339,17 +579,18 @@ void set_init_1(void)
|
||||
ga_init(&ga, 1, 100);
|
||||
for (size_t n = 0; n < ARRAY_SIZE(names); ++n) {
|
||||
bool mustfree = true;
|
||||
char *p;
|
||||
# ifdef UNIX
|
||||
if (*names[n] == NUL) {
|
||||
p = (char_u *)"/tmp";
|
||||
p = "/tmp";
|
||||
mustfree = false;
|
||||
}
|
||||
else
|
||||
# endif
|
||||
p = (char_u *)vim_getenv(names[n]);
|
||||
p = vim_getenv(names[n]);
|
||||
if (p != NULL && *p != NUL) {
|
||||
// First time count the NUL, otherwise count the ','.
|
||||
len = (int)STRLEN(p) + 3;
|
||||
len = (int)strlen(p) + 3;
|
||||
ga_grow(&ga, len);
|
||||
if (!GA_EMPTY(&ga))
|
||||
STRCAT(ga.ga_data, ",");
|
||||
@@ -363,8 +604,7 @@ void set_init_1(void)
|
||||
}
|
||||
}
|
||||
if (ga.ga_data != NULL) {
|
||||
set_string_default("bsk", ga.ga_data);
|
||||
xfree(ga.ga_data);
|
||||
set_string_default("bsk", ga.ga_data, true);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -425,17 +665,34 @@ void set_init_1(void)
|
||||
|
||||
#if defined(MSWIN) || defined(MAC)
|
||||
/* Set print encoding on platforms that don't default to latin1 */
|
||||
set_string_default("penc",
|
||||
(char_u *)"hp-roman8"
|
||||
);
|
||||
set_string_default("printencoding", "hp-roman8", false);
|
||||
#endif
|
||||
|
||||
/* 'printexpr' must be allocated to be able to evaluate it. */
|
||||
set_string_default(
|
||||
"pexpr",
|
||||
(char_u *)
|
||||
"system('lpr' . (&printdevice == '' ? '' : ' -P' . &printdevice) . ' ' . v:fname_in) . delete(v:fname_in) + v:shell_error"
|
||||
);
|
||||
// 'printexpr' must be allocated to be able to evaluate it.
|
||||
set_string_default("printexpr",
|
||||
#ifdef UNIX
|
||||
"system(['lpr'] "
|
||||
"+ (empty(&printdevice)?[]:['-P', &printdevice]) "
|
||||
"+ [v:fname_in])"
|
||||
". delete(v:fname_in)"
|
||||
"+ v:shell_error",
|
||||
#elif defined(MSWIN)
|
||||
"system(['copy', v:fname_in, "
|
||||
"empty(&printdevice)?'LPT1':&printdevice])"
|
||||
". delete(v:fname_in)",
|
||||
#else
|
||||
"",
|
||||
#endif
|
||||
false);
|
||||
|
||||
set_string_default("viewdir", stdpaths_user_data_subpath("view", 0), true);
|
||||
set_string_default("backupdir", stdpaths_user_data_subpath("backup", 0),
|
||||
true);
|
||||
set_string_default("directory", stdpaths_user_data_subpath("swap", 2), true);
|
||||
set_string_default("undodir", stdpaths_user_data_subpath("undo", 0), true);
|
||||
// Set default for &runtimepath. All necessary expansions are performed in
|
||||
// this function.
|
||||
set_runtimepath_default();
|
||||
|
||||
/*
|
||||
* Set all the options (except the terminal options) to their default
|
||||
@@ -478,14 +735,16 @@ void set_init_1(void)
|
||||
* default.
|
||||
*/
|
||||
for (opt_idx = 0; options[opt_idx].fullname; opt_idx++) {
|
||||
char *p;
|
||||
if ((options[opt_idx].flags & P_GETTEXT)
|
||||
&& options[opt_idx].var != NULL)
|
||||
p = (char_u *)_(*(char **)options[opt_idx].var);
|
||||
else
|
||||
p = option_expand(opt_idx, NULL);
|
||||
&& options[opt_idx].var != NULL) {
|
||||
p = _(*(char **)options[opt_idx].var);
|
||||
} else {
|
||||
p = (char *) option_expand(opt_idx, NULL);
|
||||
}
|
||||
if (p != NULL) {
|
||||
p = vim_strsave(p);
|
||||
*(char_u **)options[opt_idx].var = p;
|
||||
p = xstrdup(p);
|
||||
*(char **)options[opt_idx].var = p;
|
||||
/* VIMEXP
|
||||
* Defaults for all expanded options are currently the same for Vi
|
||||
* and Vim. When this changes, add some code here! Also need to
|
||||
@@ -493,7 +752,7 @@ void set_init_1(void)
|
||||
*/
|
||||
if (options[opt_idx].flags & P_DEF_ALLOCED)
|
||||
xfree(options[opt_idx].def_val[VI_DEFAULT]);
|
||||
options[opt_idx].def_val[VI_DEFAULT] = p;
|
||||
options[opt_idx].def_val[VI_DEFAULT] = (char_u *) p;
|
||||
options[opt_idx].flags |= P_DEF_ALLOCED;
|
||||
}
|
||||
}
|
||||
@@ -522,14 +781,14 @@ void set_init_1(void)
|
||||
(void)set_chars_option(&p_lcs);
|
||||
|
||||
/* enc_locale() will try to find the encoding of the current locale. */
|
||||
p = enc_locale();
|
||||
char_u *p = enc_locale();
|
||||
if (p != NULL) {
|
||||
char_u *save_enc;
|
||||
|
||||
/* Try setting 'encoding' and check if the value is valid.
|
||||
* If not, go back to the default "utf-8". */
|
||||
save_enc = p_enc;
|
||||
p_enc = p;
|
||||
p_enc = (char_u *) p;
|
||||
if (STRCMP(p_enc, "gb18030") == 0) {
|
||||
/* We don't support "gb18030", but "cp936" is a good substitute
|
||||
* for practical purposes, thus use that. It's not an alias to
|
||||
@@ -674,7 +933,9 @@ set_options_default (
|
||||
///
|
||||
/// @param name The name of the option
|
||||
/// @param val The value of the option
|
||||
void set_string_default(const char *name, const char_u *val)
|
||||
/// @param allocated If true, do not copy default as it was already allocated.
|
||||
static void set_string_default(const char *name, char *val, bool allocated)
|
||||
FUNC_ATTR_NONNULL_ALL
|
||||
{
|
||||
int opt_idx = findoption((char_u *)name);
|
||||
if (opt_idx >= 0) {
|
||||
@@ -682,7 +943,10 @@ void set_string_default(const char *name, const char_u *val)
|
||||
xfree(options[opt_idx].def_val[VI_DEFAULT]);
|
||||
}
|
||||
|
||||
options[opt_idx].def_val[VI_DEFAULT] = (char_u *) xstrdup((char *) val);
|
||||
options[opt_idx].def_val[VI_DEFAULT] = (char_u *) (
|
||||
allocated
|
||||
? (char_u *) val
|
||||
: (char_u *) xstrdup(val));
|
||||
options[opt_idx].flags |= P_DEF_ALLOCED;
|
||||
}
|
||||
}
|
||||
@@ -5948,7 +6212,7 @@ static void paste_option_changed(void)
|
||||
old_p_paste = p_paste;
|
||||
}
|
||||
|
||||
/// vimrc_found() - Called when a ".vimrc" or "VIMINIT" has been found.
|
||||
/// vimrc_found() - Called when a vimrc or "VIMINIT" has been found.
|
||||
///
|
||||
/// Set the values for options that didn't get set yet to the Vim defaults.
|
||||
/// When "fname" is not NULL, use it to set $"envname" when it wasn't set yet.
|
||||
|
@@ -176,7 +176,7 @@ return {
|
||||
vi_def=true,
|
||||
expand=true,
|
||||
varname='p_bdir',
|
||||
defaults={if_true={vi=macros('DFLT_BDIR')}}
|
||||
defaults={if_true={vi=''}}
|
||||
},
|
||||
{
|
||||
full_name='backupext', abbreviation='bex',
|
||||
@@ -627,7 +627,7 @@ return {
|
||||
vi_def=true,
|
||||
expand=true,
|
||||
varname='p_dir',
|
||||
defaults={if_true={vi=macros('DFLT_DIR')}}
|
||||
defaults={if_true={vi=''}}
|
||||
},
|
||||
{
|
||||
full_name='display', abbreviation='dy',
|
||||
@@ -1916,7 +1916,7 @@ return {
|
||||
vi_def=true,
|
||||
expand=true,
|
||||
varname='p_rtp',
|
||||
defaults={if_true={vi=macros('DFLT_RUNTIMEPATH')}}
|
||||
defaults={if_true={vi=''}}
|
||||
},
|
||||
{
|
||||
full_name='scroll', abbreviation='scr',
|
||||
@@ -2524,7 +2524,7 @@ return {
|
||||
vi_def=true,
|
||||
expand=true,
|
||||
varname='p_udir',
|
||||
defaults={if_true={vi="."}}
|
||||
defaults={if_true={vi=''}}
|
||||
},
|
||||
{
|
||||
full_name='undofile', abbreviation='udf',
|
||||
@@ -2585,7 +2585,7 @@ return {
|
||||
vi_def=true,
|
||||
expand=true,
|
||||
varname='p_vdir',
|
||||
defaults={if_true={vi=macros('DFLT_VDIR')}}
|
||||
defaults={if_true={vi=''}}
|
||||
},
|
||||
{
|
||||
full_name='viewoptions', abbreviation='vop',
|
||||
|
@@ -415,6 +415,74 @@ static char *remove_tail(char *p, char *pend, char *name)
|
||||
return pend;
|
||||
}
|
||||
|
||||
/// Iterate over colon-separated list
|
||||
///
|
||||
/// @note Environment variables must not be modified during iteration.
|
||||
///
|
||||
/// @param[in] val Value of the environment variable to iterate over.
|
||||
/// @param[in] iter Pointer used for iteration. Must be NULL on first
|
||||
/// iteration.
|
||||
/// @param[out] dir Location where pointer to the start of the current
|
||||
/// directory name should be saved. May be set to NULL.
|
||||
/// @param[out] len Location where current directory length should be saved.
|
||||
///
|
||||
/// @return Next iter argument value or NULL when iteration should stop.
|
||||
const void *vim_colon_env_iter(const char *const val,
|
||||
const void *const iter,
|
||||
const char **const dir,
|
||||
size_t *const len)
|
||||
FUNC_ATTR_NONNULL_ARG(1, 3, 4) FUNC_ATTR_WARN_UNUSED_RESULT
|
||||
{
|
||||
const char *varval = (const char *) iter;
|
||||
if (varval == NULL) {
|
||||
varval = val;
|
||||
}
|
||||
*dir = varval;
|
||||
const char *const dirend = strchr(varval, ':');
|
||||
if (dirend == NULL) {
|
||||
*len = strlen(varval);
|
||||
return NULL;
|
||||
} else {
|
||||
*len = (size_t) (dirend - varval);
|
||||
return dirend + 1;
|
||||
}
|
||||
}
|
||||
|
||||
/// Iterate over colon-separated list in reverse order
|
||||
///
|
||||
/// @note Environment variables must not be modified during iteration.
|
||||
///
|
||||
/// @param[in] val Value of the environment variable to iterate over.
|
||||
/// @param[in] iter Pointer used for iteration. Must be NULL on first
|
||||
/// iteration.
|
||||
/// @param[out] dir Location where pointer to the start of the current
|
||||
/// directory name should be saved. May be set to NULL.
|
||||
/// @param[out] len Location where current directory length should be saved.
|
||||
///
|
||||
/// @return Next iter argument value or NULL when iteration should stop.
|
||||
const void *vim_colon_env_iter_rev(const char *const val,
|
||||
const void *const iter,
|
||||
const char **const dir,
|
||||
size_t *const len)
|
||||
FUNC_ATTR_NONNULL_ARG(1, 3, 4) FUNC_ATTR_WARN_UNUSED_RESULT
|
||||
{
|
||||
const char *varend = (const char *) iter;
|
||||
if (varend == NULL) {
|
||||
varend = val + strlen(val) - 1;
|
||||
}
|
||||
const size_t varlen = (size_t) (varend - val) + 1;
|
||||
const char *const colon = xmemrchr(val, ':', varlen);
|
||||
if (colon == NULL) {
|
||||
*len = varlen;
|
||||
*dir = val;
|
||||
return NULL;
|
||||
} else {
|
||||
*dir = colon + 1;
|
||||
*len = (size_t) (varend - colon);
|
||||
return colon - 1;
|
||||
}
|
||||
}
|
||||
|
||||
/// Vim's version of getenv().
|
||||
/// Special handling of $HOME, $VIM and $VIMRUNTIME, allowing the user to
|
||||
/// override the vim runtime directory at runtime. Also does ACP to 'enc'
|
||||
|
@@ -366,11 +366,17 @@ int os_mkdir_recurse(const char *const dir, int32_t mode,
|
||||
}
|
||||
while (e != real_end) {
|
||||
if (e > past_head) {
|
||||
*e = '/';
|
||||
*e = PATHSEP;
|
||||
} else {
|
||||
*past_head = past_head_save;
|
||||
}
|
||||
e += strlen(e);
|
||||
const size_t component_len = strlen(e);
|
||||
e += component_len;
|
||||
if (e == real_end
|
||||
&& memcnt(e - component_len, PATHSEP, component_len) == component_len) {
|
||||
// Path ends with something like "////". Ignore this.
|
||||
break;
|
||||
}
|
||||
int ret;
|
||||
if ((ret = os_mkdir(curdir, mode)) != 0) {
|
||||
*failed_dir = curdir;
|
||||
|
@@ -5,6 +5,7 @@
|
||||
#include <uv.h>
|
||||
|
||||
#include "nvim/os/fs_defs.h"
|
||||
#include "nvim/os/stdpaths_defs.h"
|
||||
#include "nvim/vim.h"
|
||||
|
||||
#ifdef INCLUDE_GENERATED_DECLARATIONS
|
||||
@@ -12,6 +13,7 @@
|
||||
# include "os/mem.h.generated.h"
|
||||
# include "os/env.h.generated.h"
|
||||
# include "os/users.h.generated.h"
|
||||
# include "os/stdpaths.h.generated.h"
|
||||
#endif
|
||||
|
||||
#endif // NVIM_OS_OS_H
|
||||
|
108
src/nvim/os/stdpaths.c
Normal file
108
src/nvim/os/stdpaths.c
Normal file
@@ -0,0 +1,108 @@
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "nvim/os/stdpaths_defs.h"
|
||||
#include "nvim/os/os.h"
|
||||
#include "nvim/path.h"
|
||||
#include "nvim/memory.h"
|
||||
#include "nvim/ascii.h"
|
||||
|
||||
/// Names of the environment variables, mapped to XDGVarType values
|
||||
static const char *xdg_env_vars[] = {
|
||||
[kXDGConfigHome] = "XDG_CONFIG_HOME",
|
||||
[kXDGDataHome] = "XDG_DATA_HOME",
|
||||
[kXDGCacheHome] = "XDG_CACHE_HOME",
|
||||
[kXDGRuntimeDir] = "XDG_RUNTIME_DIR",
|
||||
[kXDGConfigDirs] = "XDG_CONFIG_DIRS",
|
||||
[kXDGDataDirs] = "XDG_DATA_DIRS",
|
||||
};
|
||||
|
||||
/// Defaults for XDGVarType values
|
||||
///
|
||||
/// Used in case environment variables contain nothing. Need to be expanded.
|
||||
static const char *const xdg_defaults[] = {
|
||||
#ifdef WIN32
|
||||
// Windows
|
||||
[kXDGConfigHome] = "$LOCALAPPDATA\\nvim\\config",
|
||||
[kXDGDataHome] = "$LOCALAPPDATA\\nvim\\data",
|
||||
[kXDGCacheHome] = "$LOCALAPPDATA\\nvim\\cache",
|
||||
[kXDGRuntimeDir] = "",
|
||||
[kXDGConfigDirs] = NULL,
|
||||
[kXDGDataDirs] = NULL,
|
||||
#else
|
||||
// Linux, BSD, CYGWIN, Apple
|
||||
[kXDGConfigHome] = "~/.config",
|
||||
[kXDGDataHome] = "~/.local/share",
|
||||
[kXDGCacheHome] = "~/.cache",
|
||||
[kXDGRuntimeDir] = "",
|
||||
[kXDGConfigDirs] = "/etc/xdg/",
|
||||
[kXDGDataDirs] = "/usr/local/share/:/usr/share/",
|
||||
#endif
|
||||
};
|
||||
|
||||
/// Return XDG variable value
|
||||
///
|
||||
/// @param[in] idx XDG variable to use.
|
||||
///
|
||||
/// @return [allocated] variable value.
|
||||
char *stdpaths_get_xdg_var(const XDGVarType idx)
|
||||
FUNC_ATTR_WARN_UNUSED_RESULT
|
||||
{
|
||||
const char *const env = xdg_env_vars[idx];
|
||||
const char *const fallback = xdg_defaults[idx];
|
||||
|
||||
const char *const env_val = os_getenv(env);
|
||||
char *ret = NULL;
|
||||
if (env_val != NULL) {
|
||||
ret = xstrdup(env_val);
|
||||
} else if (fallback) {
|
||||
ret = (char *) expand_env_save((char_u *)fallback);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/// Return nvim-specific XDG directory subpath
|
||||
///
|
||||
/// @param[in] idx XDG directory to use.
|
||||
///
|
||||
/// @return [allocated] `{xdg_directory}/nvim`
|
||||
static char *get_xdg_home(const XDGVarType idx)
|
||||
FUNC_ATTR_WARN_UNUSED_RESULT
|
||||
{
|
||||
char *dir = stdpaths_get_xdg_var(idx);
|
||||
if (dir) {
|
||||
dir = concat_fnames_realloc(dir, "nvim", true);
|
||||
}
|
||||
return dir;
|
||||
}
|
||||
|
||||
/// Return subpath of $XDG_CONFIG_HOME
|
||||
///
|
||||
/// @param[in] fname New component of the path.
|
||||
///
|
||||
/// @return [allocated] `$XDG_CONFIG_HOME/nvim/{fname}`
|
||||
char *stdpaths_user_conf_subpath(const char *fname)
|
||||
FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_NONNULL_ALL
|
||||
{
|
||||
return concat_fnames_realloc(get_xdg_home(kXDGConfigHome), fname, true);
|
||||
}
|
||||
|
||||
/// Return subpath of $XDG_DATA_HOME
|
||||
///
|
||||
/// @param[in] fname New component of the path.
|
||||
/// @param[in] trailing_pathseps Amount of trailing path separators to add.
|
||||
///
|
||||
/// @return [allocated] `$XDG_DATA_HOME/nvim/{fname}`
|
||||
char *stdpaths_user_data_subpath(const char *fname,
|
||||
const size_t trailing_pathseps)
|
||||
FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_NONNULL_ALL
|
||||
{
|
||||
char *ret = concat_fnames_realloc(get_xdg_home(kXDGDataHome), fname, true);
|
||||
if (trailing_pathseps) {
|
||||
const size_t len = strlen(ret);
|
||||
ret = xrealloc(ret, len + trailing_pathseps + 1);
|
||||
memset(ret + len, PATHSEP, trailing_pathseps);
|
||||
ret[len + trailing_pathseps] = NUL;
|
||||
}
|
||||
return ret;
|
||||
}
|
14
src/nvim/os/stdpaths_defs.h
Normal file
14
src/nvim/os/stdpaths_defs.h
Normal file
@@ -0,0 +1,14 @@
|
||||
#ifndef NVIM_OS_STDPATHS_DEFS_H
|
||||
#define NVIM_OS_STDPATHS_DEFS_H
|
||||
|
||||
/// List of possible XDG variables
|
||||
typedef enum {
|
||||
kXDGConfigHome, ///< XDG_CONFIG_HOME
|
||||
kXDGDataHome, ///< XDG_DATA_HOME
|
||||
kXDGCacheHome, ///< XDG_CACHE_HOME
|
||||
kXDGRuntimeDir, ///< XDG_RUNTIME_DIR
|
||||
kXDGConfigDirs, ///< XDG_CONFIG_DIRS
|
||||
kXDGDataDirs, ///< XDG_DATA_DIRS
|
||||
} XDGVarType;
|
||||
|
||||
#endif // NVIM_OS_STDPATHS_DEFS_H
|
@@ -20,7 +20,7 @@
|
||||
|
||||
// Unix system-dependent file names
|
||||
#ifndef SYS_VIMRC_FILE
|
||||
# define SYS_VIMRC_FILE "$VIM/nvimrc"
|
||||
# define SYS_VIMRC_FILE "$VIM/sysinit.vim"
|
||||
#endif
|
||||
#ifndef DFLT_HELPFILE
|
||||
# define DFLT_HELPFILE "$VIMRUNTIME/doc/help.txt"
|
||||
@@ -28,46 +28,11 @@
|
||||
#ifndef SYNTAX_FNAME
|
||||
# define SYNTAX_FNAME "$VIMRUNTIME/syntax/%s.vim"
|
||||
#endif
|
||||
#ifndef USR_EXRC_FILE
|
||||
# define USR_EXRC_FILE "~/.exrc"
|
||||
#endif
|
||||
#ifndef USR_VIMRC_FILE
|
||||
# define USR_VIMRC_FILE "~/.nvimrc"
|
||||
#endif
|
||||
#ifndef USR_VIMRC_FILE2
|
||||
# define USR_VIMRC_FILE2 "~/.nvim/nvimrc"
|
||||
#endif
|
||||
#ifndef EXRC_FILE
|
||||
# define EXRC_FILE ".exrc"
|
||||
#endif
|
||||
#ifndef VIMRC_FILE
|
||||
# define VIMRC_FILE ".nvimrc"
|
||||
#endif
|
||||
#ifndef SHADA_FILE
|
||||
# define SHADA_FILE "~/.nvim/shada/main.shada"
|
||||
#endif
|
||||
|
||||
// Default for 'backupdir'.
|
||||
#ifndef DFLT_BDIR
|
||||
# define DFLT_BDIR ".,~/tmp,~/"
|
||||
#endif
|
||||
|
||||
// Default for 'directory'.
|
||||
#ifndef DFLT_DIR
|
||||
# define DFLT_DIR ".,~/tmp,/var/tmp,/tmp"
|
||||
#endif
|
||||
|
||||
// Default for 'viewdir'.
|
||||
#ifndef DFLT_VDIR
|
||||
# define DFLT_VDIR "~/.nvim/view"
|
||||
#endif
|
||||
|
||||
#ifdef RUNTIME_GLOBAL
|
||||
# define DFLT_RUNTIMEPATH "~/.nvim," RUNTIME_GLOBAL ",$VIMRUNTIME," \
|
||||
RUNTIME_GLOBAL "/after,~/.nvim/after"
|
||||
#else
|
||||
# define DFLT_RUNTIMEPATH \
|
||||
"~/.nvim,$VIM/vimfiles,$VIMRUNTIME,$VIM/vimfiles/after,~/.nvim/after"
|
||||
#endif
|
||||
|
||||
#endif // NVIM_OS_UNIX_DEFS_H
|
||||
|
@@ -7,13 +7,9 @@
|
||||
#define TEMP_FILE_PATH_MAXLEN _MAX_PATH
|
||||
|
||||
// Defines needed to fix the build on Windows:
|
||||
// - USR_EXRC_FILE
|
||||
// - USR_VIMRC_FILE
|
||||
// - SHADA_FILE
|
||||
// - DFLT_DIR
|
||||
// - DFLT_BDIR
|
||||
// - DFLT_VDIR
|
||||
// - DFLT_RUNTIMEPATH
|
||||
// - EXRC_FILE
|
||||
// - VIMRC_FILE
|
||||
// - SYNTAX_FNAME
|
||||
|
@@ -329,6 +329,31 @@ int vim_fnamencmp(char_u *x, char_u *y, size_t len)
|
||||
#endif
|
||||
}
|
||||
|
||||
/// Append fname2 to fname1
|
||||
///
|
||||
/// @param[in] fname1 First fname to append to.
|
||||
/// @param[in] len1 Length of fname1.
|
||||
/// @param[in] fname2 Secord part of the file name.
|
||||
/// @param[in] len2 Length of fname2.
|
||||
/// @param[in] sep If true and fname1 does not end with a path separator,
|
||||
/// add a path separator before fname2.
|
||||
///
|
||||
/// @return fname1
|
||||
static inline char *do_concat_fnames(char *fname1, const size_t len1,
|
||||
const char *fname2, const size_t len2,
|
||||
const bool sep)
|
||||
FUNC_ATTR_NONNULL_ALL FUNC_ATTR_NONNULL_RET
|
||||
{
|
||||
if (sep && *fname1 && !after_pathsep(fname1, fname1 + len1)) {
|
||||
fname1[len1] = PATHSEP;
|
||||
memmove(fname1 + len1 + 1, fname2, len2 + 1);
|
||||
} else {
|
||||
memmove(fname1 + len1, fname2, len2 + 1);
|
||||
}
|
||||
|
||||
return fname1;
|
||||
}
|
||||
|
||||
/// Concatenate file names fname1 and fname2 into allocated memory.
|
||||
///
|
||||
/// Only add a '/' or '\\' when 'sep' is true and it is necessary.
|
||||
@@ -339,17 +364,33 @@ int vim_fnamencmp(char_u *x, char_u *y, size_t len)
|
||||
/// if necessary
|
||||
/// @return [allocated] Concatenation of fname1 and fname2.
|
||||
char *concat_fnames(const char *fname1, const char *fname2, bool sep)
|
||||
FUNC_ATTR_NONNULL_ARG(1, 2) FUNC_ATTR_NONNULL_RET
|
||||
FUNC_ATTR_NONNULL_ALL FUNC_ATTR_NONNULL_RET
|
||||
{
|
||||
char *dest = xmalloc(strlen(fname1) + strlen(fname2) + 3);
|
||||
const size_t len1 = strlen(fname1);
|
||||
const size_t len2 = strlen(fname2);
|
||||
char *dest = xmalloc(len1 + len2 + 3);
|
||||
memmove(dest, fname1, len1 + 1);
|
||||
return do_concat_fnames(dest, len1, fname2, len2, sep);
|
||||
}
|
||||
|
||||
strcpy(dest, fname1);
|
||||
if (sep) {
|
||||
add_pathsep(dest);
|
||||
}
|
||||
strcat(dest, fname2);
|
||||
|
||||
return dest;
|
||||
/// Concatenate file names fname1 and fname2
|
||||
///
|
||||
/// Like concat_fnames(), but in place of allocating new memory it reallocates
|
||||
/// fname1. For this reason fname1 must be allocated with xmalloc, and can no
|
||||
/// longer be used after running concat_fnames_realloc.
|
||||
///
|
||||
/// @param fname1 is the first part of the path or filename
|
||||
/// @param fname2 is the second half of the path or filename
|
||||
/// @param sep is a flag to indicate a path separator should be added
|
||||
/// if necessary
|
||||
/// @return [allocated] Concatenation of fname1 and fname2.
|
||||
char *concat_fnames_realloc(char *fname1, const char *fname2, bool sep)
|
||||
FUNC_ATTR_NONNULL_ALL FUNC_ATTR_NONNULL_RET
|
||||
{
|
||||
const size_t len1 = strlen(fname1);
|
||||
const size_t len2 = strlen(fname2);
|
||||
return do_concat_fnames(xrealloc(fname1, len1 + len2 + 3), len1,
|
||||
fname2, len2, sep);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@@ -1583,6 +1583,20 @@ shada_read_main_cycle_end:
|
||||
kh_dealloc(strset, &oldfiles_set);
|
||||
}
|
||||
|
||||
/// Default shada file location: cached path
|
||||
static char *default_shada_file = NULL;
|
||||
|
||||
/// Get the default ShaDa file
|
||||
static const char *shada_get_default_file(void)
|
||||
FUNC_ATTR_WARN_UNUSED_RESULT
|
||||
{
|
||||
if (default_shada_file == NULL) {
|
||||
char *shada_dir = stdpaths_user_data_subpath("shada", 0);
|
||||
default_shada_file = concat_fnames_realloc(shada_dir, "main.shada", true);
|
||||
}
|
||||
return default_shada_file;
|
||||
}
|
||||
|
||||
/// Get the ShaDa file name to use
|
||||
///
|
||||
/// If "file" is given and not empty, use it (has already been expanded by
|
||||
@@ -1600,22 +1614,7 @@ static char *shada_filename(const char *file)
|
||||
file = used_shada_file;
|
||||
} else {
|
||||
if ((file = find_shada_parameter('n')) == NULL || *file == NUL) {
|
||||
#ifdef SHADA_FILE2
|
||||
// don't use $HOME when not defined (turned into "c:/"!).
|
||||
if (os_getenv((char_u *)"HOME") == NULL) {
|
||||
// don't use $VIM when not available.
|
||||
expand_env((char_u *)"$VIM", NameBuff, MAXPATHL);
|
||||
if (STRCMP("$VIM", NameBuff) != 0) { // $VIM was expanded
|
||||
file = SHADA_FILE2;
|
||||
} else {
|
||||
file = SHADA_FILE;
|
||||
}
|
||||
} else {
|
||||
#endif
|
||||
file = SHADA_FILE;
|
||||
#ifdef SHADA_FILE2
|
||||
}
|
||||
#endif
|
||||
file = shada_get_default_file();
|
||||
}
|
||||
// XXX It used to be one level lower, so that whatever is in
|
||||
// `used_shada_file` was expanded. I intentionally moved it here
|
||||
|
@@ -4,3 +4,6 @@ set shell=sh
|
||||
|
||||
" Don't depend on system locale, always use utf-8
|
||||
set encoding=utf-8
|
||||
|
||||
" Use safer defaults for various directories
|
||||
set backupdir=. directory=. undodir=. viewdir=.
|
||||
|
@@ -1067,31 +1067,6 @@ void list_version(void)
|
||||
version_msg(SYS_VIMRC_FILE);
|
||||
version_msg("\"\n");
|
||||
#endif // ifdef SYS_VIMRC_FILE
|
||||
#ifdef USR_VIMRC_FILE
|
||||
version_msg(_(" user vimrc file: \""));
|
||||
version_msg(USR_VIMRC_FILE);
|
||||
version_msg("\"\n");
|
||||
#endif // ifdef USR_VIMRC_FILE
|
||||
#ifdef USR_VIMRC_FILE2
|
||||
version_msg(_(" 2nd user vimrc file: \""));
|
||||
version_msg(USR_VIMRC_FILE2);
|
||||
version_msg("\"\n");
|
||||
#endif // ifdef USR_VIMRC_FILE2
|
||||
#ifdef USR_VIMRC_FILE3
|
||||
version_msg(_(" 3rd user vimrc file: \""));
|
||||
version_msg(USR_VIMRC_FILE3);
|
||||
version_msg("\"\n");
|
||||
#endif // ifdef USR_VIMRC_FILE3
|
||||
#ifdef USR_EXRC_FILE
|
||||
version_msg(_(" user exrc file: \""));
|
||||
version_msg(USR_EXRC_FILE);
|
||||
version_msg("\"\n");
|
||||
#endif // ifdef USR_EXRC_FILE
|
||||
#ifdef USR_EXRC_FILE2
|
||||
version_msg(_(" 2nd user exrc file: \""));
|
||||
version_msg(USR_EXRC_FILE2);
|
||||
version_msg("\"\n");
|
||||
#endif // ifdef USR_EXRC_FILE2
|
||||
#ifdef HAVE_PATHDEF
|
||||
|
||||
if (*default_vim_dir != NUL) {
|
||||
|
Reference in New Issue
Block a user