diff --git a/config/nvim/init.lua b/config/nvim/init.lua new file mode 100644 index 0000000..c31dc06 --- /dev/null +++ b/config/nvim/init.lua @@ -0,0 +1,110 @@ +-- Locals +local fn = vim.fn + +-- Install packer automagically +local install_path = fn.stdpath("data") .. "/site/pack/packer/start/packer.nvim" +if fn.empty(fn.glob(install_path)) > 0 then + PACKER_BOOTSTRAP = fn.system({ + "git", + "clone", + "--depth", + "1", + "https://github.com/wbthomason/packer.nvim", + install_path, + }) +end + +require("packer").startup(function(use) + use({ "wbthomason/packer.nvim" }) + + use({ "nvim-lua/popup.nvim" }) + use({ "nvim-lua/plenary.nvim" }) + + -- Colorschemes go here + use({ "folke/tokyonight.nvim" }) + + -- Make commenting code great + use({ "tpope/vim-commentary" }) + + -- Icons used by many plugins + use({ "kyazdani42/nvim-web-devicons" }) + + -- Auto pairs plugin that automatically closes brackets and quotes + use({ "windwp/nvim-autopairs" }) + + -- File tree + use({ "kyazdani42/nvim-tree.lua" }) + + -- Treesitter for better syntax highlighting + use({ + "nvim-treesitter/nvim-treesitter", + run = ":TSUpdate", + { + { "JoosepAlviste/nvim-ts-context-commentstring" }, + { "nvim-treesitter/playground" }, + { "windwp/nvim-ts-autotag" }, + }, + }) + + -- Git things + use({ "lewis6991/gitsigns.nvim" }) + use({ "tpope/vim-fugitive" }) + + -- LSP stuff + use({ "neovim/nvim-lspconfig" }) + use({ "williamboman/nvim-lsp-installer" }) + use({ "jose-elias-alvarez/null-ls.nvim" }) + + -- Completion, snippets, etc + use({ + "hrsh7th/nvim-cmp", + { + { "hrsh7th/cmp-nvim-lsp" }, + { "hrsh7th/cmp-buffer" }, + { "hrsh7th/cmp-path" }, + { "hrsh7th/cmp-cmdline" }, + }, + }) + use({ "L3MON4D3/LuaSnip", { + "saadparwaiz1/cmp_luasnip", + } }) + + use({ "nvim-telescope/telescope.nvim" }) + + -- Statusline + use({ "nvim-lualine/lualine.nvim" }) + + -- Highlight todo comments + use({ + "folke/todo-comments.nvim", + config = function() + require("todo-comments").setup({}) + end, + }) + + use({ + "folke/trouble.nvim", + config = function() + require("trouble").setup({}) + end, + }) + + if PACKER_BOOTSTRAP then + require("packer").sync() + end +end) + +vim.g.mapleader = " " + +require("user.options") +require("user.theme") + +require("nvim-autopairs").setup({}) + +require("user.file-tree") +require("user.treesitter") +require("user.telescope") +require("user.git") +require("user.lsp") +require("user.lualine") +require("user.remaps") diff --git a/config/nvim/lua/user/file-tree.lua b/config/nvim/lua/user/file-tree.lua new file mode 100644 index 0000000..400b7b4 --- /dev/null +++ b/config/nvim/lua/user/file-tree.lua @@ -0,0 +1,40 @@ +local tree_cb = require("nvim-tree.config").nvim_tree_callback +local nmap = require("user.utils").nmap + +require("nvim-tree").setup({ + disable_netrw = true, + hijack_netrw = true, + open_on_setup = true, + hijack_cursor = true, + open_on_tab = true, + update_cwd = true, + auto_close = true, + update_focused_file = { + enable = true, + }, + view = { + width = 30, + side = "left", + auto_resize = true, + mappings = { + list = { + { + key = "", + cb = tree_cb("tabnew"), + }, + }, + }, + }, + filters = { + custom = { ".git" }, + }, + git = { + ignore = false, + }, +}) + +vim.g.nvim_tree_add_trailing = 1 +vim.g.nvim_tree_indent_markers = 1 +-- TODO: Change git icons to something similar to vscode + +nmap("b", ":NvimTreeToggle") diff --git a/config/nvim/lua/user/git.lua b/config/nvim/lua/user/git.lua new file mode 100644 index 0000000..b539d46 --- /dev/null +++ b/config/nvim/lua/user/git.lua @@ -0,0 +1,17 @@ +require("gitsigns").setup({ + signcolumn = true, + keymaps = { + noremap = true, + + ["n gs"] = ":Gitsigns stage_hunk", + ["n gu"] = ":Gitsigns undo_stage_hunk", + ["n gr"] = ":Gitsigns reset_hunk", + }, + current_line_blame = true, + current_line_blame_opts = { + delay = 1000, + }, + current_line_blame_formatter_opts = { + relative_time = true, + }, +}) diff --git a/config/nvim/lua/user/lsp.lua b/config/nvim/lua/user/lsp.lua new file mode 100644 index 0000000..bc51700 --- /dev/null +++ b/config/nvim/lua/user/lsp.lua @@ -0,0 +1,179 @@ +local lsp_installer = require("nvim-lsp-installer") +local cmp = require("cmp") +local null_ls = require("null-ls") +local list_includes_item = require("user.utils").list_includes_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 = "", +} + +local formatting = null_ls.builtins.formatting +local diagnostics = null_ls.builtins.diagnostics + +null_ls.setup({ + sources = { + formatting.prettierd, + formatting.stylua, + formatting.black, + formatting.gofmt, + formatting.goimports, + formatting.shfmt, + }, + on_attach = function() + vim.cmd([[ + augroup LspFormatting + autocmd! * + autocmd BufWritePre lua vim.lsp.buf.formatting_sync() + augroup END + ]]) + end, +}) + +-- Other formats that work weird with null_ls +vim.cmd([[autocmd BufWritePre *.svelte lua vim.lsp.buf.formatting_sync(nil, 1000)]]) + +cmp.setup({ + snippet = { + expand = function(args) + require("luasnip").lsp_expand(args.body) + end, + }, + mapping = { + [""] = cmp.mapping.select_next_item({ behavior = cmp.SelectBehavior.Select }), + [""] = cmp.mapping.select_prev_item({ behavior = cmp.SelectBehavior.Select }), + [""] = cmp.mapping(function(fallback) + if cmp.visible() then + cmp.close() + else + cmp.complete() + end + end), + [""] = cmp.mapping.confirm({ + select = true, + behavior = cmp.SelectBehavior.Insert, + }), + }, + sources = cmp.config.sources({ + { name = "nvim_lsp" }, + { name = "luasnip" }, + }, { + { name = "path" }, + { name = "buffer" }, + }), + completion = { + completeopt = "menu,menuone,noselect,noinsert,preview", + }, + experimental = { + ghost_text = true, + }, + sorting = { + comparators = { + cmp.config.compare.score, + cmp.config.compare.sort_text, + cmp.config.compare.kind, + }, + }, + documentation = { + border = { "╭", "─", "╮", "│", "╯", "─", "╰", "│" }, + zindex = 999, + format = { "markdown" }, + }, + formatting = { + format = function(entry, vim_item) + vim_item.kind = string.format("%s %s", kind_icons[vim_item.kind], vim_item.kind) + vim_item.menu = ({ + buffer = "[Buffer]", + luasnip = "[Snippet]", + nvim_lua = "[Lua]", + path = "[File]", + })[entry.source.name] + + return vim_item + end, + }, +}) + +cmp.setup.cmdline("/", { + sources = { + { name = "cmdline" }, + }, +}) + +cmp.setup.cmdline(":", { + sources = { + { name = "cmdline" }, + }, +}) + +local capabilities = require("cmp_nvim_lsp").update_capabilities(vim.lsp.protocol.make_client_capabilities()) + +local lsps_with_disabled_formatting = { "tsserver", "gopls" } + +local on_attach = function(client) + if list_includes_item(lsps_with_disabled_formatting, client.name) then + client.resolved_capabilities.document_formatting = false + client.resolved_capabilities.document_range_formatting = false + end +end + +lsp_installer.on_server_ready(function(server) + local opts = { + capabilities = capabilities, + on_attach = on_attach, + } + + if server.name == "sumneko_lua" then + local runtime_path = vim.split(package.path, ";") + table.insert(runtime_path, "lua/?.lua") + table.insert(runtime_path, "lua/?/init/lua") + + opts.settings = { + Lua = { + runtime = { + version = "LuaJIT", + path = runtime_path, + }, + diagnostics = { + library = vim.api.nvim_get_runtime_file("", true), + }, + telemetry = { + enable = false, + }, + }, + } + end + + server:setup(opts) +end) + +-- Don't show diagnostics as virtual text +vim.lsp.handlers["textDocument/publishDiagnostics"] = vim.lsp.with(vim.lsp.diagnostic.on_publish_diagnostics, { + update_in_insert = true, + virtual_text = false, +}) + +require("luasnip.loaders.from_vscode").load() diff --git a/config/nvim/lua/user/lualine.lua b/config/nvim/lua/user/lualine.lua new file mode 100644 index 0000000..4d7abd7 --- /dev/null +++ b/config/nvim/lua/user/lualine.lua @@ -0,0 +1,60 @@ +local lualine = require("lualine") + +local hide_in_width = function() + return vim.fn.winwidth(0) > 80 +end + +local branch = { + "branch", + icons_enabled = true, + icon = "", +} + +local diagnostics = { + "diagnostics", + sections = { "error", "warn" }, + symbols = { error = " ", warn = " " }, + colored = false, + update_in_insert = false, + always_visible = true, +} + +local mode = { + "mode", + fmt = function(str) + return "-- " .. str .. " --" + end, +} + +local diff = { + "diff", + colored = false, + symbols = { added = " ", modified = " ", removed = " " }, -- changes diff symbols + cond = hide_in_width, +} + +local filetype = { + "filetype", +} + +local location = function() + local line, column = unpack(vim.api.nvim_win_get_cursor(0)) + + return "Ln " .. line .. ", Col " .. column +end + +lualine.setup({ + options = { + disabled_filetypes = { "NvimTree" }, + component_separators = { left = "", right = "" }, + section_separators = { left = "", right = "" }, + }, + sections = { + lualine_a = { branch, diagnostics }, + lualine_b = { mode }, + lualine_c = {}, + lualine_x = { diff, "encoding", filetype }, + lualine_y = { location }, + lualine_z = {}, + }, +}) diff --git a/config/nvim/lua/user/options.lua b/config/nvim/lua/user/options.lua new file mode 100644 index 0000000..b0f95f5 --- /dev/null +++ b/config/nvim/lua/user/options.lua @@ -0,0 +1,30 @@ +local opt = vim.opt + +-- 2 tabs converted to spaces + autoindentation +opt.tabstop = 2 +opt.shiftwidth = 2 +opt.expandtab = true +opt.autoindent = true + +-- What the **** is this +opt.shortmess = "filnxtToOFc" + +-- Create splits like a normal human being +opt.splitbelow = true +opt.splitright = true + +-- Other settings +opt.number = true +opt.relativenumber = true +opt.wrap = true +opt.swapfile = false +opt.hidden = true +opt.writebackup = false +opt.encoding = "utf-8" +opt.updatetime = 300 +opt.mouse = "a" +opt.cursorline = true +opt.clipboard = "unnamedplus" +opt.fillchars:append({ eob = " " }) + +-- TODO: Add settings for nvim-treesitter provided folding diff --git a/config/nvim/lua/user/remaps.lua b/config/nvim/lua/user/remaps.lua new file mode 100644 index 0000000..4d32e44 --- /dev/null +++ b/config/nvim/lua/user/remaps.lua @@ -0,0 +1,40 @@ +local utils = require("user.utils") +local nmap = utils.nmap + +-- Move focus between splits +nmap("h", "h") -- Leader+h - focus left split +nmap("l", "l") -- Leader+l - focus right split +nmap("j", "j") -- Leader+j - focus split under focused one +nmap("k", "k") -- Leader+k - focus split above focused one + +-- Resize splits +nmap("", ":resize -2") -- Control+j - decrease split height +nmap("", ":resize +2") -- Control+k - increase split height +nmap("", ":vert resize -5") -- Control+h - decrease split width +nmap("", ":vert resize +5") -- Control+l - increase split width + +-- Open splits +nmap("sv", ":vs") -- Leader+s+v - split current window vertically +nmap("sh", ":split") -- Leader+s+h - split current window horizontally + +-- Tabs +nmap("H", ":tabprev") -- Shift+h - open previous tab +nmap("L", ":tabnext") -- Shift+l - open next tab +nmap("", ":tabnew") -- Control+t - open new empty tab +nmap("", ":tabclose") -- Control+w - close current tab +nmap("", ":-tabmove") -- Switch current tab with previous one +nmap("", ":+tabmove") -- Switch current tab with next one + +-- Telescope +nmap("f", ":Telescope find_files") -- Leader+f - find files with Telescope +nmap("p", ":Telescope") -- Leader+p - open Telescope as command palette + +-- LSP +nmap("gd", ":lua vim.lsp.buf.definition()") -- g+d - Go to definition +nmap("gr", ":lua vim.lsp.buf.references()") -- g+r - Show references +nmap("K", ":lua vim.lsp.buf.hover()") -- Shift+k - Show documentation in hover window +nmap("", ":lua vim.lsp.buf.rename()") -- F2 - Rename thing under the cursor +nmap("d", ':lua vim.diagnostic.open_float(nil, {focus = false, scope = "cursor"})') -- Leader+d - show diagnostics in float window + +-- Git +nmap("gg", ":G") -- Leader+g+g - open vim-fugitive window diff --git a/config/nvim/lua/user/telescope.lua b/config/nvim/lua/user/telescope.lua new file mode 100644 index 0000000..1fb86a5 --- /dev/null +++ b/config/nvim/lua/user/telescope.lua @@ -0,0 +1,6 @@ +require("telescope").setup({ + defaults = { + sorting_strategy = "ascending", + file_ignore_patterns = { ".git/", "node_modules/" }, + }, +}) diff --git a/config/nvim/lua/user/theme.lua b/config/nvim/lua/user/theme.lua new file mode 100644 index 0000000..948f5eb --- /dev/null +++ b/config/nvim/lua/user/theme.lua @@ -0,0 +1,14 @@ +local cmd = vim.cmd + +vim.g.tokyonight_style = "night" +cmd([[colorscheme tokyonight]]) + +cmd([[ +hi NvimTreeGitNew guifg=green +hi NvimTreeGitStaged guifg=lightgreen +hi NvimTreeGitDeleted guifg=red +hi NvimTreeGitDirty guifg=lightblue +hi NvimTreeGitMerge guifg=yellow +hi NvimTreeGitIgnored guifg=gray +hi NvimTreeOpenedFolderName gui=italic,bold +]]) diff --git a/config/nvim/lua/user/treesitter.lua b/config/nvim/lua/user/treesitter.lua new file mode 100644 index 0000000..795dd6b --- /dev/null +++ b/config/nvim/lua/user/treesitter.lua @@ -0,0 +1,9 @@ +require("nvim-treesitter.configs").setup({ + ensure_installed = "maintained", + highlight = { + enable = true, + }, + context_commentstring = { + enable = true, + }, +}) diff --git a/config/nvim/lua/user/utils.lua b/config/nvim/lua/user/utils.lua new file mode 100644 index 0000000..28a410a --- /dev/null +++ b/config/nvim/lua/user/utils.lua @@ -0,0 +1,21 @@ +local M = {} + +local function map(mode, shortcut, command) + vim.api.nvim_set_keymap(mode, shortcut, command, { noremap = true, silent = true }) +end + +M.nmap = function(shortcut, command) + map("n", shortcut, command) +end + +M.list_includes_item = function(list, item) + for _, value in pairs(list) do + if value == item then + return true + end + end + + return false +end + +return M