The code snippets will require replacing the mini.surround plugin:
|
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", |
|
}) |
with
nvim-surround might not be actually needed here, since it might be doable with mini.surround, but that is an exercise for the reader
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
The code snippets will require replacing the mini.surround plugin:
dotconf/nvim/init.lua
Lines 876 to 891 in 829ea31
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:
from the neovim's docs:
this means if we want to create a textobject 'type' for the rust language, we need to create
queries/rust/textobjects.scmand this is what we put inside it:in lisp languages comments are made with
;but I've found that people usually use;;, both workextends 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_typethat have anytype, and then we mark the generic_type nodes as@type.outer, while to get the@type.innerwe 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:
basically that's it :3
edit:
this was the original query (this is worse):