diff --git a/lua/core/keymaps.lua b/lua/core/keymaps.lua index 0c3514d2..7e743dd5 100644 --- a/lua/core/keymaps.lua +++ b/lua/core/keymaps.lua @@ -129,12 +129,9 @@ M.dadbod_keymaps = { -- Session management keymaps (all under m for Memory) M.session_keymaps = { - { mode = 'n', lhs = 'ms', rhs = function() _G.MiniSession.save() end, - opts = { desc = 'Memory: Save session' } }, - { mode = 'n', lhs = 'ml', rhs = function() _G.MiniSession.load() end, - opts = { desc = 'Memory: Load session' } }, - { mode = 'n', lhs = 'md', rhs = function() _G.MiniSession.delete() end, - opts = { desc = 'Memory: Delete session' } }, + { mode = 'n', lhs = 'mw', rhs = function() require('mini.sessions').write() end, opts = { desc = 'Memory: Write session' } }, + { mode = 'n', lhs = 'mr', rhs = function() require('mini.sessions').read() end, opts = { desc = 'Memory: Read session' } }, + { mode = 'n', lhs = 'md', rhs = function() require('mini.sessions').delete() end, opts = { desc = 'Memory: Delete session' } }, } -- Setup function for dadbod keymaps @@ -294,6 +291,11 @@ local function init_keymaps() -- Set up session keymaps M.setup_session_keymaps() + -- Set up session keymaps + for _, mapping in ipairs(M.session_keymaps) do + vim.keymap.set(mapping.mode, mapping.lhs, mapping.rhs, mapping.opts) + end + -- Set up git signs keymaps M.setup_gitsigns_keymaps() diff --git a/lua/plugins/nvim-lspconfig.lua b/lua/plugins/nvim-lspconfig.lua index fdc330c0..8f367092 100644 --- a/lua/plugins/nvim-lspconfig.lua +++ b/lua/plugins/nvim-lspconfig.lua @@ -137,6 +137,11 @@ return { local client = vim.lsp.get_client_by_id(args.data.client_id) if not client then return end + -- Disable semantic tokens for gopls + if client.name == "gopls" then + client.server_capabilities.semanticTokensProvider = nil + end + -- Only set up document formatting for null-ls if client.name ~= "null-ls" then client.server_capabilities.documentFormattingProvider = false @@ -188,36 +193,65 @@ return { ensure_installed = vim.tbl_keys(servers), } + -- Custom semantic tokens handler for gopls + local semantic_tokens_handler = function(err, result, ctx, config) + local client = vim.lsp.get_client_by_id(ctx.client_id) + if not client then return end + + -- Check if client has the required semantic tokens capabilities + local semantic_tokens = client.server_capabilities.semanticTokensProvider + if not semantic_tokens or not semantic_tokens.legend then + -- If no legend is provided, disable semantic tokens for this client + client.server_capabilities.semanticTokensProvider = nil + return + end + + -- If we have a valid legend, proceed with default handler + vim.lsp.semantic_tokens.on_full(err, result, ctx, config) + end + mason_lspconfig.setup_handlers { function(server_name) local server_config = servers[server_name] or {} - -- For gopls, disable semantic tokens in capabilities + -- For gopls, add debug logging if server_name == "gopls" then - server_config.capabilities = vim.tbl_deep_extend("force", capabilities, { - textDocument = { - semanticTokens = { - dynamicRegistration = false, - formats = {}, - multilineTokenSupport = false, - overlappingTokenSupport = false, - requests = { - full = false, - range = false, - delta = false - }, - serverCancelSupport = false, - tokenModifiers = {}, - tokenTypes = {} - } - } - }) - else - server_config.capabilities = capabilities + -- Create a custom on_attach that disables semantic tokens + local orig_on_attach = server_config.on_attach + server_config.on_attach = function(client, bufnr) + -- Disable semantic tokens for this client + client.server_capabilities.semanticTokensProvider = nil + -- Call original on_attach if it exists + if orig_on_attach then + orig_on_attach(client, bufnr) + end + end end + server_config.capabilities = capabilities require('lspconfig')[server_name].setup(server_config) end, } + + -- Override the semantic tokens handler to be more resilient + vim.lsp.handlers['textDocument/semanticTokens/full'] = function(err, result, ctx, config) + -- If there's an error or no result, just return + if err or not result then return end + + local client = vim.lsp.get_client_by_id(ctx.client_id) + if not client then return end + + local bufnr = ctx.bufnr + if not bufnr then return end + + -- Get the highlighter safely + local highlighter = vim.lsp.semantic_tokens.create_highlighter(bufnr, client) + if not highlighter then return end + + -- Process the response safely + pcall(function() + highlighter:process_response(result, client, ctx.request.version) + end) + end end, } diff --git a/lua/plugins/session.lua b/lua/plugins/session.lua new file mode 100644 index 00000000..34b9f1e4 --- /dev/null +++ b/lua/plugins/session.lua @@ -0,0 +1,53 @@ +return { + 'echasnovski/mini.sessions', + version = '*', + event = "VimEnter", + config = function() + require('mini.sessions').setup({ + -- Whether to read latest session if Neovim opened without file arguments + autoread = false, + -- Whether to write current session before quitting Neovim + autowrite = true, + -- Directory where global sessions are stored (use `''` to disable) + directory = vim.fn.stdpath('data') .. '/sessions', + -- File for local session (use `''` to disable) + file = '', + -- Whether to force possibly harmful actions (meaning depends on function) + force = { read = false, write = true, delete = false }, + -- Hook functions for actions. Default `nil` means 'do nothing'. + hooks = { + -- Before successful action + pre = { + read = function() + -- Skip session operations for Go projects + local current_dir = vim.fn.getcwd() + local has_go_files = vim.fn.glob(current_dir .. "/*.go") ~= "" or + vim.fn.glob(current_dir .. "/go.mod") ~= "" or + vim.fn.glob(current_dir .. "/go.work") ~= "" + + if has_go_files then + return false -- Skip for Go projects + end + return true + end, + write = function() + -- Skip session operations for Go projects + local current_dir = vim.fn.getcwd() + local has_go_files = vim.fn.glob(current_dir .. "/*.go") ~= "" or + vim.fn.glob(current_dir .. "/go.mod") ~= "" or + vim.fn.glob(current_dir .. "/go.work") ~= "" + + if has_go_files then + return false -- Skip for Go projects + end + return true + end, + }, + -- After successful action + post = { read = nil, write = nil, delete = nil }, + }, + -- Whether to print session path after action + verbose = { read = false, write = true, delete = true }, + }) + end +}