Signed-off-by: Aaron Pham <contact@aarnphm.xyz>
This commit is contained in:
@@ -4,6 +4,7 @@ local lsp = vim.lsp
|
||||
|
||||
---@class avante.utils: LazyUtilCore
|
||||
---@field tokens avante.utils.tokens
|
||||
---@field root avante.utils.root
|
||||
local M = {}
|
||||
|
||||
setmetatable(M, {
|
||||
@@ -30,6 +31,10 @@ M.has = function(plugin)
|
||||
return package.loaded[plugin] ~= nil
|
||||
end
|
||||
|
||||
M.is_win = function()
|
||||
return jit.os:find("Windows") ~= nil
|
||||
end
|
||||
|
||||
---@return "linux" | "darwin" | "windows"
|
||||
M.get_os_name = function()
|
||||
local os_name = vim.uv.os_uname().sysname
|
||||
@@ -254,8 +259,34 @@ function M.get_hl(name)
|
||||
return api.nvim_get_hl(0, { name = name })
|
||||
end
|
||||
|
||||
M.lsp = {}
|
||||
|
||||
---@alias vim.lsp.Client.filter {id?: number, bufnr?: number, name?: string, method?: string, filter?:fun(client: vim.lsp.Client):boolean}
|
||||
|
||||
---@param opts? vim.lsp.Client.filter
|
||||
---@return vim.lsp.Client[]
|
||||
M.lsp.get_clients = function(opts)
|
||||
---@type vim.lsp.Client[]
|
||||
local ret = vim.lsp.get_clients(opts)
|
||||
return (opts and opts.filter) and vim.tbl_filter(opts.filter, ret) or ret
|
||||
end
|
||||
|
||||
--- vendor from lazy.nvim for early access and override
|
||||
|
||||
---@param path string
|
||||
---@return string
|
||||
function M.norm(path)
|
||||
if path:sub(1, 1) == "~" then
|
||||
local home = vim.uv.os_homedir()
|
||||
if home:sub(-1) == "\\" or home:sub(-1) == "/" then
|
||||
home = home:sub(1, -2)
|
||||
end
|
||||
path = home .. path:sub(2)
|
||||
end
|
||||
path = path:gsub("\\", "/"):gsub("/+", "/")
|
||||
return path:sub(-1) == "/" and path:sub(1, -2) or path
|
||||
end
|
||||
|
||||
---@param msg string|string[]
|
||||
---@param opts? LazyNotifyOpts
|
||||
function M.notify(msg, opts)
|
||||
|
||||
161
lua/avante/utils/root.lua
Normal file
161
lua/avante/utils/root.lua
Normal file
@@ -0,0 +1,161 @@
|
||||
-- COPIED and MODIFIED from https://github.com/LazyVim/LazyVim/blob/main/lua/lazyvim/util/root.lua
|
||||
local Utils = require("avante.utils")
|
||||
|
||||
---@class avante.utils.root
|
||||
---@overload fun(): string
|
||||
local M = setmetatable({}, {
|
||||
__call = function(m)
|
||||
return m.get()
|
||||
end,
|
||||
})
|
||||
|
||||
---@class AvanteRoot
|
||||
---@field paths string[]
|
||||
---@field spec AvanteRootSpec
|
||||
|
||||
---@alias AvanteRootFn fun(buf: number): (string|string[])
|
||||
|
||||
---@alias AvanteRootSpec string|string[]|AvanteRootFn
|
||||
|
||||
---@type AvanteRootSpec[]
|
||||
M.spec = { "lsp", { ".git", "lua" }, "cwd" }
|
||||
|
||||
M.detectors = {}
|
||||
|
||||
function M.detectors.cwd()
|
||||
return { vim.uv.cwd() }
|
||||
end
|
||||
|
||||
---@param buf number
|
||||
function M.detectors.lsp(buf)
|
||||
local bufpath = M.bufpath(buf)
|
||||
if not bufpath then
|
||||
return {}
|
||||
end
|
||||
local roots = {} ---@type string[]
|
||||
for _, client in pairs(Utils.lsp.get_clients({ bufnr = buf })) do
|
||||
local workspace = client.config.workspace_folders
|
||||
for _, ws in pairs(workspace or {}) do
|
||||
roots[#roots + 1] = vim.uri_to_fname(ws.uri)
|
||||
end
|
||||
if client.root_dir then
|
||||
roots[#roots + 1] = client.root_dir
|
||||
end
|
||||
end
|
||||
return vim.tbl_filter(function(path)
|
||||
path = Utils.norm(path)
|
||||
return path and bufpath:find(path, 1, true) == 1
|
||||
end, roots)
|
||||
end
|
||||
|
||||
---@param patterns string[]|string
|
||||
function M.detectors.pattern(buf, patterns)
|
||||
patterns = type(patterns) == "string" and { patterns } or patterns
|
||||
local path = M.bufpath(buf) or vim.uv.cwd()
|
||||
local pattern = vim.fs.find(function(name)
|
||||
for _, p in ipairs(patterns) do
|
||||
if name == p then
|
||||
return true
|
||||
end
|
||||
if p:sub(1, 1) == "*" and name:find(vim.pesc(p:sub(2)) .. "$") then
|
||||
return true
|
||||
end
|
||||
end
|
||||
return false
|
||||
end, { path = path, upward = true })[1]
|
||||
return pattern and { vim.fs.dirname(pattern) } or {}
|
||||
end
|
||||
|
||||
function M.bufpath(buf)
|
||||
return M.realpath(vim.api.nvim_buf_get_name(assert(buf)))
|
||||
end
|
||||
|
||||
function M.cwd()
|
||||
return M.realpath(vim.uv.cwd()) or ""
|
||||
end
|
||||
|
||||
function M.realpath(path)
|
||||
if path == "" or path == nil then
|
||||
return nil
|
||||
end
|
||||
path = vim.uv.fs_realpath(path) or path
|
||||
return Utils.norm(path)
|
||||
end
|
||||
|
||||
---@param spec AvanteRootSpec
|
||||
---@return AvanteRootFn
|
||||
function M.resolve(spec)
|
||||
if M.detectors[spec] then
|
||||
return M.detectors[spec]
|
||||
elseif type(spec) == "function" then
|
||||
return spec
|
||||
end
|
||||
return function(buf)
|
||||
return M.detectors.pattern(buf, spec)
|
||||
end
|
||||
end
|
||||
|
||||
---@param opts? { buf?: number, spec?: AvanteRootSpec[], all?: boolean }
|
||||
function M.detect(opts)
|
||||
opts = opts or {}
|
||||
opts.spec = opts.spec or type(vim.g.root_spec) == "table" and vim.g.root_spec or M.spec
|
||||
opts.buf = (opts.buf == nil or opts.buf == 0) and vim.api.nvim_get_current_buf() or opts.buf
|
||||
|
||||
local ret = {} ---@type AvanteRoot[]
|
||||
for _, spec in ipairs(opts.spec) do
|
||||
local paths = M.resolve(spec)(opts.buf)
|
||||
paths = paths or {}
|
||||
paths = type(paths) == "table" and paths or { paths }
|
||||
local roots = {} ---@type string[]
|
||||
for _, p in ipairs(paths) do
|
||||
local pp = M.realpath(p)
|
||||
if pp and not vim.tbl_contains(roots, pp) then
|
||||
roots[#roots + 1] = pp
|
||||
end
|
||||
end
|
||||
table.sort(roots, function(a, b)
|
||||
return #a > #b
|
||||
end)
|
||||
if #roots > 0 then
|
||||
ret[#ret + 1] = { spec = spec, paths = roots }
|
||||
if opts.all == false then
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
return ret
|
||||
end
|
||||
|
||||
---@type table<number, string>
|
||||
M.cache = {}
|
||||
|
||||
-- returns the root directory based on:
|
||||
-- * lsp workspace folders
|
||||
-- * lsp root_dir
|
||||
-- * root pattern of filename of the current buffer
|
||||
-- * root pattern of cwd
|
||||
---@param opts? {normalize?:boolean, buf?:number}
|
||||
---@return string
|
||||
function M.get(opts)
|
||||
opts = opts or {}
|
||||
local buf = opts.buf or vim.api.nvim_get_current_buf()
|
||||
local ret = M.cache[buf]
|
||||
if not ret then
|
||||
local roots = M.detect({ all = false, buf = buf })
|
||||
ret = roots[1] and roots[1].paths[1] or vim.uv.cwd()
|
||||
M.cache[buf] = ret
|
||||
end
|
||||
if opts and opts.normalize then
|
||||
return ret
|
||||
end
|
||||
return Utils.is_win() and ret:gsub("/", "\\") or ret
|
||||
end
|
||||
|
||||
function M.git()
|
||||
local root = M.get()
|
||||
local git_root = vim.fs.find(".git", { path = root, upward = true })[1]
|
||||
local ret = git_root and vim.fn.fnamemodify(git_root, ":h") or root
|
||||
return ret
|
||||
end
|
||||
|
||||
return M
|
||||
Reference in New Issue
Block a user