diff --git a/flake-modules/dev/list-plugins/list-plugins.py b/flake-modules/dev/list-plugins/list-plugins.py index 9bdd0f17..90050015 100755 --- a/flake-modules/dev/list-plugins/list-plugins.py +++ b/flake-modules/dev/list-plugins/list-plugins.py @@ -83,7 +83,6 @@ KNOWN_PATHS: dict[ Kind.NEOVIM, True, ), - "plugins/by-name/vim-matchup/default.nix": (State.OLD, Kind.VIM, False), "plugins/colorschemes/base16/default.nix": (State.NEW, Kind.VIM, True), "plugins/lsp/default.nix": (State.NEW, Kind.MISC, False), } diff --git a/plugins/by-name/vim-matchup/default.nix b/plugins/by-name/vim-matchup/default.nix index 347f0de0..7cc6bca6 100644 --- a/plugins/by-name/vim-matchup/default.nix +++ b/plugins/by-name/vim-matchup/default.nix @@ -1,213 +1,394 @@ { lib, - helpers, - pkgs, config, ... }: -with lib; -{ - options.plugins.vim-matchup = { - enable = mkEnableOption "vim-matchup"; +let + inherit (lib.nixvim) defaultNullOpts mkNullOrStr'; + inherit (lib) types; +in +lib.nixvim.vim-plugin.mkVimPlugin { + name = "vim-matchup"; + globalPrefix = "matchup_"; - package = lib.mkPackageOption pkgs "vim-matchup" { - default = [ - "vimPlugins" + maintainers = [ lib.maintainers.GaetanLepage ]; + + # TODO: Added 2024-12-16; remove after 25.05 + optionsRenamedToSettings = import ./renamed-options.nix; + imports = + let + basePluginPath = [ + "plugins" "vim-matchup" ]; - }; + in + [ + (lib.mkRenamedOptionModule + ( + basePluginPath + ++ [ + "matchParen" + "deffered" + ] + ) + ( + basePluginPath + ++ [ + "settings" + "matchparen_deferred" + ] + ) + ) + ] + ++ (lib.nixvim.mkSettingsRenamedOptionModules (basePluginPath ++ [ "treesitterIntegration" ]) + (basePluginPath ++ [ "treesitter" ]) + [ + "enable" + "disable" + "disableVirtualText" + "includeMatchWords" + ] + ); - treesitterIntegration = { - enable = mkEnableOption "treesitter integration"; - disable = helpers.defaultNullOpts.mkListOf types.str [ - ] "Languages for each to disable this module"; - - disableVirtualText = helpers.defaultNullOpts.mkBool false '' - Do not use virtual text to highlight the virtual end of a block, for languages without - explicit end markers (e.g., Python). + extraOptions = { + treesitter = lib.nixvim.mkSettingsOption { + description = '' + Options provided to the treesitter matchup integration. ''; - includeMatchWords = helpers.defaultNullOpts.mkBool false '' - Additionally include traditional vim regex matches for symbols. For example, highlights - `/* */` comments in C++ which are not supported in tree-sitter matching - ''; - }; + options = { + enable = lib.mkEnableOption "treesitter integration"; - matchParen = { - enable = helpers.defaultNullOpts.mkBool true "Control matching parentheses"; - - fallback = helpers.defaultNullOpts.mkBool true '' - If matchParen is not enabled fallback to the standard vim matchparen. - ''; - - singleton = helpers.defaultNullOpts.mkBool false "Whether to highlight known words even if there is no match"; - - offscreen = helpers.defaultNullOpts.mkNullable (types.submodule { - options = { - method = - helpers.defaultNullOpts.mkEnumFirstDefault - [ - "status" - "popup" - "status_manual" - ] - '' - 'status': Replace the status-line for off-screen matches. - - If a match is off of the screen, the line belonging to that match will be displayed - syntax-highlighted in the status line along with the line number (if line numbers - are enabled). If the match is above the screen border, an additional Δ symbol will - be shown to indicate that the matching line is really above the cursor line. - - 'popup': Show off-screen matches in a popup (vim) or floating (neovim) window. - - 'status_manual': Compute the string which would be displayed in the status-line or - popup, but do not display it. The function MatchupStatusOffscreen() can be used to - get the text. - ''; - scrolloff = helpers.defaultNullOpts.mkBool false '' - When enabled, off-screen matches will not be shown in the statusline while the - cursor is at the screen edge (respects the value of 'scrolloff'). - This is intended to prevent flickering while scrolling with j and k. - ''; - }; - }) { method = "status"; } "Dictionary controlling the behavior with off-screen matches."; - - stopline = helpers.defaultNullOpts.mkInt 400 '' - The number of lines to search in either direction while highlighting matches. - Set this conservatively since high values may cause performance issues. - ''; - - timeout = helpers.defaultNullOpts.mkInt 300 "Adjust timeouts in milliseconds for matchparen highlighting"; - - insertTimeout = helpers.defaultNullOpts.mkInt 60 "Adjust timeouts in milliseconds for matchparen highlighting"; - - deferred = { - enable = helpers.defaultNullOpts.mkBool false '' - Deferred highlighting improves cursor movement performance (for example, when using hjkl) - by delaying highlighting for a short time and waiting to see if the cursor continues - moving + disable = defaultNullOpts.mkListOf types.str [ ] '' + Languages for which to disable this module. ''; - showDelay = helpers.defaultNullOpts.mkInt 50 '' - Adjust delays in milliseconds for deferred highlighting + disable_virtual_text = defaultNullOpts.mkBool false '' + Do not use virtual text to highlight the virtual end of a block, for languages without + explicit end markers (e.g., Python). ''; - hideDelay = helpers.defaultNullOpts.mkInt 700 '' - Adjust delays in milliseconds for deferred highlighting + include_match_words = defaultNullOpts.mkBool false '' + Additionally include traditional vim regex matches for symbols. + For example, highlights `/* */` comments in C++ which are not supported in tree-sitter + matching. ''; }; - - hiSurroundAlways = helpers.defaultNullOpts.mkBool false '' - Highlight surrounding delimiters always as the cursor moves - Note: this feature requires deferred highlighting to be supported and enabled. - ''; + example = { + enable = true; + disable = [ + "c" + "ruby" + ]; + }; }; - - motion = { - enable = helpers.defaultNullOpts.mkBool true "Control motions"; - overrideNPercent = helpers.defaultNullOpts.mkInt 6 '' - In vim, {count}% goes to the {count} percentage in the file. match-up overrides this - motion for small {count} (by default, anything less than 7). To allow {count}% for {count} - less than 12 set overrideNPercent to 11. - - To disable this feature set it to 0. - - To always enable this feature, use any value greater than 99 - ''; - cursorEnd = helpers.defaultNullOpts.mkBool true '' - If enabled, cursor will land on the end of mid and close words while moving downwards - (%/]%). While moving upwards (g%, [%) the cursor will land on the beginning. - ''; - }; - - textObj = { - enable = helpers.defaultNullOpts.mkBool true "Controls text objects"; - - linewiseOperators = helpers.defaultNullOpts.mkListOf types.str [ - "d" - "y" - ] "Modify the set of operators which may operate line-wise"; - }; - - enableSurround = helpers.defaultNullOpts.mkBool false "To enable the delete surrounding (ds%) and change surrounding (cs%) maps"; - - enableTransmute = helpers.defaultNullOpts.mkBool false "To enable the experimental transmute module"; - - delimStopline = helpers.defaultNullOpts.mkInt 1500 '' - To configure the number of lines to search in either direction while using motions and text - objects. Does not apply to match highlighting (see matchParenStopline instead) - ''; - - delimNoSkips = - helpers.defaultNullOpts.mkEnumFirstDefault - [ - 0 - 1 - 2 - ] - '' - To disable matching within strings and comments: - - 0: matching is enabled within strings and comments - - 1: recognize symbols within comments - - 2: don't recognize anything in comments - ''; }; - # TODO introduced 2024-03-07: remove 2024-05-07 - imports = [ - (mkRenamedOptionModule - [ - "plugins" - "vim-matchup" - "matchParen" - "deffered" - ] - [ - "plugins" - "vim-matchup" - "matchParen" - "deferred" - ] - ) - ]; + extraConfig = cfg: { + warnings = lib.optional (cfg.treesitter.enable && (!config.plugins.treesitter.enable)) '' + Nixvim (plugins.vim-matchup): `plugins.vim-matchup.treesitter.enable` is `true`, but the + treesitter plugin itself is not. + -> Set `plugins.treesitter.enable` to `true`. + ''; - config = - let - cfg = config.plugins.vim-matchup; - in - mkIf cfg.enable { - extraPlugins = [ cfg.package ]; + plugins.treesitter.settings.matchup = cfg.treesitter; + }; - plugins.treesitter.settings.matchup = mkIf cfg.treesitterIntegration.enable { - inherit (cfg.treesitterIntegration) enable disable; - disable_virtual_text = cfg.treesitterIntegration.disableVirtualText; - include_match_words = cfg.treesitterIntegration.includeMatchWords; + settingsOptions = { + enabled = defaultNullOpts.mkFlagInt 1 '' + Set to `0` to disable the plugin entirely. + ''; + + mappings_enabled = defaultNullOpts.mkFlagInt 1 '' + Set to `0` to disable all mappings. + ''; + + mouse_enabled = defaultNullOpts.mkFlagInt 1 '' + Set to `0` to disable selecting matches with double click. + ''; + + motion_enabled = defaultNullOpts.mkFlagInt 1 '' + Set to `0` to disable motions (`|matchup-%|`, `|%|`, `|[%|`, `|]%|`). + ''; + + text_obj_enabled = defaultNullOpts.mkFlagInt 1 '' + Set to `0` to disable text objects (`|a%|`, `|i%|`). + ''; + + transmute_enabled = defaultNullOpts.mkFlagInt 0 '' + Set to 1 to enable the experimental transmute feature (`|matchup-transmute|`). + ''; + + delim_stopline = defaultNullOpts.mkUnsignedInt 1500 '' + Configures the number of lines to search in either direction while using motions and text + objects. + Does not apply to match highlighting (see `matchparen_stopline` instead). + ''; + + delim_noskips = defaultNullOpts.mkEnumFirstDefault [ 0 1 2 ] '' + This option controls whether matching is done within strings and comments. + + - By default, it is set to `0` which means all valid matches are made within strings and + comments. + - If set to `1`, symbols like `()` will still be matched but words like `for` and `end` will + not. + - If set to `2`, nothing will be matched within strings and comments. + ''; + + delim_nomids = defaultNullOpts.mkFlagInt 0 '' + If set to `1`, middle words (like `return`) are not matched to start and end words for + highlighting and motions. + ''; + + delim_start_plaintext = defaultNullOpts.mkFlagInt 1 '' + When enabled (the default), the plugin will be loaded for all buffers, including ones without + a file type set. + + This allows matching to be done in new buffers and plain text files but adds a small start-up + cost to vim. + ''; + + matchparen_enabled = defaultNullOpts.mkFlagInt 1 '' + This option can disable match highlighting at `|startup|`. + + Note: vim's built-in plugin `|pi_paren|` plugin is also disabled. + The variable `g:loaded_matchparen` has no effect on match-up. + + You can also enable and disable highlighting for specific buffers using the variable + `|b:matchup_matchparen_enabled|`. + ''; + + matchparen_singleton = defaultNullOpts.mkFlagInt 0 '' + Whether or not to highlight recognized words even if there is no match. + ''; + + matchparen_offscreen = defaultNullOpts.mkNullable' { + pluginDefault = { + method = "status"; }; + description = '' + Attrs controlling the behavior with off-screen matches. + If empty, this feature is disabled. + ''; + type = types.submodule { + freeformType = with types; attrsOf anything; + options = { + method = defaultNullOpts.mkNullable' { + pluginDefault = "status"; + type = types.enum [ + "status" + "status_manual" + "popup" + ]; + example = "popup"; + description = '' + Sets the method to use to show off-screen matches. + Possible values are: - globals = { - matchup_surround_enabled = cfg.enableSurround; - matchup_transmute_enabled = cfg.enableTransmute; + - `"status"` (default): Replace the |status-line| for off-screen matches.\ + If a match is off of the screen, the line belonging to that match will be displayed + syntax-highlighted in the status line along with the line number (if line numbers + are enabled). + If the match is above the screen border, an additional `Δ` symbol will be shown to + indicate that the matching line is really above the cursor line. + - `"status_manual"`: Compute the string which would be displayed in the status-line or + popup, but do not display it. + The function `MatchupStatusOffscreen()` can be used to get the text. + - `"popup"`: Use a floating window to show the off-screen match. + ''; + }; - matchup_delim_stopline = cfg.delimStopline; - matchup_delim_noskips = cfg.delimNoSkips; + scrolloff = defaultNullOpts.mkFlagInt 0 '' + When enabled, off-screen matches will not be shown in the statusline while the cursor is + at the screen edge (respects the value of `'scrolloff'`). - matchup_matchparen_enabled = cfg.matchParen.enable; - matchup_matchparen_fallback = cfg.matchParen.fallback; - matchup_matchparen_offscreen = cfg.matchParen.offscreen; - matchup_matchparen_stopline = cfg.matchParen.stopline; - matchup_matchparen_timeout = cfg.matchParen.timeout; - matchup_matchparen_insert_timeout = cfg.matchParen.insertTimeout; - matchup_matchparen_deferred = cfg.matchParen.deferred.enable; - matchup_matchparen_deferred_show_delay = cfg.matchParen.deferred.showDelay; - matchup_matchparen_deferred_hide_delay = cfg.matchParen.deferred.hideDelay; - matchup_matchparen_hi_surround_always = cfg.matchParen.hiSurroundAlways; + This is intended to prevent flickering while scrolling with `j` and `k`. + ''; - matchup_motion_enabled = cfg.motion.enable; - matchup_motion_override_Npercent = cfg.motion.overrideNPercent; - matchup_motion_cursor_end = cfg.motion.cursorEnd; + fullwidth = defaultNullOpts.mkFlagInt 0 '' + For `"popup"` method: make the floating window as wide as the current window. + ''; - matchup_text_obj_enabled = cfg.textObj.enable; - matchup_text_obj_linewise_operators = cfg.textObj.linewiseOperators; + highlight = mkNullOrStr' { + description = '' + For popup method on vim only: set to a highlight group to override the colors in the + popup window. + The default is to use `*hl-Pmenu*`. + ''; + example = "OffscreenPopup"; + }; + + syntax_hl = defaultNullOpts.mkFlagInt 0 '' + For popup method on vim only: syntax highlight the code in the popup. + May have performance implications. + ''; + + border = defaultNullOpts.mkNullable (with types; either intFlag (listOf str)) 0 '' + For floating window on neovim only: set to add a border. + If the value is the integer `1`, default borders are enabled. + + A list or string can be specified as described in `|nvim_open_win()|`. + ''; + }; }; + example.__empty = null; }; + + matchparen_stopline = defaultNullOpts.mkUnsignedInt 400 '' + The number of lines to search in either direction while highlighting matches. + + Set this conservatively since high values may cause performance issues. + ''; + + matchparen_timeout = defaultNullOpts.mkUnsignedInt 300 '' + Adjust the timeouts in milliseconds for highlighting. + ''; + + matchparen_insert_timeout = defaultNullOpts.mkUnsignedInt 60 '' + Adjust the timeouts in milliseconds for highlighting. + ''; + + matchparen_deferred = defaultNullOpts.mkFlagInt 0 '' + Deferred highlighting improves cursor movement performance (for example, when using `|hjkl|`) + by delaying highlighting for a short time and waiting to see if the cursor continues moving. + ''; + + matchparen_deferred_show_delay = defaultNullOpts.mkUnsignedInt 50 '' + Delay, in milliseconds, between when the cursor moves and when we start checking if the cursor + is on a match. + + Applies to both making highlights and clearing them for deferred highlighting. + ''; + + matchparen_deferred_hide_delay = defaultNullOpts.mkUnsignedInt 700 '' + If the cursor has not stopped moving, assume highlight is stale after this many milliseconds. + + Stale highlights are hidden. + ''; + + matchparen_deferred_fade_time = defaultNullOpts.mkUnsignedInt 0 '' + When set to `{time}` in milliseconds, the deferred highlighting behavior is changed in two + ways: + + 1. Highlighting of matches is preserved for at least `{time}` even when the cursor is moved + away. + 2. If the cursor stays on the same match for longer than `{time}`, highlighting is cleared. + + The effect is that highlighting occurs momentarily and then disappears, regardless of where + the cursor is. + It is possible that fading takes longer than `{time}`, if vim is busy doing other things. + + This value should be greater than the deferred show delay. + ''; + + matchparen_pumvisible = defaultNullOpts.mkFlagInt 1 '' + If set to `1`, matches will be made even when the `|popupmenu-completion|` is visible. + + If you use an auto-complete plugin which interacts badly with matching, set this option to + `0`. + ''; + + matchparen_nomode = defaultNullOpts.mkStr' { + pluginDefault = ""; + example = "vV\"; + description = '' + When not empty, match highlighting will be disabled in the specified modes, where each mode + is a single character like in the `|mode()|` function. + + E.g., to disable highlighting in insert mode, + ```nix + matchparen_nomode = "i"; + ``` + and in visual modes, + ```nix + matchparen_nomode = "vV\"; + ``` + + Note: In visual modes, this takes effect only after moving the cursor. + ''; + }; + + matchparen_hi_surround_always = defaultNullOpts.mkFlagInt 0 '' + Always highlight the surrounding words, if possible. + This is like `|(matchup-hi-surround)|` but is updated each time the cursor moves. + + This requires deferred matching (`matchparen_deferred = 1`). + ''; + + matchparen_hi_background = defaultNullOpts.mkFlagInt 0 '' + Highlight buffer background between matches. + This uses the `MatchBackground` highlighting group and is linked to `ColorColumn` by default. + ''; + + matchparen_end_sign = defaultNullOpts.mkStr "◀" '' + Configure the virtual symbol shown for closeless matches in languages like C++ and python. + + ```cpp + if (true) + cout << ""; + else + cout << ""; ◀ if + ``` + ''; + + motion_override_Npercent = defaultNullOpts.mkUnsignedInt 6 '' + In vim, `{count}%` goes to the `{count}` percentage in the file (see `|N%|`). + match-up overrides this motion for small `{count}` (by default, anything less than 7). + + - For example, to allow `{count}%` for `{count}` less than 12, set it to `11`. + - To disable this feature, and restore vim's default `{count}%`, set it to `0`. + - To always enable this feature, use any value greater than 99. + ''; + + motion_cursor_end = defaultNullOpts.mkFlagInt 1 '' + If enabled, cursor will land on the end of mid and close words while moving downwards + (`|%|/|]%|`). + While moving upwards (`|g%|`, `|[%|`) the cursor will land on the beginning. + Set to `0` to disable. + + Note: this has no effect on operators: `d%` will delete `|inclusive|` of the ending word (this + is compatible with matchit). + ''; + + delim_count_fail = defaultNullOpts.mkFlagInt 0 '' + When disabled (default), giving an invalid count to the `|[%|` and `|]%|` motions and the text + objects `|i%|` and `|a%|` will cause the motion or operation to fail. + + When enabled, they will move as far as possible. + + Note: targeting high counts when this option is enabled can become slow because many positions + need to be tried before giving up. + ''; + + text_obj_linewise_operators = defaultNullOpts.mkListOf types.str [ "d" "y" ] '' + Modifies the set of operators which may operate line-wise with `|i%|` (see + `|matchup-feat-linewise|`). + + You may use `"v"`, `"V"`, and `"\"` (i.e., an actual CTRL-V character) to specify the + corresponding visual mode. + + You can also specify custom plugin operators with 'g@' and optionally, an expression separated + by a comma. + ''; + + surround_enabled = defaultNullOpts.mkFlagInt 0 '' + Enables the surround module which provides maps `|ds%|` and `|cs%|`. + ''; + + override_vimtex = defaultNullOpts.mkFlagInt 0 '' + By default, match-up is disabled for tex files when the plugin `|vimtex|` is detected. + + To enable match-up for tex files, set this option to `1`. + This will replace vimtex's built-in highlighting and `%` map. + + Note: matching may be computationally intensive for complex LaTeX documents. + If you experience slowdowns, consider also setting `matchparen_deferred` to `1`. + ''; + }; + + settingsExample = { + mouse_enabled = 0; + surround_enabled = 1; + transmute_enabled = 1; + matchparen_offscreen.method = "popup"; + }; } diff --git a/plugins/by-name/vim-matchup/renamed-options.nix b/plugins/by-name/vim-matchup/renamed-options.nix new file mode 100644 index 00000000..1edf9542 --- /dev/null +++ b/plugins/by-name/vim-matchup/renamed-options.nix @@ -0,0 +1,130 @@ +[ + { + old = "enableSurround"; + new = "surround_enabled"; + } + { + old = "enableTransmute"; + new = "transmute_enabled"; + } + "delimStopline" + { + old = "delimNoSkips"; + new = "delim_noskips"; + } + { + old = [ + "motion" + "enable" + ]; + new = "motion_enabled"; + } + { + old = [ + "motion" + "cursorEnd" + ]; + new = "motion_cursor_end"; + } + { + old = [ + "motion" + "overrideNPercent" + ]; + new = "motion_override_Npercent"; + } + { + old = [ + "textObj" + "enable" + ]; + new = "text_obj_enabled"; + } + { + old = [ + "textObj" + "linewiseOperators" + ]; + new = "text_obj_linewise_operators"; + } + { + old = [ + "matchParen" + "enable" + ]; + new = "matchparen_enabled"; + } + { + old = [ + "matchParen" + "fallback" + ]; + new = "matchparen_fallback"; + } + { + old = [ + "matchParen" + "singleton" + ]; + new = "matchparen_singleton"; + } + { + old = [ + "matchParen" + "offscreen" + ]; + new = "matchparen_offscreen"; + } + { + old = [ + "matchParen" + "stopline" + ]; + new = "matchparen_stopline"; + } + { + old = [ + "matchParen" + "timeout" + ]; + new = "matchparen_timeout"; + } + { + old = [ + "matchParen" + "insertTimeout" + ]; + new = "matchparen_insert_timeout"; + } + { + old = [ + "matchParen" + "deferred" + "enable" + ]; + new = "matchparen_deferred"; + } + { + old = [ + "matchParen" + "deferred" + "showDelay" + ]; + new = "matchparen_deferred_show_delay"; + } + { + old = [ + "matchParen" + "deferred" + "hideDelay" + ]; + new = "matchparen_deferred_hide_delay"; + } + { + old = [ + "matchParen" + "hiSurroundAlways" + ]; + new = "matchparen_deferred_hi_surround_always"; + } +] diff --git a/tests/test-sources/plugins/by-name/vim-matchup/default.nix b/tests/test-sources/plugins/by-name/vim-matchup/default.nix index 0e02295e..dc030a73 100644 --- a/tests/test-sources/plugins/by-name/vim-matchup/default.nix +++ b/tests/test-sources/plugins/by-name/vim-matchup/default.nix @@ -2,4 +2,71 @@ empty = { plugins.vim-matchup.enable = true; }; + + defaults = { + plugins.vim-matchup = { + enable = true; + + settings = { + enabled = 1; + mappings_enabled = 1; + mouse_enabled = 1; + motion_enabled = 1; + text_obj_enabled = 1; + transmute_enabled = 0; + delim_stopline = 1500; + delim_noskips = 0; + delim_nomids = 0; + delim_start_plaintext = 1; + matchparen_enabled = 1; + matchparen_singleton = 0; + matchparen_offscreen.method = "status"; + matchparen_stopline = 400; + matchparen_timeout = 300; + matchparen_insert_timeout = 60; + matchparen_deferred = 0; + matchparen_deferred_show_delay = 50; + matchparen_deferred_hide_delay = 700; + matchparen_deferred_fade_time = 0; + matchparen_pumvisible = 1; + matchparen_nomode = ""; + matchparen_hi_surround_always = 0; + matchparen_hi_background = 0; + matchparen_end_sign = "◀"; + motion_override_Npercent = 6; + motion_cursor_end = 1; + delim_count_fail = 0; + text_obj_linewise_operators = [ + "d" + "y" + ]; + surround_enabled = 0; + override_vimtex = 0; + }; + }; + }; + + example = { + plugins = { + treesitter.enable = true; + vim-matchup = { + enable = true; + + treesitter = { + enable = true; + disable = [ + "c" + "ruby" + ]; + }; + + settings = { + mouse_enabled = 0; + surround_enabled = 1; + transmute_enabled = 1; + matchparen_offscreen.method = "popup"; + }; + }; + }; + }; }