Replies: 2 comments 13 replies
-
Yes, implementing custom textobject for 'mini.ai' is pretty reasonable. For the "next"/"last" case you describe I'd suggest going the route of textobject function that returns array of regions (similar to this example) where each region is a valid indent scope that is (in theory) allowed to be selected. The 'mini.ai' will then take care of the rest ( For a more complicated behavior textobject function can return a single region which will be used/selected. This puts more burden on the implementation, but in return is more flexible. You can also take a look at how LazyVim used to do something similar (prior to its move to 'snacks.scope', of course). All in all, I don't think it will be added in 'mini.nvim' (either 'mini.ai' or 'mini.extra'). Not the last reason for this is that there are many different approaches this new textobject may take (including once described here) without obviously better one. That said, if you do come up with something, please share your solution here. It might be a good candidate to be added later in the wiki. |
Beta Was this translation helpful? Give feedback.
-
Here's my initial attempt that works as if
With
Ended up quite dirty due to all the edge cases 😄 And probably what I'm doing here is rewriting a certain part of local function get_line_indent(line)
local prev_nonblank = vim.fn.prevnonblank(line)
local res = vim.fn.indent(prev_nonblank)
-- Compute indent of blank line
if line ~= prev_nonblank then
local next_indent = vim.fn.indent(vim.fn.nextnonblank(line))
res = math.max(res, next_indent)
end
return res
end
local function ai_indent(ai_type)
local res = {}
local target_indent = math.max(
get_line_indent(vim.fn.line(".")),
1 -- If cursor is at an unindented part, target all top-level indents
)
local from_line, to_line
local scoping = false
local eob = vim.fn.line("$")
for i = 1, eob, 1 do
-- Find region end
if scoping then
local line = vim.fn.getline(i)
if not line:match("^%s*$") and vim.fn.indent(i) < target_indent then
to_line = i
if ai_type == "a" then
from_line = math.max(from_line - 1, 1)
else
to_line = to_line - 1
end
local region = {
from = { line = from_line, col = 1 },
to = { line = to_line, col = vim.fn.col({ to_line, "$" }) },
vis_mode = "V"
}
table.insert(res, region)
scoping = false
end
-- Find region start
else
if get_line_indent(i) >= target_indent then
from_line = i
scoping = true
end
end
-- Last buffer line edge case
if i == eob and scoping then
if ai_type == "a" then
from_line = math.max(from_line - 1, 1)
end
local region = {
from = { line = from_line, col = 1 },
to = { line = eob, col = vim.fn.col({ eob, "$" }) },
vis_mode = "V"
}
table.insert(res, region)
end
end
return res
end
-- To use:
require("mini.ai").setup({
custom_textobjects = {
["i"] = ai_indent
}
}) However, functionality feels quite complete, which is good! Feedback welcome, I'd like to iterate on this. |
Beta Was this translation helpful? Give feedback.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
-
They may be pretty ambiguous/opinionated to define for the indent textobject, but what I would find extremely useful would be:
forward-seeking:
vii
would jump to the next indented blockn
/l
:vini
Illustration forward-seeking
vii
:Questions:
Is it possible to implement a custom indent-textobject in the
mini.ai
module instead of themini.indentscope
module, or would it be better to either fork and start hacking onmini.indentscope
or try to implement it all from the ground up?Beta Was this translation helpful? Give feedback.
All reactions