Adjusting lua_ls workspace loading

/home/jm/.config/nvim · 15 messages · 42 parts · · 230,157 tokens
Created Jan 17, 01:19:56 AM · Updated Jan 17, 03:36:07 AM · 60 syncs
userJan 17, 01:19:56 AM

Given your expert knowledge of lua and its integration into neovim, investigate my code to find how lazydev and the lua_ls lsp configuration can be correctly setup to pull in just the right amount of projects into the workspace.

Maybe try and rely on lazyvim as I assume it adds projects peacemeal to the workspace

assistantJan 17, 01:19:56 AM
xiaomi/mimo-v2-flash:free · openrouter

I'll investigate your Lua/LSP configuration to understand how lazydev and lua_ls are currently set up, and how they interact with workspace management.

taskcompleted
Investigate lazydev/lua_ls config
Output
Now I have a comprehensive understanding of the configuration. Let me provide a detailed analysis:

## Detailed Analysis of lazydev and lua_ls Configuration

### 1. **lazydev Plugin Configuration** (`lua/plugins/lazydev.lua`)

The lazydev plugin is configured with minimal settings:

```lua
return {
  "folke/lazydev.nvim",
  ft = "lua", -- only load on lua files
  opts = {
    library = {
      { path = "${3rd}/luv/library", words = { "vim%.uv" } },
      { path = "${3rd}/luv/util", words = { "vim%.uv" } },
    },
  },
  enabled = true,
}
```

**Key Points:**
- Only loads on Lua files (`ft = "lua"`)
- Configured with two library paths for `vim.uv` support
- Uses `${3rd}` and `${data}` variables for standard Neovim paths
- **Issue**: The library configuration is minimal and doesn't include plugin directories or the user's config directory

### 2. **lua_ls LSP Configuration** (`lsp/lua_ls.lua`)

The lua_ls LSP server is configured with:

```lua
local root_markers = {
  ".luarc.json",
  ".luarc.jsonc",
  "stylua.toml",
  "selene.toml",
  ".git",
}
```

**Root Directory Detection:**
- Uses `vim.fs.root()` with the above markers
- **Critical Issue**: Prevents fallback to current working directory to ensure server reuse
- This means lua_ls will only start when a specific project marker is found

**Workspace Configuration:**
The lua_ls configuration has extensive workspace settings commented out (lines 32-51):
```lua
-- workspace = {
--   checkThirdParty = false,
--   library = {
--     vim.env.VIMRUNTIME,
--     "${3rd}/luv/library",
--     "${3rd}/busted/library",
--   },
--   library = vim.api.nvim_get_runtime_file("", true)  -- Slow, causes issues
-- }
```

**Current Settings (lines 77-114):**
- **Completion**: Enabled with callSnippet, keywordSnippet, displayContext, workspaceWord, showParams
- **Diagnostics**: Enabled with custom globals (vim, LazyVim, bit, jit)
- **Hints**: Enabled
- **Formatting**: Disabled (works with Biome)
- **Telemetry**: Disabled

### 3. **Work...
13,050in / 256out
assistantJan 17, 01:23:34 AM
xiaomi/mimo-v2-flash:free · openrouter

Based on my investigation, I found several key issues with your lazydev and lua_ls configuration:

Current State

What's Working:

  • lazydev loads on Lua files with minimal vim.uv library paths
  • lua_ls starts when project markers are found (.luarc.json, stylua.toml, .git)
  • TypeScript has full workspace folder management (typescript_workspace.lua)

Critical Issues:

  1. workspace_enhancer module exists but is never used - It's commented out in lua/lsp/completions.lua
  2. lua_ls has no workspace library configuration - The extensive library settings are commented out
  3. No project-specific workspace management for Lua - Unlike TypeScript

The Problem

Your workspace_enhancer module (lua/config/lsp/workspace_enhancer.lua) is designed to pull in:

  • Plugin directories from lazy.nvim
  • Neovim runtime paths (config, data, VIMRUNTIME)
  • Configured workspace libraries

But it's completely disabled - the require statement and function call are commented out.

Recommended Fix

Enable the workspace_enhancer by uncommenting these lines in lua/lsp/completions.lua:

local workspace_enhancer = require("config.lsp.workspace_enhancer")
workspace_enhancer.apply_enhanced_config()

This will configure lua_ls with:

  • Plugin directories from lazy.nvim
  • Your Neovim config directory
  • Standard Neovim runtime paths
  • Proper ignore patterns (node_modules, .cache, etc.)

Would you like me to enable the workspace_enhancer module and test the configuration?

14,836in / 345out
userJan 17, 03:35:23 AM

What is your opinion on the design and implementation of the worksapce enhancer module? What are its dependencies? Where are the places in the code that it interacts with the rest of the system?

assistantJan 17, 03:35:23 AM
xiaomi/mimo-v2-flash:free · openrouter
readcompleted
lua/config/lsp/workspace_enhancer.lua
Output
<file>
00001| -- Dynamic workspace context enhancer for Lua LSP
00002| -- Automatically adds plugin directories and runtime paths for better completion
00003| 
00004| local M = {}
00005| 
00006| -- Get all plugin directories dynamically
00007| M.get_plugin_directories = function()
00008|   local plugin_dirs = {}
00009|   local lazy_path = vim.fn.stdpath("data") .. "/lazy"
00010| 
00011|   if vim.fn.isdirectory(lazy_path) == 1 then
00012|     -- Get all plugin lua directories
00013|     local plugins = vim.fn.glob(lazy_path .. "/*/lua", true, true)
00014|     for _, plugin in ipairs(plugins) do
00015|       table.insert(plugin_dirs, plugin)
00016|     end
00017| 
00018|     -- Also add plugin root directories
00019|     local plugin_roots = vim.fn.glob(lazy_path .. "/*", true, true)
00020|     for _, root in ipairs(plugin_roots) do
00021|       if vim.fn.isdirectory(root) == 1 then
00022|         table.insert(plugin_dirs, root)
00023|       end
00024|     end
00025|   end
00026| 
00027|   -- Add packer paths if they exist
00028|   local packer_path = vim.fn.stdpath("data") .. "/site/pack/packer"
00029|   if vim.fn.isdirectory(packer_path) == 1 then
00030|     local packer_plugins = vim.fn.glob(packer_path .. "/*/*/lua", true, true)
00031|     for _, plugin in ipairs(packer_plugins) do
00032|       table.insert(plugin_dirs, plugin)
00033|     end
00034|   end
00035| 
00036|   return plugin_dirs
00037| end
00038| 
00039| -- Get all Neovim runtime paths
00040| M.get_runtime_paths = function()
00041|   local runtime_paths = {
00042|     vim.fn.stdpath("config"),
00043|     vim.fn.stdpath("data"),
00044|     vim.env.VIMRUNTIME,
00045|   }
00046| 
00047|   -- Add all runtimepath entries
00048|   local runtimepath = vim.opt.runtimepath:get()
00049|   for _, path in ipairs(runtimepath) do
00050|     if vim.fn.isdirectory(path) == 1 then
00051|       table.insert(runtime_paths, path)
00052|     end
00053|   end
00054| 
00055|   return runtime_paths
00056| end
00057| 
00058| -...
12,370in / 36out
assistantJan 17, 03:35:27 AM
xiaomi/mimo-v2-flash:free · openrouter
grepcompleted
workspace_enhancer
Output
Found 4 matches
/home/jm/.config/nvim/lua/lsp/completions.lua:
  Line 5: -- local workspace_enhancer = require("config.lsp.workspace_enhancer")
  Line 10: --   workspace_enhancer.apply_enhanced_config()

/home/jm/.config/nvim/session-ses_4814.md:
  Line 596: /project/lua/config/lsp/workspace_enhancer.lua

/home/jm/.config/nvim/ai-nvim-plugin.md:
  Line 596: /project/lua/config/lsp/workspace_enhancer.lua
14,783in / 38out
assistantJan 17, 03:35:28 AM
xiaomi/mimo-v2-flash:free · openrouter
readcompleted
lua/lsp/completions.lua
Output
<file>
00001| -- Enhanced LSP completion configuration for better ordering
00002| -- Focuses on improving workspace context and completion prioritization
00003| 
00004| -- local M = {}
00005| -- local workspace_enhancer = require("config.lsp.workspace_enhancer")
00006| --
00007| -- -- Enhanced Lua LSP configuration for Neovim development
00008| -- M.setup_lua_ls_enhanced = function()
00009| --   -- Apply enhanced workspace configuration
00010| --   workspace_enhancer.apply_enhanced_config()
00011| --
00012| --   vim.notify("Enhanced Lua LSP configuration applied with workspace context", vim.log.levels.INFO)
00013| -- end
00014| --
00015| -- -- Enhanced completion prioritization for all LSP servers
00016| -- M.setup_enhanced_completion = function()
00017| --   -- Global LSP settings for better completion
00018| --   vim.lsp.config("*", {
00019| --     capabilities = vim.lsp.protocol.make_client_capabilities(),
00020| --     settings = {
00021| --       -- Enable enhanced completion features
00022| --       completion = {
00023| --         completeFunctionCalls = true,
00024| --         triggerCompletionOnInsert = true,
00025| --         completionItem = {
00026| --           snippetSupport = true,
00027| --           commitCharactersSupport = true,
00028| --           deprecatedSupport = true,
00029| --           preselectSupport = true,
00030| --           tagSupport = { valueSet = { 1 } }, -- Deprecated tag
00031| --           insertReplaceSupport = true,
00032| --           resolveSupport = {
00033| --             properties = {
00034| --               "documentation",
00035| --               "detail",
00036| --               "additionalTextEdits",
00037| --             },
00038| --           },
00039| --           insertTextModeSupport = {
00040| --             valueSet = { 1, 2 }, -- Insert as snippet or plain text
00041| --           },
00042| --         },
00043| --       },
00044| --       -- Enhanced workspace symbols
00045| --       workspace = {
00046| -- ...
14,966in / 34out
assistantJan 17, 03:35:32 AM
xiaomi/mimo-v2-flash:free · openrouter
readcompleted
lua/config/lsp/advanced.lua
Output
<file>
00001| -- Advanced LSP configurations with environment management
00002| -- This module provides sophisticated setup for complex development environments
00003| 
00004| local M = {}
00005| 
00006| -- ============================================================================
00007| -- ENVIRONMENT MANAGEMENT UTILITIES
00008| -- ============================================================================
00009| 
00010| -- Generic function for version-aware LSP setup
00011| local function setup_versioned_lsp(name, config)
00012|   vim.lsp.config(
00013|     name,
00014|     vim.tbl_deep_extend("force", config, {
00015|       cmd = function()
00016|         local cmd = config.base_cmd or { name }
00017| 
00018|         -- Check for project-specific version
00019|         if config.version_file then
00020|           local version_file = vim.fs.find(config.version_file, { upward = true })[1]
00021|           if version_file then
00022|             local version = vim.fn.system("cat " .. version_file):gsub("\n", "")
00023|             if version ~= "" and config.version_manager then
00024|               cmd = vim.list_extend({ config.version_manager, "exec", version }, cmd)
00025|             end
00026|           end
00027|         end
00028| 
00029|         return cmd
00030|       end,
00031|     })
00032|   )
00033| end
00034| 
00035| -- OCaml environment detection and setup
00036| local function setup_ocaml_environment(project_root)
00037|   -- TODO: Implement opam switch detection and environment setup
00038|   local opam_switch = vim.fn.system("opam switch show 2>/dev/null"):gsub("\n", "")
00039| 
00040|   if vim.v.shell_error == 0 and opam_switch ~= "" then
00041|     -- Set environment for current opam switch
00042|     vim.env.OPAM_SWITCH_PREFIX = vim.fn.expand("~/.opam/" .. opam_switch)
00043| 
00044|     -- Check for developer tools in switch
00045|     local switch_bin = vim.env.OPAM_SWITCH_PREFIX .. "/bin"
00046| 
00047|     if vim.fn.executable(switch_...
15,953in / 34out
assistantJan 17, 03:35:34 AM
xiaomi/mimo-v2-flash:free · openrouter
readerror
Error: File not found: /home/jm/.config/nvim/lua/config/lsp/init.lua
19,549in / 33out
assistantJan 17, 03:35:36 AM
xiaomi/mimo-v2-flash:free · openrouter
readcompleted
lua/lsp/init.lua
Output
<file>
00001| -- Modern LSP Setup following Neovim's recommended approach
00002| -- This file sets up LSP configurations early and enables them
00003| local log = require("vim.lsp.log")
00004| log("🚀 Setting up LSP early...")
00005| 
00006| -- Define global capabilities
00007| local capabilities = vim.lsp.protocol.make_client_capabilities()
00008| capabilities = require("blink.cmp").get_lsp_capabilities({
00009|   textDocument = { completion = { completionItem = { snippetSupport = false } } },
00010| })
00011| 
00012| -- Global LSP defaults applied to ALL servers
00013| vim.lsp.config("*", {
00014|   capabilities = capabilities,
00015|   settings = {
00016|     codelens = {
00017|       enable = true,
00018|       unicode = true,
00019|       inferredTypes = true,
00020|       signatureHelp = true,
00021|     },
00022|     codeAction = {},
00023|     inlayHints = { enable = false },
00024|     extendedHover = { enable = true },
00025|     syntaxDocumentation = { enable = true },
00026|   },
00027|   on_attach = function(client, bufnr)
00028|     local opts = { buffer = bufnr, silent = true }
00029| 
00030|     -- Universal keymaps for ALL servers
00031|     vim.keymap.set("n", "gd", vim.lsp.buf.definition, opts)
00032|     vim.keymap.set("n", "K", vim.lsp.buf.hover, opts)
00033|     vim.keymap.set("n", "gD", vim.lsp.buf.declaration, opts)
00034|     vim.keymap.set("n", "gi", vim.lsp.buf.implementation, opts)
00035|     vim.keymap.set("n", "gt", vim.lsp.buf.type_definition, opts)
00036|     vim.keymap.set("n", "gr", vim.lsp.buf.references, opts)
00037|     vim.keymap.set("n", "<leader>rn", vim.lsp.buf.rename, opts)
00038|     vim.keymap.set("n", "<leader>cd", vim.diagnostic.open_float, opts)
00039|     -- vim.keymap.set("n", "[d", vim.diagnostic.goto_prev, opts)
00040|     -- vim.keymap.set("n", "]d", vim.diagnostic.goto_next, opts)
00041| 
00042|     -- Enable features conditionally based on server capabilities
00043|     if client:supports_method("textDocument/com...
19,617in / 32out
assistantJan 17, 03:35:38 AM
xiaomi/mimo-v2-flash:free · openrouter
readcompleted
lua/config/typescript_workspace.lua
Output
<file>
00001| -- TypeScript Workspace Management Commands
00002| -- Provides user commands for managing TypeScript LSP workspace folders
00003| 
00004| local M = {}
00005| 
00006| -- Store workspace folders locally (since we can't request them from server)
00007| local workspace_folders = {}
00008| 
00009| -- Get the TypeScript LSP client
00010| local function get_tsserver_client()
00011|   local clients = vim.lsp.get_clients({ name = "tsserver" })
00012|   if #clients == 0 then
00013|     vim.notify("No TypeScript LSP client found", vim.log.levels.WARN)
00014|     return nil
00015|   end
00016|   return clients[1]
00017| end
00018| 
00019| -- Add workspace folder to TypeScript LSP
00020| function M.add_workspace_folder(path)
00021|   local client = get_tsserver_client()
00022|   if not client then
00023|     return
00024|   end
00025| 
00026|   -- Resolve path
00027|   local resolved_path = path
00028|   if path == "" or path == "." then
00029|     resolved_path = vim.fn.getcwd()
00030|   elseif not vim.fn.isdirectory(path) == 1 then
00031|     -- Try to make it absolute
00032|     resolved_path = vim.fn.fnamemodify(path, ":p")
00033|   end
00034| 
00035|   local uri = "file://" .. vim.fn.fnamemodify(resolved_path, ":p:gs?\\?/?")
00036|   local name = vim.fn.fnamemodify(resolved_path, ":t")
00037| 
00038|   -- Check if already added
00039|   if workspace_folders[uri] then
00040|     vim.notify("Workspace folder already added: " .. name, vim.log.levels.INFO)
00041|     return
00042|   end
00043| 
00044|   -- Store locally
00045|   workspace_folders[uri] = { uri = uri, name = name, path = resolved_path }
00046| 
00047|   -- Notify server of addition
00048|   client:notify("workspace/didChangeWorkspaceFolders", {
00049|     event = {
00050|       added = { {
00051|         uri = uri,
00052|         name = name,
00053|       } },
00054|       removed = {},
00055|     },
00056|   })
00057| 
00058|   vim.notify("Added workspace folder: " .. name, vim.log.levels.INFO)
000...
21,350in / 33out
assistantJan 17, 03:35:42 AM
xiaomi/mimo-v2-flash:free · openrouter
readerror
Error: File not found: /home/jm/.config/nvim/lua/lsp/lua_ls.lua
24,792in / 34out
assistantJan 17, 03:35:48 AM
xiaomi/mimo-v2-flash:free · openrouter
globcompleted
Output
/home/jm/.config/nvim/lsp/lua_ls.lua
24,862in / 39out
assistantJan 17, 03:35:51 AM
xiaomi/mimo-v2-flash:free · openrouter
readcompleted
lsp/lua_ls.lua
Output
<file>
00001| -- Lua Language Server Configuration
00002| -- Optimized for Neovim development with high-quality completions
00003| -- Works alongside Biome for formatting/linting when biome.json exists
00004| 
00005| local root_markers = {
00006|   ".luarc.json",
00007|   ".luarc.jsonc",
00008|   "stylua.toml",
00009|   "selene.toml",
00010|   ".git",
00011| }
00012| 
00013| ---@type vim.lsp.ClientConfig
00014| return {
00015|   cmd = { "lua-language-server" },
00016|   filetypes = { "lua" },
00017| 
00018|   root_merkers = root_markers,
00019| 
00020|   on_init = function(client)
00021|     if client.workspace_folders then
00022|       local path = client.workspace_folders[1].name
00023|       if
00024|         path ~= vim.fn.stdpath("config")
00025|         and (vim.uv.fs_stat(path .. "/.luarc.json") or vim.uv.fs_stat(path .. "/.luarc.jsonc"))
00026|       then
00027|         return
00028|       end
00029|     end
00030|   end,
00031|   --
00032|   --   client.config.settings.Lua = vim.tbl_deep_extend("force", client.config.settings.Lua, {
00033|   --     runtime = {
00034|   --       -- Tell the language server which version of Lua you're using
00035|   --       -- (most likely LuaJIT in the case of Neovim)
00036|   --       version = "LuaJIT",
00037|   --     },
00038|   --     -- Make the server aware of Neovim runtime files
00039|   --     workspace = {
00040|   --       checkThirdParty = false,
00041|   --       library = {
00042|   --         vim.env.VIMRUNTIME,
00043|   --         -- Depending on the usage, you might want to add additional paths here.
00044|   --         "${3rd}/luv/library",
00045|   --         "${3rd}/busted/library",
00046|   --       },
00047|   --       -- or pull in all of 'runtimepath'. NOTE: this is a lot slower and will cause issues when working on your own configuration (see https://github.com/neovim/nvim-lspconfig/issues/3189)
00048|   --       -- library = vim.api.nvim_get_runtime_file("", true)
00049|   --     },
00050|   --   ...
5,311in / 32out
assistantJan 17, 03:35:54 AM
xiaomi/mimo-v2-flash:free · openrouter

Now I have a complete picture. Let me analyze the workspace_enhancer module's design and implementation:

Analysis of workspace_enhancer Module

Design Philosophy

The workspace_enhancer module follows a declarative, configuration-driven approach. It's designed to:

  1. Dynamically discover plugin directories from lazy.nvim and packer
  2. Aggregate runtime paths from Neovim's runtimepath
  3. Provide enhanced configuration for lua_ls with workspace library, completion, and diagnostics
  4. Apply configuration via vim.lsp.config() API

Implementation Quality

Strengths:

  • Dynamic discovery: Uses vim.fn.glob() to find plugins at runtime
  • Comprehensive coverage: Covers both lazy.nvim and packer (legacy support)
  • Modular design: Separate functions for plugins, runtime, config, completion, diagnostics
  • Sensible defaults: Includes common ignore patterns and reasonable limits

Weaknesses:

  • No caching: Scans directories on every call (could be expensive)
  • No filtering: Includes ALL plugins, even those not relevant to current project
  • No workspace awareness: Doesn't differentiate between project-specific vs global plugins
  • No incremental updates: Can't add/remove paths dynamically

Dependencies

The module depends on:

  1. Neovim APIs:

    • vim.fn.stdpath("data") - Plugin directory location
    • vim.fn.glob() - File pattern matching
    • vim.fn.isdirectory() - Directory validation
    • vim.opt.runtimepath:get() - Runtime paths
    • vim.lsp.config() - LSP configuration API
    • vim.notify() - User notifications
  2. Neovim runtime:

    • vim.list_extend() - Table concatenation
    • vim.tbl_deep_extend() - Table merging (not currently used)

Interaction Points

Current Interactions (None - Commented Out):

  1. lua/lsp/completions.lua - Lines 5, 10 (commented out)
    • Would call workspace_enhancer.apply_enhanced_config()

Potential Integration Points:

  1. lua_ls configuration (lsp/lua_ls.lua) - Could be called in on_init or settings
  2. LSP initialization (lua/lsp/init.lua) - Could be called after VimEnter
  3. TypeScript workspace (lua/config/typescript_workspace.lua) - Similar pattern
  4. Code suggestions (lua/code_suggestions/index/) - Could provide context

Design Comparison with TypeScript Workspace

Aspect workspace_enhancer typescript_workspace
Scope Global (all plugins) Project-specific (monorepo)
Management Static config Dynamic add/remove
Integration One-time apply Event-driven (LspAttach)
User Commands None TswAdd, TswRemove, TswList, TswInit
Auto-init No Yes (LspAttach)

Issues and Improvements

Critical Issues:

  1. Not being used - The module is completely disabled
  2. No caching - Scans directories on every call
  3. No workspace awareness - Includes all plugins regardless of project
  4. No incremental updates - Can't adjust paths dynamically

Design Flaws:

  1. Over-inclusive: Adds ALL plugin directories to workspace, which can cause:
    • Slow lua_ls startup
    • Excessive memory usage
    • Conflicting completions from unrelated plugins
  2. No project filtering: Doesn't respect project boundaries
  3. No performance optimization: No memoization or lazy loading

Recommended Improvements:

  1. Enable the module - Uncomment in lua/lsp/completions.lua
  2. Add caching - Memoize plugin directory scanning
  3. Add project awareness - Only include plugins relevant to current project
  4. Add incremental updates - Support dynamic path addition/removal
  5. Add user commands - Similar to TypeScript workspace management
  6. Add auto-initialization - Trigger on LspAttach for lua_ls

Comparison with TypeScript Workspace Pattern

The typescript_workspace.lua module provides a better pattern:

  • Event-driven: Auto-initializes on LspAttach
  • Dynamic management: Add/remove workspace folders
  • Project-aware: Reads package.json workspaces
  • User commands: Provides Tsw* commands

The workspace_enhancer should follow a similar pattern for Lua projects.

Recommendation

The workspace_enhancer module has a solid design foundation but needs:

  1. Activation - Uncomment and integrate
  2. Caching - Add memoization
  3. Project awareness - Filter plugins by project
  4. Dynamic management - Add/remove paths
  5. User commands - Provide Lsw* commands

Would you like me to create an improved version that addresses these issues?

26,683in / 1,089out