mirror of
https://github.com/neovim/neovim
synced 2025-07-19 02:31:45 +00:00
feat: NVIM_APPNAME supports relative paths #25233
Problem: NVIM_APPNAME does not allow path separators in the name, so relative paths can't be used: NVIM_APPNAME="neovim-configs/first-config" nvim NVIM_APPNAME="neovim-configs/second-config" nvim Solution: Let NVIM_APPNAME be a relative path. Absolute paths are not supported. fix #23056 fix #24966
This commit is contained in:
@ -169,6 +169,8 @@ The following new APIs and features were added.
|
|||||||
• |vim.lsp.util.locations_to_items()| sets the `user_data` of each item to the
|
• |vim.lsp.util.locations_to_items()| sets the `user_data` of each item to the
|
||||||
original LSP `Location` or `LocationLink`.
|
original LSP `Location` or `LocationLink`.
|
||||||
|
|
||||||
|
• |$NVIM_APPNAME| can be set to a relative path instead of only a name.
|
||||||
|
|
||||||
==============================================================================
|
==============================================================================
|
||||||
CHANGED FEATURES *news-changed*
|
CHANGED FEATURES *news-changed*
|
||||||
|
|
||||||
|
@ -1366,6 +1366,9 @@ The $XDG_CONFIG_HOME, $XDG_DATA_HOME, $XDG_RUNTIME_DIR, $XDG_STATE_HOME,
|
|||||||
$XDG_CACHE_HOME, $XDG_CONFIG_DIRS and $XDG_DATA_DIRS environment variables
|
$XDG_CACHE_HOME, $XDG_CONFIG_DIRS and $XDG_DATA_DIRS environment variables
|
||||||
are used if defined, else default values (listed below) are used.
|
are used if defined, else default values (listed below) are used.
|
||||||
|
|
||||||
|
Throughout the help pages these defaults are used as placeholders, e.g.
|
||||||
|
"~/.config" is understood to mean "$XDG_CONFIG_HOME or ~/.config".
|
||||||
|
|
||||||
CONFIG DIRECTORY (DEFAULT) ~
|
CONFIG DIRECTORY (DEFAULT) ~
|
||||||
*$XDG_CONFIG_HOME* Nvim: stdpath("config")
|
*$XDG_CONFIG_HOME* Nvim: stdpath("config")
|
||||||
Unix: ~/.config ~/.config/nvim
|
Unix: ~/.config ~/.config/nvim
|
||||||
@ -1392,10 +1395,12 @@ CACHE DIRECTORY (DEFAULT) ~
|
|||||||
Windows: ~/AppData/Local/Temp ~/AppData/Local/Temp/nvim-data
|
Windows: ~/AppData/Local/Temp ~/AppData/Local/Temp/nvim-data
|
||||||
|
|
||||||
LOG FILE (DEFAULT) ~
|
LOG FILE (DEFAULT) ~
|
||||||
`$NVIM_LOG_FILE` Nvim: stdpath("log")
|
`$NVIM_LOG_FILE` Nvim: stdpath("log")/log
|
||||||
Unix: ~/.local/state/nvim ~/.local/state/nvim/log
|
Unix: ~/.local/state/nvim ~/.local/state/nvim/log
|
||||||
Windows: ~/AppData/Local/nvim-data ~/AppData/Local/nvim-data/log
|
Windows: ~/AppData/Local/nvim-data ~/AppData/Local/nvim-data/log
|
||||||
|
|
||||||
|
Note that stdpath("log") is currently an alias for stdpath("state").
|
||||||
|
|
||||||
ADDITIONAL CONFIGS DIRECTORY (DEFAULT) ~
|
ADDITIONAL CONFIGS DIRECTORY (DEFAULT) ~
|
||||||
*$XDG_CONFIG_DIRS* Nvim: stdpath("config_dirs")
|
*$XDG_CONFIG_DIRS* Nvim: stdpath("config_dirs")
|
||||||
Unix: /etc/xdg/ /etc/xdg/nvim
|
Unix: /etc/xdg/ /etc/xdg/nvim
|
||||||
@ -1407,18 +1412,14 @@ ADDITIONAL DATA DIRECTORY (DEFAULT) ~
|
|||||||
/usr/share /usr/share/nvim
|
/usr/share /usr/share/nvim
|
||||||
Windows: Not applicable Not applicable
|
Windows: Not applicable Not applicable
|
||||||
|
|
||||||
Note: Throughout the help pages these defaults are used as placeholders, e.g.
|
|
||||||
"~/.config" is understood to mean "$XDG_CONFIG_HOME or ~/.config".
|
|
||||||
|
|
||||||
Note: The log file directory is controlled by `$XDG_STATE_HOME`.
|
|
||||||
|
|
||||||
NVIM_APPNAME *$NVIM_APPNAME*
|
NVIM_APPNAME *$NVIM_APPNAME*
|
||||||
The standard directories can be further configured by the `$NVIM_APPNAME`
|
The standard directories can be further configured by the `$NVIM_APPNAME`
|
||||||
environment variable. This variable controls the sub-directory that Nvim will
|
environment variable. This variable controls the sub-directory that Nvim will
|
||||||
read from (and auto-create) in each of the base directories. For example,
|
read from (and auto-create) in each of the base directories. For example,
|
||||||
setting `$NVIM_APPNAME` to "foo" before starting will cause Nvim to look for
|
setting `$NVIM_APPNAME` to "foo" before starting will cause Nvim to look for
|
||||||
configuration files in `$XDG_CONFIG_HOME/foo` instead of
|
configuration files in `$XDG_CONFIG_HOME/foo` instead of
|
||||||
`$XDG_CONFIG_HOME/nvim`.
|
`$XDG_CONFIG_HOME/nvim`. `$NVIM_APPNAME` must be a name, such as "foo", or a
|
||||||
|
relative path, such as "foo/bar".
|
||||||
|
|
||||||
One use-case for $NVIM_APPNAME is to "isolate" Nvim applications.
|
One use-case for $NVIM_APPNAME is to "isolate" Nvim applications.
|
||||||
Alternatively, for true isolation, on Linux you can use cgroups namespaces: >
|
Alternatively, for true isolation, on Linux you can use cgroups namespaces: >
|
||||||
|
@ -3279,12 +3279,18 @@ static void vim_mktempdir(void)
|
|||||||
char tmp[TEMP_FILE_PATH_MAXLEN];
|
char tmp[TEMP_FILE_PATH_MAXLEN];
|
||||||
char path[TEMP_FILE_PATH_MAXLEN];
|
char path[TEMP_FILE_PATH_MAXLEN];
|
||||||
char user[40] = { 0 };
|
char user[40] = { 0 };
|
||||||
|
char appname[40] = { 0 };
|
||||||
|
|
||||||
(void)os_get_username(user, sizeof(user));
|
(void)os_get_username(user, sizeof(user));
|
||||||
// Usernames may contain slashes! #19240
|
// Usernames may contain slashes! #19240
|
||||||
memchrsub(user, '/', '_', sizeof(user));
|
memchrsub(user, '/', '_', sizeof(user));
|
||||||
memchrsub(user, '\\', '_', sizeof(user));
|
memchrsub(user, '\\', '_', sizeof(user));
|
||||||
|
|
||||||
|
// Appname may be a relative path, replace slashes to make it name-like.
|
||||||
|
xstrlcpy(appname, get_appname(), sizeof(appname));
|
||||||
|
memchrsub(appname, '/', '%', sizeof(appname));
|
||||||
|
memchrsub(appname, '\\', '%', sizeof(appname));
|
||||||
|
|
||||||
// Make sure the umask doesn't remove the executable bit.
|
// Make sure the umask doesn't remove the executable bit.
|
||||||
// "repl" has been reported to use "0177".
|
// "repl" has been reported to use "0177".
|
||||||
mode_t umask_save = umask(0077);
|
mode_t umask_save = umask(0077);
|
||||||
@ -3298,7 +3304,6 @@ static void vim_mktempdir(void)
|
|||||||
// "/tmp/" exists, now try to create "/tmp/nvim.<user>/".
|
// "/tmp/" exists, now try to create "/tmp/nvim.<user>/".
|
||||||
add_pathsep(tmp);
|
add_pathsep(tmp);
|
||||||
|
|
||||||
const char *appname = get_appname();
|
|
||||||
xstrlcat(tmp, appname, sizeof(tmp));
|
xstrlcat(tmp, appname, sizeof(tmp));
|
||||||
xstrlcat(tmp, ".", sizeof(tmp));
|
xstrlcat(tmp, ".", sizeof(tmp));
|
||||||
xstrlcat(tmp, user, sizeof(tmp));
|
xstrlcat(tmp, user, sizeof(tmp));
|
||||||
|
@ -251,7 +251,7 @@ int main(int argc, char **argv)
|
|||||||
argv0 = argv[0];
|
argv0 = argv[0];
|
||||||
|
|
||||||
if (!appname_is_valid()) {
|
if (!appname_is_valid()) {
|
||||||
os_errmsg("$NVIM_APPNAME is not a valid file name.\n");
|
os_errmsg("$NVIM_APPNAME must be a name or relative path.\n");
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -69,15 +69,23 @@ const char *get_appname(void)
|
|||||||
return env_val;
|
return env_val;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Ensure that APPNAME is valid. In particular, it cannot contain directory separators.
|
/// Ensure that APPNAME is valid. Must be a name or relative path.
|
||||||
bool appname_is_valid(void)
|
bool appname_is_valid(void)
|
||||||
{
|
{
|
||||||
const char *appname = get_appname();
|
const char *appname = get_appname();
|
||||||
const size_t appname_len = strlen(appname);
|
if (path_is_absolute(appname)
|
||||||
for (size_t i = 0; i < appname_len; i++) {
|
// TODO(justinmk): on Windows, path_is_absolute says "/" is NOT absolute. Should it?
|
||||||
if (appname[i] == PATHSEP) {
|
|| strequal(appname, "/")
|
||||||
return false;
|
|| strequal(appname, "\\")
|
||||||
}
|
|| strequal(appname, ".")
|
||||||
|
|| strequal(appname, "..")
|
||||||
|
#ifdef BACKSLASH_IN_FILENAME
|
||||||
|
|| strstr(appname, "\\..") != NULL
|
||||||
|
|| strstr(appname, "..\\") != NULL
|
||||||
|
#endif
|
||||||
|
|| strstr(appname, "/..") != NULL
|
||||||
|
|| strstr(appname, "../") != NULL) {
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -377,4 +377,14 @@ describe('tmpdir', function()
|
|||||||
rm_tmpdir()
|
rm_tmpdir()
|
||||||
eq('E5431: tempdir disappeared (3 times)', meths.get_vvar('errmsg'))
|
eq('E5431: tempdir disappeared (3 times)', meths.get_vvar('errmsg'))
|
||||||
end)
|
end)
|
||||||
|
|
||||||
|
it('$NVIM_APPNAME relative path', function()
|
||||||
|
clear({ env={
|
||||||
|
NVIM_APPNAME='a/b',
|
||||||
|
NVIM_LOG_FILE=testlog,
|
||||||
|
TMPDIR=os_tmpdir,
|
||||||
|
} })
|
||||||
|
matches([=[.*[/\\]a%%b%.[^/\\]+]=], funcs.tempname())
|
||||||
|
end)
|
||||||
|
|
||||||
end)
|
end)
|
||||||
|
@ -598,8 +598,7 @@ describe('stdpath()', function()
|
|||||||
end)
|
end)
|
||||||
|
|
||||||
it('reacts to $NVIM_APPNAME', function()
|
it('reacts to $NVIM_APPNAME', function()
|
||||||
local appname = "NVIM_APPNAME_TEST____________________________________" ..
|
local appname = 'NVIM_APPNAME_TEST' .. ('_'):rep(106)
|
||||||
"______________________________________________________________________"
|
|
||||||
clear({env={ NVIM_APPNAME=appname }})
|
clear({env={ NVIM_APPNAME=appname }})
|
||||||
eq(appname, funcs.fnamemodify(funcs.stdpath('config'), ':t'))
|
eq(appname, funcs.fnamemodify(funcs.stdpath('config'), ':t'))
|
||||||
eq(appname, funcs.fnamemodify(funcs.stdpath('cache'), ':t'))
|
eq(appname, funcs.fnamemodify(funcs.stdpath('cache'), ':t'))
|
||||||
@ -616,10 +615,24 @@ describe('stdpath()', function()
|
|||||||
|
|
||||||
-- Check that Nvim rejects invalid APPNAMEs
|
-- Check that Nvim rejects invalid APPNAMEs
|
||||||
-- Call jobstart() and jobwait() in the same RPC request to reduce flakiness.
|
-- Call jobstart() and jobwait() in the same RPC request to reduce flakiness.
|
||||||
eq(1, exec_lua([[
|
local function test_appname(testAppname, expected_exitcode)
|
||||||
local child = vim.fn.jobstart({ vim.v.progpath }, { env = { NVIM_APPNAME = 'a/b\\c' } })
|
local lua_code = string.format([[
|
||||||
return vim.fn.jobwait({ child }, 3000)[1]
|
local child = vim.fn.jobstart({ vim.v.progpath, '--clean', '--headless', '+qall!' }, { env = { NVIM_APPNAME = %q } })
|
||||||
]]))
|
return vim.fn.jobwait({ child }, %d)[1]
|
||||||
|
]], alter_slashes(testAppname), 3000)
|
||||||
|
eq(expected_exitcode, exec_lua(lua_code))
|
||||||
|
end
|
||||||
|
-- Invalid appnames:
|
||||||
|
test_appname('a/../b', 1)
|
||||||
|
test_appname('../a', 1)
|
||||||
|
test_appname('a/..', 1)
|
||||||
|
test_appname('..', 1)
|
||||||
|
test_appname('.', 1)
|
||||||
|
test_appname('/', 1)
|
||||||
|
test_appname(is_os('win') and 'C:/a/b' or '/a/b', 1)
|
||||||
|
-- Valid appnames:
|
||||||
|
test_appname('a/b', 0)
|
||||||
|
test_appname('a/b\\c', 0)
|
||||||
end)
|
end)
|
||||||
|
|
||||||
describe('returns a String', function()
|
describe('returns a String', function()
|
||||||
|
Reference in New Issue
Block a user