diff --git a/src/nvim/main.c b/src/nvim/main.c index dfe30b5dbe..8e78d572ab 100644 --- a/src/nvim/main.c +++ b/src/nvim/main.c @@ -2027,8 +2027,8 @@ static void do_system_initialization(void) /// 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, …). +/// 2. Sourcing user config file ($XDG_CONFIG_HOME/nvim/init.lua or init.vim). +/// 3. Sourcing other config files ($XDG_CONFIG_DIRS[1]/nvim/init.lua or init.vim, …). /// 4. Execution of EXINIT environment variable. /// /// @return True if it is needed to attempt to source exrc file according to @@ -2073,6 +2073,11 @@ static bool do_user_initialization(void) char *const config_dirs = stdpaths_get_xdg_var(kXDGConfigDirs); if (config_dirs != NULL) { + const char vim_path_tail[] = { 'n', 'v', 'i', 'm', PATHSEP, + 'i', 'n', 'i', 't', '.', 'v', 'i', 'm', NUL }; + const char lua_path_tail[] = { 'n', 'v', 'i', 'm', PATHSEP, + 'i', 'n', 'i', 't', '.', 'l', 'u', 'a', NUL }; + const void *iter = NULL; do { const char *dir; @@ -2081,12 +2086,34 @@ static bool do_user_initialization(void) 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); + + // Build: //init.lua + char *init_lua = xmalloc(dir_len + sizeof(lua_path_tail) + 1); + memmove(init_lua, dir, dir_len); + init_lua[dir_len] = PATHSEP; + memmove(init_lua + dir_len + 1, lua_path_tail, sizeof(lua_path_tail)); + + // Build: //init.vim + char *vimrc = xmalloc(dir_len + sizeof(vim_path_tail) + 1); memmove(vimrc, dir, dir_len); vimrc[dir_len] = PATHSEP; - memmove(vimrc + dir_len + 1, path_tail, sizeof(path_tail)); + memmove(vimrc + dir_len + 1, vim_path_tail, sizeof(vim_path_tail)); + + if (os_path_exists(init_lua) + && do_source(init_lua, true, DOSO_VIMRC, NULL)) { + if (os_path_exists(vimrc)) { + semsg(_("E5422: Conflicting configs: \"%s\" \"%s\""), init_lua, vimrc); + } + + xfree(vimrc); + xfree(init_lua); + xfree(config_dirs); + do_exrc = p_exrc; + return do_exrc; + } + xfree(init_lua); + + // init.vim if (do_source(vimrc, true, DOSO_VIMRC, NULL) != FAIL) { do_exrc = p_exrc; if (do_exrc) { diff --git a/test/functional/core/startup_spec.lua b/test/functional/core/startup_spec.lua index a13ed8f0e0..c1085f624a 100644 --- a/test/functional/core/startup_spec.lua +++ b/test/functional/core/startup_spec.lua @@ -1421,6 +1421,58 @@ describe('user config init', function() ) end) end) + + describe('from XDG_CONFIG_DIRS', function() + local xdgdir = 'Xxdgconfigdirs' + + before_each(function() + -- Remove init.lua from XDG_CONFIG_HOME so nvim falls back to XDG_CONFIG_DIRS + os.remove(init_lua_path) + rmdir(xdgdir) + mkdir_p(xdgdir .. pathsep .. 'nvim') + end) + + after_each(function() + rmdir(xdgdir) + end) + + it('loads init.lua from XDG_CONFIG_DIRS when no config in XDG_CONFIG_HOME', function() + write_file( + table.concat({ xdgdir, 'nvim', 'init.lua' }, pathsep), + [[vim.g.xdg_config_dirs_lua = 1]] + ) + clear { + args_rm = { '-u' }, + env = { XDG_CONFIG_HOME = xconfig, XDG_DATA_HOME = xdata, XDG_CONFIG_DIRS = xdgdir }, + } + eq(1, eval('g:xdg_config_dirs_lua')) + eq( + fn.fnamemodify(table.concat({ xdgdir, 'nvim', 'init.lua' }, pathsep), ':p'), + eval('$MYVIMRC') + ) + end) + + it('prefers init.lua over init.vim, shows E5422', function() + write_file(table.concat({ xdgdir, 'nvim', 'init.lua' }, pathsep), [[vim.g.xdg_lua = 1]]) + write_file(table.concat({ xdgdir, 'nvim', 'init.vim' }, pathsep), [[let g:xdg_vim = 1]]) + clear { + args_rm = { '-u' }, + env = { XDG_CONFIG_HOME = xconfig, XDG_DATA_HOME = xdata, XDG_CONFIG_DIRS = xdgdir }, + } + eq(1, eval('g:xdg_lua')) + eq(0, eval('get(g:, "xdg_vim", 0)')) + t.matches('E5422: Conflicting configs:', eval('v:errmsg')) + end) + + it('falls back to init.vim when no init.lua', function() + write_file(table.concat({ xdgdir, 'nvim', 'init.vim' }, pathsep), [[let g:xdg_vim = 1]]) + clear { + args_rm = { '-u' }, + env = { XDG_CONFIG_HOME = xconfig, XDG_DATA_HOME = xdata, XDG_CONFIG_DIRS = xdgdir }, + } + eq(1, eval('g:xdg_vim')) + end) + end) end) describe('runtime:', function()