diff --git a/lib/neovim-plugin.nix b/lib/neovim-plugin.nix index 46d7969f96..2a58b84ce5 100644 --- a/lib/neovim-plugin.nix +++ b/lib/neovim-plugin.nix @@ -110,11 +110,12 @@ with lib; { extraPlugins = (optional installPackage cfg.package) ++ extraPlugins; inherit extraPackages; - - ${extraConfigNamespace} = optionalString callSetup '' + } + (optionalAttrs callSetup { + ${extraConfigNamespace} = '' require('${luaName}')${setup}(${optionalString (cfg ? settings) (toLuaObject cfg.settings)}) ''; - } + }) (optionalAttrs (isColorscheme && (colorscheme != null)) { colorscheme = mkDefault colorscheme; }) (extraConfig cfg) ]); diff --git a/lib/utils.nix b/lib/utils.nix index ae82ecac6a..3f58ec6256 100644 --- a/lib/utils.nix +++ b/lib/utils.nix @@ -4,7 +4,14 @@ _nixvimTests, }: with lib; -{ +rec { + # Whether a string contains something other than whitespaces + hasContent = str: builtins.match "[[:space:]]*" str == null; + + # Concatenate a list of strings, adding a newline at the end of each one, + # but skipping strings containing only whitespace characters + concatNonEmptyLines = lines: concatLines (builtins.filter hasContent lines); + listToUnkeyedAttrs = list: builtins.listToAttrs (lib.lists.imap0 (idx: lib.nameValuePair "__unkeyed-${toString idx}") list); @@ -118,4 +125,26 @@ with lib; ${string} end ''; + + # Wrap Vimscript for using in lua, + # but only if the string contains something other than whitespaces + # TODO: account for a possible ']]' in the string + wrapVimscriptForLua = + string: + optionalString (hasContent string) '' + vim.cmd([[ + ${string} + ]]) + ''; + + # Wrap lua script for using in Vimscript, + # but only if the string contains something other than whitespaces + # TODO: account for a possible 'EOF' if the string + wrapLuaForVimscript = + string: + optionalString (hasContent string) '' + lua << EOF + ${string} + EOF + ''; } diff --git a/modules/autocmd.nix b/modules/autocmd.nix index 280894e9f3..8b9cd76a92 100644 --- a/modules/autocmd.nix +++ b/modules/autocmd.nix @@ -42,7 +42,7 @@ with lib; let inherit (config) autoGroups autoCmd; in - mkIf (autoGroups != { } || autoCmd != { }) { + mkIf (autoGroups != { } || autoCmd != [ ]) { # Introduced early October 2023. # TODO remove in early December 2023. assertions = [ diff --git a/modules/diagnostics.nix b/modules/diagnostics.nix index 0daee58e4d..189e525fa2 100644 --- a/modules/diagnostics.nix +++ b/modules/diagnostics.nix @@ -19,7 +19,7 @@ with lib; }; config = { - extraConfigLuaPre = optionalString (config.diagnostics != { }) '' + extraConfigLuaPre = mkIf (config.diagnostics != { }) '' vim.diagnostic.config(${helpers.toLuaObject config.diagnostics}) ''; }; diff --git a/modules/highlights.nix b/modules/highlights.nix index a6a7d057ef..1a0280ae9b 100644 --- a/modules/highlights.nix +++ b/modules/highlights.nix @@ -35,50 +35,52 @@ with lib; }; }; - config = { - extraConfigLuaPre = - (optionalString (config.highlight != { }) - # lua - '' - -- Highlight groups {{ - do - local highlights = ${helpers.toLuaObject config.highlight} + config = mkMerge [ + { + extraConfigLuaPre = + mkIf (config.highlight != { }) + # lua + '' + -- Highlight groups {{ + do + local highlights = ${helpers.toLuaObject config.highlight} - for k,v in pairs(highlights) do - vim.api.nvim_set_hl(0, k, v) + for k,v in pairs(highlights) do + vim.api.nvim_set_hl(0, k, v) + end end - end - -- }} - '' - ) - + (optionalString (config.match != { }) - # lua - '' - -- Match groups {{ - do - local match = ${helpers.toLuaObject config.match} + -- }} + ''; + extraConfigLuaPost = + mkIf (config.highlightOverride != { }) + # lua + '' + -- Highlight groups {{ + do + local highlights = ${helpers.toLuaObject config.highlightOverride} - for k,v in pairs(match) do - vim.fn.matchadd(k, v) + for k,v in pairs(highlights) do + vim.api.nvim_set_hl(0, k, v) + end end - end -- }} - '' - ); - - extraConfigLuaPost = - optionalString (config.highlightOverride != { }) - # lua - '' - -- Highlight groups {{ - do - local highlights = ${helpers.toLuaObject config.highlightOverride} + ''; + } + { + extraConfigLuaPre = + mkIf (config.match != { }) + # lua + '' + -- Match groups {{ + do + local match = ${helpers.toLuaObject config.match} - for k,v in pairs(highlights) do - vim.api.nvim_set_hl(0, k, v) + for k,v in pairs(match) do + vim.fn.matchadd(k, v) + end end - end - -- }} - ''; - }; + -- }} + ''; + } + ]; } diff --git a/modules/keymaps.nix b/modules/keymaps.nix index e517766749..e58b978942 100644 --- a/modules/keymaps.nix +++ b/modules/keymaps.nix @@ -90,7 +90,7 @@ with lib; ${concatStringsSep "\n" luaDefs} ''; - extraConfigLua = optionalString (config.keymaps != [ ]) '' + extraConfigLua = mkIf (config.keymaps != [ ]) '' -- Set up keybinds {{{ do local __nixvim_binds = ${helpers.toLuaObject (map normalizeMapping config.keymaps)} diff --git a/modules/opts.nix b/modules/opts.nix index f7b2d1a706..959d629fc7 100644 --- a/modules/opts.nix +++ b/modules/opts.nix @@ -55,31 +55,35 @@ in }; config = { - extraConfigLuaPre = concatLines ( - mapAttrsToList ( - optionName: - { - prettyName, - luaVariableName, - luaApi, - ... - }: - let - varName = "nixvim_${luaVariableName}"; - optionDefinitions = config.${optionName}; - in - optionalString (optionDefinitions != { }) '' - -- Set up ${prettyName} {{{ - do - local ${varName} = ${helpers.toLuaObject optionDefinitions} + extraConfigLuaPre = + let + content = helpers.concatNonEmptyLines ( + mapAttrsToList ( + optionName: + { + prettyName, + luaVariableName, + luaApi, + ... + }: + let + varName = "nixvim_${luaVariableName}"; + optionDefinitions = config.${optionName}; + in + optionalString (optionDefinitions != { }) '' + -- Set up ${prettyName} {{{ + do + local ${varName} = ${helpers.toLuaObject optionDefinitions} - for k,v in pairs(${varName}) do - vim.${luaApi}[k] = v - end - end - -- }}} - '' - ) optionsAttrs - ); + for k,v in pairs(${varName}) do + vim.${luaApi}[k] = v + end + end + -- }}} + '' + ) optionsAttrs + ); + in + mkIf (content != "") content; }; } diff --git a/modules/output.nix b/modules/output.nix index 0cfdd5b7b6..0beb31d440 100644 --- a/modules/output.nix +++ b/modules/output.nix @@ -1,4 +1,9 @@ -{ lib, config, ... }: +{ + lib, + config, + helpers, + ... +}: with lib; let pluginWithConfigType = types.submodule { @@ -97,29 +102,27 @@ in }; }; - config = - let - contentLua = '' - ${config.extraConfigLuaPre} - vim.cmd([[ - ${config.extraConfigVim} - ]]) - ${config.extraConfigLua} - ${config.extraConfigLuaPost} - ''; - - contentVim = '' - lua << EOF - ${config.extraConfigLuaPre} - EOF - ${config.extraConfigVim} - lua << EOF - ${config.extraConfigLua} - ${config.extraConfigLuaPost} - EOF - ''; - in - { - content = if config.type == "lua" then contentLua else contentVim; - }; + config = { + content = + if config.type == "lua" then + # Lua + helpers.concatNonEmptyLines [ + config.extraConfigLuaPre + (helpers.wrapVimscriptForLua config.extraConfigVim) + config.extraConfigLua + config.extraConfigLuaPost + ] + else + # Vimscript + helpers.concatNonEmptyLines [ + (helpers.wrapLuaForVimscript config.extraConfigLuaPre) + config.extraConfigVim + (helpers.wrapLuaForVimscript ( + helpers.concatNonEmptyLines [ + config.extraConfigLua + config.extraConfigLuaPost + ] + )) + ]; + }; } diff --git a/modules/top-level/output.nix b/modules/top-level/output.nix index 268316fcb8..bd62d2174f 100644 --- a/modules/top-level/output.nix +++ b/modules/top-level/output.nix @@ -107,16 +107,10 @@ with lib; } ); - customRC = - let - hasContent = str: (builtins.match "[[:space:]]*" str) == null; - in - (optionalString (hasContent neovimConfig.neovimRcContent) '' - vim.cmd([[ - ${neovimConfig.neovimRcContent} - ]]) - '') - + config.content; + customRC = helpers.concatNonEmptyLines [ + (helpers.wrapVimscriptForLua neovimConfig.neovimRcContent) + config.content + ]; init = helpers.writeLua "init.lua" customRC; @@ -146,7 +140,7 @@ with lib; ''; }; - extraConfigLuaPre = lib.optionalString config.wrapRc '' + extraConfigLuaPre = lib.mkIf config.wrapRc '' -- Ignore the user lua configuration vim.opt.runtimepath:remove(vim.fn.stdpath('config')) -- ~/.config/nvim vim.opt.runtimepath:remove(vim.fn.stdpath('config') .. "/after") -- ~/.config/nvim/after diff --git a/tests/test-sources/modules/output.nix b/tests/test-sources/modules/output.nix index 143b8bd4f6..74d7bd0964 100644 --- a/tests/test-sources/modules/output.nix +++ b/tests/test-sources/modules/output.nix @@ -4,4 +4,90 @@ # Make sure jsregexp is in LUA_PATH extraConfigLua = ''require("jsregexp")''; }; + + # Test that all extraConfigs are present in output + all-configs.module = + { + config, + pkgs, + lib, + ... + }: + let + configs = { + extraConfigLuaPre = "string.format('extraConfigLuaPre1')"; + extraConfigLua = "string.format('extraConfigLua2')"; + extraConfigLuaPost = "string.format('extraConfigLuaPost3')"; + extraConfigVim = "let g:var = 'extraConfigVim4'"; + }; + mkConfigAssertions = name: value: [ + { + assertion = lib.hasInfix "extraConfigLuaPre1" value; + message = "Configuration file ${name} does not contain extraConfigLuaPre."; + } + { + assertion = lib.hasInfix "extraConfigLua2" value; + message = "Configuration file ${name} does not contain extraConfigLua."; + } + { + assertion = lib.hasInfix "extraConfigLuaPost3" value; + message = "Configuration file ${name} does not contain extraConfigLuaPost."; + } + { + assertion = lib.hasInfix "extraConfigVim4" value; + message = "Configuration file ${name} does not contain extraConfigVim."; + } + ]; + in + configs + // { + files = { + "test.lua" = configs; + "test.vim" = configs; + }; + + # Plugin configs + extraPlugins = [ + { + plugin = pkgs.emptyDirectory; + config = "let g:var = 'neovimRcContent5'"; + } + ]; + + assertions = + mkConfigAssertions "init.lua" config.content + ++ mkConfigAssertions "test.lua" config.files."test.lua".content + ++ mkConfigAssertions "test.vim" config.files."test.vim".content + # Check the final generated init.lua too + ++ mkConfigAssertions "initPath" (builtins.readFile config.initPath) + ++ [ + # Only init.lua contains configuration from plugin definitions + { + assertion = lib.hasInfix "neovimRcContent5" (builtins.readFile config.initPath); + message = "Configuration file init.lua does not contain plugin configs"; + } + ]; + }; + + files-default-empty.module = + { config, helpers, ... }: + { + files = { + # lua type + "test.lua" = { }; + # vim type + "test.vim" = { }; + }; + + assertions = [ + { + assertion = !helpers.hasContent config.files."test.lua".content; + message = "Default content of test.lua file is expected to be empty."; + } + { + assertion = !helpers.hasContent config.files."test.vim".content; + message = "Default content of test.vim file is expected to be empty."; + } + ]; + }; }