---@class lazyvim.util.mini local M = {} ---@alias Mini.ai.loc {line:number, col:number} ---@alias Mini.ai.region {from:Mini.ai.loc, to:Mini.ai.loc} -- Mini.ai indent text object -- For "a", it will include the non-whitespace line surrounding the indent block. -- "a" is line-wise, "i" is character-wise. function M.ai_indent(ai_type) local spaces = (" "):rep(vim.o.tabstop) local lines = vim.api.nvim_buf_get_lines(0, 0, -1, false) local indents = {} ---@type {line: number, indent: number, text: string}[] for l, line in ipairs(lines) do if not line:find("^%s*$") then indents[#indents + 1] = { line = l, indent = #line:gsub("\t", spaces):match("^%s*"), text = line } end end local ret = {} ---@type (Mini.ai.region | {indent: number})[] for i = 1, #indents do if i == 1 or indents[i - 1].indent < indents[i].indent then local from, to = i, i for j = i + 1, #indents do if indents[j].indent < indents[i].indent then break end to = j end from = ai_type == "a" and from > 1 and from - 1 or from to = ai_type == "a" and to < #indents and to + 1 or to ret[#ret + 1] = { indent = indents[i].indent, from = { line = indents[from].line, col = ai_type == "a" and 1 or indents[from].indent + 1 }, to = { line = indents[to].line, col = #indents[to].text }, } end end return ret end -- taken from MiniExtra.gen_ai_spec.buffer function M.ai_buffer(ai_type) local start_line, end_line = 1, vim.fn.line("$") if ai_type == "i" then -- Skip first and last blank lines for `i` textobject local first_nonblank, last_nonblank = vim.fn.nextnonblank(start_line), vim.fn.prevnonblank(end_line) -- Do nothing for buffer with all blanks if first_nonblank == 0 or last_nonblank == 0 then return { from = { line = start_line, col = 1 } } end start_line, end_line = first_nonblank, last_nonblank end local to_col = math.max(vim.fn.getline(end_line):len(), 1) return { from = { line = start_line, col = 1 }, to = { line = end_line, col = to_col } } end -- register all text objects with which-key function M.ai_whichkey() ---@type table local i = { [" "] = "Whitespace", ['"'] = 'Balanced "', ["'"] = "Balanced '", ["`"] = "Balanced `", ["("] = "Balanced (", [")"] = "Balanced ) including white-space", [">"] = "Balanced > including white-space", [""] = "Balanced <", ["]"] = "Balanced ] including white-space", ["["] = "Balanced [", ["}"] = "Balanced } including white-space", ["{"] = "Balanced {", ["?"] = "User Prompt", _ = "Underscore", a = "Argument", b = "Balanced ), ], }", c = "Class", d = "Digit(s)", e = "Word in CamelCase & snake_case", f = "Function", g = "Entire file", i = "Indent", o = "Block, conditional, loop", q = "Quote `, \", '", t = "Tag", u = "Use/call function & method", U = "Use/call without dot in name", } local a = vim.deepcopy(i) for k, v in pairs(a) do a[k] = v:gsub(" including.*", "") end local ic = vim.deepcopy(i) local ac = vim.deepcopy(a) for key, name in pairs({ n = "Next", l = "Last" }) do i[key] = vim.tbl_extend("force", { name = "Inside " .. name .. " textobject" }, ic) a[key] = vim.tbl_extend("force", { name = "Around " .. name .. " textobject" }, ac) end require("which-key").register({ mode = { "o", "x" }, i = i, a = a, }) end return M