Skip to content

Commit

Permalink
plugins/treesitter-textobjects: init
Browse files Browse the repository at this point in the history
  • Loading branch information
GaetanLepage committed Nov 23, 2023
1 parent 0b1984e commit 563a42c
Show file tree
Hide file tree
Showing 3 changed files with 352 additions and 0 deletions.
1 change: 1 addition & 0 deletions plugins/default.nix
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@
./languages/treesitter/treesitter-context.nix
./languages/treesitter/treesitter-playground.nix
./languages/treesitter/treesitter-refactor.nix
./languages/treesitter/treesitter-textobjects.nix
./languages/treesitter/ts-autotag.nix
./languages/treesitter/ts-context-commentstring.nix
./languages/typst/typst-vim.nix
Expand Down
267 changes: 267 additions & 0 deletions plugins/languages/treesitter/treesitter-textobjects.nix
Original file line number Diff line number Diff line change
@@ -0,0 +1,267 @@
{
lib,
helpers,
config,
pkgs,
...
}:
with lib; {
options.plugins.treesitter-textobjects = let
disable = helpers.defaultNullOpts.mkNullable (with types; listOf str) "[]" ''
List of languages to disable this module for.
'';

mkKeymapsOption = desc:
helpers.defaultNullOpts.mkNullable
(
with types;
attrsOf (
either
str
(submodule {
options = {
query = mkOption {
type = str;
description = "";
example = "@class.inner";
};

queryGroup = helpers.mkNullOrOption str ''
You can also use captures from other query groups like `locals.scm`
'';

desc = helpers.mkNullOrOption str ''
You can optionally set descriptions to the mappings (used in the `desc`
parameter of `nvim_buf_set_keymap`) which plugins like _which-key_ display.
'';
};
})
)
)
"{}"
desc;
in
helpers.extraOptionsOptions
// {
enable =
mkEnableOption
"treesitter-textobjects (requires plugins.treesitter.enable to be true)";

package = helpers.mkPackageOption "treesitter-textobjects" pkgs.vimPlugins.nvim-treesitter-textobjects;

select = {
enable = helpers.defaultNullOpts.mkBool false ''
Text object selection:
Define your own text objects mappings similar to `ip` (inner paragraph) and `ap`
(a paragraph).
'';

inherit disable;

lookahead = helpers.defaultNullOpts.mkBool false ''
Whether or not to look ahead for the textobject.
'';

keymaps = mkKeymapsOption ''
Map of keymaps to a tree-sitter query (`(function_definition) @function`) or capture
group (`@function.inner`).
'';

selectionModes =
helpers.defaultNullOpts.mkNullable
(
with types;
attrsOf
(
enum
["v" "V" "<c-v>"]
)
)
"{}"
''
Map of capture group to `v`(charwise), `V`(linewise), or `<c-v>`(blockwise), choose a
selection mode per capture, default is `v`(charwise).
'';

includeSurroundingWhitespace =
helpers.defaultNullOpts.mkNullable
(with types; either bool str)
"`false`"
''
`true` or `false`, when `true` textobjects are extended to include preceding or
succeeding whitespace.
Can also be a function which gets passed a table with the keys `query_string`
(`@function.inner`) and `selection_mode` (`v`) and returns `true` of `false`.
If you set this to `true` (default is `false`) then any textobject is extended to
include preceding or succeeding whitespace.
Succeeding whitespace has priority in order to act similarly to eg the built-in `ap`.
'';
};

swap = {
enable = helpers.defaultNullOpts.mkBool false ''
Swap text objects:
Define your own mappings to swap the node under the cursor with the next or previous one,
like function parameters or arguments.
'';

inherit disable;

swapNext = mkKeymapsOption ''
Map of keymaps to a list of tree-sitter capture groups (`{@parameter.inner}`).
Capture groups that come earlier in the list are preferred.
'';

swapPrevious = mkKeymapsOption ''
Same as `swapNext`, but it will swap with the previous text object.
'';
};

move = {
enable = helpers.defaultNullOpts.mkBool false ''
Go to next/previous text object~
Define your own mappings to jump to the next or previous text object.
This is similar to `|]m|`, `|[m|`, `|]M|`, `|[M|` Neovim's mappings to jump to the next or
previous function.
'';

inherit disable;

setJumps = helpers.defaultNullOpts.mkBool true "Whether to set jumps in the jumplist.";

gotoNextStart = mkKeymapsOption ''
Map of keymaps to a list of tree-sitter capture groups (`{@function.outer,
@class.outer}`).
The one that starts closest to the cursor will be chosen, preferring row-proximity to
column-proximity.
'';

gotoNextEnd = mkKeymapsOption ''
Same as `gotoNextStart`, but it jumps to the start of the text object.
'';

gotoPreviousStart = mkKeymapsOption ''
Same as `gotoNextStart`, but it jumps to the previous text object.
'';

gotoPreviousEnd = mkKeymapsOption ''
Same as `gotoNextEnd`, but it jumps to the previous text object.
'';

gotoNext = mkKeymapsOption ''
Will go to either the start or the end, whichever is closer.
Use if you want more granular movements.
Make it even more gradual by adding multiple queries and regex.
'';

gotoPrevious = mkKeymapsOption ''
Will go to either the start or the end, whichever is closer.
Use if you want more granular movements.
Make it even more gradual by adding multiple queries and regex.
'';
};

lspInterop = {
enable = helpers.defaultNullOpts.mkBool false "LSP interop.";

border =
helpers.defaultNullOpts.mkEnumFirstDefault
["none" "single" "double" "rounded" "solid" "shadow"]
"Define the style of the floating window border.";

peekDefinitionCode = mkKeymapsOption ''
Show textobject surrounding definition as determined using Neovim's built-in LSP in a
floating window.
Press the shortcut twice to enter the floating window
(when https://github.com/neovim/neovim/pull/12720 or its successor is merged).
'';

floatingPreviewOpts =
helpers.defaultNullOpts.mkNullable
(with types; attrsOf anything)
"{}"
''
Options to pass to `vim.lsp.util.open_floating_preview`.
For example, `maximum_height`.
'';
};
};

config = let
cfg = config.plugins.treesitter-textobjects;
in
mkIf cfg.enable {
warnings = mkIf (!config.plugins.treesitter.enable) [
"Nixvim: treesitter-textobjects needs treesitter to function as intended"
];

extraPlugins = [cfg.package];

plugins.treesitter.moduleConfig.textobjects = with cfg; let
processKeymapsOpt = keymapsOptionValue:
helpers.ifNonNull' keymapsOptionValue
(
mapAttrs
(key: mapping:
if isString mapping
then mapping
else {
inherit (mapping) query;
query_group = mapping.queryGroup;
inherit (mapping) desc;
})
keymapsOptionValue
);
in
{
select = with select; {
inherit
enable
disable
lookahead
;
keymaps = processKeymapsOpt keymaps;
selection_modes = selectionModes;
include_surrounding_whitespace =
if isString includeSurroundingWhitespace
then helpers.mkRaw includeSurroundingWhitespace
else includeSurroundingWhitespace;
};
swap = with swap; {
inherit
enable
disable
;
swap_next = processKeymapsOpt swapNext;
swap_previous = processKeymapsOpt swapPrevious;
};
move = with move; {
inherit
enable
disable
;
set_jumps = setJumps;
goto_next_start = processKeymapsOpt gotoNextStart;
goto_next_end = processKeymapsOpt gotoNextEnd;
goto_previous_start = processKeymapsOpt gotoPreviousStart;
goto_previous_end = processKeymapsOpt gotoPreviousEnd;
goto_next = processKeymapsOpt gotoNext;
goto_previous = processKeymapsOpt gotoPrevious;
};
lsp_interop = with lspInterop; {
inherit
enable
border
;
peek_definition_code = processKeymapsOpt peekDefinitionCode;
floating_preview_opts = floatingPreviewOpts;
};
}
// cfg.extraOptions;
};
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
{
empty = {
plugins = {
treesitter.enable = true;
treesitter-textobjects.enable = true;
};
};

example = {
plugins = {
treesitter.enable = true;
treesitter-textobjects = {
enable = true;

select = {
enable = true;
disable = [];
lookahead = true;
keymaps = {
af = "@function.outer";
"if" = "@function.inner";
ac = "@class.outer";
ic = {
query = "@class.inner";
desc = "Select inner part of a class region";
};
};
selectionModes = {
"@parameter.outer" = "v";
"@function.outer" = "V";
"@class.outer" = "<c-v>";
};
includeSurroundingWhitespace = true;
};
swap = {
enable = true;
disable = [];
swapNext = {
"<leader>a" = "@parameter.inner";
};
swapPrevious = {
"<leader>A" = "@parameter.inner";
};
};
move = {
enable = true;
disable = [];
setJumps = true;
gotoNextStart = {
"]m" = "@function.outer";
"]]" = "@class.outer";
};
gotoNextEnd = {
"]M" = "@function.outer";
"][" = "@class.outer";
};
gotoPreviousStart = {
"[m" = "@function.outer";
"[[" = "@class.outer";
};
gotoPreviousEnd = {
"[M" = "@function.outer";
"[]" = "@class.outer";
};
gotoNext = {
"]d" = "@conditional.outer";
};
gotoPrevious = {
"[d" = "@conditional.outer";
};
};
lspInterop = {
enable = true;
border = "none";
peekDefinitionCode = {
"<leader>df" = "@function.outer";
"<leader>dF" = "@class.outer";
};
floatingPreviewOpts = {};
};
};
};
};
}

0 comments on commit 563a42c

Please sign in to comment.