Skip to content

Commit

Permalink
perf: properly track library usage per workspace folder
Browse files Browse the repository at this point in the history
  • Loading branch information
folke committed Jun 2, 2024
1 parent f2fe955 commit 48267c8
Show file tree
Hide file tree
Showing 5 changed files with 222 additions and 91 deletions.
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -83,12 +83,12 @@ Default settings:
{
runtime = vim.env.VIMRUNTIME --[[@as string]],
library = {}, ---@type string[]|table<string,string>
---@type boolean|(fun(root_dir):boolean?)
---@type boolean|(fun(root:string):boolean?)
enabled = function(root_dir)
if vim.g.lazydev_enabled ~= nil then
return vim.g.lazydev_enabled
end
return vim.uv.fs_stat(root_dir .. "/lua") and true or false
return true
end,
-- add the cmp source for completion of:
-- `require "modname"`
Expand Down
119 changes: 34 additions & 85 deletions lua/lazydev/buf.lua
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
local Config = require("lazydev.config")
local Lsp = require("lazydev.lsp")
local Pkg = require("lazydev.pkg")
local Workspace = require("lazydev.workspace")

local M = {}

Expand All @@ -9,10 +11,6 @@ M.attached = {}
---@type table<string, vim.loader.ModuleInfo|false>
M.modules = {}

--- Mapping library name to path
---@type string[]
M.library = {}

function M.setup()
M.add(Config.runtime)
for _, lib in pairs(Config.library) do
Expand All @@ -31,18 +29,17 @@ function M.setup()
vim.api.nvim_create_autocmd("LspAttach", {
group = group,
callback = function(ev)
local buffer = ev.buf ---@type number
local client = vim.lsp.get_client_by_id(ev.data.client_id)
if client and client.name == "lua_ls" and Config.is_enabled(client) then
M.on_attach(buffer)
if client and client.name == "lua_ls" then
M.on_attach(client, ev.buf)
end
end,
})

-- Attach to all existing clients
for _, client in ipairs(M.get_clients()) do
for buf in pairs(client.attached_buffers) do
M.on_attach(buf)
M.on_attach(client, buf)
end
end

Expand All @@ -68,20 +65,20 @@ function M.add(path)
if not path:find("/lua/?$") and vim.uv.fs_stat(path .. "/lua") then
path = path .. "/lua"
end
if not vim.tbl_contains(M.library, path) then
table.insert(M.library, path)
end
Workspace:global():add(path)
end

--- Gets all LuaLS clients that are enabled
function M.get_clients()
---@param client vim.lsp.Client
return vim.tbl_filter(function(client)
return Config.is_enabled(client)
end, vim.lsp.get_clients({ name = "lua_ls" }))
return vim.lsp.get_clients({ name = "lua_ls" })
end

function M.on_attach(buf)
---@param client vim.lsp.Client
function M.on_attach(client, buf)
local root = Workspace.get_root(client, buf)
if not Config.is_enabled(root) then
return
end
if M.attached[buf] then
return
end
Expand Down Expand Up @@ -112,49 +109,35 @@ function M.on_lines(buf, first, last)
for _, line in ipairs(lines) do
local module = Pkg.get_module(line)
if module then
M.on_require(module)
M.on_require(buf, module)
end
end
end

--- Check if a module is available and add it to the library
---@param buf number
---@param modname string
function M.on_require(modname)
local mod = vim.loader.find(modname)[1]
if not mod then
local paths = Pkg.get_unloaded(modname)
mod = vim.loader.find(modname, { rtp = false, paths = paths })[1]
function M.on_require(buf, modname)
local mod = M.modules[modname]

if mod == nil then
mod = vim.loader.find(modname)[1]
if not mod then
local paths = Pkg.get_unloaded(modname)
mod = vim.loader.find(modname, { rtp = false, paths = paths })[1]
end
M.modules[modname] = mod or false
end

M.modules[modname] = mod or false

if mod then
local lua = mod.modpath:find("/lua/", 1, true)
local path = lua and mod.modpath:sub(1, lua + 3) or mod.modpath
if path and not vim.tbl_contains(M.library, path) then
table.insert(M.library, path)
if path and Workspace.find(buf):add(path) then
M.update()
end
end
end

---@param client vim.lsp.Client
function M.set_handlers(client)
client.handlers["workspace/configuration"] = client.handlers["workspace/configuration"]
---@param params lsp.ConfigurationParams
or function(err, params, ctx, cfg)
---@type any[]
local ret = vim.deepcopy(vim.lsp.handlers["workspace/configuration"](err, params, ctx, cfg))
-- Don't set workspace libraries for the fallback scope
for i, item in ipairs(params.items) do
if item.section == "Lua" and not item.scopeUri and type(ret[i]) == "table" and ret[i].workspace then
ret[i].workspace.library = nil
end
end
return ret
end
end

--- Update LuaLS settings with the current library
function M.update()
if package.loaded["neodev"] then
Expand All @@ -164,52 +147,18 @@ function M.update()
)
end
for _, client in ipairs(M.get_clients()) do
-- M.set_handlers(client)
local settings = vim.deepcopy(client.settings or {})

---@type string[]
local library = vim.tbl_get(settings, "Lua", "workspace", "library") or {}
for _, path in ipairs(M.library) do
if not vim.tbl_contains(library, path) then
table.insert(library, path)
local update = false
for _, ws in ipairs(client.workspace_folders) do
local w = Workspace.get(client.id, ws.name)
if Config.is_enabled(w.root) and w:update() then
update = true
end
end

settings = vim.tbl_deep_extend("force", settings, {
Lua = {
runtime = {
version = "LuaJIT",
path = { "?.lua", "?/init.lua" },
pathStrict = true,
},
workspace = {
checkThirdParty = false,
library = library,
},
},
})

if not vim.deep_equal(settings, client.settings) then
if Config.debug then
M.debug()
end
client.settings = settings
client.notify("workspace/didChangeConfiguration", {
settings = settings,
})
if update then
Lsp.attach(client)
Lsp.update(client)
end
end
end

function M.debug()
local Util = require("lazy.core.util")
local Plugin = require("lazy.core.plugin")
local lines = {}
for _, lib in ipairs(M.library) do
local plugin = Plugin.find(lib .. "/")
table.insert(lines, "- " .. (plugin and "**" .. plugin.name .. "** " or "") .. ("`" .. lib .. "`"))
end
Util.info(lines, { title = "lazydev.nvim" })
end

return M
9 changes: 5 additions & 4 deletions lua/lazydev/config.lua
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,12 @@ local M = {}
local defaults = {
runtime = vim.env.VIMRUNTIME --[[@as string]],
library = {}, ---@type string[]|table<string,string>
---@type boolean|(fun(root_dir):boolean?)
---@type boolean|(fun(root:string):boolean?)
enabled = function(root_dir)
if vim.g.lazydev_enabled ~= nil then
return vim.g.lazydev_enabled
end
return vim.uv.fs_stat(root_dir .. "/lua") and true or false
return true
end,
debug = false,
-- add the cmp source for completion of:
Expand All @@ -22,11 +22,12 @@ local defaults = {
---@type lazydev.Config
local options

---@param root string
---@return boolean
function M.is_enabled(client)
function M.is_enabled(root)
local enabled = M.enabled
if type(enabled) == "function" then
return enabled(client.root_dir) and true or false
return enabled(root) and true or false
end
return enabled
end
Expand Down
56 changes: 56 additions & 0 deletions lua/lazydev/lsp.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
local Config = require("lazydev.config")
local Workspace = require("lazydev.workspace")

local M = {}
M.attached = {} ---@type table<number,number>

---@param client vim.lsp.Client
function M.attach(client)
if M.attached[client.id] then
return
end
M.attached[client.id] = client.id
---@param params lsp.ConfigurationParams
client.handlers["workspace/configuration"] = function(err, params, ctx, cfg)
if not params.items then
return {}
end

local response = {}
for _, item in ipairs(params.items) do
if item.section then
local settings = client.settings
if item.scopeUri and item.section == "Lua" then
local root = vim.uri_to_fname(item.scopeUri)
if Config.is_enabled(root) then
local ws = Workspace.get(client, root)
settings = ws.settings
if Config.debug then
ws:debug()
end
end
end

local keys = vim.split(item.section, ".", { plain = true }) --- @type string[]
local value = vim.tbl_get(settings, unpack(keys))
-- For empty sections with no explicit '' key, return settings as is
if value == nil and item.section == "" then
value = client.settings
end
if value == nil then
value = vim.NIL
end
table.insert(response, value)
end
end
return response
end
end

function M.update(client)
client.notify("workspace/didChangeConfiguration", {
settings = { Lua = {} },
})
end

return M
Loading

0 comments on commit 48267c8

Please sign in to comment.