diff --git a/init.lua b/init.lua index 3adacdeef9f..951003f38f3 100644 --- a/init.lua +++ b/init.lua @@ -164,6 +164,12 @@ vim.o.scrolloff = 10 -- See `:help 'confirm'` vim.o.confirm = true +-- Disable line wrapping +vim.o.wrap = false + +-- Highlight max chars per line +-- vim.o.colorcolumn = '120' + -- [[ Basic Keymaps ]] -- See `:help vim.keymap.set()` @@ -197,6 +203,9 @@ vim.keymap.set('n', 'q', vim.diagnostic.setloclist, { desc = 'Open diagn -- or just use to exit terminal mode vim.keymap.set('t', '', '', { desc = 'Exit terminal mode' }) +-- Close current buffer +vim.keymap.set('n', 'Q', ':bd', { desc = 'Close current buffer' }) + -- TIP: Disable arrow keys in normal mode -- vim.keymap.set('n', '', 'echo "Use h to move!!"') -- vim.keymap.set('n', '', 'echo "Use l to move!!"') @@ -227,7 +236,29 @@ vim.keymap.set('n', '', '', { desc = 'Move focus to the upper win vim.api.nvim_create_autocmd('TextYankPost', { desc = 'Highlight when yanking (copying) text', group = vim.api.nvim_create_augroup('kickstart-highlight-yank', { clear = true }), - callback = function() vim.hl.on_yank() end, + callback = function() vim.hl.on_yank { timeout = 200 } end, +}) + +-- Restore cursor position on file open +vim.api.nvim_create_autocmd('BufReadPost', { + desc = 'Restore cursor position on file open', + group = vim.api.nvim_create_augroup('kickstart-restore-cursor', { clear = true }), + pattern = '*', + callback = function() + local line = vim.fn.line '\'"' + if line > 1 and line <= vim.fn.line '$' then vim.cmd 'normal! g\'"' end + end, +}) + +-- auto-create missing dirs when saving a file +vim.api.nvim_create_autocmd('BufWritePre', { + desc = 'Auto-create missing dirs when saving a file', + group = vim.api.nvim_create_augroup('kickstart-auto-create-dir', { clear = true }), + pattern = '*', + callback = function() + local dir = vim.fn.expand ':p:h' + if vim.fn.isdirectory(dir) == 0 then vim.fn.mkdir(dir, 'p') end + end, }) -- [[ Install `lazy.nvim` plugin manager ]] @@ -269,6 +300,10 @@ require('lazy').setup({ -- end, -- } -- + -- For plugins written in VimScript, use `init = function() ... end` to set + -- configuration options, usually in the format `vim.g.*`. This can also + -- contain conditionals or any other setup logic you need for the plugin. + -- -- Here is a more advanced example where we pass configuration -- options to `gitsigns.nvim`. -- @@ -559,6 +594,9 @@ require('lazy').setup({ -- For example, in C this would take you to the header. map('grD', vim.lsp.buf.declaration, '[G]oto [D]eclaration') + -- Toggle to show/hide diagnostic messages + map('td', function() vim.diagnostic.enable(not vim.diagnostic.is_enabled()) end, '[T]oggle [D]iagnostics') + -- The following two autocommands are used to highlight references of the -- word under your cursor when your cursor rests there for a little while. -- See `:help CursorHold` for information about when this is executed @@ -598,52 +636,84 @@ require('lazy').setup({ end, }) - -- Enable the following language servers - -- Feel free to add/remove any LSPs that you want here. They will automatically be installed. - -- See `:help lsp-config` for information about keys and how to configure - ---@type table + -- LSP servers and clients are able to communicate to each other what features they support. + -- By default, Neovim doesn't support everything that is in the LSP specification. + -- When you add blink.cmp, luasnip, etc. Neovim now has *more* capabilities. + -- So, we create new capabilities with blink.cmp, and then broadcast that to the servers. + -- NOTE: The following line is now commented as blink.cmp extends capabilites by default from its internal code: + -- https://github.com/Saghen/blink.cmp/blob/102db2f5996a46818661845cf283484870b60450/plugin/blink-cmp.lua + -- It has been left here as a comment for educational purposes (as the predecessor completion plugin required this explicit step). + -- + -- local capabilities = require("blink.cmp").get_lsp_capabilities() + + -- Language servers can broadly be installed in the following ways: + -- 1) via the mason package manager; or + -- 2) via your system's package manager; or + -- 3) via a release binary from a language server's repo that's accessible somewhere on your system. + + -- The servers table comprises of the following sub-tables: + -- 1. mason + -- 2. others + -- Both these tables have an identical structure of language server names as keys and + -- a table of language server configuration as values. + ---@class LspServersConfig + ---@field mason table + ---@field others table local servers = { - -- clangd = {}, - -- gopls = {}, - -- pyright = {}, - -- rust_analyzer = {}, - -- - -- Some languages (like typescript) have entire language plugins that can be useful: - -- https://github.com/pmizio/typescript-tools.nvim + -- Add any additional override configuration in any of the following tables. Available keys are: + -- - cmd (table): Override the default command used to start the server + -- - filetypes (table): Override the default list of associated filetypes for the server + -- - capabilities (table): Override fields in capabilities. Can be used to disable certain LSP features. + -- - settings (table): Override the default settings passed when initializing the server. + -- For example, to see the options for `lua_ls`, you could go to: https://luals.github.io/wiki/settings/ -- - -- But for many setups, the LSP (`ts_ls`) will work just fine - -- ts_ls = {}, - - stylua = {}, -- Used to format Lua code - - -- Special Lua Config, as recommended by neovim help docs - lua_ls = { - on_init = function(client) - if client.workspace_folders then - local path = client.workspace_folders[1].name - if path ~= vim.fn.stdpath 'config' and (vim.uv.fs_stat(path .. '/.luarc.json') or vim.uv.fs_stat(path .. '/.luarc.jsonc')) then return end - end - - client.config.settings.Lua = vim.tbl_deep_extend('force', client.config.settings.Lua, { - runtime = { - version = 'LuaJIT', - path = { 'lua/?.lua', 'lua/?/init.lua' }, - }, - workspace = { - checkThirdParty = false, - -- 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 - library = vim.tbl_extend('force', vim.api.nvim_get_runtime_file('', true), { - '${3rd}/luv/library', - '${3rd}/busted/library', - }), - }, - }) - end, - settings = { - Lua = {}, + -- Feel free to add/remove any LSPs here that you want to install via Mason. They will automatically be installed and setup. + mason = { + -- clangd = {}, + -- gopls = {}, + -- pyright = {}, + -- rust_analyzer = {}, + -- ... etc. See `:help lspconfig-all` for a list of all the pre-configured LSPs + -- + -- Some languages (like typescript) have entire language plugins that can be useful: + -- https://github.com/pmizio/typescript-tools.nvim + -- + -- But for many setups, the LSP (`ts_ls`) will work just fine + -- ts_ls = {}, + -- + lua_ls = { + on_init = function(client) + if client.workspace_folders then + local path = client.workspace_folders[1].name + if path ~= vim.fn.stdpath 'config' and (vim.uv.fs_stat(path .. '/.luarc.json') or vim.uv.fs_stat(path .. '/.luarc.jsonc')) then return end + end + + client.config.settings.Lua = vim.tbl_deep_extend('force', client.config.settings.Lua, { + runtime = { + version = 'LuaJIT', + path = { 'lua/?.lua', 'lua/?/init.lua' }, + }, + workspace = { + checkThirdParty = false, + -- 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 + library = vim.tbl_extend('force', vim.api.nvim_get_runtime_file('', true), { + '${3rd}/luv/library', + '${3rd}/busted/library', + }), + }, + }) + end, + settings = { + Lua = {}, + }, }, }, + -- This table contains config for all language servers that are *not* installed via Mason. + -- Structure is identical to the mason table from above. + others = { + -- dartls = {}, + }, } -- Ensure the servers and tools above are installed @@ -653,17 +723,34 @@ require('lazy').setup({ -- :Mason -- -- You can press `g?` for help in this menu. - local ensure_installed = vim.tbl_keys(servers or {}) + -- + -- `mason` had to be setup earlier: to configure its options see the + -- `dependencies` table for `nvim-lspconfig` above. + -- + -- You can add other tools here that you want Mason to install + -- for you, so that they are available from within Neovim. + local ensure_installed = vim.tbl_keys(servers.mason or {}) vim.list_extend(ensure_installed, { -- You can add other tools here that you want Mason to install }) require('mason-tool-installer').setup { ensure_installed = ensure_installed } - for name, server in pairs(servers) do - vim.lsp.config(name, server) - vim.lsp.enable(name) + -- Either merge all additional server configs from the `servers.mason` and `servers.others` tables + -- to the default language server configs as provided by nvim-lspconfig or + -- define a custom server config that's unavailable on nvim-lspconfig. + for server, config in pairs(vim.tbl_extend('keep', servers.mason, servers.others)) do + if not vim.tbl_isempty(config) then vim.lsp.config(server, config) end end + + -- After configuring our language servers, we now enable them + require('mason-lspconfig').setup { + ensure_installed = {}, -- explicitly set to an empty table (Kickstart populates installs via mason-tool-installer) + automatic_enable = true, -- automatically run vim.lsp.enable() for all servers that are installed via Mason + } + + -- Manually run vim.lsp.enable for all language servers that are *not* installed via Mason + if not vim.tbl_isempty(servers.others) then vim.lsp.enable(vim.tbl_keys(servers.others)) end end, }, @@ -782,7 +869,22 @@ require('lazy').setup({ }, sources = { - default = { 'lsp', 'path', 'snippets' }, + default = { 'lsp', 'path', 'snippets', 'buffer' }, + providers = { + buffer = { + -- Make buffer completions appear at the end. + score_offset = -100, + enabled = function() + -- Filetypes for which buffer completions are enabled; add filetypes to extend: + local enabled_filetypes = { + 'markdown', + 'text', + } + local filetype = vim.bo.filetype + return vim.tbl_contains(enabled_filetypes, filetype) + end, + }, + }, }, snippets = { preset = 'luasnip' }, diff --git a/lua/kickstart/plugins/debug.lua b/lua/kickstart/plugins/debug.lua index 7e58905e830..5ff1b4b87fd 100644 --- a/lua/kickstart/plugins/debug.lua +++ b/lua/kickstart/plugins/debug.lua @@ -33,7 +33,66 @@ return { { '', function() require('dap').step_over() end, desc = 'Debug: Step Over' }, { '', function() require('dap').step_out() end, desc = 'Debug: Step Out' }, { 'b', function() require('dap').toggle_breakpoint() end, desc = 'Debug: Toggle Breakpoint' }, - { 'B', function() require('dap').set_breakpoint(vim.fn.input 'Breakpoint condition: ') end, desc = 'Debug: Set Breakpoint' }, + { + 'B', + function() + local dap = require 'dap' + + -- Search for an existing breakpoint on this line in this buffer + ---@return dap.SourceBreakpoint bp that was either found, or an empty placeholder + local function find_bp() + local buf_bps = require('dap.breakpoints').get(vim.fn.bufnr())[vim.fn.bufnr()] + ---@type dap.SourceBreakpoint + for _, candidate in ipairs(buf_bps) do + if candidate.line and candidate.line == vim.fn.line '.' then return candidate end + end + + return { condition = '', logMessage = '', hitCondition = '', line = vim.fn.line '.' } + end + + -- Elicit customization via a UI prompt + ---@param bp dap.SourceBreakpoint a breakpoint + local function customize_bp(bp) + local props = { + ['Condition'] = { + value = bp.condition, + setter = function(v) bp.condition = v end, + }, + ['Hit Condition'] = { + value = bp.hitCondition, + setter = function(v) bp.hitCondition = v end, + }, + ['Log Message'] = { + value = bp.logMessage, + setter = function(v) bp.logMessage = v end, + }, + } + local menu_options = {} + for k, _ in pairs(props) do + table.insert(menu_options, k) + end + vim.ui.select(menu_options, { + prompt = 'Edit Breakpoint', + format_item = function(item) return ('%s: %s'):format(item, props[item].value) end, + }, function(choice) + if choice == nil then + -- User cancelled the selection + return + end + props[choice].setter(vim.fn.input { + prompt = ('[%s] '):format(choice), + default = props[choice].value, + }) + + -- Set breakpoint for current line, with customizations (see h:dap.set_breakpoint()) + dap.set_breakpoint(bp.condition, bp.hitCondition, bp.logMessage) + end) + end + + customize_bp(find_bp()) + end, + desc = 'Debug: Edit Breakpoint', + }, -- Toggle to see last session result. Without this, you can't see session output in case of unhandled exception. { '', function() require('dapui').toggle() end, desc = 'Debug: See last session result.' }, },