feat: $NVIM_APPNAME #22128

This commit implements the ability to control all of the XDG paths
Neovim should use. This is done by setting an environment variable named
NVIM_APPNAME. For example, setting $NVIM_APPNAME makes Neovim look for
its configuration directory in $XDG_CONFIG_HOME/$NVIM_APPNAME instead of
$XDG_CONFIG_HOME/nvim.

If NVIM_APPNAME is not set or is an empty string, "nvim" will be used as
default.

The usecase for this feature is to enable an easy way to switch from
configuration to configuration. One might argue that the various $XDG
environment variables can already be used for this usecase. However,
setting $XDG environment variables also affects tools spawned by Neovim.
For example, while setting $XDG_CONFIG_HOME will enable Neovim to use a
different configuration directory, it will also prevent Git from finding
its "default" configuration.

Closes https://github.com/neovim/neovim/issues/21691
This commit is contained in:
Ghjuvan Lacambre
2023-02-16 13:15:02 +01:00
committed by GitHub
parent 631775c05d
commit d34c64e342
8 changed files with 99 additions and 36 deletions

View File

@@ -5368,13 +5368,14 @@ void get_xdg_var_list(const XDGVarType xdg, typval_T *rettv)
return;
}
const void *iter = NULL;
const char *appname = get_appname();
do {
size_t dir_len;
const char *dir;
iter = vim_env_iter(ENV_SEPCHAR, dirs, iter, &dir, &dir_len);
if (dir != NULL && dir_len > 0) {
char *dir_with_nvim = xmemdupz(dir, dir_len);
dir_with_nvim = concat_fnames_realloc(dir_with_nvim, "nvim", true);
dir_with_nvim = concat_fnames_realloc(dir_with_nvim, appname, true);
tv_list_append_string(list, dir_with_nvim, (ssize_t)strlen(dir_with_nvim));
xfree(dir_with_nvim);
}

View File

@@ -5181,7 +5181,10 @@ static void vim_mktempdir(void)
// "/tmp/" exists, now try to create "/tmp/nvim.<user>/".
add_pathsep(tmp);
xstrlcat(tmp, "nvim.", sizeof(tmp));
const char *appname = get_appname();
xstrlcat(tmp, appname, sizeof(tmp));
xstrlcat(tmp, ".", sizeof(tmp));
xstrlcat(tmp, user, sizeof(tmp));
(void)os_mkdir(tmp, 0700); // Always create, to avoid a race.
bool owned = os_file_owned(tmp);

View File

@@ -91,13 +91,14 @@ char *server_address_new(const char *name)
{
static uint32_t count = 0;
char fmt[ADDRESS_MAX_SIZE];
const char *appname = get_appname();
#ifdef MSWIN
int r = snprintf(fmt, sizeof(fmt), "\\\\.\\pipe\\%s.%" PRIu64 ".%" PRIu32,
name ? name : "nvim", os_get_pid(), count++);
name ? name : appname, os_get_pid(), count++);
#else
char *dir = stdpaths_get_xdg_var(kXDGRuntimeDir);
int r = snprintf(fmt, sizeof(fmt), "%s/%s.%" PRIu64 ".%" PRIu32,
dir, name ? name : "nvim", os_get_pid(), count++);
dir, name ? name : appname, os_get_pid(), count++);
xfree(dir);
#endif
if ((size_t)r >= sizeof(fmt)) {

View File

@@ -57,6 +57,18 @@ static const char *const xdg_defaults[] = {
#endif
};
/// Get the value of $NVIM_APPNAME or "nvim" if not set.
///
/// @return $NVIM_APPNAME value
const char *get_appname(void)
{
const char *env_val = os_getenv("NVIM_APPNAME");
if (env_val == NULL || *env_val == '\0') {
env_val = "nvim";
}
return env_val;
}
/// Return XDG variable value
///
/// @param[in] idx XDG variable to use.
@@ -100,25 +112,28 @@ char *stdpaths_get_xdg_var(const XDGVarType idx)
/// Return Nvim-specific XDG directory subpath.
///
/// Windows: Uses "…/nvim-data" for kXDGDataHome to avoid storing
/// Windows: Uses "…/$NVIM_APPNAME-data" for kXDGDataHome to avoid storing
/// configuration and data files in the same path. #4403
///
/// @param[in] idx XDG directory to use.
///
/// @return [allocated] "{xdg_directory}/nvim"
/// @return [allocated] "{xdg_directory}/$NVIM_APPNAME"
char *get_xdg_home(const XDGVarType idx)
FUNC_ATTR_WARN_UNUSED_RESULT
{
char *dir = stdpaths_get_xdg_var(idx);
const char *appname = get_appname();
size_t appname_len = strlen(appname);
assert(appname_len < (IOSIZE - sizeof("-data")));
if (dir) {
xstrlcpy(IObuff, appname, appname_len + 1);
#if defined(MSWIN)
dir = concat_fnames_realloc(dir,
((idx == kXDGDataHome
|| idx == kXDGStateHome) ? "nvim-data" : "nvim"),
true);
#else
dir = concat_fnames_realloc(dir, "nvim", true);
if (idx == kXDGDataHome || idx == kXDGStateHome) {
STRCAT(IObuff, "-data");
}
#endif
dir = concat_fnames_realloc(dir, IObuff, true);
#ifdef BACKSLASH_IN_FILENAME
slash_adjust(dir);
@@ -131,7 +146,7 @@ char *get_xdg_home(const XDGVarType idx)
///
/// @param[in] fname New component of the path.
///
/// @return [allocated] `$XDG_CACHE_HOME/nvim/{fname}`
/// @return [allocated] `$XDG_CACHE_HOME/$NVIM_APPNAME/{fname}`
char *stdpaths_user_cache_subpath(const char *fname)
FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_NONNULL_ALL FUNC_ATTR_NONNULL_RET
{
@@ -142,7 +157,7 @@ char *stdpaths_user_cache_subpath(const char *fname)
///
/// @param[in] fname New component of the path.
///
/// @return [allocated] `$XDG_CONFIG_HOME/nvim/{fname}`
/// @return [allocated] `$XDG_CONFIG_HOME/$NVIM_APPNAME/{fname}`
char *stdpaths_user_conf_subpath(const char *fname)
FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_NONNULL_ALL FUNC_ATTR_NONNULL_RET
{
@@ -153,7 +168,7 @@ char *stdpaths_user_conf_subpath(const char *fname)
///
/// @param[in] fname New component of the path.
///
/// @return [allocated] `$XDG_DATA_HOME/nvim/{fname}`
/// @return [allocated] `$XDG_DATA_HOME/$NVIM_APPNAME/{fname}`
char *stdpaths_user_data_subpath(const char *fname)
FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_NONNULL_ALL FUNC_ATTR_NONNULL_RET
{
@@ -166,7 +181,7 @@ char *stdpaths_user_data_subpath(const char *fname)
/// @param[in] trailing_pathseps Amount of trailing path separators to add.
/// @param[in] escape_commas If true, all commas will be escaped.
///
/// @return [allocated] `$XDG_STATE_HOME/nvim/{fname}`.
/// @return [allocated] `$XDG_STATE_HOME/$NVIM_APPNAME/{fname}`.
char *stdpaths_user_state_subpath(const char *fname, const size_t trailing_pathseps,
const bool escape_commas)
FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_NONNULL_ALL FUNC_ATTR_NONNULL_RET

View File

@@ -1435,7 +1435,6 @@ static inline size_t compute_double_env_sep_len(const char *const val, const siz
return ret;
}
#define NVIM_SIZE (sizeof("nvim") - 1)
/// Add directories to a ENV_SEPCHAR-separated array from a colon-separated one
///
/// Commas are escaped in process. To each item PATHSEP "nvim" is appended in
@@ -1464,6 +1463,8 @@ static inline char *add_env_sep_dirs(char *dest, const char *const val, const ch
return dest;
}
const void *iter = NULL;
const char *appname = get_appname();
const size_t appname_len = strlen(appname);
do {
size_t dir_len;
const char *dir;
@@ -1474,8 +1475,8 @@ static inline char *add_env_sep_dirs(char *dest, const char *const val, const ch
if (!after_pathsep(dest - 1, dest)) {
*dest++ = PATHSEP;
}
memmove(dest, "nvim", NVIM_SIZE);
dest += NVIM_SIZE;
memmove(dest, appname, appname_len);
dest += appname_len;
if (suf1 != NULL) {
*dest++ = PATHSEP;
memmove(dest, suf1, len1);
@@ -1529,14 +1530,18 @@ static inline char *add_dir(char *dest, const char *const dir, const size_t dir_
if (!after_pathsep(dest - 1, dest)) {
*dest++ = PATHSEP;
}
const char *appname = get_appname();
size_t appname_len = strlen(appname);
assert(appname_len < (IOSIZE - sizeof("-data")));
xstrlcpy(IObuff, appname, appname_len + 1);
#if defined(MSWIN)
size_t size = (type == kXDGDataHome ? sizeof("nvim-data") - 1 : NVIM_SIZE);
memmove(dest, (type == kXDGDataHome ? "nvim-data" : "nvim"), size);
dest += size;
#else
memmove(dest, "nvim", NVIM_SIZE);
dest += NVIM_SIZE;
if (type == kXDGDataHome || type == kXDGStateHome) {
STRCAT(IObuff, "-data");
appname_len += 5;
}
#endif
xstrlcpy(dest, IObuff, appname_len + 1);
dest += appname_len;
if (suf1 != NULL) {
*dest++ = PATHSEP;
memmove(dest, suf1, len1);
@@ -1596,16 +1601,17 @@ char *runtimepath_default(bool clean_arg)
size_t config_len = 0;
size_t vimruntime_len = 0;
size_t libdir_len = 0;
const char *appname = get_appname();
size_t appname_len = strlen(appname);
if (data_home != NULL) {
data_len = strlen(data_home);
if (data_len != 0) {
size_t nvim_data_size = appname_len;
#if defined(MSWIN)
size_t nvim_size = (sizeof("nvim-data") - 1);
#else
size_t nvim_size = NVIM_SIZE;
nvim_data_size += sizeof("-data");
#endif
if (data_len != 0) {
rtp_size += ((data_len + memcnt(data_home, ',', data_len)
+ nvim_size + 1 + SITE_SIZE + 1
+ nvim_data_size + 1 + SITE_SIZE + 1
+ !after_pathsep(data_home, data_home + data_len)) * 2
+ AFTER_SIZE + 1);
}
@@ -1614,7 +1620,7 @@ char *runtimepath_default(bool clean_arg)
config_len = strlen(config_home);
if (config_len != 0) {
rtp_size += ((config_len + memcnt(config_home, ',', config_len)
+ NVIM_SIZE + 1
+ appname_len + 1
+ !after_pathsep(config_home, config_home + config_len)) * 2
+ AFTER_SIZE + 1);
}
@@ -1632,9 +1638,9 @@ char *runtimepath_default(bool clean_arg)
}
}
rtp_size += compute_double_env_sep_len(data_dirs,
NVIM_SIZE + 1 + SITE_SIZE + 1,
appname_len + 1 + SITE_SIZE + 1,
AFTER_SIZE + 1);
rtp_size += compute_double_env_sep_len(config_dirs, NVIM_SIZE + 1,
rtp_size += compute_double_env_sep_len(config_dirs, appname_len + 1,
AFTER_SIZE + 1);
char *rtp = NULL;
if (rtp_size == 0) {
@@ -1675,7 +1681,6 @@ freeall:
return rtp;
}
#undef NVIM_SIZE
static void cmd_source(char *fname, exarg_T *eap)
{