mirror of
https://github.com/LazyVim/LazyVim.git
synced 2025-06-22 08:53:33 +02:00
feat(mini.ai): mini.ai
is back in core with some improved features. Removing it was a mistake.
This commit is contained in:
parent
4105c0ad3a
commit
d8644c4715
8 changed files with 158 additions and 108 deletions
4
NEWS.md
4
NEWS.md
|
@ -2,6 +2,9 @@
|
||||||
|
|
||||||
## 11.x
|
## 11.x
|
||||||
|
|
||||||
|
- `mini.ai` is back as a default plugin! Removing it was a mistake.
|
||||||
|
It's a great plugin that enhances the native text objects.
|
||||||
|
|
||||||
- `:LazyExtras` now has multiple new sections:
|
- `:LazyExtras` now has multiple new sections:
|
||||||
|
|
||||||
- **Enabled**: extras that are currently enabled
|
- **Enabled**: extras that are currently enabled
|
||||||
|
@ -42,7 +45,6 @@ Additionally, some core plugins have been moved to extras.
|
||||||
|
|
||||||
- plugins moved to extras:
|
- plugins moved to extras:
|
||||||
|
|
||||||
- `mini.ai` which I couldn't live without, but not everyone needs it
|
|
||||||
- `mini.surround`
|
- `mini.surround`
|
||||||
- `mini.indentscope` scopes are now also highlighted with `indent-blankline`
|
- `mini.indentscope` scopes are now also highlighted with `indent-blankline`
|
||||||
- `nvim-treesitter-context`
|
- `nvim-treesitter-context`
|
||||||
|
|
|
@ -132,7 +132,7 @@ local defaults = {
|
||||||
}
|
}
|
||||||
|
|
||||||
M.json = {
|
M.json = {
|
||||||
version = 3,
|
version = 4,
|
||||||
data = {
|
data = {
|
||||||
version = nil, ---@type string?
|
version = nil, ---@type string?
|
||||||
news = {}, ---@type table<string, string>
|
news = {}, ---@type table<string, string>
|
||||||
|
|
|
@ -182,4 +182,37 @@ return {
|
||||||
import = "lazyvim.plugins.extras.coding.mini-comment",
|
import = "lazyvim.plugins.extras.coding.mini-comment",
|
||||||
enabled = vim.fn.has("nvim-0.10") == 0,
|
enabled = vim.fn.has("nvim-0.10") == 0,
|
||||||
},
|
},
|
||||||
|
|
||||||
|
-- Better text-objects
|
||||||
|
{
|
||||||
|
"echasnovski/mini.ai",
|
||||||
|
event = "VeryLazy",
|
||||||
|
opts = function()
|
||||||
|
LazyVim.on_load("which-key.nvim", function()
|
||||||
|
vim.schedule(LazyVim.mini.ai_whichkey)
|
||||||
|
end)
|
||||||
|
local ai = require("mini.ai")
|
||||||
|
return {
|
||||||
|
n_lines = 500,
|
||||||
|
custom_textobjects = {
|
||||||
|
o = ai.gen_spec.treesitter({ -- code block
|
||||||
|
a = { "@block.outer", "@conditional.outer", "@loop.outer" },
|
||||||
|
i = { "@block.inner", "@conditional.inner", "@loop.inner" },
|
||||||
|
}),
|
||||||
|
f = ai.gen_spec.treesitter({ a = "@function.outer", i = "@function.inner" }), -- function
|
||||||
|
c = ai.gen_spec.treesitter({ a = "@class.outer", i = "@class.inner" }), -- class
|
||||||
|
t = { "<([%p%w]-)%f[^<%w][^<>]->.-</%1>", "^<.->().*()</[^/]->$" }, -- tags
|
||||||
|
d = { "%f[%d]%d+" }, -- digits
|
||||||
|
e = { -- Word with case
|
||||||
|
{ "%u[%l%d]+%f[^%l%d]", "%f[%S][%l%d]+%f[^%l%d]", "%f[%P][%l%d]+%f[^%l%d]", "^[%l%d]+%f[^%l%d]" },
|
||||||
|
"^().*()$",
|
||||||
|
},
|
||||||
|
i = LazyVim.mini.ai_indent, -- indent
|
||||||
|
g = LazyVim.mini.ai_buffer, -- buffer
|
||||||
|
u = ai.gen_spec.function_call(), -- u for "Usage"
|
||||||
|
U = ai.gen_spec.function_call({ name_pattern = "[%w_]" }), -- without dot in function name
|
||||||
|
},
|
||||||
|
}
|
||||||
|
end,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,97 +0,0 @@
|
||||||
-- Better text-objects
|
|
||||||
return {
|
|
||||||
"echasnovski/mini.ai",
|
|
||||||
desc = "Enhanced text objects",
|
|
||||||
recommended = true,
|
|
||||||
-- keys = {
|
|
||||||
-- { "a", mode = { "x", "o" } },
|
|
||||||
-- { "i", mode = { "x", "o" } },
|
|
||||||
-- },
|
|
||||||
event = "VeryLazy",
|
|
||||||
opts = function()
|
|
||||||
local ai = require("mini.ai")
|
|
||||||
return {
|
|
||||||
n_lines = 500,
|
|
||||||
custom_textobjects = {
|
|
||||||
o = ai.gen_spec.treesitter({
|
|
||||||
a = { "@block.outer", "@conditional.outer", "@loop.outer" },
|
|
||||||
i = { "@block.inner", "@conditional.inner", "@loop.inner" },
|
|
||||||
}, {}),
|
|
||||||
f = ai.gen_spec.treesitter({ a = "@function.outer", i = "@function.inner" }, {}),
|
|
||||||
c = ai.gen_spec.treesitter({ a = "@class.outer", i = "@class.inner" }, {}),
|
|
||||||
t = { "<([%p%w]-)%f[^<%w][^<>]->.-</%1>", "^<.->().*()</[^/]->$" },
|
|
||||||
d = { "%f[%d]%d+" }, -- digits
|
|
||||||
e = { -- Word with case
|
|
||||||
{
|
|
||||||
"%u[%l%d]+%f[^%l%d]",
|
|
||||||
"%f[%S][%l%d]+%f[^%l%d]",
|
|
||||||
"%f[%P][%l%d]+%f[^%l%d]",
|
|
||||||
"^[%l%d]+%f[^%l%d]",
|
|
||||||
},
|
|
||||||
"^().*()$",
|
|
||||||
},
|
|
||||||
g = function() -- Whole buffer, similar to `gg` and 'G' motion
|
|
||||||
local from = { line = 1, col = 1 }
|
|
||||||
local to = {
|
|
||||||
line = vim.fn.line("$"),
|
|
||||||
col = math.max(vim.fn.getline("$"):len(), 1),
|
|
||||||
}
|
|
||||||
return { from = from, to = to }
|
|
||||||
end,
|
|
||||||
u = ai.gen_spec.function_call(), -- u for "Usage"
|
|
||||||
U = ai.gen_spec.function_call({ name_pattern = "[%w_]" }), -- without dot in function name
|
|
||||||
},
|
|
||||||
}
|
|
||||||
end,
|
|
||||||
config = function(_, opts)
|
|
||||||
require("mini.ai").setup(opts)
|
|
||||||
-- register all text objects with which-key
|
|
||||||
LazyVim.on_load("which-key.nvim", function()
|
|
||||||
---@type table<string, string|table>
|
|
||||||
local i = {
|
|
||||||
[" "] = "Whitespace",
|
|
||||||
['"'] = 'Balanced "',
|
|
||||||
["'"] = "Balanced '",
|
|
||||||
["`"] = "Balanced `",
|
|
||||||
["("] = "Balanced (",
|
|
||||||
[")"] = "Balanced ) including white-space",
|
|
||||||
[">"] = "Balanced > including white-space",
|
|
||||||
["<lt>"] = "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",
|
|
||||||
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)
|
|
||||||
end,
|
|
||||||
}
|
|
|
@ -9,16 +9,8 @@ local prios = {
|
||||||
["lazyvim.plugins.extras.dap.core"] = 1,
|
["lazyvim.plugins.extras.dap.core"] = 1,
|
||||||
}
|
}
|
||||||
|
|
||||||
local used = {} ---@type table<string, boolean>
|
|
||||||
|
|
||||||
---@type string[]
|
---@type string[]
|
||||||
Config.json.data.extras = vim.tbl_filter(function(extra)
|
Config.json.data.extras = LazyVim.dedup(Config.json.data.extras)
|
||||||
if used[extra] then
|
|
||||||
return false
|
|
||||||
end
|
|
||||||
used[extra] = true
|
|
||||||
return true
|
|
||||||
end, Config.json.data.extras)
|
|
||||||
|
|
||||||
table.sort(Config.json.data.extras, function(a, b)
|
table.sort(Config.json.data.extras, function(a, b)
|
||||||
local pa = prios[a] or 10
|
local pa = prios[a] or 10
|
||||||
|
|
|
@ -78,6 +78,13 @@ function M.migrate()
|
||||||
return extra == "lazyvim.plugins.extras.editor.symbols-outline" and "lazyvim.plugins.extras.editor.outline"
|
return extra == "lazyvim.plugins.extras.editor.symbols-outline" and "lazyvim.plugins.extras.editor.outline"
|
||||||
or extra
|
or extra
|
||||||
end, json.data.extras or {})
|
end, json.data.extras or {})
|
||||||
|
elseif json.data.version == 3 then
|
||||||
|
json.data.extras = vim.tbl_filter(function(extra)
|
||||||
|
return not (
|
||||||
|
extra == "lazyvim.plugins.extras.coding.mini-ai"
|
||||||
|
or extra == "lazyvim.plugins.extras.ui.treesitter-rewrite"
|
||||||
|
)
|
||||||
|
end, json.data.extras or {})
|
||||||
end
|
end
|
||||||
|
|
||||||
M.save()
|
M.save()
|
||||||
|
|
112
lua/lazyvim/util/mini.lua
Normal file
112
lua/lazyvim/util/mini.lua
Normal file
|
@ -0,0 +1,112 @@
|
||||||
|
---@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<string, string|table>
|
||||||
|
local i = {
|
||||||
|
[" "] = "Whitespace",
|
||||||
|
['"'] = 'Balanced "',
|
||||||
|
["'"] = "Balanced '",
|
||||||
|
["`"] = "Balanced `",
|
||||||
|
["("] = "Balanced (",
|
||||||
|
[")"] = "Balanced ) including white-space",
|
||||||
|
[">"] = "Balanced > including white-space",
|
||||||
|
["<lt>"] = "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
|
|
@ -12,6 +12,7 @@ M.deprecated_extras = {
|
||||||
["lazyvim.plugins.extras.ui.dashboard"] = "`dashboard.nvim` is now the default **LazyVim** starter.",
|
["lazyvim.plugins.extras.ui.dashboard"] = "`dashboard.nvim` is now the default **LazyVim** starter.",
|
||||||
["lazyvim.plugins.extras.coding.native_snippets"] = "Native snippets are now the default for **Neovim >= 0.10**",
|
["lazyvim.plugins.extras.coding.native_snippets"] = "Native snippets are now the default for **Neovim >= 0.10**",
|
||||||
["lazyvim.plugins.extras.ui.treesitter-rewrite"] = "Disabled `treesitter-rewrite` extra for now. Not ready yet.",
|
["lazyvim.plugins.extras.ui.treesitter-rewrite"] = "Disabled `treesitter-rewrite` extra for now. Not ready yet.",
|
||||||
|
["lazyvim.plugins.extras.coding.mini-ai"] = "`mini.ai` is now a code LazyVim plugin (again)",
|
||||||
}
|
}
|
||||||
|
|
||||||
M.deprecated_modules = {
|
M.deprecated_modules = {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue