mirror of
https://github.com/neovim/neovim.git
synced 2024-12-19 02:34:59 -07:00
feat(comment): allow commentstring to be determined from node metadata
**Problem:** Some weird languages have different comment syntax depending on the location in the code, and we do not have a way to determine the correct `commentstring` for these special cases. **Solution:** Allow queries to specify `commentstring` values in metadata, allowing users/`nvim-treesitter` to provide a better commenting experience without hugely increasing the scope of the code in core.
This commit is contained in:
parent
442d338cb5
commit
416d75fb82
@ -264,6 +264,10 @@ PLUGINS
|
||||
|
||||
• EditorConfig
|
||||
• spelling_language property is now supported.
|
||||
• Commenting
|
||||
• 'commentstring' values can now be specified in a Treesitter capture's
|
||||
`bo.commentstring` metadata field, providing finer grained support for
|
||||
languages like `JSX`.
|
||||
|
||||
STARTUP
|
||||
|
||||
|
@ -519,6 +519,19 @@ attribute: >query
|
||||
((super_important_node) @superimportant (#set! priority 105))
|
||||
<
|
||||
|
||||
*treesitter-highlight-commentstring*
|
||||
Treesitter highlighting supports finer-grained 'commentstring's, used by the
|
||||
built-in |commenting| plugin. When the cursor is within a node that sets the
|
||||
`bo.commentstring` metadata property (|treesitter-directive-set!|), that
|
||||
property defines the comment delimiter (where "innermost wins"). This is
|
||||
useful for languages like `JSX` that have different comment syntax depending
|
||||
on the code region, for example: >query
|
||||
|
||||
((jsx_element) @_tag (#set! @_tag bo.commentstring "{/* %s */}"))
|
||||
<
|
||||
When multiple captures set this metadata over a region, only the innermost
|
||||
(most specific) one is applied to a given area.
|
||||
|
||||
==============================================================================
|
||||
TREESITTER LANGUAGE INJECTIONS *treesitter-language-injections*
|
||||
<
|
||||
|
@ -19,6 +19,18 @@ local function get_commentstring(ref_position)
|
||||
local row, col = ref_position[1] - 1, ref_position[2]
|
||||
local ref_range = { row, col, row, col + 1 }
|
||||
|
||||
-- Get 'commentstring' from tree-sitter captures' metadata.
|
||||
-- Traverse backwards to prefer narrower captures.
|
||||
local caps = vim.treesitter.get_captures_at_pos(0, row, col)
|
||||
for i = #caps, 1, -1 do
|
||||
local id, metadata = caps[i].id, caps[i].metadata
|
||||
local md_cms = metadata['bo.commentstring'] or metadata[id] and metadata[id]['bo.commentstring']
|
||||
|
||||
if md_cms then
|
||||
return md_cms
|
||||
end
|
||||
end
|
||||
|
||||
-- - Get 'commentstring' from the deepest LanguageTree which both contains
|
||||
-- reference range and has valid 'commentstring' (meaning it has at least
|
||||
-- one associated 'filetype' with valid 'commentstring').
|
||||
|
@ -486,6 +486,7 @@ predicate_handlers['any-vim-match?'] = predicate_handlers['any-match?']
|
||||
---@class vim.treesitter.query.TSMetadata
|
||||
---@field range? Range
|
||||
---@field conceal? string
|
||||
---@field bo.commentstring? string
|
||||
---@field [integer]? vim.treesitter.query.TSMetadata
|
||||
---@field [string]? integer|string
|
||||
|
||||
|
@ -586,6 +586,140 @@ describe('commenting', function()
|
||||
feed('.')
|
||||
eq(get_lines(), { '"set background=dark', 'lua << EOF', '-- print(1)', 'EOF' })
|
||||
end)
|
||||
|
||||
it('respects tree-sitter commentstring metadata', function()
|
||||
exec_lua [=[
|
||||
vim.treesitter.query.set('vim', 'highlights', [[
|
||||
((list) @_list (#set! @_list bo.commentstring "!! %s"))
|
||||
]])
|
||||
]=]
|
||||
setup_treesitter()
|
||||
|
||||
local lines = {
|
||||
'set background=dark',
|
||||
'let mylist = [',
|
||||
[[ \"a",]],
|
||||
[[ \"b",]],
|
||||
[[ \"c",]],
|
||||
' \\]',
|
||||
}
|
||||
set_lines(lines)
|
||||
|
||||
set_cursor(1, 0)
|
||||
feed('gcc')
|
||||
eq(
|
||||
{ '"set background=dark', 'let mylist = [', [[ \"a",]], [[ \"b",]], [[ \"c",]], ' \\]' },
|
||||
get_lines()
|
||||
)
|
||||
|
||||
-- Should work with dot-repeat
|
||||
set_cursor(4, 0)
|
||||
feed('.')
|
||||
eq({
|
||||
'"set background=dark',
|
||||
'let mylist = [',
|
||||
[[ \"a",]],
|
||||
[[ !! \"b",]],
|
||||
[[ \"c",]],
|
||||
' \\]',
|
||||
}, get_lines())
|
||||
end)
|
||||
|
||||
it('only applies the innermost tree-sitter commentstring metadata', function()
|
||||
exec_lua [=[
|
||||
vim.treesitter.query.set('vim', 'highlights', [[
|
||||
((list) @_list (#gsub! @_list "(.*)" "%1") (#set! bo.commentstring "!! %s"))
|
||||
((script_file) @_src (#set! @_src bo.commentstring "## %s"))
|
||||
]])
|
||||
]=]
|
||||
setup_treesitter()
|
||||
|
||||
local lines = {
|
||||
'set background=dark',
|
||||
'let mylist = [',
|
||||
[[ \"a",]],
|
||||
[[ \"b",]],
|
||||
[[ \"c",]],
|
||||
' \\]',
|
||||
}
|
||||
set_lines(lines)
|
||||
|
||||
set_cursor(1, 0)
|
||||
feed('gcc')
|
||||
eq({
|
||||
'## set background=dark',
|
||||
'let mylist = [',
|
||||
[[ \"a",]],
|
||||
[[ \"b",]],
|
||||
[[ \"c",]],
|
||||
' \\]',
|
||||
}, get_lines())
|
||||
|
||||
-- Should work with dot-repeat
|
||||
set_cursor(4, 0)
|
||||
feed('.')
|
||||
eq({
|
||||
'## set background=dark',
|
||||
'let mylist = [',
|
||||
[[ \"a",]],
|
||||
[[ !! \"b",]],
|
||||
[[ \"c",]],
|
||||
' \\]',
|
||||
}, get_lines())
|
||||
end)
|
||||
|
||||
it('respects injected tree-sitter commentstring metadata', function()
|
||||
exec_lua [=[
|
||||
vim.treesitter.query.set('lua', 'highlights', [[
|
||||
((string) @string (#set! @string bo.commentstring "; %s"))
|
||||
]])
|
||||
]=]
|
||||
setup_treesitter()
|
||||
|
||||
local lines = {
|
||||
'set background=dark',
|
||||
'lua << EOF',
|
||||
'print[[',
|
||||
'Inside string',
|
||||
']]',
|
||||
'EOF',
|
||||
}
|
||||
set_lines(lines)
|
||||
|
||||
set_cursor(1, 0)
|
||||
feed('gcc')
|
||||
eq({
|
||||
'"set background=dark',
|
||||
'lua << EOF',
|
||||
'print[[',
|
||||
'Inside string',
|
||||
']]',
|
||||
'EOF',
|
||||
}, get_lines())
|
||||
|
||||
-- Should work with dot-repeat
|
||||
set_cursor(4, 0)
|
||||
feed('.')
|
||||
eq({
|
||||
'"set background=dark',
|
||||
'lua << EOF',
|
||||
'print[[',
|
||||
'; Inside string',
|
||||
']]',
|
||||
'EOF',
|
||||
}, get_lines())
|
||||
|
||||
set_cursor(3, 0)
|
||||
feed('.')
|
||||
eq({
|
||||
'"set background=dark',
|
||||
'lua << EOF',
|
||||
'-- print[[',
|
||||
'; Inside string',
|
||||
']]',
|
||||
'EOF',
|
||||
}, get_lines())
|
||||
end)
|
||||
end)
|
||||
|
||||
describe('Textobject', function()
|
||||
|
Loading…
Reference in New Issue
Block a user