From 207ba359b0127fa5893b980abcb9186ffec1879c Mon Sep 17 00:00:00 2001 From: "Justin M. Keyes" Date: Wed, 11 Jan 2017 06:00:55 +0100 Subject: [PATCH] Windows: vim_getenv(): Find runtime relative to nvim. #3303 (#5929) In Windows we cannot rely on absolute install paths to point to the location of the runtime. Vim uses the path of the current binary as a possible location for the runtime folder. In Neovim the install location places the runtime folder in ../share/nvim/runtime. In Vim this logic is guarded by USE_EXE_NAME, which is defined for win32 and macOS. TODO: We may need to incorporate similar logic for macOS: https://github.com/vim/vim/blob/0cdb72aa38c4a0140c94d56bf8bc17cb30260ebf/src/misc1.c#L4287-L4308 --- src/nvim/os/env.c | 25 +++++++++++++++++++++++-- src/nvim/os/fs.c | 12 ++++++++++++ 2 files changed, 35 insertions(+), 2 deletions(-) diff --git a/src/nvim/os/env.c b/src/nvim/os/env.c index 83a0262545..47d541c6a7 100644 --- a/src/nvim/os/env.c +++ b/src/nvim/os/env.c @@ -560,8 +560,8 @@ const void *vim_colon_env_iter_rev(const char *const val, /// 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' -/// conversion for Win32. Results must be freed by the calling function. -/// @param name Name of environment variable to expand +/// conversion for Win32. Result must be freed by the caller. +/// @param name Environment variable to expand char *vim_getenv(const char *name) { const char *kos_env_path = os_getenv(name); @@ -598,6 +598,27 @@ char *vim_getenv(const char *name) if (p_hf != NULL && vim_strchr(p_hf, '$') == NULL) { vim_path = (char *)p_hf; } + +#ifdef WIN32 + // Find runtime path relative to the nvim binary i.e. ../share/runtime + if (vim_path == NULL) { + char exe_name[MAXPATHL]; + size_t exe_name_len = MAXPATHL; + if (os_exepath(exe_name, &exe_name_len) == 0) { + char *path_end = (char *)path_tail_with_sep((char_u *)exe_name); + *path_end = '\0'; // remove the trailing "nvim.exe" + path_end = (char *)path_tail((char_u *)exe_name); + *path_end = '\0'; // remove the trailing "bin/" + if (append_path( + exe_name, + "share" _PATHSEPSTR "nvim" _PATHSEPSTR "runtime" _PATHSEPSTR, + MAXPATHL) == OK) { + vim_path = exe_name; + } + } + } +#endif + if (vim_path != NULL) { // remove the file name char *vim_path_end = (char *)path_tail((char_u *)vim_path); diff --git a/src/nvim/os/fs.c b/src/nvim/os/fs.c index 3c821936e9..4aa727733e 100644 --- a/src/nvim/os/fs.c +++ b/src/nvim/os/fs.c @@ -192,6 +192,18 @@ int os_nodetype(const char *name) return nodetype; } +/// Gets the absolute path of the currently running executable. +/// +/// @param[out] buffer Returns the path string. +/// @param[in] size Size of `buffer`. +/// +/// @return `0` on success, or libuv error code on failure. +int os_exepath(char *buffer, size_t *size) + FUNC_ATTR_NONNULL_ALL +{ + return uv_exepath(buffer, size); +} + /// Checks if the given path represents an executable file. /// /// @param[in] name Name of the executable.