-
Notifications
You must be signed in to change notification settings - Fork 0
Description
The code snippets will require replacing the mini.surround plugin:
Lines 876 to 891 in 829ea31
| require("mini.surround").setup({ | |
| mappings = { | |
| add = "ys", | |
| delete = "ds", | |
| find = "", | |
| find_left = "", | |
| highlight = "", | |
| replace = "cs", | |
| update_n_lines = "", | |
| -- Add this only if you don't want to use extended mappings | |
| suffix_last = "", | |
| suffix_next = "", | |
| }, | |
| search_method = "cover_or_next", | |
| }) |
The idea is kind of complicated, so there will be more code snippets, but I'll try to provide explanations for how I did it.
nvim-surround has support for treesitter, which we will make heavy use of. First component would be getting familiar with nvim-surround's configuration :h nvim-surround.config.surrounds, there we can see how we can add/modify new surrounding types, this is main thing required to understand what is happening, I heavily encourage the reader to pause now and read that section now.
Another thing to read would be the source code of nvim-surround and how the function call surround is done, important part being is that we can call on treesitter to get a selection of text. Now it would be useful to learn at least basic stuff about the treesitter. Armed with this knowledge we can begin.
so the plan is now:
- write a query that will select the type
- create the surround functions that will work on those selections
from the neovim's docs:
Nvim looks for queries as *.scm files in a queries directory under
runtimepath, where each file contains queries for a specific language and
purpose, e.g., queries/lua/highlights.scm for highlighting Lua files.
By default, the first query on runtimepath is used (which usually implies
that user config takes precedence over plugins, which take precedence over
queries bundled with Nvim). If a query should extend other queries instead
of replacing them, use treesitter-query-modeline-extends.
this means if we want to create a textobject 'type' for the rust language, we need to create queries/rust/textobjects.scm and this is what we put inside it:
;; extends
(generic_type
type: (_)) @type.outer
(generic_type
type_arguments: (type_arguments
(_) @_start
(_)? @_end
(#make-range! "type.inner" @_start @_end)))
in lisp languages comments are made with ; but I've found that people usually use ;;, both work
extends means that we want to extend the default rust textobjects, if we ever install a plugin that adds rust specific textobjects this will prevent that plugin from straight up breaking
this query searches for nodes generic_type that have any type, and then we mark the generic_type nodes as @type.outer, while to get the @type.inner we have a bit more complex query, which basically gets every arguments separately and joins them together as a single capture, this allows us to precisely select only the arguments without the '<' and '>' (edit: query changed, which now allows the used of MiniSurround instead!)
I would also recommend setting this up for cpp and other languages having similar constructs
now we can move to the main code, the code should be readable by itself, but some additional notes are needed:
- the lua patterns are just copied from the source code for function calls, but replace the escaped parenthesis with angle brackets
- those mappings won't fall through if something is not defined, so if you want to change or delete you gotta add those too
basically that's it :3
edit:
this was the original query (this is worse):
(generic_type
type_arguments: (_) @type.inner) @type.outer