diff --git a/.gitignore b/.gitignore index 9bbbeea..e69de29 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +0,0 @@ -.luarc.json diff --git a/nvim/config/.luarc.json b/nvim/config/.luarc.json new file mode 100644 index 0000000..a5faeed --- /dev/null +++ b/nvim/config/.luarc.json @@ -0,0 +1,14 @@ +{ + "runtime.version": "LuaJIT", + "runtime.path": [ + "lua/?.lua", + "lua/?/init.lua" + ], + "diagnostics.globals": [ + "vim" + ], + "workspace.checkThirdParty": false, + "workspace.library": [ + "$VIMRUNTIME" + ] +} diff --git a/nvim/config/lua/plugins/lazygit.lua b/nvim/config/lua/plugins/lazygit.lua new file mode 100644 index 0000000..f6c1891 --- /dev/null +++ b/nvim/config/lua/plugins/lazygit.lua @@ -0,0 +1,17 @@ +return { + "kdheepak/lazygit.nvim", + lazy = true, + cmd = { + "LazyGit", + "LazyGitFilter", + "LazyGitConfig", + "LazyGitCurrentFile", + "LazyGitFilterCurrentFile", + }, + dependencies = { + "nvim-lua/plenary.nvim" + }, + keys = { + { "lg", "LazyGit", desc = "LazyGit" } + } +} diff --git a/nvim/config/lua/plugins/lsp.lua b/nvim/config/lua/plugins/lsp.lua index 6c5305e..c8752f8 100644 --- a/nvim/config/lua/plugins/lsp.lua +++ b/nvim/config/lua/plugins/lsp.lua @@ -1,109 +1,177 @@ return { "VonHeikemen/lsp-zero.nvim", - branch = "v2.x", + branch = "v4.x", dependencies = { "neovim/nvim-lspconfig", "hrsh7th/nvim-cmp", + "hrsh7th/cmp-path", "hrsh7th/cmp-nvim-lsp", - "L3MON4D3/LuaSnip", "onsails/lspkind.nvim", + "L3MON4D3/LuaSnip", + + { + "j-hui/fidget.nvim", + tag = "v1.6.1", + opts = {} + }, { "williamboman/mason.nvim", build = ":MasonUpdate", - }, - - "williamboman/mason-lspconfig.nvim", - - { - "j-hui/fidget.nvim", - opts = {}, - }, - { - "nvim-java/nvim-java", dependencies = { - "nvim-java/lua-async-await", - "nvim-java/nvim-java-core", - "nvim-java/nvim-java-test", - "nvim-java/nvim-java-dap", + "williamboman/mason-lspconfig.nvim", } - } + }, }, config = function() - local lspconfig = require("lspconfig") - local lsp = require("lsp-zero").preset {} local cmp = require("cmp") - local util = require("lspconfig.util"); local lspkind = require("lspkind") - local luasnip = require("luasnip") - - local has_words_before = function() - unpack = unpack or table.unpack - local line, col = unpack(vim.api.nvim_win_get_cursor(0)) - return col ~= 0 and vim.api.nvim_buf_get_lines(0, line - 1, line, true)[1]:sub(col, col):match("%s") == nil - end - - lsp.ensure_installed { - "zls", - "html", - "taplo", - "jdtls", - "cssls", - "cmake", - "ts_ls", - "bashls", - "lua_ls", - "yamlls", - "jsonls", - "pyright", - "gradle_ls", - "rust_analyzer", - "markdown_oxide", - "golangci_lint_ls", - } - - lspconfig.zls.setup {} - lspconfig.html.setup {} - lspconfig.taplo.setup {} - lspconfig.cssls.setup {} - lspconfig.cmake.setup {} - lspconfig.ts_ls.setup {} - lspconfig.bashls.setup {} - lspconfig.jsonls.setup {} - lspconfig.pyright.setup {} - lspconfig.gradle_ls.setup {} - lspconfig.rust_analyzer.setup {} - lspconfig.markdown_oxide.setup {} - lspconfig.golangci_lint_ls.setup {} vim.g.zig_fmt_autosave = false - lspconfig.yamlls.setup { - settings = { - yaml = { - keyOrdering = false + local lspconfig_defaults = require('lspconfig').util.default_config + + lspconfig_defaults.capabilities = vim.tbl_deep_extend( + 'force', + lspconfig_defaults.capabilities, + require('cmp_nvim_lsp').default_capabilities() + ) + + vim.diagnostic.config { + signs = { + text = { + [vim.diagnostic.severity.ERROR] = '', + [vim.diagnostic.severity.WARN] = '', + [vim.diagnostic.severity.HINT] = '', + [vim.diagnostic.severity.INFO] = '', } } } - lspconfig.lua_ls.setup { - settings = { - Lua = { - runtime = { - version = "LuaJIT" - }, - diagnostics = { - globals = { "vim" } - }, - workspace = { - library = vim.api.nvim_get_runtime_file("", true) - } - } + vim.api.nvim_create_autocmd('LspAttach', { + desc = 'LSP actions', + callback = function(event) + local opts = {buffer = event.buf} + local snacks = require("snacks") + + vim.keymap.set('n', 'vd', vim.diagnostic.open_float, opts) + vim.keymap.set('n', 'rn', vim.lsp.buf.rename, opts) + vim.keymap.set('n', 'ca', vim.lsp.buf.code_action, opts) + vim.keymap.set('n', 'D', vim.lsp.buf.type_definition, opts) + + vim.keymap.set('n', 'gD', snacks.picker.lsp_declarations, opts) + vim.keymap.set('n', 'gd', snacks.picker.lsp_definitions, opts) + vim.keymap.set('n', 'gi', snacks.picker.lsp_implementations, opts) + vim.keymap.set('n', 'gr', snacks.picker.lsp_references, opts) + vim.keymap.set('n', 'K', vim.lsp.buf.hover, opts) + + vim.keymap.set('n', ']d', vim.diagnostic.goto_next, opts) + vim.keymap.set('n', '[d', vim.diagnostic.goto_prev, opts) + + vim.keymap.set('n', 'K', vim.lsp.buf.signature_help, opts) + + vim.keymap.set('n', 'fs', snacks.picker.lsp_symbols, opts) + vim.keymap.set('n', 'fd', snacks.picker.diagnostics, opts) + + vim.keymap.set({ 'n', 'x' }, 'cf', function() + vim.lsp.buf.format { async = true } + end, opts) + end + }) + + vim.api.nvim_set_hl(0, 'CmpItemAbbrDeprecated', { bg='NONE', strikethrough=true, fg='#808080' }) + vim.api.nvim_set_hl(0, 'CmpItemAbbrMatch', { bg='NONE', fg='#569CD6' }) + vim.api.nvim_set_hl(0, 'CmpItemAbbrMatchFuzzy', { link='CmpIntemAbbrMatch' }) + vim.api.nvim_set_hl(0, 'CmpItemKindVariable', { bg='NONE', fg='#9CDCFE' }) + vim.api.nvim_set_hl(0, 'CmpItemKindInterface', { link='CmpItemKindVariable' }) + vim.api.nvim_set_hl(0, 'CmpItemKindText', { link='CmpItemKindVariable' }) + vim.api.nvim_set_hl(0, 'CmpItemKindFunction', { bg='NONE', fg='#C586C0' }) + vim.api.nvim_set_hl(0, 'CmpItemKindMethod', { link='CmpItemKindFunction' }) + vim.api.nvim_set_hl(0, 'CmpItemKindKeyword', { bg='NONE', fg='#D4D4D4' }) + vim.api.nvim_set_hl(0, 'CmpItemKindProperty', { link='CmpItemKindKeyword' }) + vim.api.nvim_set_hl(0, 'CmpItemKindUnit', { link='CmpItemKindKeyword' }) + + cmp.setup { + sources = { + { name = 'path' }, + { name = 'nvim_lsp' }, + { name = 'luasnip', keyword_length = 2 }, + }, + snippet = { + expand = function(args) + require('luasnip').lsp_expand(args.body) + end + }, + mapping = cmp.mapping.preset.insert { + [''] = cmp.mapping.confirm { select = true }, + [''] = cmp.mapping.scroll_docs(-4), + [''] = cmp.mapping.scroll_docs( 4), + [''] = cmp.mapping(function(fallback) + local luasnip = require('luasnip') + local col = vim.fn.col('.') - 1 + + if cmp.visible() then + cmp.select_next_item { behavior = 'select' } + elseif luasnip.expand_or_locally_jumpable() then + luasnip.expand_or_jump() + elseif col == 0 or vim.fn.getline('.'):sub(col, col):match('%s') then + fallback() + else + cmp.complete() + end + end, { 'i', 's' }), + [''] = cmp.mapping(function(fallback) + local luasnip = require('luasnip') + + if cmp.visible() then + cmp.select_prev_item { behavior = 'select' } + elseif luasnip.locally_jumpable(-1) then + luasnip.jump(-1) + else + fallback() + end + end, { 'i', 's' }), + [''] = cmp.mapping.complete(), + }, + window = { + completion = { + winhighlight = "Normal:Pmenu,FloatBorder:Pmenu,Search:None", + col_offset = 0, + side_padding = 0, + }, + }, + formatting = { + fields = { + "kind", "abbr", "menu" + }, + format = function(entry, vim_item) + local kind = require('lspkind').cmp_format({ + maxwidth = 50, + mode = 'symbol', + preset = 'default', + menu = { + buffer = "[Buf]", + nvim_lsp = "[LSP]", + luasnip = "[Snp]", + nvim_lua = "[Lua]", + path = "[Pth]", + } + })(entry, vim_item) + + kind.kind = " " .. kind.kind .. " " + + return kind + end } } - if os.getenv("NIX_CC") ~= nil then + local lspconfig = require('lspconfig') + local util = require('lspconfig.util'); + + if os.getenv('NIX_CC') ~= nil then + local nixcc = os.getenv('NIX_CC') + lspconfig.clangd.setup { root_dir = util.root_pattern( '.clangd', @@ -112,12 +180,12 @@ return { 'compile_commands.json' ), cmd = { - "clangd", - "--header-insertion=never", - "--offset-encoding=utf-16", - "--query-driver=" - .. os.getenv("NIX_CC") .. "/bin/g++" .. "," - .. os.getenv("NIX_CC") .. "/bin/gcc" + 'clangd', + '--header-insertion=never', + '--offset-encoding=utf-8', + '--query-driver=' + .. nixcc .. '/bin/g++' .. ',' + .. nixcc .. '/bin/gcc' } } else @@ -129,159 +197,101 @@ return { 'compile_commands.json' ), cmd = { - "clangd", - "--header-insertion=never", - "--offset-encoding=utf-16", - "--query-driver=gcc,g++" + 'clangd', + '--header-insertion=never', + '--offset-encoding=utf-8', + '--query-driver=g++,gcc' } } end - require('java').setup {} - lspconfig.jdtls.setup {} + require('mason').setup { } - local cmp_mappings = { - [''] = cmp.mapping.select_prev_item({ - behavior = cmp.SelectBehavior.Insert - }), - [''] = cmp.mapping.select_next_item({ - behavior = cmp.SelectBehavior.Insert - }), - [''] = cmp.mapping.confirm({ - select = true, - behavior = cmp.ConfirmBehavior.Replace - }), - [""] = cmp.mapping.complete(), - [""] = cmp.mapping(function(fallback) - if cmp.visible() then - cmp.select_next_item() - elseif luasnip.expand_or_jumpable() then - luasnip.expand_or_jump() - elseif has_words_before() then - cmp.complete() - else - fallback() - end - end, { "i", "s" }), - [""] = cmp.mapping(function(fallback) - if cmp.visible() then - cmp.select_prev_item() - elseif luasnip.jumpable(-1) then - luasnip.jump(-1) - else - fallback() - end - end, { "i", "s" }), - } - - lsp.setup_nvim_cmp { - mapping = cmp_mappings, - formatting = { - fields = { - "kind", - "abbr", - "menu" - }, - format = lspkind.cmp_format({ - maxwidth = 50, - before = function(entry, vim_item) - local kind_icons = { - Text = "", - Method = "󰆧", - Function = "󰊕", - Constructor = "", - Field = "󰇽", - Variable = "󰂡", - Class = "󰠱", - Interface = "", - Module = "", - Property = "󰜢", - Unit = "", - Value = "󰎠", - Enum = "", - Keyword = "󰌋", - Snippet = "", - Color = "󰏘", - File = "󰈙", - Reference = "", - Folder = "󰉋", - EnumMember = "", - Constant = "󰏿", - Struct = "", - Event = "", - Operator = "󰆕", - TypeParameter = "󰅲", - } - - vim_item.kind = string.format("%s", kind_icons[vim_item.kind]) - - vim_item.menu = ({ - buffer = "[Buff]", - nvim_lsp = "[LSP ]", - ultisnips = "[Snps]", - nvim_lua = "[Lua ]", - cmp_tabnine = "[TbNn]", - look = "[Look]", - path = "[Path]", - spell = "[Spll]", - calc = "[Calc]", - emoji = "[Emji]" - })[entry.source.name] - - return vim_item - end - }) - } - } - - lsp.set_preferences({ - suggest_lsp_servers = false, - sign_icons = { - error = 'E', - warn = 'W', - hint = 'H', - info = 'I' - } - }) - - lsp.on_attach(function(_, bufnr) - local snacks = require('snacks') - local opts = { buffer = bufnr, remap = false } - - vim.keymap.set('n', 'vd', vim.diagnostic.open_float, opts) - vim.keymap.set('n', 'rn', vim.lsp.buf.rename, opts) - vim.keymap.set('n', 'ca', vim.lsp.buf.code_action, opts) - vim.keymap.set('n', 'D', vim.lsp.buf.type_definition, opts) - - vim.keymap.set('n', 'gD', snacks.picker.lsp_declarations, opts) - vim.keymap.set('n', 'gd', snacks.picker.lsp_definitions, opts) - vim.keymap.set('n', 'gi', snacks.picker.lsp_implementations, opts) - vim.keymap.set('n', 'gr', snacks.picker.lsp_references, opts) - vim.keymap.set('n', 'K', vim.lsp.buf.hover, opts) - - vim.keymap.set('n', ']d', vim.diagnostic.goto_next, opts) - vim.keymap.set('n', '[d', vim.diagnostic.goto_prev, opts) - - vim.keymap.set('n', 'q', vim.diagnostic.setloclist, opts) - - vim.keymap.set('n', 'K', vim.lsp.buf.signature_help, opts) - - vim.keymap.set({ 'n', 'v' }, 'cf', function() - vim.lsp.buf.format { async = true } - end, opts) - - vim.keymap.set('n', 'fs', snacks.picker.lsp_symbols, opts) - vim.keymap.set('n', 'fd', snacks.picker.diagnostics, opts) - end) - - lsp.nvim_workspace() - lsp.setup() - - vim.lsp.handlers["textDocument/publishDiagnostics"] = vim.lsp.with(vim.lsp.diagnostic.on_publish_diagnostics, { - virtual_text = { - prefix = "◉", - spacing = 6 + require('mason-lspconfig').setup { + ensure_installed = { + "zls", + "taplo", + "cmake", + "biome", + "gopls", + "bashls", + "lua_ls", + "yamlls", + "pyright", + "rust_analyzer", + "markdown_oxide", }, - }) + handlers = { + function(server_name) + require('lspconfig')[server_name].setup{} + end, + yamlls = function() + local lspconfig = require('lspconfig') + + lspconfig.yamlls.setup { + settings = { + yaml = { + keyOrdering = false + } + } + } + end, + lua_ls = function() + local lspconfig = require('lspconfig') + + lspconfig.lua_ls.setup { + settings = { + Lua = { + telemetry = { + enable = false + } + } + }, + on_init = function(client) + local join = vim.fs.joinpath + local path = client.workspace_folders[1].name + + -- Don't do anything if there is project local config + if vim.uv.fs_stat(join(path, '.luarc.json')) + or vim.uv.fs_stat(join(path, '.luarc.jsonc')) + then + return + end + + -- Apply neovim specific settings + local runtime_path = vim.split(package.path, ';') + table.insert(runtime_path, join('lua', '?.lua')) + table.insert(runtime_path, join('lua', '?', 'init.lua')) + + local nvim_settings = { + runtime = { + -- Tell the language server which version of Lua you're using + version = 'LuaJIT', + path = runtime_path + }, + diagnostics = { + -- Get the language server to recognize the `vim` global + globals = {'vim'} + }, + workspace = { + checkThirdParty = false, + library = { + -- Make the server aware of Neovim runtime files + vim.env.VIMRUNTIME, + vim.fn.stdpath('config'), + }, + }, + } + + client.config.settings.Lua = vim.tbl_deep_extend( + 'force', + client.config.settings.Lua, + nvim_settings + ) + end + } + end + } + } end } diff --git a/nvim/config/lua/plugins/nvim-tree.lua b/nvim/config/lua/plugins/nvim-tree.lua new file mode 100644 index 0000000..eee404d --- /dev/null +++ b/nvim/config/lua/plugins/nvim-tree.lua @@ -0,0 +1,100 @@ +local function label(path) + path = path:gsub(os.getenv 'HOME', '~', 1) + return path:gsub('([a-zA-Z])[a-z0-9]+', '%1') .. + (path:match '[a-zA-Z]([a-z0-9]*)$' or '') +end + +return { + "nvim-tree/nvim-tree.lua", + version = "*", + lazy = false, + dependencies = { + "nvim-tree/nvim-web-devicons" + }, + keys = { + { + "nn", + function() + vim.cmd [[:NvimTreeToggle]] + end, + silent = true + } + }, + config = function() + vim.g.loaded_netrw = 1 + vim.g.loaded_netrwPlugin = 1 + + local nt = require("nvim-tree") + + nt.setup { + disable_netrw = true, + sort = { + sorter = "case_sensitive", + }, + view = { + width = 25, + }, + filters = { + dotfiles = false, + }, + live_filter = { + prefix = " ", + }, + renderer = { + root_folder_label = label, + group_empty = label, + indent_width = 2, + indent_markers = { + enable = true, + inline_arrows = true, + icons = { + corner = "└", + edge = "│", + item = "│", + bottom = "─", + none = " ", + }, + }, + icons = { + git_placement = "right_align", + glyphs = { + git = { + staged = "", + unmerged = "", + renamed = "", + untracked = "", + deleted = "", + ignored = "", + } + } + } + } + } + + vim.api.nvim_create_autocmd("QuitPre", { + callback = function() + local tree_wins = {} + local floating_wins = {} + local wins = vim.api.nvim_list_wins() + + for _, w in ipairs(wins) do + local bufname = vim.api.nvim_buf_get_name(vim.api.nvim_win_get_buf(w)) + + if bufname:match("NvimTree_") ~= nil then + table.insert(tree_wins, w) + end + + if vim.api.nvim_win_get_config(w).relative ~= '' then + table.insert(floating_wins, w) + end + end + + if 1 == #wins - #floating_wins - #tree_wins then + for _, w in ipairs(tree_wins) do + vim.api.nvim_win_close(w, true) + end + end + end + }) + end +} diff --git a/nvim/config/lua/plugins/snacks.lua b/nvim/config/lua/plugins/snacks.lua index 55b7c32..b2634d2 100644 --- a/nvim/config/lua/plugins/snacks.lua +++ b/nvim/config/lua/plugins/snacks.lua @@ -3,13 +3,6 @@ return { priority = 1000, lazy = false, keys = { - { - "nn", - function() - require("snacks").picker.explorer() - end, - silent = true, - }, { "ss", function() @@ -109,9 +102,6 @@ return { enabled = false, }, }, - explorer = { - replace_netrw = true, - }, scratch = { ft = function() return "markdown"