diff --git a/lib/languages.nix b/lib/languages.nix index c4074144..556c38cf 100644 --- a/lib/languages.nix +++ b/lib/languages.nix @@ -1,9 +1,13 @@ {lib}: let inherit (builtins) isString getAttr; inherit (lib.options) mkOption; - inherit (lib.types) listOf bool str submodule attrsOf anything either nullOr; + inherit (lib.strings) concatStringsSep; + inherit (lib.types) listOf bool str submodule attrsOf anything either nullOr oneOf enum; + inherit (lib.attrsets) attrNames; inherit (lib.nvim.attrsets) mapListToAttrs; inherit (lib.nvim.types) luaInline; + inherit (lib.lists) isList; + inherit (lib) genAttrs recursiveUpdate; in { # TODO: remove diagnosticsToLua = { @@ -34,6 +38,18 @@ in { description = "Turn on ${desc} for enabled languages by default"; }; + # resolveLspOptions + # servers: AttrsOf lspOptions + # selected: AttrsOf lspOptions | List of string keys from servers + # Returns: AttrsOf lspOptions + resolveLspOptions = { + servers, + selected, + }: + if isList selected + then genAttrs selected (name: servers.${name}) + else selected; + lspOptions = submodule { freeformType = attrsOf anything; options = { @@ -77,4 +93,27 @@ in { }; }; }; + + mkLspOption = {servers, ...} @ args: let + serverNames = attrNames servers; + defaultAttrs = { + type = oneOf [ + (attrsOf lib.nvim.languages.lspOptions) + (listOf (enum serverNames)) + ]; + description = '' + Either a full set of selected LSP options as an attribute set, + or a list of server names from: ${concatStringsSep ", " serverNames}. + ''; + default = {}; + example = { + clangd = { + filetypes = ["c"]; + root_markers = ["CMakeLists.txt"]; + }; + }; + }; + cleanedArgs = removeAttrs args ["servers"]; + in + mkOption (recursiveUpdate defaultAttrs cleanedArgs); } diff --git a/modules/neovim/init/lsp.nix b/modules/neovim/init/lsp.nix index 712f88f9..1b22388c 100644 --- a/modules/neovim/init/lsp.nix +++ b/modules/neovim/init/lsp.nix @@ -11,19 +11,43 @@ inherit (lib.attrsets) mapAttrsToList attrNames filterAttrs; inherit (lib.generators) mkLuaInline; inherit (lib.nvim.languages) lspOptions; - inherit (lib.nvim.dag) entryAfter; + inherit (lib.nvim.dag) entryAnywhere; inherit (lib.nvim.lua) toLuaObject; cfg = config.vim.lsp; lspConfigurations = mapAttrsToList ( - name: value: '' - vim.lsp.config["${name}"] = ${toLuaObject value} - '' + # TODO: Determine the best thing to do about merging in lspconfig + name: value: + /* + lua + */ + ''vim.lsp.config["${name}"] = ${toLuaObject value}'' ) cfg.servers; + # Approach 1: + # Create function perhaps called mkLspConfig + # mkLspConfig servers; + # that expands to something like + # vim.lsp.servers = cfg.lsp.servers...... + # vim.luaConfigRC.lspconfigMerge = entryAfter ["lsp-servers"] ''vim.lsp.config["${name}"] = vim.tbl_deep_extend("force", lspconfig.${name}, vim.lsp.config["${name}"])'' + + + # Approach 2: + # lspConfigurations = + # mapAttrsToList ( + # name: value: ''vim.lsp.config["${name}"] = vim.tbl_deep_extend("force", lspconfig.${name}, ${toLuaObject value})'' + # ) + # (filterAttrs (n: _: n != "*") cfg.servers); + # Then also need to configure global * settings + # globalConfiguration = + # mapAttrsToList ( + # name: value: ''vim.lsp.config["${name}"] = ${toLuaObject value}'' + # ) + # (filterAttrs (n: _: n == "*") cfg.servers); + enabledServers = filterAttrs (_: u: u.enable) cfg.servers; in { options = { @@ -81,15 +105,18 @@ in { } (mkIf (cfg.servers != {}) { - # Enable lspconfig in order to merge in the predefined opts - vim.lsp.lspconfig.enable = true; - vim.luaConfigRC.lsp-servers = entryAfter ["lspconfig"] '' - -- Individual LSP configurations managed by nvf. - ${concatLines lspConfigurations} + vim.luaConfigRC.lsp-servers = + entryAnywhere + # Or entryAfter ["lspconfig"] if we go with the second approach + /* + lua + */ + '' + ${concatLines lspConfigurations} - -- Enable configured LSPs explicitly - vim.lsp.enable(${toLuaObject (filter (name: name != "*") (attrNames enabledServers))}) - ''; + -- Enable configured LSPs explicitly + vim.lsp.enable(${toLuaObject (filter (name: name != "*") (attrNames enabledServers))}); + ''; }) ]; } diff --git a/modules/plugins/languages/markdown.nix b/modules/plugins/languages/markdown.nix index 32c16240..23848835 100644 --- a/modules/plugins/languages/markdown.nix +++ b/modules/plugins/languages/markdown.nix @@ -9,18 +9,27 @@ inherit (lib.modules) mkIf mkMerge; inherit (lib.options) mkEnableOption mkOption; inherit (lib.lists) isList; - inherit (lib.types) bool enum package listOf str nullOr; - inherit (lib.nvim.lua) toLuaObject; + inherit (lib.types) bool enum either package listOf str nullOr; + inherit (lib.nvim.lua) expToLua toLuaObject; inherit (lib.nvim.types) diagnostics mkGrammarOption mkPluginSetupOption; inherit (lib.nvim.dag) entryAnywhere; - inherit (lib.nvim.attrsets) mapListToAttrs; cfg = config.vim.languages.markdown; - defaultServers = ["marksman"]; + defaultServer = "marksman"; servers = { marksman = { - enable = true; - cmd = ["${pkgs.marksman}/bin/marksman" "server"]; + package = pkgs.marksman; + lspConfig = '' + lspconfig.marksman.setup{ + capabilities = capabilities; + on_attach = default_on_attach; + cmd = ${ + if isList cfg.lsp.package + then expToLua cfg.lsp.package + else ''{"${cfg.lsp.package}/bin/marksman", "server"}'' + }, + } + ''; }; }; @@ -60,10 +69,17 @@ in { lsp = { enable = mkEnableOption "Enable Markdown LSP support" // {default = config.vim.lsp.enable;}; - servers = mkOption { + server = mkOption { + type = enum (attrNames servers); + default = defaultServer; description = "Markdown LSP server to use"; - type = listOf (enum (attrNames servers)); - default = defaultServers; + }; + + package = mkOption { + type = either package (listOf str); + default = servers.${cfg.lsp.server}.package; + example = ''[lib.getExe pkgs.jdt-language-server " - data " " ~/.cache/jdtls/workspace "]''; + description = "Markdown LSP server package, or the command to run as a list of strings"; }; }; @@ -145,12 +161,8 @@ in { }) (mkIf cfg.lsp.enable { - vim.lsp.servers = - mapListToAttrs (n: { - name = n; - value = servers.${n}; - }) - cfg.lsp.servers; + vim.lsp.lspconfig.enable = true; + vim.lsp.lspconfig.sources.markdown-lsp = servers.${cfg.lsp.server}.lspConfig; }) (mkIf cfg.format.enable { diff --git a/modules/plugins/languages/nix.nix b/modules/plugins/languages/nix.nix index 9edf5637..39f2a76b 100644 --- a/modules/plugins/languages/nix.nix +++ b/modules/plugins/languages/nix.nix @@ -6,14 +6,15 @@ }: let inherit (builtins) attrNames; inherit (lib) concatStringsSep; + inherit (lib.generators) mkLuaInline; inherit (lib.meta) getExe; inherit (lib.options) mkEnableOption mkOption; inherit (lib.modules) mkIf mkMerge; inherit (lib.lists) isList; - inherit (lib.types) enum package listOf; + inherit (lib.types) enum package; inherit (lib.nvim.types) mkGrammarOption diagnostics; - inherit (lib.nvim.attrsets) mapListToAttrs; inherit (lib.nvim.lua) expToLua; + inherit (lib.nvim.languages) resolveLspOptions mkLspOption; cfg = config.vim.languages.nix; @@ -22,18 +23,18 @@ then expToLua package else ''{"${package}/bin/${defaultCmd}"}''; - formattingCmd = mkIf (cfg.format.enable && cfg.lsp.enable) { - formatting = mkMerge [ - (mkIf (cfg.format.type == "alejandra") { + formattingCmd = lib.mkIf (cfg.format.enable && cfg.lsp.enable) { + formatting = lib.mkMerge [ + (lib.mkIf (cfg.format.type == "alejandra") { command = ["${cfg.format.package}/bin/alejandra" "--quiet"]; }) - (mkIf (cfg.format.type == "nixfmt") { + (lib.mkIf (cfg.format.type == "nixfmt") { command = ["${cfg.format.package}/bin/nixfmt"]; }) ]; }; - defaultServers = ["nil_ls"]; + defaultServers = ["nil_ls"] servers = { nil_ls = { enable = true; @@ -100,11 +101,9 @@ in { lsp = { enable = mkEnableOption "Nix LSP support" // {default = config.vim.lsp.enable;}; - servers = mkOption { - description = "Nix LSP server to use"; - type = listOf (enum (attrNames servers)); + servers = mkLspOption { + inherit servers; default = defaultServers; - example = ["nixd"]; }; }; @@ -154,14 +153,14 @@ in { }) (mkIf cfg.lsp.enable { - vim.lsp.servers = - mapListToAttrs (n: { - name = n; - value = servers.${n}; - }) - cfg.lsp.servers; + # TODO: Map this to include lspconfig stuff so that we can do + vim.lsp.servers = resolveLspOptions { + inherit servers; + selected = cfg.lsp.servers; + }; }) + # TODO: Figure out what do here. This is not necessarily correct as other lsps might not have formatting by default (mkIf (cfg.format.enable && !cfg.lsp.enable) { vim.formatter.conform-nvim = { enable = true;