diff --git a/lib/utils.nix b/lib/utils.nix index ae82ecac6a..bc16fa1288 100644 --- a/lib/utils.nix +++ b/lib/utils.nix @@ -5,6 +5,9 @@ }: with lib; { + # Whether a string contains something other than whitespace + hasContent = str: (builtins.match "[[:space:]]*" str) == null; + listToUnkeyedAttrs = list: builtins.listToAttrs (lib.lists.imap0 (idx: lib.nameValuePair "__unkeyed-${toString idx}") list); diff --git a/modules/output.nix b/modules/output.nix index 0cfdd5b7b6..39cd78c0ed 100644 --- a/modules/output.nix +++ b/modules/output.nix @@ -1,4 +1,9 @@ -{ lib, config, ... }: +{ + config, + lib, + helpers, + ... +}: with lib; let pluginWithConfigType = types.submodule { @@ -74,20 +79,30 @@ in "vim" "lua" ]; - default = "lua"; + default = if lib.hasSuffix ".vim" config.target then "vim" else "lua"; + defaultText = lib.literalMD ''`"lua"` unless `config.target` ends with `".vim"`''; description = "Whether the generated file is a vim or a lua file"; + readOnly = true; }; - path = mkOption { + target = mkOption { type = types.str; description = "Path of the file relative to the config directory"; + default = "init.lua"; }; content = mkOption { - type = types.str; + type = types.lines; description = "The content of the config file"; - readOnly = true; visible = false; + # FIXME: can't be readOnly because we prefix it in top-level modules + }; + + finalConfig = mkOption { + type = types.package; + description = "The config file written as a derivation"; + readOnly = true; + internal = true; }; extraLuaPackages = mkOption { @@ -97,29 +112,56 @@ in }; }; + imports = [ (lib.mkRenamedOptionModule [ "path" ] [ "target" ]) ]; + config = let - contentLua = '' - ${config.extraConfigLuaPre} - vim.cmd([[ - ${config.extraConfigVim} - ]]) - ${config.extraConfigLua} - ${config.extraConfigLuaPost} - ''; + derivationName = "nvim-" + lib.replaceStrings [ "/" ] [ "-" ] config.target; - contentVim = '' - lua << EOF - ${config.extraConfigLuaPre} - EOF - ${config.extraConfigVim} - lua << EOF - ${config.extraConfigLua} - ${config.extraConfigLuaPost} - EOF - ''; + writer = if config.type == "lua" then helpers.writeLua else pkgs.writeText; + + concatConfig = parts: lib.concatStringsSep "\n" (lib.filter helpers.hasContent parts); + + wrapConfig = + fn: parts: + let + s = concatConfig (toList parts); + in + optionalString (helpers.hasContent s) (fn s); + + contentLua = concatConfig [ + config.extraConfigLuaPre + (wrapConfig (s: '' + vim.cmd([[ + ${s} + ]]) + '') config.extraConfigVim) + config.extraConfigLua + config.extraConfigLuaPost + ]; + + contentVim = concatConfig [ + (wrapConfig (s: '' + lua << EOF + ${s} + EOF + '') config.extraConfigLuaPre) + config.extraConfigVim + (wrapConfig + (s: '' + lua << EOF + ${s} + EOF + '') + [ + config.extraConfigLua + config.extraConfigLuaPost + ] + ) + ]; in { content = if config.type == "lua" then contentLua else contentVim; + finalConfig = writer derivationName config.content; }; } diff --git a/modules/top-level/files/default.nix b/modules/top-level/files/default.nix index c8a3d24840..410181cb77 100644 --- a/modules/top-level/files/default.nix +++ b/modules/top-level/files/default.nix @@ -64,8 +64,8 @@ in extraFiles = lib.mkDerivedConfig options.files ( lib.mapAttrs' ( _: file: { - name = file.path; - value.source = file.plugin; + name = file.target; + value.source = file.finalConfig; } ) ); diff --git a/modules/top-level/files/submodule.nix b/modules/top-level/files/submodule.nix index d231cf6a87..3e9f025f75 100644 --- a/modules/top-level/files/submodule.nix +++ b/modules/top-level/files/submodule.nix @@ -1,27 +1,13 @@ +{ name, lib, ... }: { - name, - config, - lib, - helpers, - ... -}: -{ - options = { - plugin = lib.mkOption { - type = lib.types.package; - description = "A derivation with the content of the file in it"; - readOnly = true; - internal = true; - }; + imports = [ + (lib.mkRenamedOptionModule [ + "plugin" + "finalConfig" + ]) + ]; + + config = { + target = lib.mkDefault name; }; - config = - let - derivationName = "nvim-" + lib.replaceStrings [ "/" ] [ "-" ] name; - in - { - path = lib.mkDefault name; - type = lib.mkDefault (if lib.hasSuffix ".vim" name then "vim" else "lua"); - # No need to use mkDerivedConfig; this option is readOnly. - plugin = helpers.writeLua derivationName config.content; - }; } diff --git a/modules/top-level/output.nix b/modules/top-level/output.nix index 268316fcb8..6c51e8d4f1 100644 --- a/modules/top-level/output.nix +++ b/modules/top-level/output.nix @@ -54,13 +54,6 @@ with lib; readOnly = true; }; - initPath = mkOption { - type = types.str; - description = "The path to the `init.lua` file."; - readOnly = true; - visible = false; - }; - printInitPackage = mkOption { type = types.package; description = "A tool to show the content of the generated `init.lua` file."; @@ -69,90 +62,69 @@ with lib; }; }; + imports = [ + (lib.mkRemovedOptionModule [ "initPath" ] '' + Use `finalConfig' instead. + '') + ]; + config = let - defaultPlugin = { - plugin = null; - config = ""; - optional = false; + neovimConfig = pkgs.neovimUtils.makeNeovimConfig { + inherit (config) + extraPython3Packages + extraLuaPackages + viAlias + vimAlias + withRuby + withNodeJs + ; + plugins = config.extraPlugins; + # We handle `customRC` ourselves, to position it after `extraConfigLuaPre` }; - normalizedPlugins = map ( - x: defaultPlugin // (if x ? plugin then x else { plugin = x; }) - ) config.extraPlugins; - - neovimConfig = pkgs.neovimUtils.makeNeovimConfig ( - { - inherit (config) - extraPython3Packages - extraLuaPackages - viAlias - vimAlias - withRuby - withNodeJs - ; - # inherit customRC; - plugins = normalizedPlugins; - } - # Necessary to make sure the runtime path is set properly in NixOS 22.05, - # or more generally before the commit: - # cda1f8ae468 - neovim: pass packpath via the wrapper - // optionalAttrs (functionArgs pkgs.neovimUtils.makeNeovimConfig ? configure) { - configure.packages = { - nixvim = { - start = map (x: x.plugin) normalizedPlugins; - opt = [ ]; - }; - }; - } - ); - - customRC = - let - hasContent = str: (builtins.match "[[:space:]]*" str) == null; - in - (optionalString (hasContent neovimConfig.neovimRcContent) '' - vim.cmd([[ - ${neovimConfig.neovimRcContent} - ]]) - '') - + config.content; - - init = helpers.writeLua "init.lua" customRC; - extraWrapperArgs = builtins.concatStringsSep " " ( (optional (config.extraPackages != [ ]) ''--prefix PATH : "${makeBinPath config.extraPackages}"'') - ++ (optional config.wrapRc ''--add-flags -u --add-flags "${init}"'') + ++ (optional config.wrapRc ''--add-flags -u --add-flags "${config.finalConfig}"'') ); - wrappedNeovim = pkgs.wrapNeovimUnstable config.package ( + configPrefix = + if config.type == "lua" then + '' + vim.cmd([[ + ${neovimConfig.neovimRcContent} + ]]) + '' + else + neovimConfig.neovimRcContent; + in + { + content = lib.mkIf (helpers.hasContent neovimConfig.neovimRcContent) (lib.mkBefore configPrefix); + + finalPackage = pkgs.wrapNeovimUnstable config.package ( neovimConfig // { wrapperArgs = lib.escapeShellArgs neovimConfig.wrapperArgs + " " + extraWrapperArgs; + # We handle wrapRc ourselves so we can control how init.lua is written wrapRc = false; } ); - in - { - type = lib.mkForce "lua"; - finalPackage = wrappedNeovim; - initPath = "${init}"; printInitPackage = pkgs.writeShellApplication { name = "nixvim-print-init"; runtimeInputs = [ pkgs.bat ]; text = '' - bat --language=lua "${init}" + bat --language=lua "${config.finalConfig}" ''; }; - extraConfigLuaPre = lib.optionalString config.wrapRc '' + extraConfigLuaPre = 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 vim.opt.runtimepath:remove(vim.fn.stdpath('data') .. "/site") -- ~/.local/share/nvim/site ''; - extraPlugins = if config.wrapRc then [ config.filesPlugin ] else [ ]; + extraPlugins = mkIf config.wrapRc [ config.filesPlugin ]; }; } diff --git a/wrappers/_shared.nix b/wrappers/_shared.nix index 0aca2c6003..d9a6577eb0 100644 --- a/wrappers/_shared.nix +++ b/wrappers/_shared.nix @@ -3,9 +3,6 @@ filesOpt ? null, # Filepath prefix to apply to extraFiles filesPrefix ? "nvim/", - # Filepath to use when adding `cfg.initPath` to `filesOpt` - # Is prefixed with `filesPrefix` - initName ? "init.lua", }: { pkgs, @@ -59,7 +56,7 @@ in ) extraFiles ) // { - ${filesPrefix + initName}.source = cfg.initPath; + ${filesPrefix + cfg.target}.source = cfg.finalConfig; } ) ) diff --git a/wrappers/modules/nixos.nix b/wrappers/modules/nixos.nix index b65e5d73e9..8ae92c2f92 100644 --- a/wrappers/modules/nixos.nix +++ b/wrappers/modules/nixos.nix @@ -8,5 +8,6 @@ config = { wrapRc = lib.mkForce true; + target = lib.mkDefault "sysinit.lua"; }; } diff --git a/wrappers/nixos.nix b/wrappers/nixos.nix index 7ffe29cde1..630c80a57b 100644 --- a/wrappers/nixos.nix +++ b/wrappers/nixos.nix @@ -42,7 +42,6 @@ in "environment" "etc" ]; - initName = "sysinit.lua"; }) ];