aboutsummaryrefslogtreecommitdiffstats
path: root/lua
diff options
context:
space:
mode:
authorGeorge Harker <george@george-graphics.co.uk>2023-03-19 18:09:18 -0700
committerAmaan Qureshi <amaanq12@gmail.com>2023-03-24 13:07:53 -0400
commitd1333dd7e51729a581fed3e429fa035bff77a3db (patch)
tree961499041e8e3da94963e7331e09754d423b40a1 /lua
parentfix: shim 0.9 deprecations (diff)
downloadnvim-treesitter-d1333dd7e51729a581fed3e429fa035bff77a3db.tar
nvim-treesitter-d1333dd7e51729a581fed3e429fa035bff77a3db.tar.gz
nvim-treesitter-d1333dd7e51729a581fed3e429fa035bff77a3db.tar.bz2
nvim-treesitter-d1333dd7e51729a581fed3e429fa035bff77a3db.tar.lz
nvim-treesitter-d1333dd7e51729a581fed3e429fa035bff77a3db.tar.xz
nvim-treesitter-d1333dd7e51729a581fed3e429fa035bff77a3db.tar.zst
nvim-treesitter-d1333dd7e51729a581fed3e429fa035bff77a3db.zip
refactor(indent)!: Rework indent, aligned indent
indents now use @indent.X style captures, and indent.PROP for properties to set on those captures, as documented in the help. Captures are: indent.auto indent.begin indent.end indent.dedent indent.branch indent.ignore indent.align indent.zero Properties are: indent.immediate indent.start_at_same_line indent.open_delimiter indent.close_delimiter indent.increment indent.avoid_last_matching_next Multiple opening delims on one line and multiple closing on a line are collapsed so as not to over indent, The final line of @indent.align blocks which must in some cases be treated specially to avoid clashing with the next line is treated the same regardless of whether the @indent.align capture actually uses aligned indentation or just normal indentation. The indent.avoid_last_matching_next property controls this. Adjust python to use these. List, set, dict and tuple all use @indent.align which permits both hanging and aligned styles. Finally, try: on it’s own will indent when typing live but make no guaranteeds about whole-file formatting. Includes lucario387:fix-align-indent
Diffstat (limited to 'lua')
-rw-r--r--lua/nvim-treesitter/indent.lua101
1 files changed, 73 insertions, 28 deletions
diff --git a/lua/nvim-treesitter/indent.lua b/lua/nvim-treesitter/indent.lua
index cf819d05b..8035a73d8 100644
--- a/lua/nvim-treesitter/indent.lua
+++ b/lua/nvim-treesitter/indent.lua
@@ -42,7 +42,10 @@ local function find_delimiter(bufnr, node, delimiter)
local linenr = child:start()
local line = vim.api.nvim_buf_get_lines(bufnr, linenr, linenr + 1, false)[1]
local end_char = { child:end_() }
- return child, #line == end_char[2]
+ local trimmed_after_delim
+ local escaped_delimiter = delimiter:gsub("[%-%.%+%[%]%(%)%$%^%%%?%*]", "%%%1")
+ trimmed_after_delim, _ = line:sub(end_char[2] + 1):gsub("[%s" .. escaped_delimiter .. "]*", "")
+ return child, #trimmed_after_delim == 0
end
end
end
@@ -185,51 +188,93 @@ function M.get_indent(lnum)
is_processed = true
end
+ if is_in_err and not q.aligned_indent[node:id()] then
+ -- only when the node is in error, promote the
+ -- first child's aligned indent to the error node
+ -- to work around ((ERROR "X" . (_)) @aligned_indent (#set! "delimeter" "AB"))
+ -- matching for all X, instead set do
+ -- (ERROR "X" @aligned_indent (#set! "delimeter" "AB") . (_))
+ -- and we will fish it out here.
+ for c in node:iter_children() do
+ if q.aligned_indent[c:id()] then
+ q.aligned_indent[node:id()] = q.aligned_indent[c:id()]
+ break
+ end
+ end
+ end
-- do not indent for nodes that starts-and-ends on same line and starts on target line (lnum)
- if q.aligned_indent[node:id()] and srow ~= erow and (srow ~= lnum - 1) then
+ if should_process and q.aligned_indent[node:id()] and (srow ~= erow or is_in_err) and (srow ~= lnum - 1) then
local metadata = q.aligned_indent[node:id()]
- local o_delim_node, is_last_in_line ---@type TSNode|nil, boolean|nil
- local c_delim_node ---@type TSNode|nil
+ local o_delim_node, o_is_last_in_line ---@type TSNode|nil, boolean|nil
+ local c_delim_node, c_is_last_in_line ---@type TSNode|nil, boolean|nil, boolean|nil
+ local indent_is_absolute = false
if metadata.delimiter then
---@type string
local opening_delimiter = metadata.delimiter and metadata.delimiter:sub(1, 1)
- o_delim_node, is_last_in_line = find_delimiter(bufnr, node, opening_delimiter)
+ o_delim_node, o_is_last_in_line = find_delimiter(bufnr, node, opening_delimiter)
+ ---@type string
local closing_delimiter = metadata.delimiter and metadata.delimiter:sub(2, 2)
- c_delim_node, _ = find_delimiter(bufnr, node, closing_delimiter)
+ c_delim_node, c_is_last_in_line = find_delimiter(bufnr, node, closing_delimiter)
else
o_delim_node = node
c_delim_node = node
end
if o_delim_node then
- if is_last_in_line then
+ local o_srow, o_scol = o_delim_node:start()
+ local c_srow = nil
+ if c_delim_node then
+ c_srow, _ = c_delim_node:start()
+ end
+ if o_is_last_in_line then
-- hanging indent (previous line ended with starting delimiter)
- indent = indent + indent_size * 1
- else
- local o_srow, o_scol = o_delim_node:start()
- local final_line_indent = false
- if c_delim_node then
- local c_srow, _ = c_delim_node:start()
- if c_srow ~= o_srow and c_srow == lnum - 1 then
- -- delims end on current line, and are not open and closed same line.
- -- final_line_indent controls this behavior, for example this is not desirable
- -- for a tuple.
- final_line_indent = metadata.final_line_indent or false
+ -- should be processed like indent
+ if should_process then
+ indent = indent + indent_size * 1
+ if c_is_last_in_line then
+ -- If current line is outside the range of a node marked with `@aligned_indent`
+ -- Then its indent level shouldn't be affected by `@aligned_indent` node
+ if c_srow and c_srow < lnum - 1 then
+ indent = math.max(indent - indent_size, 0)
+ end
end
end
- if final_line_indent then
- -- last line must be indented more in cases where
- -- it would be same indent as next line
- local aligned_indent = o_scol + (metadata.increment or 1)
- if aligned_indent <= indent then
- return indent + indent_size * 1
- else
- return aligned_indent
- end
+ else
+ -- aligned indent
+ if c_is_last_in_line and c_srow and o_srow ~= c_srow and c_srow < lnum - 1 then
+ -- If current line is outside the range of a node marked with `@aligned_indent`
+ -- Then its indent level shouldn't be affected by `@aligned_indent` node
+ indent = math.max(indent - indent_size, 0)
+ else
+ indent = o_scol + (metadata.increment or 1)
+ indent_is_absolute = true
+ end
+ end
+ -- deal with the final line
+ local avoid_last_matching_next = false
+ if c_srow and c_srow ~= o_srow and c_srow == lnum - 1 then
+ -- delims end on current line, and are not open and closed same line.
+ -- then this last line may need additional indent to avoid clashes
+ -- with the next. `avoid_last_matching_next` controls this behavior,
+ -- for example this is needed for function parameters.
+ avoid_last_matching_next = metadata.avoid_last_matching_next or false
+ end
+ if avoid_last_matching_next then
+ -- last line must be indented more in cases where
+ -- it would be same indent as next line (we determine this as one
+ -- width more than the open indent to avoid confusing with any
+ -- hanging indents)
+ if indent <= vim.fn.indent(o_srow + 1) + indent_size then
+ indent = indent + indent_size * 1
else
- return o_scol + (metadata.increment or 1)
+ indent = indent
end
end
+ is_processed = true
+ if indent_is_absolute then
+ -- don't allow further indenting by parent nodes, this is an absolute position
+ return indent
+ end
end
end