diff --git a/.gitignore b/.gitignore index a52bd495579..a074298234b 100644 --- a/.gitignore +++ b/.gitignore @@ -5,10 +5,4 @@ nvim spell/ -# In your personal fork, you likely want to comment this, since it's recommended to track -# nvim-pack-lock.json in version control - see :help vim.pack-lockfile -# For the official `nvim-lua/kickstart.nvim` git repository, we leave it ignored to avoid unneeded -# merge conflicts. -nvim-pack-lock.json - .DS_Store diff --git a/init.lua b/init.lua index feb5b5f6c95..6122ab79cd8 100644 --- a/init.lua +++ b/init.lua @@ -99,7 +99,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` @@ -185,6 +185,42 @@ do -- See `:help hlsearch` vim.keymap.set('n', '', 'nohlsearch') + -- Close the current buffer with a double . + -- - Special windows (nvim-tree, help, quickfix, ...) are closed instead of having their buffer deleted. + -- - If other files are open, the window stays and shows the next one (mini.bufremove). + -- - If this was the last file, its window is closed too (unless it's the only window). + -- - If the buffer has unsaved changes, ask whether to save, discard, or cancel. + local function close_buffer(force) + local buf = vim.api.nvim_get_current_buf() + local has_other_files = vim.iter(vim.api.nvim_list_bufs()):any(function(b) return b ~= buf and vim.bo[b].buflisted end) + + if not has_other_files and #vim.api.nvim_tabpage_list_wins(0) > 1 then + vim.cmd.close() + vim.api.nvim_buf_delete(buf, { force = force }) + else + require('mini.bufremove').delete(buf, force) + end + end + + vim.keymap.set('n', '', function() + if vim.bo.buftype ~= '' then + pcall(vim.cmd.close) + return + end + + if not vim.bo.modified then return close_buffer(false) end + + local name = vim.fn.expand '%:t' + if name == '' then name = '[No Name]' end + local choice = vim.fn.confirm(('"%s" has unsaved changes.'):format(name), '&Save and close\n&Discard and close\n&Cancel', 3, 'Warning') + if choice == 1 then + vim.cmd.write() + close_buffer(false) + elseif choice == 2 then + close_buffer(true) + end + end, { desc = 'Close buffer' }) + -- Diagnostic Config & Keymaps -- See `:help vim.diagnostic.Opts` vim.diagnostic.config { @@ -423,18 +459,7 @@ do -- 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`. - vim.pack.add { gh 'folke/tokyonight.nvim' } - ---@diagnostic disable-next-line: missing-fields - require('tokyonight').setup { - styles = { - comments = { italic = false }, -- Disable italics in comments - }, - } - - -- 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' + -- Colorscheme (catppuccin) is configured in `lua/custom/plugins/colorscheme.lua`. -- Highlight todo, notes, etc in comments vim.pack.add { gh 'folke/todo-comments.nvim' } @@ -473,6 +498,9 @@ do -- - sr)' - [S]urround [R]eplace [)] ['] require('mini.surround').setup() + -- Delete buffers without closing their windows (used by the keymap) + require('mini.bufremove').setup() + -- Simple and easy statusline. -- You could remove this setup call if you don't like it, -- and try some other statusline plugin @@ -728,11 +756,89 @@ do end, }) + -- JSON/YAML schemas from https://www.schemastore.org (package.json, tsconfig, appsettings, GitHub workflows, etc.) + vim.pack.add { gh 'b0o/SchemaStore.nvim' } + + -- Vue's TypeScript plugin ships inside the Mason `vue-language-server` package. vtsls loads it + -- so TypeScript inside .vue files is handled by vtsls, while vue_ls handles templates/styles. + local vue_language_server_path = vim.fn.stdpath 'data' .. '/mason/packages/vue-language-server/node_modules/@vue/language-server' + -- 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 + -- + -- C# (Roslyn) is configured separately in `lua/custom/plugins/dotnet.lua`. ---@type table local servers = { + -- JavaScript / TypeScript (also serves TypeScript inside .vue files) + vtsls = { + filetypes = { 'javascript', 'javascriptreact', 'javascript.jsx', 'typescript', 'typescriptreact', 'typescript.tsx', 'vue' }, + settings = { + vtsls = { + tsserver = { + globalPlugins = { + { + name = '@vue/typescript-plugin', + location = vue_language_server_path, + languages = { 'vue' }, + configNamespace = 'typescript', + }, + }, + }, + }, + typescript = { + inlayHints = { + parameterNames = { enabled = 'literals' }, + parameterTypes = { enabled = true }, + variableTypes = { enabled = false }, + propertyDeclarationTypes = { enabled = true }, + functionLikeReturnTypes = { enabled = true }, + enumMemberValues = { enabled = true }, + }, + }, + }, + }, + vue_ls = {}, -- Vue templates, styles and SFC structure + -- Angular templates; uses the project's @angular/language-service from node_modules. + -- Only starts inside a workspace with angular.json / nx.json, so plain TS projects don't get it. + angularls = { workspace_required = true }, + eslint = {}, -- ESLint diagnostics and code actions, driven by the project's eslint config + html = {}, + cssls = {}, + + -- Python: pyright for types/navigation, ruff for linting, import sorting and formatting + pyright = { + settings = { + pyright = { disableOrganizeImports = true }, -- ruff handles imports + python = { analysis = { typeCheckingMode = 'standard' } }, + }, + }, + ruff = { + on_init = function(client) + client.server_capabilities.hoverProvider = false -- Let pyright provide hover + end, + }, + + -- Data / config files + jsonls = { + settings = { + json = { + schemas = require('schemastore').json.schemas(), + validate = { enable = true }, + }, + }, + }, + yamlls = { + settings = { + yaml = { + schemaStore = { enable = false, url = '' }, -- Use SchemaStore.nvim's catalog instead + schemas = require('schemastore').yaml.schemas(), + }, + }, + }, + taplo = {}, -- TOML + + -- clangd = {}, -- gopls = {}, -- pyright = {}, @@ -787,7 +893,12 @@ do } -- Automatically install LSPs and related tools to stdpath for Neovim - require('mason').setup {} + require('mason').setup { + registries = { + 'github:mason-org/mason-registry', + 'github:Crashdummyy/mason-registry', -- Provides the `roslyn` C# language server + }, + } -- Translates between nvim-lspconfig server names and mason.nvim package names (e.g. lua_ls <-> lua-language-server) require('mason-lspconfig').setup { @@ -804,6 +915,12 @@ do 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 + 'roslyn', -- C# language server (used by roslyn.nvim) + 'csharpier', -- C# formatter + 'prettierd', -- JS/TS/Vue/Angular/HTML/CSS/JSON/YAML formatter + 'sqlfluff', -- SQL linter + 'sql-formatter', -- SQL formatter + 'yamllint', -- YAML linter }) require('mason-tool-installer').setup { ensure_installed = ensure_installed } @@ -846,6 +963,27 @@ do -- -- You can use 'stop_after_first' to run the first available formatter from the list -- javascript = { "prettierd", "prettier", stop_after_first = true }, + cs = { 'csharpier' }, + python = { 'ruff_organize_imports', 'ruff_format' }, + javascript = { 'prettierd', 'prettier', stop_after_first = true }, + javascriptreact = { 'prettierd', 'prettier', stop_after_first = true }, + typescript = { 'prettierd', 'prettier', stop_after_first = true }, + typescriptreact = { 'prettierd', 'prettier', stop_after_first = true }, + vue = { 'prettierd', 'prettier', stop_after_first = true }, + html = { 'prettierd', 'prettier', stop_after_first = true }, + htmlangular = { 'prettierd', 'prettier', stop_after_first = true }, + css = { 'prettierd', 'prettier', stop_after_first = true }, + scss = { 'prettierd', 'prettier', stop_after_first = true }, + json = { 'prettierd', 'prettier', stop_after_first = true }, + jsonc = { 'prettierd', 'prettier', stop_after_first = true }, + yaml = { 'prettierd', 'prettier', stop_after_first = true }, + toml = { 'taplo' }, + sql = { 'sql_formatter' }, + }, + formatters = { + sql_formatter = { + prepend_args = { '--language', 'transactsql' }, + }, }, } @@ -948,7 +1086,11 @@ 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', 'razor', 'angular', 'vue', 'python', 'javascript', 'typescript', 'tsx', 'jsdoc', + 'css', 'scss', 'sql', 'toml', 'yaml', 'json', 'xml', + } require('nvim-treesitter').install(parsers) ---@param buf integer @@ -1023,7 +1165,7 @@ do -- NOTE: You can add your own plugins, configuration, etc. in `lua/custom/plugins/*.lua`. -- -- For independent modules, uncomment the convenience loader: - -- require 'custom.plugins' + require 'custom.plugins' -- -- `custom.plugins` automatically loads files from that directory, but their -- order is unspecified. If plugins depend on each other, keep them in the same diff --git a/lazy-lock.json b/lazy-lock.json new file mode 100644 index 00000000000..4d4fd14356e --- /dev/null +++ b/lazy-lock.json @@ -0,0 +1,25 @@ +{ + "LuaSnip": { "branch": "master", "commit": "642b0c595e11608b4c18219e93b88d7637af27bc" }, + "blink.cmp": { "branch": "main", "commit": "78336bc89ee5365633bcf754d93df01678b5c08f" }, + "catppuccin": { "branch": "main", "commit": "edefef779ab08ce1a4a404713e3012b0d202bd35" }, + "conform.nvim": { "branch": "master", "commit": "016802de402556da54c36bd7359b441266b01cdd" }, + "fidget.nvim": { "branch": "main", "commit": "9e0201673e08e997e7cf52afca5565c70bd117f3" }, + "gitsigns.nvim": { "branch": "main", "commit": "070a5d7b985546cc57e1fc61e5bc507fecac6045" }, + "guess-indent.nvim": { "branch": "main", "commit": "84a4987ff36798c2fc1169cbaff67960aed9776f" }, + "lazy.nvim": { "branch": "main", "commit": "306a05526ada86a7b30af95c5cc81ffba93fef97" }, + "lazydev.nvim": { "branch": "main", "commit": "ff2cbcba459b637ec3fd165a2be59b7bbaeedf0d" }, + "mason-lspconfig.nvim": { "branch": "main", "commit": "b3298993d55fa194279b5eb9dbfb3a43da65cadf" }, + "mason-tool-installer.nvim": { "branch": "main", "commit": "443f1ef8b5e6bf47045cb2217b6f748a223cf7dc" }, + "mason.nvim": { "branch": "main", "commit": "2a6940af80375532e5e9e7c1f2fc6319a1b7a69d" }, + "mini.nvim": { "branch": "main", "commit": "561751e839b99a4baca36b9d963166b66d2536a6" }, + "nvim-lspconfig": { "branch": "master", "commit": "a9bb4d5f4276aa5cddc015faa3ecc5a7b5a26b14" }, + "nvim-tree.lua": { "branch": "master", "commit": "531b807b8f0d6f75016a0ee1e0cd5ce2086e9d95" }, + "nvim-treesitter": { "branch": "master", "commit": "cf12346a3414fa1b06af75c79faebe7f76df080a" }, + "nvim-web-devicons": { "branch": "master", "commit": "58447c1fca354bbf184425e4a8d01deecbd6f3c4" }, + "plenary.nvim": { "branch": "master", "commit": "74b06c6c75e4eeb3108ec01852001636d85a932b" }, + "telescope-fzf-native.nvim": { "branch": "main", "commit": "b25b749b9db64d375d782094e2b9dce53ad53a40" }, + "telescope-ui-select.nvim": { "branch": "master", "commit": "6e51d7da30bd139a6950adf2a47fda6df9fa06d2" }, + "telescope.nvim": { "branch": "master", "commit": "40aedd8a68c78a656a10a8d62d80c54af59420fb" }, + "todo-comments.nvim": { "branch": "main", "commit": "31e3c38ce9b29781e4422fc0322eb0a21f4e8668" }, + "which-key.nvim": { "branch": "main", "commit": "3aab2147e74890957785941f0c1ad87d0a44c15a" } +} diff --git a/lua/custom/plugins/colorscheme.lua b/lua/custom/plugins/colorscheme.lua new file mode 100644 index 00000000000..28330aab395 --- /dev/null +++ b/lua/custom/plugins/colorscheme.lua @@ -0,0 +1,21 @@ +-- Colorscheme: https://github.com/catppuccin/nvim + +vim.pack.add { { src = 'https://github.com/catppuccin/nvim', name = 'catppuccin' } } + +---@diagnostic disable-next-line: missing-fields +require('catppuccin').setup { + flavour = 'mocha', -- latte, frappe, macchiato, mocha + no_italic = false, + styles = { + comments = {}, -- Disable italics in comments + }, + integrations = { + gitsigns = true, + nvimtree = true, + telescope = { enabled = true }, + which_key = true, + mini = { enabled = true }, + }, +} + +vim.cmd.colorscheme 'catppuccin' diff --git a/lua/custom/plugins/dotnet.lua b/lua/custom/plugins/dotnet.lua new file mode 100644 index 00000000000..d0156fc0c5d --- /dev/null +++ b/lua/custom/plugins/dotnet.lua @@ -0,0 +1,36 @@ +-- C# / .NET: https://github.com/seblyng/roslyn.nvim +-- +-- Uses the Roslyn language server (the same one VS Code's C# Dev Kit uses), installed by Mason +-- as the `roslyn` package (see `ensure_installed` in init.lua). +-- +-- Opening a .cs file finds the nearest .sln/.slnx/.csproj. When several solutions are found, +-- run `:Roslyn target` to pick one. `:Roslyn restart` restarts the server. + +vim.pack.add { 'https://github.com/seblyng/roslyn.nvim' } + +require('roslyn').setup { + -- Keep diagnostics scoped to open files; set to 'full' for whole-solution diagnostics (slower) + broad_search = false, +} + +vim.lsp.config('roslyn', { + settings = { + ['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_parameters = true, + }, + ['csharp|code_lens'] = { + dotnet_enable_references_code_lens = true, + }, + ['csharp|completion'] = { + dotnet_show_completion_items_from_unimported_namespaces = true, + }, + ['csharp|background_analysis'] = { + dotnet_analyzer_diagnostics_scope = 'openFiles', + dotnet_compiler_diagnostics_scope = 'fullSolution', + }, + }, +}) diff --git a/lua/custom/plugins/lint.lua b/lua/custom/plugins/lint.lua new file mode 100644 index 00000000000..9f870cebca7 --- /dev/null +++ b/lua/custom/plugins/lint.lua @@ -0,0 +1,35 @@ +-- Linting: https://github.com/mfussenegger/nvim-lint +-- +-- Most languages lint through their language server instead: +-- C# -> roslyn analyzers, JS/TS/Vue/Angular -> eslint LSP, Python -> ruff LSP, +-- JSON/YAML -> schema validation in jsonls/yamlls. +-- nvim-lint covers the tools that have no language server. + +vim.pack.add { 'https://github.com/mfussenegger/nvim-lint' } + +local lint = require 'lint' + +lint.linters_by_ft = { + sql = { 'sqlfluff' }, + yaml = { 'yamllint' }, +} + +-- Default to T-SQL unless the project has its own .sqlfluff config (which then sets the dialect) +lint.linters.sqlfluff.args = { + 'lint', + '--format=json', + function() + if vim.fs.root(0, { '.sqlfluff' }) then return '--nocolor' end + return '--dialect=tsql' + end, + '-', +} + +local lint_augroup = vim.api.nvim_create_augroup('lint', { clear = true }) +vim.api.nvim_create_autocmd({ 'BufEnter', 'BufWritePost', 'InsertLeave' }, { + group = lint_augroup, + callback = function() + -- Only lint buffers you can modify, to skip LSP hover popups and similar + if vim.bo.modifiable then lint.try_lint() end + end, +}) diff --git a/lua/custom/plugins/nvim-tree.lua b/lua/custom/plugins/nvim-tree.lua new file mode 100644 index 00000000000..ff8f5413d98 --- /dev/null +++ b/lua/custom/plugins/nvim-tree.lua @@ -0,0 +1,21 @@ +-- File explorer: https://github.com/nvim-tree/nvim-tree.lua + +-- nvim-tree recommends disabling netrw so it takes over directory buffers (e.g. `nvim .`) +vim.g.loaded_netrw = 1 +vim.g.loaded_netrwPlugin = 1 + +local plugins = { { src = 'https://github.com/nvim-tree/nvim-tree.lua', version = vim.version.range '*' } } +if vim.g.have_nerd_font then table.insert(plugins, 'https://github.com/nvim-tree/nvim-web-devicons') end +vim.pack.add(plugins) + +require('nvim-tree').setup { + hijack_netrw = true, + sync_root_with_cwd = true, + update_focused_file = { enable = true }, + view = { width = 35 }, + renderer = { group_empty = true }, + filters = { dotfiles = false }, +} + +vim.keymap.set('n', '\\', 'NvimTreeToggle', { desc = 'Toggle file tree' }) +vim.keymap.set('n', 'e', 'NvimTreeFindFileToggle', { desc = 'Toggle file tree at current [E]xplorer file' }) diff --git a/nvim-pack-lock.json b/nvim-pack-lock.json new file mode 100644 index 00000000000..aa72c39a9a2 --- /dev/null +++ b/nvim-pack-lock.json @@ -0,0 +1,108 @@ +{ + "plugins": { + "LuaSnip": { + "rev": "642b0c595e11608b4c18219e93b88d7637af27bc", + "src": "https://github.com/L3MON4D3/LuaSnip", + "version": "2.0.0 - 3.0.0" + }, + "SchemaStore.nvim": { + "rev": "411163b2be396495c76788a016cb1354f1e8acd0", + "src": "https://github.com/b0o/SchemaStore.nvim" + }, + "blink.cmp": { + "rev": "78336bc89ee5365633bcf754d93df01678b5c08f", + "src": "https://github.com/saghen/blink.cmp", + "version": "1.0.0 - 2.0.0" + }, + "catppuccin": { + "rev": "edefef779ab08ce1a4a404713e3012b0d202bd35", + "src": "https://github.com/catppuccin/nvim" + }, + "conform.nvim": { + "rev": "016802de402556da54c36bd7359b441266b01cdd", + "src": "https://github.com/stevearc/conform.nvim" + }, + "fidget.nvim": { + "rev": "9e0201673e08e997e7cf52afca5565c70bd117f3", + "src": "https://github.com/j-hui/fidget.nvim" + }, + "gitsigns.nvim": { + "rev": "070a5d7b985546cc57e1fc61e5bc507fecac6045", + "src": "https://github.com/lewis6991/gitsigns.nvim" + }, + "guess-indent.nvim": { + "rev": "84a4987ff36798c2fc1169cbaff67960aed9776f", + "src": "https://github.com/NMAC427/guess-indent.nvim" + }, + "mason-lspconfig.nvim": { + "rev": "b3298993d55fa194279b5eb9dbfb3a43da65cadf", + "src": "https://github.com/mason-org/mason-lspconfig.nvim" + }, + "mason-tool-installer.nvim": { + "rev": "443f1ef8b5e6bf47045cb2217b6f748a223cf7dc", + "src": "https://github.com/WhoIsSethDaniel/mason-tool-installer.nvim" + }, + "mason.nvim": { + "rev": "2a6940af80375532e5e9e7c1f2fc6319a1b7a69d", + "src": "https://github.com/mason-org/mason.nvim" + }, + "mini.nvim": { + "rev": "561751e839b99a4baca36b9d963166b66d2536a6", + "src": "https://github.com/nvim-mini/mini.nvim" + }, + "nvim-lint": { + "rev": "3d55c8f67c6ae5c15e1042571e107c7a3d5c5f4e", + "src": "https://github.com/mfussenegger/nvim-lint" + }, + "nvim-lspconfig": { + "rev": "a9bb4d5f4276aa5cddc015faa3ecc5a7b5a26b14", + "src": "https://github.com/neovim/nvim-lspconfig" + }, + "nvim-tree.lua": { + "rev": "531b807b8f0d6f75016a0ee1e0cd5ce2086e9d95", + "src": "https://github.com/nvim-tree/nvim-tree.lua", + "version": ">=0.0.0" + }, + "nvim-treesitter": { + "rev": "728e031f6b11d03d1f0708b7dc4fb0f1d9c8a137", + "src": "https://github.com/nvim-treesitter/nvim-treesitter", + "version": "'main'" + }, + "nvim-web-devicons": { + "rev": "58447c1fca354bbf184425e4a8d01deecbd6f3c4", + "src": "https://github.com/nvim-tree/nvim-web-devicons" + }, + "plenary.nvim": { + "rev": "74b06c6c75e4eeb3108ec01852001636d85a932b", + "src": "https://github.com/nvim-lua/plenary.nvim" + }, + "roslyn.nvim": { + "rev": "bf1bd4e70bc7068d1b4aebf4ce03cc19a86615be", + "src": "https://github.com/seblyng/roslyn.nvim" + }, + "telescope-fzf-native.nvim": { + "rev": "b25b749b9db64d375d782094e2b9dce53ad53a40", + "src": "https://github.com/nvim-telescope/telescope-fzf-native.nvim" + }, + "telescope-ui-select.nvim": { + "rev": "6e51d7da30bd139a6950adf2a47fda6df9fa06d2", + "src": "https://github.com/nvim-telescope/telescope-ui-select.nvim" + }, + "telescope.nvim": { + "rev": "40aedd8a68c78a656a10a8d62d80c54af59420fb", + "src": "https://github.com/nvim-telescope/telescope.nvim" + }, + "todo-comments.nvim": { + "rev": "31e3c38ce9b29781e4422fc0322eb0a21f4e8668", + "src": "https://github.com/folke/todo-comments.nvim" + }, + "tokyonight.nvim": { + "rev": "cdc07ac78467a233fd62c493de29a17e0cf2b2b6", + "src": "https://github.com/folke/tokyonight.nvim" + }, + "which-key.nvim": { + "rev": "3aab2147e74890957785941f0c1ad87d0a44c15a", + "src": "https://github.com/folke/which-key.nvim" + } + } +}