Created
August 30, 2025 23:01
-
-
Save coffebar/59d7496c9735547bacb28059708ff0fd to your computer and use it in GitHub Desktop.
compare ts_ls and volar capabilities at runtime
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| -- Script to compare ts_ls and volar capabilities at runtime | |
| -- This will definitively show what capabilities conflict | |
| local function get_client_caps(client_name) | |
| -- Get list of all active LSP clients | |
| local clients = vim.lsp.get_clients and vim.lsp.get_clients() or vim.lsp.get_active_clients() | |
| for _, client in ipairs(clients) do | |
| if client.name == client_name then | |
| local caps = {} | |
| for capability, value in pairs(client.server_capabilities) do | |
| if value ~= false and value ~= nil then | |
| caps[capability] = true | |
| end | |
| end | |
| return caps | |
| end | |
| end | |
| return {} | |
| end | |
| local function compare_capabilities() | |
| -- Get capabilities from both servers | |
| local ts_caps = get_client_caps("ts_ls") | |
| local volar_caps = get_client_caps("volar") | |
| if next(ts_caps) == nil then | |
| print("Error: ts_ls not found. Make sure a .vue or .ts file is open") | |
| return | |
| end | |
| if next(volar_caps) == nil then | |
| print("Error: volar not found. Make sure a .vue file is open") | |
| return | |
| end | |
| -- Find overlapping capabilities | |
| local conflicts = {} | |
| local volar_only = {} | |
| local ts_only = {} | |
| for cap, _ in pairs(volar_caps) do | |
| if ts_caps[cap] then | |
| table.insert(conflicts, cap) | |
| else | |
| table.insert(volar_only, cap) | |
| end | |
| end | |
| for cap, _ in pairs(ts_caps) do | |
| if not volar_caps[cap] then | |
| table.insert(ts_only, cap) | |
| end | |
| end | |
| -- Sort for consistent output | |
| table.sort(conflicts) | |
| table.sort(volar_only) | |
| table.sort(ts_only) | |
| -- Generate output | |
| local output = {} | |
| table.insert(output, "=== LSP Capability Comparison ===") | |
| table.insert(output, "Date: " .. os.date()) | |
| table.insert(output, "") | |
| table.insert(output, "CONFLICTING CAPABILITIES (both servers provide):") | |
| table.insert(output, "-" .. string.rep("-", 50)) | |
| for _, cap in ipairs(conflicts) do | |
| table.insert(output, " " .. cap) | |
| end | |
| table.insert(output, "") | |
| table.insert(output, "VOLAR-ONLY CAPABILITIES (Vue-specific):") | |
| table.insert(output, "-" .. string.rep("-", 50)) | |
| for _, cap in ipairs(volar_only) do | |
| table.insert(output, " " .. cap) | |
| end | |
| table.insert(output, "") | |
| table.insert(output, "TS_LS-ONLY CAPABILITIES:") | |
| table.insert(output, "-" .. string.rep("-", 50)) | |
| for _, cap in ipairs(ts_only) do | |
| table.insert(output, " " .. cap) | |
| end | |
| -- Generate Neovim config | |
| table.insert(output, "") | |
| table.insert(output, "=== RECOMMENDED CONFIG ===") | |
| table.insert(output, "-" .. string.rep("-", 50)) | |
| table.insert(output, "-- Option 1: Disable conflicts in Volar") | |
| table.insert(output, "on_attach = function(client, _)") | |
| table.insert(output, " if client.name == 'volar' then") | |
| table.insert(output, " local disable = {") | |
| for _, cap in ipairs(conflicts) do | |
| table.insert(output, " '" .. cap .. "',") | |
| end | |
| table.insert(output, " }") | |
| table.insert(output, " for _, cap in ipairs(disable) do") | |
| table.insert(output, " client.server_capabilities[cap] = false") | |
| table.insert(output, " end") | |
| table.insert(output, " end") | |
| table.insert(output, "end") | |
| table.insert(output, "") | |
| table.insert(output, "-- Option 2: Keep only Vue-specific features") | |
| table.insert(output, "on_attach = function(client, _)") | |
| table.insert(output, " if client.name == 'volar' then") | |
| table.insert(output, " local vue_only = {") | |
| for _, cap in ipairs(volar_only) do | |
| table.insert(output, " " .. cap .. " = true,") | |
| end | |
| -- Add essential capabilities | |
| table.insert(output, " textDocumentSync = true,") | |
| table.insert(output, " workspace = true,") | |
| table.insert(output, " }") | |
| table.insert(output, " for capability, _ in pairs(client.server_capabilities) do") | |
| table.insert(output, " if not vue_only[capability] then") | |
| table.insert(output, " client.server_capabilities[capability] = false") | |
| table.insert(output, " end") | |
| table.insert(output, " end") | |
| table.insert(output, " end") | |
| table.insert(output, "end") | |
| -- Write to file | |
| local file = io.open("/tmp/lsp_comparison_results.txt", "w") | |
| if file then | |
| file:write(table.concat(output, "\n")) | |
| file:close() | |
| print("Comparison results written to: /tmp/lsp_comparison_results.txt") | |
| -- Also print summary | |
| print("\n=== SUMMARY ===") | |
| print("Conflicting capabilities: " .. #conflicts) | |
| print("Volar-only capabilities: " .. #volar_only) | |
| print("ts_ls-only capabilities: " .. #ts_only) | |
| print("\nRun :e /tmp/lsp_comparison_results.txt to see full results") | |
| else | |
| -- Print to console if can't write file | |
| print(table.concat(output, "\n")) | |
| end | |
| end | |
| -- Usage: | |
| -- 1. Comment out the on_attach function in your Volar config (lspconfig.lua) | |
| -- 2. Restart Neovim completely (:qa and reopen) | |
| -- 3. Open a .vue file (both ts_ls and volar will start) | |
| -- 4. Run :luafile /tmp/compare_lsp_runtime.lua | |
| -- The comparison will run automatically and save results to /tmp/lsp_comparison_results.txt | |
| -- Run the comparison automatically when this file is sourced | |
| compare_capabilities() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment