2024-08-19 05:40:57 -04:00
|
|
|
local api = vim.api
|
|
|
|
|
|
|
|
---@class avante.Utils: LazyUtilCore
|
|
|
|
---@field colors avante.util.colors
|
|
|
|
local M = {}
|
|
|
|
|
|
|
|
setmetatable(M, {
|
|
|
|
__index = function(t, k)
|
|
|
|
local ok, lazyutil = pcall(require, "lazy.core.util")
|
|
|
|
if ok and lazyutil[k] then
|
|
|
|
return lazyutil[k]
|
|
|
|
end
|
|
|
|
|
|
|
|
---@diagnostic disable-next-line: no-unknown
|
|
|
|
t[k] = require("avante.utils." .. k)
|
|
|
|
return t[k]
|
|
|
|
end,
|
|
|
|
})
|
|
|
|
|
2024-08-20 14:24:33 -04:00
|
|
|
---Check if a plugin is installed
|
|
|
|
---@param plugin string
|
|
|
|
---@return boolean
|
|
|
|
M.has = function(plugin)
|
|
|
|
return require("lazy.core.config").plugins[plugin] ~= nil
|
|
|
|
end
|
|
|
|
|
2024-08-19 05:40:57 -04:00
|
|
|
---@param str string
|
|
|
|
---@param opts? {suffix?: string, prefix?: string}
|
|
|
|
function M.trim(str, opts)
|
|
|
|
if not opts then
|
|
|
|
return str
|
|
|
|
end
|
|
|
|
if opts.suffix then
|
|
|
|
return str:sub(-1) == opts.suffix and str:sub(1, -2) or str
|
|
|
|
elseif opts.prefix then
|
|
|
|
return str:sub(1, 1) == opts.prefix and str:sub(2) or str
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
function M.in_visual_mode()
|
|
|
|
local current_mode = vim.fn.mode()
|
|
|
|
return current_mode == "v" or current_mode == "V" or current_mode == ""
|
|
|
|
end
|
|
|
|
|
2024-08-19 12:09:04 -04:00
|
|
|
---Get the selected content and range in Visual mode
|
|
|
|
---@return avante.SelectionResult | nil Selected content and range
|
2024-08-19 05:40:57 -04:00
|
|
|
function M.get_visual_selection_and_range()
|
|
|
|
local Range = require("avante.range")
|
|
|
|
local SelectionResult = require("avante.selection_result")
|
|
|
|
|
|
|
|
if not M.in_visual_mode() then
|
|
|
|
return nil
|
|
|
|
end
|
|
|
|
-- Get the start and end positions of Visual mode
|
|
|
|
local start_pos = vim.fn.getpos("v")
|
|
|
|
local end_pos = vim.fn.getpos(".")
|
|
|
|
-- Get the start and end line and column numbers
|
|
|
|
local start_line = start_pos[2]
|
|
|
|
local start_col = start_pos[3]
|
|
|
|
local end_line = end_pos[2]
|
|
|
|
local end_col = end_pos[3]
|
|
|
|
-- If the start point is after the end point, swap them
|
|
|
|
if start_line > end_line or (start_line == end_line and start_col > end_col) then
|
|
|
|
start_line, end_line = end_line, start_line
|
|
|
|
start_col, end_col = end_col, start_col
|
|
|
|
end
|
|
|
|
local content = ""
|
|
|
|
local range = Range.new({ line = start_line, col = start_col }, { line = end_line, col = end_col })
|
|
|
|
-- Check if it's a single-line selection
|
|
|
|
if start_line == end_line then
|
|
|
|
-- Get partial content of a single line
|
|
|
|
local line = vim.fn.getline(start_line)
|
|
|
|
-- content = string.sub(line, start_col, end_col)
|
|
|
|
content = line
|
|
|
|
else
|
|
|
|
-- Multi-line selection: Get all lines in the selection
|
|
|
|
local lines = vim.fn.getline(start_line, end_line)
|
|
|
|
-- Extract partial content of the first line
|
|
|
|
-- lines[1] = string.sub(lines[1], start_col)
|
|
|
|
-- Extract partial content of the last line
|
|
|
|
-- lines[#lines] = string.sub(lines[#lines], 1, end_col)
|
|
|
|
-- Concatenate all lines in the selection into a string
|
|
|
|
content = table.concat(lines, "\n")
|
|
|
|
end
|
|
|
|
if not content then
|
|
|
|
return nil
|
|
|
|
end
|
|
|
|
-- Return the selected content and range
|
|
|
|
return SelectionResult.new(content, range)
|
|
|
|
end
|
|
|
|
|
|
|
|
---Wrapper around `api.nvim_buf_get_lines` which defaults to the current buffer
|
|
|
|
---@param start integer
|
|
|
|
---@param _end integer
|
|
|
|
---@param buf integer?
|
|
|
|
---@return string[]
|
|
|
|
function M.get_buf_lines(start, _end, buf)
|
|
|
|
return api.nvim_buf_get_lines(buf or 0, start, _end, false)
|
|
|
|
end
|
|
|
|
|
|
|
|
---Get cursor row and column as (1, 0) based
|
|
|
|
---@param win_id integer?
|
|
|
|
---@return integer, integer
|
|
|
|
function M.get_cursor_pos(win_id)
|
|
|
|
return unpack(api.nvim_win_get_cursor(win_id or 0))
|
|
|
|
end
|
|
|
|
|
|
|
|
---Check if the buffer is likely to have actionable conflict markers
|
|
|
|
---@param bufnr integer?
|
|
|
|
---@return boolean
|
|
|
|
function M.is_valid_buf(bufnr)
|
|
|
|
bufnr = bufnr or 0
|
|
|
|
return #vim.bo[bufnr].buftype == 0 and vim.bo[bufnr].modifiable
|
|
|
|
end
|
|
|
|
|
|
|
|
---@param name string?
|
|
|
|
---@return table<string, string>
|
|
|
|
function M.get_hl(name)
|
|
|
|
if not name then
|
|
|
|
return {}
|
|
|
|
end
|
|
|
|
return api.nvim_get_hl(0, { name = name })
|
|
|
|
end
|
|
|
|
|
|
|
|
--- vendor from lazy.nvim for early access and override
|
|
|
|
|
|
|
|
---@param msg string|string[]
|
|
|
|
---@param opts? LazyNotifyOpts
|
|
|
|
function M.notify(msg, opts)
|
|
|
|
if vim.in_fast_event() then
|
|
|
|
return vim.schedule(function()
|
|
|
|
M.notify(msg, opts)
|
|
|
|
end)
|
|
|
|
end
|
|
|
|
|
|
|
|
opts = opts or {}
|
|
|
|
if type(msg) == "table" then
|
|
|
|
---@diagnostic disable-next-line: no-unknown
|
|
|
|
msg = table.concat(
|
|
|
|
vim.tbl_filter(function(line)
|
|
|
|
return line or false
|
|
|
|
end, msg),
|
|
|
|
"\n"
|
|
|
|
)
|
|
|
|
end
|
|
|
|
if opts.stacktrace then
|
|
|
|
msg = msg .. M.pretty_trace({ level = opts.stacklevel or 2 })
|
|
|
|
end
|
|
|
|
local lang = opts.lang or "markdown"
|
|
|
|
local n = opts.once and vim.notify_once or vim.notify
|
|
|
|
n(msg, opts.level or vim.log.levels.INFO, {
|
|
|
|
on_open = function(win)
|
|
|
|
local ok = pcall(function()
|
|
|
|
vim.treesitter.language.add("markdown")
|
|
|
|
end)
|
|
|
|
if not ok then
|
|
|
|
pcall(require, "nvim-treesitter")
|
|
|
|
end
|
|
|
|
vim.wo[win].conceallevel = 3
|
|
|
|
vim.wo[win].concealcursor = ""
|
|
|
|
vim.wo[win].spell = false
|
|
|
|
local buf = vim.api.nvim_win_get_buf(win)
|
|
|
|
if not pcall(vim.treesitter.start, buf, lang) then
|
|
|
|
vim.bo[buf].filetype = lang
|
|
|
|
vim.bo[buf].syntax = lang
|
|
|
|
end
|
|
|
|
end,
|
|
|
|
title = opts.title or "lazy.nvim",
|
|
|
|
})
|
|
|
|
end
|
|
|
|
|
|
|
|
---@param msg string|string[]
|
|
|
|
---@param opts? LazyNotifyOpts
|
|
|
|
function M.error(msg, opts)
|
|
|
|
opts = opts or {}
|
|
|
|
opts.level = vim.log.levels.ERROR
|
|
|
|
M.notify(msg, opts)
|
|
|
|
end
|
|
|
|
|
|
|
|
---@param msg string|string[]
|
|
|
|
---@param opts? LazyNotifyOpts
|
|
|
|
function M.info(msg, opts)
|
|
|
|
opts = opts or {}
|
|
|
|
opts.level = vim.log.levels.INFO
|
|
|
|
M.notify(msg, opts)
|
|
|
|
end
|
|
|
|
|
|
|
|
---@param msg string|string[]
|
|
|
|
---@param opts? LazyNotifyOpts
|
|
|
|
function M.warn(msg, opts)
|
|
|
|
opts = opts or {}
|
|
|
|
opts.level = vim.log.levels.WARN
|
|
|
|
M.notify(msg, opts)
|
|
|
|
end
|
|
|
|
|
|
|
|
---@param msg string|table
|
|
|
|
---@param opts? LazyNotifyOpts
|
|
|
|
function M.debug(msg, opts)
|
|
|
|
if not require("avante.config").options.debug then
|
|
|
|
return
|
|
|
|
end
|
|
|
|
opts = opts or {}
|
|
|
|
if opts.title then
|
|
|
|
opts.title = "lazy.nvim: " .. opts.title
|
|
|
|
end
|
|
|
|
if type(msg) == "string" then
|
|
|
|
M.notify(msg, opts)
|
|
|
|
else
|
|
|
|
opts.lang = "lua"
|
|
|
|
M.notify(vim.inspect(msg), opts)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2024-08-21 21:28:17 +08:00
|
|
|
function M.tbl_indexof(tbl, value)
|
|
|
|
for i, v in ipairs(tbl) do
|
|
|
|
if v == value then
|
|
|
|
return i
|
|
|
|
end
|
|
|
|
end
|
|
|
|
return nil
|
|
|
|
end
|
|
|
|
|
|
|
|
function M.update_win_options(winid, opt_name, key, value)
|
|
|
|
local cur_opt_value = api.nvim_get_option_value(opt_name, { win = winid })
|
|
|
|
|
|
|
|
if cur_opt_value:find(key .. ":") then
|
|
|
|
cur_opt_value = cur_opt_value:gsub(key .. ":[^,]*", key .. ":" .. value)
|
|
|
|
else
|
|
|
|
if #cur_opt_value > 0 then
|
|
|
|
cur_opt_value = cur_opt_value .. ","
|
|
|
|
end
|
|
|
|
cur_opt_value = cur_opt_value .. key .. ":" .. value
|
|
|
|
end
|
|
|
|
|
|
|
|
api.nvim_set_option_value(opt_name, cur_opt_value, { win = winid })
|
|
|
|
end
|
|
|
|
|
|
|
|
function M.get_win_options(winid, opt_name, key)
|
|
|
|
local cur_opt_value = api.nvim_get_option_value(opt_name, { win = winid })
|
|
|
|
if not cur_opt_value then
|
|
|
|
return
|
|
|
|
end
|
|
|
|
local pieces = vim.split(cur_opt_value, ",")
|
|
|
|
for _, piece in ipairs(pieces) do
|
|
|
|
local kv_pair = vim.split(piece, ":")
|
|
|
|
if kv_pair[1] == key then
|
|
|
|
return kv_pair[2]
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2024-08-21 23:20:30 +08:00
|
|
|
function M.unlock_buf(bufnr)
|
|
|
|
vim.bo[bufnr].modified = false
|
|
|
|
vim.bo[bufnr].modifiable = true
|
|
|
|
end
|
|
|
|
|
|
|
|
function M.lock_buf(bufnr)
|
|
|
|
vim.bo[bufnr].modified = false
|
|
|
|
vim.bo[bufnr].modifiable = false
|
|
|
|
end
|
|
|
|
|
|
|
|
---@param winnr? number
|
|
|
|
---@return nil
|
|
|
|
M.scroll_to_end = function(winnr)
|
|
|
|
winnr = winnr or 0
|
|
|
|
local bufnr = api.nvim_win_get_buf(winnr)
|
|
|
|
local lnum = api.nvim_buf_line_count(bufnr)
|
|
|
|
local last_line = api.nvim_buf_get_lines(bufnr, -2, -1, true)[1]
|
|
|
|
api.nvim_win_set_cursor(winnr, { lnum, api.nvim_strwidth(last_line) })
|
|
|
|
end
|
|
|
|
|
|
|
|
---@param bufnr nil|integer
|
|
|
|
---@return nil
|
|
|
|
M.buf_scroll_to_end = function(bufnr)
|
|
|
|
for _, winnr in ipairs(M.buf_list_wins(bufnr or 0)) do
|
|
|
|
M.scroll_to_end(winnr)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
---@param bufnr nil|integer
|
|
|
|
---@return integer[]
|
|
|
|
M.buf_list_wins = function(bufnr)
|
|
|
|
local wins = {}
|
|
|
|
|
|
|
|
if not bufnr or bufnr == 0 then
|
|
|
|
bufnr = api.nvim_get_current_buf()
|
|
|
|
end
|
|
|
|
|
|
|
|
for _, winnr in ipairs(api.nvim_list_wins()) do
|
|
|
|
if api.nvim_win_is_valid(winnr) and api.nvim_win_get_buf(winnr) == bufnr then
|
|
|
|
table.insert(wins, winnr)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
return wins
|
|
|
|
end
|
|
|
|
|
2024-08-19 05:40:57 -04:00
|
|
|
return M
|