diff --git a/nvim/after/ftplugin/go.lua b/nvim/after/ftplugin/go.lua new file mode 100644 index 0000000..7e13d97 --- /dev/null +++ b/nvim/after/ftplugin/go.lua @@ -0,0 +1 @@ +vim.cmd [[autocmd BufWritePre * lua vim.lsp.buf.format()]] diff --git a/nvim/after/ftplugin/lua.lua b/nvim/after/ftplugin/lua.lua new file mode 100644 index 0000000..45a6d74 --- /dev/null +++ b/nvim/after/ftplugin/lua.lua @@ -0,0 +1,4 @@ +vim.opt_local.tabstop = 2 +vim.opt_local.shiftwidth = 2 +vim.opt_local.softtabstop = 2 +vim.opt_local.expandtab = true diff --git a/nvim/init.lua b/nvim/init.lua new file mode 100644 index 0000000..a7420d9 --- /dev/null +++ b/nvim/init.lua @@ -0,0 +1,4 @@ +require("options") +require("keymap") +require("plugins/init") +require("lsp-config") diff --git a/nvim/lazy-lock.json b/nvim/lazy-lock.json new file mode 100644 index 0000000..2539dac --- /dev/null +++ b/nvim/lazy-lock.json @@ -0,0 +1,13 @@ +{ + "LuaSnip": { "branch": "master", "commit": "c9b9a22904c97d0eb69ccb9bab76037838326817" }, + "cmp-nvim-lsp": { "branch": "main", "commit": "99290b3ec1322070bcfb9e846450a46f6efa50f0" }, + "github-theme": { "branch": "main", "commit": "c106c9472154d6b2c74b74565616b877ae8ed31d" }, + "lazy.nvim": { "branch": "main", "commit": "6c3bda4aca61a13a9c63f1c1d1b16b9d3be90d7a" }, + "mason-lspconfig.nvim": { "branch": "main", "commit": "1a31f824b9cd5bc6f342fc29e9a53b60d74af245" }, + "mason.nvim": { "branch": "main", "commit": "fc98833b6da5de5a9c5b1446ac541577059555be" }, + "nvim-cmp": { "branch": "main", "commit": "c27370703e798666486e3064b64d59eaf4bdc6d5" }, + "nvim-lspconfig": { "branch": "master", "commit": "fd26f8626c03b424f7140d454031d1dcb8d23513" }, + "plenary.nvim": { "branch": "master", "commit": "857c5ac632080dba10aae49dba902ce3abf91b35" }, + "telescope-file-browser.nvim": { "branch": "master", "commit": "626998e5c1b71c130d8bc6cf7abb6709b98287bb" }, + "telescope.nvim": { "branch": "master", "commit": "814f102cd1da3dc78c7d2f20f2ef3ed3cdf0e6e4" } +} diff --git a/nvim/lua/keymap.lua b/nvim/lua/keymap.lua new file mode 100644 index 0000000..3bb2ffd --- /dev/null +++ b/nvim/lua/keymap.lua @@ -0,0 +1,5 @@ +vim.g.mapleader = " " +vim.keymap.set("n", "", " :noh", { desc = "Clear search highlighting" }) + +-- Find and replace visual selection using CTRL-r +vim.keymap.set("v", "", "\"hy:%s/h//gc") diff --git a/nvim/lua/lsp-config.lua b/nvim/lua/lsp-config.lua new file mode 100644 index 0000000..2d6dbcf --- /dev/null +++ b/nvim/lua/lsp-config.lua @@ -0,0 +1,123 @@ +require("mason").setup() +require("mason-lspconfig").setup({ + ensure_installed = { + 'lua_ls', + 'gopls', + 'bashls', + }, + automatic_installation = true, +}) + +-- Customized on_attach function +-- See `:help vim.diagnostic.*` for documentation on any of the below functions +-- +local opts = { noremap = true, silent = true } +vim.keymap.set("n", "e", vim.diagnostic.open_float, opts) +vim.keymap.set("n", "[d", vim.diagnostic.goto_prev, opts) +vim.keymap.set("n", "]d", vim.diagnostic.goto_next, opts) +vim.keymap.set("n", "q", vim.diagnostic.setloclist, opts) + +local on_attach = function(client, bufnr) + -- Enable completion triggered by + vim.api.nvim_buf_set_option(bufnr, "omnifunc", "v:lua.vim.lsp.omnifunc") + + if client.name == "rust_analyzer" then + -- This requires Neovim 0.10 or later + vim.lsp.inlay_hint.enable() + end + + -- See `:help vim.lsp.*` for documentation on any of the below functions + local bufopts = { noremap = true, silent = true, buffer = bufnr } + vim.keymap.set("n", "gD", vim.lsp.buf.declaration, bufopts) + vim.keymap.set("n", "gd", vim.lsp.buf.definition, bufopts) + vim.keymap.set("n", "K", vim.lsp.buf.hover, bufopts) + vim.keymap.set("n", "gi", vim.lsp.buf.implementation, bufopts) + vim.keymap.set("n", "", vim.lsp.buf.signature_help, bufopts) + vim.keymap.set("n", "wa", vim.lsp.buf.add_workspace_folder, bufopts) + vim.keymap.set("n", "wr", vim.lsp.buf.remove_workspace_folder, bufopts) + vim.keymap.set("n", "wl", function() + print(vim.inspect(vim.lsp.buf.list_workspace_folders())) + end, bufopts) + vim.keymap.set("n", "D", vim.lsp.buf.type_definition, bufopts) + vim.keymap.set("n", "rn", vim.lsp.buf.rename, bufopts) + vim.keymap.set("n", "ca", vim.lsp.buf.code_action, bufopts) + vim.keymap.set("n", "gr", vim.lsp.buf.references, bufopts) + vim.keymap.set("n", "lf", function() + vim.lsp.buf.format({ + async = true, + }) + end, bufopts) +end + +-- Specify the border characters +local border = { + { '┌', 'FloatBorder' }, + { '─', 'FloatBorder' }, + { '┐', 'FloatBorder' }, + { '│', 'FloatBorder' }, + { '┘', 'FloatBorder' }, + { '─', 'FloatBorder' }, + { '└', 'FloatBorder' }, + { '│', 'FloatBorder' }, +} + +-- Add the border on hover and on signature help popup window +local handlers = { + ['textDocument/hover'] = vim.lsp.with(vim.lsp.handlers.hover, { border = "rounded" }), + ['textDocument/signatureHelp'] = vim.lsp.with(vim.lsp.handlers.signature_help, { border = "rounded" }), +} + +-- Add border to the diagnostic popup window +vim.diagnostic.config({ + virtual_text = { + prefix = '■ ', -- Could be '●', '▎', 'x', '■', ,  + }, + signs = false, -- Show signs in the gutter + underline = true, + update_in_insert = false, -- Don't update diagnostics in insert mode + severity_sort = true, -- Sort diagnostics by severity + float = { border = "rounded" }, +}) + +local capabilities = require('cmp_nvim_lsp').default_capabilities() + +require("lspconfig").lua_ls.setup({ + on_attach = on_attach, + settings = { + Lua = { + format = { + enable = true, + defaultConfig = { + indent_style = "space", + indent_size = "2", + } + }, + runtime = { + -- Tell the language server which version of Lua you're using (most likely LuaJIT in the case of Neovim) + version = "LuaJIT", + }, + diagnostics = { + -- Get the language server to recognize the `vim` global + globals = { "vim" }, + }, + workspace = { + -- Make the server aware of Neovim runtime files + library = vim.api.nvim_get_runtime_file("", true), + }, + -- Do not send telemetry data containing a randomized but unique identifier + telemetry = { + enable = false, + }, + } + }, + capabilities = capabilities, + handlers = handlers +}) +require("lspconfig").gopls.setup {capabilities = capabilities, handlers = handlers} +require("lspconfig").bashls.setup {capabilities = capabilities, handlers = handlers, + settings = { + bashIde = { + globPattern = "*@(.sh|.inc|.bash|.command)" + } + } +} diff --git a/nvim/lua/options.lua b/nvim/lua/options.lua new file mode 100644 index 0000000..2a22814 --- /dev/null +++ b/nvim/lua/options.lua @@ -0,0 +1,22 @@ +vim.g.mapleader = ' ' +vim.g.maplocalleader = ' ' + +-- case insensitive search +vim.opt.ignorecase = true +vim.opt.smartcase = true + +-- show line numbers +vim.opt.number = true +vim.opt.relativenumber = true + +-- show trailing whitespace +vim.opt.list = true +vim.opt.listchars = { + tab = '▏ ', + multispace = '▏ ', + trail = '·', + extends = '…', + precedes = '…' +} + +vim.cmd([[match errorMsg /\s\+$/]]) diff --git a/nvim/lua/plugins/completions.lua b/nvim/lua/plugins/completions.lua new file mode 100644 index 0000000..60d949c --- /dev/null +++ b/nvim/lua/plugins/completions.lua @@ -0,0 +1,61 @@ +vim.opt.completeopt = { 'menu', 'menuone', 'noselect' } +-- Set up nvim-cmp +local cmp = require('cmp') +local luasnip = require('luasnip') +local select_opts = { behavior = cmp.SelectBehavior.Select } + +cmp.setup({ + snippet = { + expand = function(args) + luasnip.lsp_expand(args.body) + end + }, + window = { + documentation = cmp.config.window.bordered(), + completion = { border = 'rounded' } + }, + formatting = { + fields = { 'menu', 'abbr', 'kind' }, + format = function(entry, item) + local menu_icon = { + nvim_lsp = 'λ', + luasnip = '⋗', + buffer = 'Ω', + path = '🖫', + } + + item.menu = menu_icon[entry.source.name] + return item + end, + }, + mapping = { + -- Trigger completion menu with + [''] = cmp.mapping(function(fallback) + local col = vim.fn.col('.') - 1 + + if cmp.visible() then + cmp.select_next_item(select_opts) + elseif col == 0 or vim.fn.getline('.'):sub(col, col):match('%s') then + fallback() + else + cmp.complete() + end + end, { 'i', 's' }), + + -- Trigger completion menu with + [''] = cmp.mapping(cmp.mapping.complete(), { 'i', 'c' }), -- Open completion menu + + -- Navigate completion menu with and + [''] = cmp.mapping.select_next_item(), -- Next item + [''] = cmp.mapping.select_prev_item(), -- Previous item + + -- Confirm selection with (Enter) + [''] = cmp.mapping.confirm({ select = true }), -- Confirm selection + }, + sources = cmp.config.sources({ + { name = 'nvim_lsp' }, -- LSP source + { name = 'buffer' }, -- Buffer source + { name = 'path' }, -- Path source + { name = 'luasnip' }, -- Path source + }), +}) diff --git a/nvim/lua/plugins/init.lua b/nvim/lua/plugins/init.lua new file mode 100644 index 0000000..2da8a29 --- /dev/null +++ b/nvim/lua/plugins/init.lua @@ -0,0 +1,52 @@ +local lazypath = vim.fn.stdpath("data") .. "/lazy/lazy.nvim" +if not vim.loop.fs_stat(lazypath) then + vim.fn.system({ + "git", + "clone", + "--filter=blob:none", + "https://github.com/folke/lazy.nvim.git", + "--branch=stable", -- latest stable release + lazypath, + }) +end +vim.opt.rtp:prepend(lazypath) + +local plugins = { + "williamboman/mason.nvim", + "williamboman/mason-lspconfig.nvim", + { + "neovim/nvim-lspconfig", + dependencies = { 'hrsh7th/cmp-nvim-lsp' } + }, + { + 'projekt0n/github-nvim-theme', + name = 'github-theme', + lazy = false, -- make sure we load this during startup if it is your main colorscheme + priority = 1000, -- make sure to load this before all the other start plugins + config = function() + require('github-theme').setup({ + -- ... + }) + + vim.cmd('colorscheme github_light_colorblind') + -- vim.cmd('colorscheme github_dark_colorblind') + -- vim.cmd('colorscheme github_dark') + end, + }, + { + "nvim-telescope/telescope-file-browser.nvim", + dependencies = { "nvim-telescope/telescope.nvim", "nvim-lua/plenary.nvim" } + }, + 'hrsh7th/nvim-cmp', -- Auto-completion plugin + dependencies = { + 'hrsh7th/cmp-nvim-lsp', -- LSP source for nvim-cmp + 'hrsh7th/cmp-buffer', -- Buffer source for nvim-cmp + 'hrsh7th/cmp-path', -- Path source for nvim-cmp + }, + 'L3MON4D3/LuaSnip', +} + +require("lazy").setup(plugins) + +require("plugins/telescope") +require("plugins/completions") diff --git a/nvim/lua/plugins/telescope.lua b/nvim/lua/plugins/telescope.lua new file mode 100644 index 0000000..34d8c9a --- /dev/null +++ b/nvim/lua/plugins/telescope.lua @@ -0,0 +1,20 @@ +require("telescope").setup { + extensions = { + file_browser = { + initial_mode = "normal", + -- ... + }, + }, +} +require("telescope").load_extension "file_browser" +-- require("telescope").load_extension "find_files" + +-- vim.keymap.set("n", "fb", ":Telescope file_browser") + +-- open file_browser with the path of the current buffer +vim.keymap.set("n", "fb", ":Telescope file_browser path=%:p:h select_buffer=true") +local builtin = require('telescope.builtin') +vim.keymap.set('n', 'ff', builtin.find_files, { desc = 'Telescope find files' }) +vim.keymap.set('n', 'fg', builtin.live_grep, { desc = 'Telescope live grep' }) +vim.keymap.set('n', 'b', builtin.buffers, { desc = 'Telescope buffers' }) +vim.keymap.set('n', 'fh', builtin.help_tags, { desc = 'Telescope help tags' })