diff --git a/init.lua b/init.lua index f06caeb4f56..aaa952555ae 100644 --- a/init.lua +++ b/init.lua @@ -1,47 +1,4 @@ ---[[ - -===================================================================== -==================== READ THIS BEFORE CONTINUING ==================== -===================================================================== -======== .-----. ======== -======== .----------------------. | === | ======== -======== |.-""""""""""""""""""-.| |-----| ======== -======== || || | === | ======== -======== || KICKSTART.NVIM || |-----| ======== -======== || || | === | ======== -======== || || |-----| ======== -======== ||:Tutor || |:::::| ======== -======== |'-..................-'| |____o| ======== -======== `"")----------------(""` ___________ ======== -======== /::::::::::| |::::::::::\ \ no mouse \ ======== -======== /:::========| |==hjkl==:::\ \ required \ ======== -======== '""""""""""""' '""""""""""""' '""""""""""' ======== -======== ======== -===================================================================== -===================================================================== - -What is Kickstart? - - Kickstart.nvim is *not* a distribution. - - Kickstart.nvim is a starting point for your own configuration. - The goal is that you can read every line of code, top-to-bottom, understand - what your configuration is doing, and modify it to suit your needs. - - Once you've done that, you can start exploring, configuring and tinkering to - make Neovim your own! That might mean leaving Kickstart just the way it is for a while - or immediately breaking it into modular pieces. It's up to you! - - If you don't know anything about Lua, I recommend taking some time to read through - a guide. One possible example which will only take 10-15 minutes: - - https://learnxinyminutes.com/docs/lua/ - - After understanding a bit more about Lua, you can use `:help lua-guide` as a - reference for how Neovim integrates Lua. - - :help lua-guide - - (or HTML version): https://neovim.io/doc/user/lua-guide.html - -Kickstart Guide: +--[[Kickstart Guide: TODO: The very first thing you should do is to run the command `:Tutor` in Neovim. @@ -78,10 +35,6 @@ Kickstart Guide: If you experience any errors while trying to install kickstart, run `:checkhealth` for more info. -I hope you enjoy your Neovim journey, -- TJ - -P.S. You can delete this when you're done too. It's your config now! :) --]] -- ============================================================ @@ -99,7 +52,7 @@ do vim.g.maplocalleader = ' ' -- Set to true if you have a Nerd Font installed and selected in the terminal - vim.g.have_nerd_font = false + vim.g.have_nerd_font = true -- [[ Setting options ]] -- See `:help vim.o` @@ -218,7 +171,15 @@ do -- NOTE: This won't work in all terminal emulators/tmux/etc. Try your own mapping -- or just use to exit terminal mode vim.keymap.set('t', '', '', { desc = 'Exit terminal mode' }) - + vim.keymap.set('n', 'tt', function() + vim.cmd 'botright split' + vim.cmd 'resize 12' + vim.cmd 'terminal' + + vim.opt_local.number = false + vim.opt_local.relativenumber = false + vim.opt_local.signcolumn = 'no' + end, { desc = '[T]erminal split' }) -- 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!!"') @@ -233,7 +194,6 @@ do vim.keymap.set('n', '', '', { desc = 'Move focus to the right window' }) vim.keymap.set('n', '', '', { desc = 'Move focus to the lower window' }) vim.keymap.set('n', '', '', { desc = 'Move focus to the upper window' }) - -- NOTE: Some terminals have colliding keymaps or are not able to send distinct keycodes -- vim.keymap.set("n", "", "H", { desc = "Move window to the left" }) -- vim.keymap.set("n", "", "L", { desc = "Move window to the right" }) @@ -252,7 +212,16 @@ do callback = function() vim.hl.on_yank() end, }) end - +-- C# files usually use 4 spaces. +vim.api.nvim_create_autocmd('FileType', { + pattern = 'cs', + callback = function() + vim.bo.shiftwidth = 4 + vim.bo.tabstop = 4 + vim.bo.softtabstop = 4 + vim.bo.expandtab = true + end, +}) -- ============================================================ -- SECTION 3: PLUGIN MANAGER INTRO -- vim.pack intro, build hooks @@ -364,40 +333,40 @@ do -- Useful plugin to show you pending keybinds. vim.pack.add { gh 'folke/which-key.nvim' } require('which-key').setup { - -- Delay between pressing a key and opening which-key (milliseconds) delay = 0, icons = { mappings = vim.g.have_nerd_font }, - -- Document existing key chains spec = { { 's', group = '[S]earch', mode = { 'n', 'v' } }, { 't', group = '[T]oggle' }, - { 'h', group = 'Git [H]unk', mode = { 'n', 'v' } }, -- Enable gitsigns recommended keymaps first + { 'h', group = '[H]arpoon / Git Hunk', mode = { 'n', 'v' } }, + { 'c', group = '[C]ode / C#' }, + { 'x', group = 'Trouble' }, + { 'o', group = '[O]verseer / Tasks' }, { 'gr', group = 'LSP Actions', mode = { 'n' } }, }, } - -- [[ Colorscheme ]] -- You can easily change to a different colorscheme. -- Change the name of the colorscheme plugin below, and then -- change the command under that to load whatever the name of that colorscheme is. -- -- If you want to see what colorschemes are already installed, you can use `:Telescope colorscheme`. + -- Highlight todo, notes, etc in comments + -- [[ Colorscheme ]] + + -- [[ Colorscheme ]] + vim.pack.add { gh 'folke/tokyonight.nvim' } - ---@diagnostic disable-next-line: missing-fields + + vim.o.termguicolors = true + vim.o.background = 'dark' + require('tokyonight').setup { - styles = { - comments = { italic = false }, -- Disable italics in comments - }, + style = 'night', } - -- Load the colorscheme here. - -- Like many other themes, this one has different styles, and you could load - -- any other, such as 'tokyonight-storm', 'tokyonight-moon', or 'tokyonight-day'. - vim.cmd.colorscheme 'tokyonight-night' - - -- Highlight todo, notes, etc in comments - vim.pack.add { gh 'folke/todo-comments.nvim' } - require('todo-comments').setup { signs = false } + vim.cmd.colorscheme 'tokyonight' + require('todo-comments').setup { signs = true } -- [[ mini.nvim ]] -- A collection of various small independent plugins/modules @@ -488,6 +457,65 @@ do -- NOTE: You can install multiple plugins at once vim.pack.add(telescope_plugins) + -- [[ Harpoon ]] + -- Quick file marking and jumping. + -- Great for switching between your main project files without searching every time. + vim.pack.add { + { + src = gh 'ThePrimeagen/harpoon', + version = 'harpoon2', + }, + } + + local harpoon = require 'harpoon' + harpoon:setup {} + + vim.keymap.set('n', 'ha', function() harpoon:list():add() end, { desc = '[H]arpoon [A]dd file' }) + + vim.keymap.set('n', 'hh', function() harpoon.ui:toggle_quick_menu(harpoon:list()) end, { desc = '[H]arpoon menu' }) + + vim.keymap.set('n', 'h1', function() harpoon:list():select(1) end, { desc = '[H]arpoon file 1' }) + + vim.keymap.set('n', 'h2', function() harpoon:list():select(2) end, { desc = '[H]arpoon file 2' }) + + vim.keymap.set('n', 'h3', function() harpoon:list():select(3) end, { desc = '[H]arpoon file 3' }) + + vim.keymap.set('n', 'h4', function() harpoon:list():select(4) end, { desc = '[H]arpoon file 4' }) + + vim.keymap.set('n', 'hn', function() harpoon:list():next() end, { desc = '[H]arpoon [N]ext file' }) + + vim.keymap.set('n', 'hp', function() harpoon:list():prev() end, { desc = '[H]arpoon [P]revious file' }) + + -- [[ Trouble ]] + -- Better diagnostics, references, symbols, quickfix, and LSP result lists. + vim.pack.add { gh 'folke/trouble.nvim' } + + require('trouble').setup {} + + vim.keymap.set('n', 'xx', 'Trouble diagnostics toggle', { desc = 'Trouble diagnostics' }) + vim.keymap.set('n', 'xX', 'Trouble diagnostics toggle filter.buf=0', { desc = 'Trouble buffer diagnostics' }) + vim.keymap.set('n', 'xs', 'Trouble symbols toggle', { desc = 'Trouble symbols' }) + vim.keymap.set('n', 'xl', 'Trouble lsp toggle', { desc = 'Trouble LSP' }) + vim.keymap.set('n', 'xq', 'Trouble qflist toggle', { desc = 'Trouble quickfix list' }) + vim.keymap.set('n', 'xlc', 'Trouble loclist toggle', { desc = 'Trouble location list' }) + + -- [[ Oil ]] + -- File explorer that lets you edit directories like normal buffers. + -- Great for creating, renaming, moving, and deleting files/folders. + vim.pack.add { gh 'stevearc/oil.nvim' } + + require('oil').setup { + default_file_explorer = false, + view_options = { + show_hidden = true, + }, + } + + -- Open the parent directory of the current file. + vim.keymap.set('n', '-', 'Oil', { desc = 'Open parent directory' }) + + -- Open Oil with a leader key. + vim.keymap.set('n', 'e', 'Oil', { desc = '[E]xplore files' }) -- See `:help telescope` and `:help telescope.setup()` require('telescope').setup { @@ -590,72 +618,50 @@ end -- ============================================================ do -- [[ LSP Configuration ]] - -- Brief aside: **What is LSP?** - -- - -- LSP is an initialism you've probably heard, but might not understand what it is. - -- - -- LSP stands for Language Server Protocol. It's a protocol that helps editors - -- and language tooling communicate in a standardized fashion. - -- - -- In general, you have a "server" which is some tool built to understand a particular - -- language (such as `gopls`, `lua_ls`, `rust_analyzer`, etc.). These Language Servers - -- (sometimes called LSP servers, but that's kind of like ATM Machine) are standalone - -- processes that communicate with some "client" - in this case, Neovim! - -- - -- LSP provides Neovim with features like: - -- - Go to definition - -- - Find references - -- - Autocompletion - -- - Symbol Search - -- - and more! - -- - -- Thus, Language Servers are external tools that must be installed separately from - -- Neovim. This is where `mason` and related plugins come into play. - -- - -- If you're wondering about lsp vs treesitter, you can check out the wonderfully - -- and elegantly composed help section, `:help lsp-vs-treesitter` -- Useful status updates for LSP. vim.pack.add { gh 'j-hui/fidget.nvim' } require('fidget').setup {} - -- This function gets run when an LSP attaches to a particular buffer. - -- That is to say, every time a new file is opened that is associated with - -- an lsp (for example, opening `main.rs` is associated with `rust_analyzer`) this - -- function will be executed to configure the current buffer + -- LSP keymaps that activate when an LSP attaches to a buffer. vim.api.nvim_create_autocmd('LspAttach', { group = vim.api.nvim_create_augroup('kickstart-lsp-attach', { clear = true }), callback = function(event) - -- NOTE: Remember that Lua is a real programming language, and as such it is possible - -- to define small helper and utility functions so you don't have to repeat yourself. - -- - -- In this case, we create a function that lets us more easily define mappings specific - -- for LSP related items. It sets the mode, buffer and description for us each time. local map = function(keys, func, desc, mode) mode = mode or 'n' vim.keymap.set(mode, keys, func, { buffer = event.buf, desc = 'LSP: ' .. desc }) end - -- Rename the variable under your cursor. - -- Most Language Servers support renaming across files, etc. + -- Rename the variable, method, class, etc. under your cursor. map('grn', vim.lsp.buf.rename, '[R]e[n]ame') - -- Execute a code action, usually your cursor needs to be on top of an error - -- or a suggestion from your LSP for this to activate. + -- Execute a code action. map('gra', vim.lsp.buf.code_action, '[G]oto Code [A]ction', { 'n', 'x' }) - -- WARN: This is not Goto Definition, this is Goto Declaration. - -- For example, in C this would take you to the header. + -- Go to declaration. map('grD', vim.lsp.buf.declaration, '[G]oto [D]eclaration') - -- 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 - -- - -- When you move your cursor, the highlights will be cleared (the second autocommand). + -- Format the current buffer. + map('cf', function() vim.lsp.buf.format { async = true } end, '[C]ode [F]ormat') + + -- Show diagnostics under cursor. + map( + 'cd', + function() + vim.diagnostic.open_float { + scope = 'cursor', + border = 'rounded', + } + end, + '[C]ode [D]iagnostics' + ) + local client = vim.lsp.get_client_by_id(event.data.client_id) + + -- Highlight references of the word under your cursor. if client and client:supports_method('textDocument/documentHighlight', event.buf) then local highlight_augroup = vim.api.nvim_create_augroup('kickstart-lsp-highlight', { clear = false }) + vim.api.nvim_create_autocmd({ 'CursorHold', 'CursorHoldI' }, { buffer = event.buf, group = highlight_augroup, @@ -677,62 +683,60 @@ do }) end - -- The following code creates a keymap to toggle inlay hints in your - -- code, if the language server you are using supports them - -- - -- This may be unwanted, since they displace some of your code + -- Toggle inlay hints if supported. if client and client:supports_method('textDocument/inlayHint', event.buf) then - map('th', function() vim.lsp.inlay_hint.enable(not vim.lsp.inlay_hint.is_enabled { bufnr = event.buf }) end, '[T]oggle Inlay [H]ints') + map( + 'th', + function() + vim.lsp.inlay_hint.enable(not vim.lsp.inlay_hint.is_enabled { bufnr = event.buf }, { + bufnr = event.buf, + }) + end, + '[T]oggle Inlay [H]ints' + ) end 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 + -- Regular LSP servers. + -- IMPORTANT: + -- Do not put roslyn here. + -- Do not put stylua here. ---@type 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 - -- - -- 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) - client.server_capabilities.documentFormattingProvider = false -- Disable formatting (formatting is done by stylua) + -- Formatting is handled by stylua, not lua_ls. + client.server_capabilities.documentFormattingProvider = false 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 - local current_settings = client.config.settings --[[@as lspconfig.settings.lua_ls]] - client.config.settings.Lua = vim.tbl_deep_extend('force', current_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.api.nvim_get_runtime_file('', true), + client.config.settings = vim.tbl_deep_extend('force', client.config.settings or {}, { + Lua = { + runtime = { + version = 'LuaJIT', + path = { 'lua/?.lua', 'lua/?/init.lua' }, + }, + workspace = { + checkThirdParty = false, + library = vim.tbl_extend('force', vim.api.nvim_get_runtime_file('', true), { + '${3rd}/luv/library', + '${3rd}/busted/library', + }), + }, }, }) end, - ---@type lspconfig.settings.lua_ls + settings = { Lua = { - format = { enable = false }, -- Disable formatting (formatting is done by stylua) + format = { + enable = false, + }, }, }, }, @@ -743,34 +747,91 @@ do gh 'mason-org/mason.nvim', gh 'mason-org/mason-lspconfig.nvim', gh 'WhoIsSethDaniel/mason-tool-installer.nvim', - } - -- Automatically install LSPs and related tools to stdpath for Neovim - require('mason').setup {} + -- C# Roslyn support. + gh 'seblyng/roslyn.nvim', + } - -- Translates between nvim-lspconfig server names and mason.nvim package names (e.g. lua_ls <-> lua-language-server) - require('mason-lspconfig').setup { - automatic_enable = false, -- Change this to true if you want to automatically enable servers that are installed manually (e.g. via :Mason / :MasonInstall) + -- Mason setup. + -- Roslyn.nvim recommends this custom registry because it provides a newer Roslyn package. + -- It provides `roslyn` and `roslyn-nightly`. + require('mason').setup { + registries = { + 'github:mason-org/mason-registry', + 'github:Crashdummyy/mason-registry', + }, } - -- Ensure the servers and tools above are installed - -- - -- To check the current status of installed tools and/or manually install - -- other tools, you can run - -- :Mason - -- - -- You can press `g?` for help in this menu. - local ensure_installed = vim.tbl_keys(servers or {}) - vim.list_extend(ensure_installed, { - -- You can add other tools here that you want Mason to install - }) + -- Tools to install through Mason. + -- Keep formatters/tools separate from LSP servers. + local ensure_installed = { + 'lua_ls', + 'stylua', + 'roslyn', + } - require('mason-tool-installer').setup { ensure_installed = ensure_installed } + require('mason-tool-installer').setup { + ensure_installed = ensure_installed, + } + -- Enable regular LSP servers. for name, server in pairs(servers) do vim.lsp.config(name, server) vim.lsp.enable(name) end + + -- Configure Roslyn language server settings. + -- Roslyn.nvim docs say server settings should be passed through vim.lsp.config("roslyn", ...). + vim.lsp.config('roslyn', { + settings = { + ['csharp|background_analysis'] = { + dotnet_analyzer_diagnostics_scope = 'fullSolution', + dotnet_compiler_diagnostics_scope = 'fullSolution', + }, + + ['csharp|completion'] = { + dotnet_show_completion_items_from_unimported_namespaces = true, + dotnet_show_name_completion_suggestions = true, + }, + + ['csharp|inlay_hints'] = { + csharp_enable_inlay_hints_for_implicit_object_creation = true, + csharp_enable_inlay_hints_for_implicit_variable_types = true, + csharp_enable_inlay_hints_for_lambda_parameter_types = true, + csharp_enable_inlay_hints_for_types = true, + + dotnet_enable_inlay_hints_for_indexer_parameters = true, + dotnet_enable_inlay_hints_for_literal_parameters = true, + dotnet_enable_inlay_hints_for_object_creation_parameters = true, + dotnet_enable_inlay_hints_for_other_parameters = true, + dotnet_enable_inlay_hints_for_parameters = true, + + dotnet_suppress_inlay_hints_for_parameters_that_differ_only_by_suffix = true, + dotnet_suppress_inlay_hints_for_parameters_that_match_argument_name = true, + dotnet_suppress_inlay_hints_for_parameters_that_match_method_intent = true, + }, + + ['csharp|code_lens'] = { + dotnet_enable_references_code_lens = true, + dotnet_enable_tests_code_lens = true, + }, + + ['csharp|symbol_search'] = { + dotnet_search_reference_assemblies = true, + }, + + ['csharp|formatting'] = { + dotnet_organize_imports_on_format = true, + }, + }, + }) + + -- Start roslyn.nvim. + require('roslyn').setup { + broad_search = true, + lock_target = false, + silent = false, + } end -- ============================================================ @@ -785,7 +846,8 @@ do format_on_save = function(bufnr) -- You can specify filetypes to autoformat on save here: local enabled_filetypes = { - -- lua = true, + lua = true, + cs = true, -- python = true, } if enabled_filetypes[vim.bo[bufnr].filetype] then @@ -802,7 +864,8 @@ do -- rust = { 'rustfmt' }, -- Conform can also run multiple formatters sequentially -- python = { "isort", "black" }, - -- + lua = { 'stylua' }, + cs = {}, -- You can use 'stop_after_first' to run the first available formatter from the list -- javascript = { "prettierd", "prettier", stop_after_first = true }, }, @@ -812,6 +875,84 @@ do end -- ============================================================ +-- SECTION 6.5: TASK RUNNER +-- Overseer setup for dotnet build/run/test +-- ============================================================ +do + -- [[ Overseer ]] + -- Task runner for commands like dotnet build, dotnet run, and dotnet test. + vim.pack.add { gh 'stevearc/overseer.nvim' } + + local overseer = require 'overseer' + + overseer.setup {} + + overseer.register_template { + name = 'dotnet build', + builder = function() + return { + cmd = { 'dotnet' }, + args = { 'build' }, + components = { + 'default', + 'on_output_quickfix', + 'on_result_diagnostics', + }, + } + end, + } + + overseer.register_template { + name = 'dotnet run', + builder = function() + return { + cmd = { 'dotnet' }, + args = { 'run' }, + components = { + 'default', + }, + } + end, + } + + overseer.register_template { + name = 'dotnet test', + builder = function() + return { + cmd = { 'dotnet' }, + args = { 'test' }, + components = { + 'default', + 'on_output_quickfix', + 'on_result_diagnostics', + }, + } + end, + } + + overseer.register_template { + name = 'dotnet watch run', + builder = function() + return { + cmd = { 'dotnet' }, + args = { 'watch', 'run' }, + components = { + 'default', + }, + } + end, + } + + vim.keymap.set('n', 'oo', 'OverseerToggle', { desc = '[O]verseer [O]pen' }) + + vim.keymap.set('n', 'ob', function() overseer.run_task { name = 'dotnet build' } end, { desc = '[O]verseer dotnet [B]uild' }) + + vim.keymap.set('n', 'or', function() overseer.run_task { name = 'dotnet run' } end, { desc = '[O]verseer dotnet [R]un' }) + + vim.keymap.set('n', 'ot', function() overseer.run_task { name = 'dotnet test' } end, { desc = '[O]verseer dotnet [T]est' }) + + vim.keymap.set('n', 'ow', function() overseer.run_task { name = 'dotnet watch run' } end, { desc = '[O]verseer dotnet [W]atch run' }) +end -- ============================================================ -- SECTION 8: AUTOCOMPLETE & SNIPPETS -- blink.cmp and luasnip setup -- ============================================================ @@ -907,7 +1048,24 @@ do vim.pack.add { { src = gh 'nvim-treesitter/nvim-treesitter', version = 'main' } } -- Ensure basic parsers are installed - local parsers = { 'bash', 'c', 'diff', 'html', 'lua', 'luadoc', 'markdown', 'markdown_inline', 'query', 'vim', 'vimdoc' } + local parsers = { + 'bash', + 'c', + 'diff', + 'html', + 'lua', + 'luadoc', + 'markdown', + 'markdown_inline', + 'query', + 'vim', + 'vimdoc', + 'c_sharp', + 'xml', + 'json', + 'yaml', + 'toml', + } require('nvim-treesitter').install(parsers) ---@param buf integer @@ -970,10 +1128,10 @@ do -- Uncomment any of the lines below to enable them (you will need to restart nvim). -- -- require 'kickstart.plugins.debug' - -- require 'kickstart.plugins.indent_line' - -- require 'kickstart.plugins.lint' - -- require 'kickstart.plugins.autopairs' - -- require 'kickstart.plugins.neo-tree' + require 'kickstart.plugins.indent_line' + require 'kickstart.plugins.lint' + require 'kickstart.plugins.autopairs' + --require 'kickstart.plugins.neo-tree' -- require 'kickstart.plugins.gitsigns' -- adds gitsigns recommended keymaps -- NOTE: You can add your own plugins, configuration, etc from `lua/custom/plugins/*.lua`