Merge pull request #3470 from ZyX-I/pr-3198

XDG base directory specification support
This commit is contained in:
Justin M. Keyes
2015-10-25 22:38:23 -04:00
73 changed files with 1165 additions and 693 deletions

View File

@@ -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(&params);
/*
@@ -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"));

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -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
View 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;
}

View 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

View File

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

View File

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

View File

@@ -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);
}
/*

View File

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

View File

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

View File

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