diff --git a/lib/default.nix b/lib/default.nix index 693aff9..eade2e2 100644 --- a/lib/default.nix +++ b/lib/default.nix @@ -9,6 +9,7 @@ binds = import ./binds.nix {inherit lib;}; dag = import ./dag.nix {inherit lib;}; languages = import ./languages.nix {inherit lib;}; + lists = import ./lists.nix {inherit lib;}; lua = import ./lua.nix {inherit lib;}; vim = import ./vim.nix; } diff --git a/lib/lists.nix b/lib/lists.nix new file mode 100644 index 0000000..25e85ad --- /dev/null +++ b/lib/lists.nix @@ -0,0 +1,34 @@ +{lib}: let + inherit (lib.lists) elem all; +in { + /* + Checks if all values are present in the list. + + Type: + listContainsValues :: { list :: [a], values :: [a] } -> Bool + + Arguments: + list - A list of elements. + values - A list of values to check for presence in the list. + + Returns: + True if all values are present in the list, otherwise False. + + Example: + ```nix + listContainsValues { list = [1 2 3]; values = [2 3]; } + => True + + listContainsValues { list = [1 2 3]; values = [2 4]; } + => False + ``` + */ + listContainsValues = { + list, + values, + }: let + # Check if all values are present in the list + containsValue = value: elem value list; + in + all containsValue values; +} diff --git a/modules/plugins/treesitter/config.nix b/modules/plugins/treesitter/config.nix index 92802a8..cf1d595 100644 --- a/modules/plugins/treesitter/config.nix +++ b/modules/plugins/treesitter/config.nix @@ -1,17 +1,21 @@ { config, + pkgs, lib, ... }: let inherit (lib.modules) mkIf mkMerge; - inherit (lib.lists) optional; + inherit (lib.lists) optional optionals; + inherit (lib.trivial) boolToString; + inherit (lib.nvim.lists) listContainsValues; inherit (lib.nvim.binds) mkSetBinding addDescriptionsToMappings; + inherit (lib.nvim.lua) toLuaObject; inherit (lib.nvim.dag) entryBefore entryAnywhere; cfg = config.vim.treesitter; usingNvimCmp = config.vim.autocomplete.enable && config.vim.autocomplete.type == "nvim-cmp"; - self = import ./treesitter.nix {inherit lib;}; + self = import ./treesitter.nix {inherit pkgs lib;}; mappingDefinitions = self.options.vim.treesitter.mappings; mappings = addDescriptionsToMappings cfg.mappings mappingDefinitions; in { @@ -20,6 +24,7 @@ in { startPlugins = ["nvim-treesitter"] ++ optional usingNvimCmp "cmp-treesitter"; autocomplete.sources = {"treesitter" = "[Treesitter]";}; + treesitter.grammars = optionals cfg.addDefaultGrammars cfg.defaultGrammars; maps = { # HACK: Using mkSetLuaBinding and putting the lua code does not work for some reason: It just selects the whole file. @@ -41,17 +46,31 @@ in { ''); luaConfigRC.treesitter = entryAnywhere '' - require'nvim-treesitter.configs'.setup { - highlight = { + require('nvim-treesitter.configs').setup { + -- Disable imperative treesitter options that would attempt to fetch + -- grammars into the read-only Nix store. To add additional grammars here + -- you must use the `config.vim.treesitter.grammars` option. + auto_install = false, + sync_install = false, + ensure_installed = {}, + + -- Indentation module for Treesitter + indent = { enable = true, disable = {}, }, - auto_install = false, - ensure_installed = {}, + -- Highlight module for Treesitter + highlight = { + enable = ${boolToString cfg.highlight.enable}, + disable = ${toLuaObject cfg.highlight.disable}, + additional_vim_regex_highlighting = false, + }, + -- Indentation module for Treesitter incremental_selection = { enable = true, + disable = {}, keymaps = { init_selection = false, node_incremental = false, diff --git a/modules/plugins/treesitter/default.nix b/modules/plugins/treesitter/default.nix index 5520cfe..a859f3a 100644 --- a/modules/plugins/treesitter/default.nix +++ b/modules/plugins/treesitter/default.nix @@ -1,7 +1,9 @@ { imports = [ + # treesitter extras + ./ts-context + ./treesitter.nix - ./context.nix ./config.nix ]; } diff --git a/modules/plugins/treesitter/treesitter.nix b/modules/plugins/treesitter/treesitter.nix index feae8d7..1ff4dfe 100644 --- a/modules/plugins/treesitter/treesitter.nix +++ b/modules/plugins/treesitter/treesitter.nix @@ -1,20 +1,15 @@ -{lib, ...}: let - inherit (lib.options) mkOption mkEnableOption; +{ + pkgs, + lib, + ... +}: let + inherit (lib.options) mkOption mkEnableOption literalMD; + inherit (lib.types) listOf package str either bool; inherit (lib.nvim.binds) mkMappingOption; - inherit (lib.types) listOf package; + inherit (lib.nvim.types) luaInline mkGrammarOption; in { options.vim.treesitter = { enable = mkEnableOption "treesitter, also enabled automatically through language options"; - fold = mkEnableOption "fold with treesitter"; - autotagHtml = mkEnableOption "autoclose and rename html tag"; - grammars = mkOption { - type = listOf package; - default = []; - description = '' - List of treesitter grammars to install. For supported languages - use the `vim.language..treesitter` option - ''; - }; mappings.incrementalSelection = { init = mkMappingOption "Init selection [treesitter]" "gnn"; @@ -22,5 +17,85 @@ in { incrementByScope = mkMappingOption "Increment selection by scope [treesitter]" "grc"; decrementByNode = mkMappingOption "Decrement selection by node [treesitter]" "grm"; }; + + fold = mkEnableOption "fold with treesitter"; + autotagHtml = mkEnableOption "autoclose and rename html tag"; + grammars = mkOption { + type = listOf package; + default = []; + description = '' + List of treesitter grammars to install. + + For languages already supported by neovim-flake, you may + use the {option}`vim.language..treesitter` options, which + will automatically add the required grammars to this. + ''; + }; + + highlight = { + enable = mkEnableOption "highlighting with treesitter"; + disable = mkOption { + type = either (listOf str) luaInline; + default = []; + example = literalMD '' + ```lua + -- Disable slow treesitter highlight for large files + disable = function(lang, buf) + local max_filesize = 1000 * 1024 -- 1MB + local ok, stats = pcall(vim.loop.fs_stat, vim.api.nvim_buf_get_name(buf)) + if ok and stats and stats.size > max_filesize then + return true + end + end + ``` + ''; + + description = '' + List of treesitter grammars to disable highlighting for. + + This option can be either a list, in which case it will be + converted to a Lua table containing grammars to disable + highlighting for, or a string containing a **lua function** + that will be read as is. + + ::: {.warning} + A comma will be added at the end of your function, so you + do not need to add it yourself. Doing so will cause in + syntax errors within your Neovim configuration. + ::: + ''; + }; + }; + + addDefaultGrammars = mkOption { + type = bool; + default = true; + description = '' + Whether to add the default grammars to the list of grammars + to install. + This option is only relevant if treesitter has been enabled. + ''; + }; + + defaultGrammars = mkOption { + internal = true; + readOnly = true; + type = listOf package; + default = with pkgs.vimPlugins.nvim-treesitter.builtGrammars; [c lua vim vimdoc query]; + description = '' + A list of treesitter grammars that will be installed by default + if treesitter has been enabled and {option}`vim.treeesitter.addDefaultGrammars` + has been set to true. + + ::: {.note} + Regardless of which language module options you enable, Neovim + depends on those grammars to be enabled while treesitter is enabled. + + This list cannot be modified, but if you would like to bring your own + parsers instead of those provided here, you can set `addDefaultGrammars` + to false + ::: + ''; + }; }; } diff --git a/modules/plugins/treesitter/ts-context/config.nix b/modules/plugins/treesitter/ts-context/config.nix new file mode 100644 index 0000000..89ac74c --- /dev/null +++ b/modules/plugins/treesitter/ts-context/config.nix @@ -0,0 +1,31 @@ +{ + config, + lib, + ... +}: let + inherit (lib.modules) mkIf; + inherit (lib.trivial) boolToString; + inherit (lib.nvim.lua) nullString; + inherit (lib.nvim.dag) entryAfter; + + inherit (config.vim) treesitter; + cfg = treesitter.context; +in { + config = mkIf (treesitter.enable && cfg.enable) { + vim.startPlugins = ["nvim-treesitter-context"]; + + vim.luaConfigRC.treesitter-context = entryAfter ["treesitter"] '' + require'treesitter-context'.setup { + enable = true, + max_lines = ${toString cfg.maxLines}, + min_window_height = ${toString cfg.minWindowHeight}, + line_numbers = ${boolToString cfg.lineNumbers}, + multiline_threshold = ${toString cfg.multilineThreshold}, + trim_scope = '${cfg.trimScope}', + mode = '${cfg.mode}', + separator = ${nullString cfg.separator}, + max_lines = ${toString cfg.zindex}, + } + ''; + }; +} diff --git a/modules/plugins/treesitter/context.nix b/modules/plugins/treesitter/ts-context/context.nix similarity index 65% rename from modules/plugins/treesitter/context.nix rename to modules/plugins/treesitter/ts-context/context.nix index 8bb65b5..387aa81 100644 --- a/modules/plugins/treesitter/context.nix +++ b/modules/plugins/treesitter/ts-context/context.nix @@ -1,89 +1,60 @@ -{ - config, - lib, - ... -}: let +{lib, ...}: let inherit (lib.options) mkOption mkEnableOption; inherit (lib.types) int bool str nullOr enum; - inherit (lib.modules) mkIf; - inherit (lib.trivial) boolToString; - inherit (lib.nvim.lua) nullString; - inherit (lib.nvim.dag) entryAnywhere; - - inherit (config.vim) treesitter; - cfg = treesitter.context; in { options.vim.treesitter.context = { enable = mkEnableOption "context of current buffer contents [nvim-treesitter-context] "; maxLines = mkOption { - description = "How many lines the window should span. Values <=0 mean no limit."; type = int; default = 0; + description = "How many lines the window should span. Values <=0 mean no limit."; }; minWindowHeight = mkOption { - description = "Minimum editor window height to enable context. Values <= 0 mean no limit."; type = int; default = 0; + description = "Minimum editor window height to enable context. Values <= 0 mean no limit."; }; lineNumbers = mkOption { - description = ""; type = bool; default = true; + description = ""; }; multilineThreshold = mkOption { - description = "Maximum number of lines to collapse for a single context line."; type = int; default = 20; + description = "Maximum number of lines to collapse for a single context line."; }; trimScope = mkOption { - description = "Which context lines to discard if [](#opt-vim.treesitter.context.maxLines) is exceeded."; type = enum ["inner" "outer"]; default = "outer"; + description = "Which context lines to discard if [](#opt-vim.treesitter.context.maxLines) is exceeded."; }; mode = mkOption { - description = "Line used to calculate context."; type = enum ["cursor" "topline"]; default = "cursor"; + description = "Line used to calculate context."; }; separator = mkOption { + type = nullOr str; + default = null; description = '' Separator between context and content. Should be a single character string, like '-'. When separator is set, the context will only show up when there are at least 2 lines above cursorline. ''; - type = nullOr str; - default = null; }; zindex = mkOption { - description = "The Z-index of the context window."; type = int; default = 20; + description = "The Z-index of the context window."; }; }; - - config = mkIf (treesitter.enable && cfg.enable) { - vim.startPlugins = ["nvim-treesitter-context"]; - - vim.luaConfigRC.treesitter-context = entryAnywhere '' - require'treesitter-context'.setup { - enable = true, - max_lines = ${toString cfg.maxLines}, - min_window_height = ${toString cfg.minWindowHeight}, - line_numbers = ${boolToString cfg.lineNumbers}, - multiline_threshold = ${toString cfg.multilineThreshold}, - trim_scope = '${cfg.trimScope}', - mode = '${cfg.mode}', - separator = ${nullString cfg.separator}, - max_lines = ${toString cfg.zindex}, - } - ''; - }; } diff --git a/modules/plugins/treesitter/ts-context/default.nix b/modules/plugins/treesitter/ts-context/default.nix new file mode 100644 index 0000000..bf53d2b --- /dev/null +++ b/modules/plugins/treesitter/ts-context/default.nix @@ -0,0 +1,6 @@ +{ + imports = [ + ./context.nix + ./config.nix + ]; +} diff --git a/modules/plugins/ui/noice/config.nix b/modules/plugins/ui/noice/config.nix index 63c4f2b..8d84584 100644 --- a/modules/plugins/ui/noice/config.nix +++ b/modules/plugins/ui/noice/config.nix @@ -1,75 +1,93 @@ { config, + pkgs, lib, ... }: let inherit (lib.modules) mkIf; + inherit (lib.lists) optionals; + inherit (lib.strings) optionalString; inherit (lib.trivial) boolToString; inherit (lib.nvim.dag) entryAnywhere; cfg = config.vim.ui.noice; + tscfg = config.vim.treesitter; + cmptype = config.vim.autocomplete.type; + + defaultGrammars = with pkgs.vimPlugins.nvim-treesitter.builtGrammars; [vim regex lua bash markdown]; in { config = mkIf cfg.enable { - vim.startPlugins = [ - "noice-nvim" - "nui-nvim" - ]; + vim = { + startPlugins = [ + "noice-nvim" + "nui-nvim" + ]; - vim.luaConfigRC.noice-nvim = entryAnywhere '' - require("noice").setup({ - lsp = { - override = { - ["vim.lsp.util.convert_input_to_markdown_lines"] = true, - ["vim.lsp.util.stylize_markdown"] = true, - ["cmp.entry.get_documentation"] = true, - }, + treesitter.grammars = optionals tscfg.addDefaultGrammars defaultGrammars; - signature = { - enabled = false, -- FIXME: enabling this file throws an error which I couldn't figure out - }, - }, - - presets = { - bottom_search = true, -- use a classic bottom cmdline for search - command_palette = true, -- position the cmdline and popupmenu together - long_message_to_split = true, -- long messages will be sent to a split - inc_rename = false, -- enables an input dialog for inc-rename.nvim - lsp_doc_border = ${boolToString config.vim.ui.borders.enable}, -- add a border to hover docs and signature help - }, - - format = { - cmdline = { pattern = "^:", icon = "", lang = "vim" }, - search_down = { kind = "search", pattern = "^/", icon = " ", lang = "regex" }, - search_up = { kind = "search", pattern = "^%?", icon = " ", lang = "regex" }, - filter = { pattern = "^:%s*!", icon = "", lang = "bash" }, - lua = { pattern = "^:%s*lua%s+", icon = "", lang = "lua" }, - help = { pattern = "^:%s*he?l?p?%s+", icon = "󰋖" }, - input = {}, - }, - - messages = { - -- NOTE: If you enable messages, then the cmdline is enabled automatically. - -- This is a current Neovim limitation. - enabled = false, -- enables the Noice messages UI - view = "notify", -- default view for messages - view_error = "notify", -- view for errors - view_warn = "notify", -- view for warnings - view_history = "messages", -- view for :messages - view_search = "virtualtext", -- view for search count messages. Set to `false` to disable - }, - - -- Hide written messages - routes = { - { - filter = { - event = "msg_show", - kind = "", - find = "written", + luaConfigRC.noice-nvim = entryAnywhere '' + require("noice").setup({ + lsp = { + override = { + ["vim.lsp.util.convert_input_to_markdown_lines"] = true, + ["vim.lsp.util.stylize_markdown"] = true, + ${optionalString (cmptype == "nvim-cmp") "[\"cmp.entry.get_documentation\"] = true,"} + }, + + signature = { + enabled = false, -- FIXME: enabling this file throws an error which I couldn't figure out }, - opts = { skip = true }, }, - }, - }) - ''; + + hover = { + enabled = true, + silent = false, -- set to true to not show a message if hover is not available + view = nil, -- when nil, use defaults from documentation + opts = {}, -- merged with defaults from documentation + }, + + presets = { + bottom_search = true, -- use a classic bottom cmdline for search + command_palette = true, -- position the cmdline and popupmenu together + long_message_to_split = true, -- long messages will be sent to a split + inc_rename = false, -- enables an input dialog for inc-rename.nvim + lsp_doc_border = ${boolToString config.vim.ui.borders.enable}, -- add a border to hover docs and signature help + }, + + format = { + cmdline = { pattern = "^:", icon = "", lang = "vim" }, + search_down = { kind = "search", pattern = "^/", icon = " ", lang = "regex" }, + search_up = { kind = "search", pattern = "^%?", icon = " ", lang = "regex" }, + filter = { pattern = "^:%s*!", icon = "", lang = "bash" }, + lua = { pattern = "^:%s*lua%s+", icon = "", lang = "lua" }, + help = { pattern = "^:%s*he?l?p?%s+", icon = "󰋖" }, + input = {}, + }, + + messages = { + -- NOTE: If you enable messages, then the cmdline is enabled automatically. + -- This is a current Neovim limitation. + enabled = true, -- enables the Noice messages UI + view = "notify", -- default view for messages + view_error = "notify", -- view for errors + view_warn = "notify", -- view for warnings + view_history = "messages", -- view for :messages + view_search = "virtualtext", -- view for search count messages. Set to `false` to disable + }, + + -- Hide written messages + routes = { + { + filter = { + event = "msg_show", + kind = "", + find = "written", + }, + opts = { skip = true }, + }, + }, + }) + ''; + }; }; }