diff --git a/nvim/coc-settings.json b/nvim/coc-settings.json deleted file mode 100644 index 1a88653..0000000 --- a/nvim/coc-settings.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "suggest.noselect": false, - "eslint.autoFixOnSave": true, - "eslint.filetypes": ["javascript", "javascriptreact", "typescript", "typescriptreact"], - "coc.preferences.formatOnSaveFiletypes": ["markdown", "mdx", "javascript", "javascriptreact", "typescript", "typescriptreact"], - "coc.preferences.jumpCommand": "vsplit" -} diff --git a/nvim/init.lua b/nvim/init.lua new file mode 100644 index 0000000..71d9257 --- /dev/null +++ b/nvim/init.lua @@ -0,0 +1,67 @@ +-- mostly sourced from https://github.com/garcia5/dotfiles/blob/master/files/nvim/init.lua + +-- Essentials +vim.g.mapleader = " " +vim.g.bulitin_lsp = true + +-- load my config +require("dwl") + +-- Behaviours +vim.opt.belloff = "all" -- NO BELLS! +vim.opt.completeopt = { "menu", "menuone", "noselect" } -- ins-completion how vsnip likes it +vim.opt.swapfile = false -- no swap files +vim.opt.inccommand = "nosplit" -- preview %s commands live as I type +-- vim.opt.grepprg = "rg --vimgrep --smart-case --no-heading" -- search with rg +-- vim.opt.grepformat = "%f:%l:%c:%m" -- filename:line number:column number:error message +vim.opt.mouse = "nv" -- use mouse in normal, visual modes +vim.opt.mousescroll = "ver:3,hor:0" -- scroll vertically by 3 lines, no horizontal scrolling +vim.opt.clipboard = "unnamed" + +-- Indentation +vim.opt.autoindent = true -- continue indentation to new line +vim.opt.smartindent = true -- add extra indent when it makes sense +vim.opt.smarttab = true -- at the start of a line behaves as expected +vim.opt.expandtab = true -- inserts spaces +vim.opt.shiftwidth = 4 -- >>, << shift line by 4 spaces +vim.opt.tabstop = 2 -- appears as 4 spaces +vim.opt.softtabstop = 2 -- behaves as 4 spaces when editing +vim.opt.copyindent = true + +-- Colors +vim.opt.termguicolors = true +vim.opt.background = "dark" +-- vim.cmd("colorscheme tokyonight-night") + +-- Look and feel +vim.opt.number = true +vim.opt.relativenumber = true +vim.opt.signcolumn = "yes" -- show the sign column always +vim.opt.cursorline = false -- don't highlight current line +vim.opt.list = true -- show list chars +vim.opt.listchars = { + -- these list chars + tab = "<->", + nbsp = "␣", + extends = "…", + precedes = "…", + trail = "·", + multispace = "·", -- show chars if I have multiple spaces between text + leadmultispace = " ", -- ...but don't show any when they're at the start +} +vim.opt.scrolloff = 2 -- padding between cursor and top/bottom of window +-- vim.opt.foldlevel = 0 -- allow folding the whole way down +-- vim.opt.foldlevelstart = 99 -- open files with all folds open +vim.opt.splitright = true -- prefer vsplitting to the right +vim.opt.splitbelow = true -- prefer splitting below +vim.opt.wrap = false -- don't wrap my text +-- vim.opt.textwidth = 120 -- wrap here for comments by default +vim.opt.cursorline = true -- hightlight line cursor is on +-- vim.opt.laststatus = 3 -- single global statusline + +-- Searching +-- vim.opt.wildmenu = true -- tab complete on command line +vim.opt.ignorecase = true -- case insensitive search... +vim.opt.smartcase = true -- unless I use caps +vim.opt.hlsearch = true -- highlight matching text +vim.opt.incsearch = true -- update results while I type \ No newline at end of file diff --git a/nvim/init.vim b/nvim/init.vim deleted file mode 100644 index b42c8d9..0000000 --- a/nvim/init.vim +++ /dev/null @@ -1,3 +0,0 @@ -set runtimepath^=~/.vim runtimepath+=~/.vim/after -let &packpath=&runtimepath -source ~/.vimrc diff --git a/nvim/lua/dwl/init.lua b/nvim/lua/dwl/init.lua new file mode 100644 index 0000000..beecf67 --- /dev/null +++ b/nvim/lua/dwl/init.lua @@ -0,0 +1,6 @@ +-- require("ag.autocmd") -- lua autocommands +local no_plugins = require("dwl.plugins") -- plugins +require("dwl.mappings") -- keymaps +if no_plugins then return end +require("dwl.lsp_config") -- LSP configs +require("dwl.treesitter") -- treesitter configs \ No newline at end of file diff --git a/nvim/lua/dwl/lsp_config.lua b/nvim/lua/dwl/lsp_config.lua new file mode 100644 index 0000000..c18a367 --- /dev/null +++ b/nvim/lua/dwl/lsp_config.lua @@ -0,0 +1,286 @@ +local lspconfig = require("lspconfig") + +local lsp_filetypes = { + -- "vue", + "typescript", + "json", + "javascript", + -- "python", + -- "rust", + "yaml", + "bash", + -- "lua", +} + +-- Give floating windows borders +vim.lsp.handlers["textDocument/hover"] = vim.lsp.with(vim.lsp.handlers.hover, { border = "rounded" }) + +-- Configure diagnostic display +vim.diagnostic.config({ + virtual_text = { + -- Only display errors w/ virtual text + severity = vim.diagnostic.severity.ERROR, + -- Prepend with diagnostic source if there is more than one attached to the buffer + -- (e.g. (eslint) Error: blah blah blah) + source = "if_many", + signs = false, + }, + float = { + severity_sort = true, + source = "if_many", + border = "solid", + header = { + "", + "LspDiagnosticsDefaultWarning", + }, + prefix = function(diagnostic) + local diag_to_format = { + [vim.diagnostic.severity.ERROR] = { "Error", "LspDiagnosticsDefaultError" }, + [vim.diagnostic.severity.WARN] = { "Warning", "LspDiagnosticsDefaultWarning" }, + [vim.diagnostic.severity.INFO] = { "Info", "LspDiagnosticsDefaultInfo" }, + [vim.diagnostic.severity.HINT] = { "Hint", "LspDiagnosticsDefaultHint" }, + } + local res = diag_to_format[diagnostic.severity] + return string.format("(%s) ", res[1]), res[2] + end, + }, + severity_sort = true, +}) + +-- Don't let tsserver or vuels do formatting, they do it wrong +local custom_format = function(bufnr) + vim.lsp.buf.format({ + bufnr = bufnr, + filter = function(client) return client.name ~= "tsserver" and client.name ~= "vuels" end, + }) +end +local format_group = vim.api.nvim_create_augroup("LspFormatting", { clear = true }) +local format_on_save = function(bufnr) + vim.api.nvim_create_autocmd("BufWritePre", { + group = format_group, + buffer = bufnr, + callback = function() custom_format(bufnr) end, + }) +end + +local custom_attach = function(client, bufnr) + local keymap_opts = { buffer = bufnr, silent = true, noremap = true } + -- LSP mappings (only apply when LSP client attached) + vim.keymap.set("n", "K", vim.lsp.buf.hover, keymap_opts) + -- vim.keymap.set("n", "", vim.lsp.buf.definition, keymap_opts) + -- vim.keymap.set("n", "gr", vim.lsp.buf.references, keymap_opts) + -- vim.keymap.set("n", "gr", vim.lsp.buf.rename, keymap_opts) + + -- diagnostics + vim.keymap.set("n", "dk", vim.diagnostic.open_float, keymap_opts) -- diagnostic(s) on current line + vim.keymap.set("n", "dn", vim.diagnostic.goto_next, keymap_opts) -- move to next diagnostic in buffer + vim.keymap.set("n", "dp", vim.diagnostic.goto_prev, keymap_opts) -- move to prev diagnostic in buffer + vim.keymap.set("n", "da", vim.diagnostic.setqflist, keymap_opts) -- show all buffer diagnostics in qflist + vim.keymap.set("n", "H", vim.lsp.buf.code_action, keymap_opts) -- code actions (handled by telescope-ui-select) + vim.keymap.set("n", "F", function() custom_format(bufnr) end, keymap_opts) -- manual formatting, because sometimes null-ls just decides to stop working + + -- use omnifunc + vim.bo[bufnr].omnifunc = "v:lua.vim.lsp.omnifunc" + vim.bo[bufnr].formatexpr = "v:lua.vim.lsp.formatexpr" +end + +local web_dev_attach = function(client, bufnr) + -- local root_files = vim.fn.readdir(vim.fn.getcwd()) + -- local volar = false + -- -- TODO: the "right" way to do this would be to check the typescript version, but that seems hard + -- for _, fname in ipairs(root_files) do + -- if fname == "pnpm-lock.yaml" then volar = true end + -- end + + -- -- disable vuels and tsserver if we're using volar + -- if volar and (client.name == "tsserver" or client.name == "vuels") then + -- client.stop() + -- return false + -- end + + -- -- disable volar if we don't have pnpm + -- if not volar and client.name == "volar" then + -- client.stop() + -- return false + -- end + + format_on_save(bufnr) + + custom_attach(client, bufnr) + return true +end + +-- Set up clients +local null_ls = require("null-ls") +null_ls.setup({ + on_attach = custom_attach, + should_attach = function(bufnr) + local cur_ft = vim.bo[bufnr].filetype + for _, ft in ipairs({ "javascript", "javascriptreact", "javascript.jsx", "typescript", "typescriptreact", "typescript.tsx"}) do + if ft == cur_ft then return true end + end + return false + end, + sources = { + --#formatters + null_ls.builtins.formatting.prettierd, + null_ls.builtins.formatting.eslint_d, + + --#diagnostics/linters + null_ls.builtins.diagnostics.eslint_d, + + --#code actions + null_ls.builtins.code_actions.eslint_d, + }, + fallback_severity = vim.diagnostic.severity.WARN, +}) + +-- python +-- lspconfig.pyright.setup({ +-- on_attach = function(client, bufnr) +-- custom_attach(client, bufnr) +-- -- 'Organize imports' keymap for pyright only +-- vim.keymap.set("n", "ii", "PyrightOrganizeImports", { +-- buffer = bufnr, +-- silent = true, +-- noremap = true, +-- }) +-- end, +-- settings = { +-- pyright = { +-- disableOrganizeImports = false, +-- analysis = { +-- useLibraryCodeForTypes = true, +-- autoSearchPaths = true, +-- diagnosticMode = "workspace", +-- autoImportCompletions = true, +-- }, +-- }, +-- }, +-- }) + +-- typescript +lspconfig.tsserver.setup({ + on_attach = function(client, bufnr) + if not web_dev_attach(client, bufnr) then return end + + -- local ts_utils = require("nvim-lsp-ts-utils") + -- ts_utils.setup({ + -- update_imports_on_move = false, + -- enable_import_on_completion = true, + -- }) + + -- ts_utils.setup_client(client) + + -- TS specific mappings + vim.keymap.set("n", "ii", "TSLspOrganize", { buffer = bufnr, silent = true, noremap = true }) -- organize imports + vim.keymap.set("n", "R", "TSLspRenameFile", { buffer = bufnr, silent = true, noremap = true }) -- rename file AND update references to it + end, +}) + +-- vue +-- lspconfig.vuels.setup({ +-- on_attach = web_dev_attach, +-- settings = { +-- vetur = { +-- completion = { +-- autoImport = true, +-- tagCasing = "kebab", +-- useScaffoldSnippets = true, +-- }, +-- useWorkspaceDependencies = true, +-- experimental = { +-- templateInterpolationService = true, +-- }, +-- }, +-- format = { +-- enable = true, +-- options = { +-- useTabs = false, +-- tabSize = 2, +-- }, +-- defaultFormatter = { +-- ts = "prettier", +-- }, +-- scriptInitialIndent = false, +-- styleInitialIndent = false, +-- }, +-- validation = { +-- template = true, +-- script = true, +-- style = true, +-- templateProps = true, +-- interpolation = true, +-- }, +-- }, +-- }) + +-- lspconfig.volar.setup({ +-- on_attach = web_dev_attach, +-- -- enable "take over mode" for typescript files as well: https://github.com/johnsoncodehk/volar/discussions/471 +-- filetypes = { "typescript", "javascript", "javascriptreact", "typescriptreact", "vue" }, +-- init_options = { +-- typescript = { +-- -- "take over mode" can be weird in monorepos, use a global typescript installation instead +-- serverPath = vim.fn.expand("~") .. "/.config/yarn/global/node_modules/typescript/lib/tsserverlibrary.js", +-- }, +-- }, +-- }) + +-- yaml +lspconfig.yamlls.setup({ + on_attach = custom_attach, +}) + +-- -- bash +-- lspconfig.bashls.setup({ +-- on_attach = custom_attach, +-- }) + +-- -- lua +-- lspconfig.sumneko_lua.setup({ +-- on_attach = function(client, bufnr) +-- custom_attach(client, bufnr) +-- format_on_save(bufnr) +-- end, +-- settings = { +-- Lua = { +-- 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, +-- }, +-- }, +-- }, +-- }) + +-- json w/ common schemas +-- lspconfig.jsonls.setup({ +-- on_attach = custom_attach, +-- settings = { +-- json = { +-- schemas = require("schemastore").json.schemas(), +-- validate = { enable = true }, +-- }, +-- }, +-- }) + +-- rust +-- lspconfig.rust_analyzer.setup({ +-- on_attach = custom_attach, +-- }) + +return { + lsp_filetypes = lsp_filetypes, +} diff --git a/nvim/lua/dwl/mappings.lua b/nvim/lua/dwl/mappings.lua new file mode 100644 index 0000000..bc80365 --- /dev/null +++ b/nvim/lua/dwl/mappings.lua @@ -0,0 +1,16 @@ +-- Mapping helper +local mapper = function(mode, key, result) vim.keymap.set(mode, key, result, { noremap = true, silent = true }) end +local no_plugins = require("dwl.plugins") + +mapper("n", "", "h") +mapper("n", "", "j") +mapper("n", "", "k") +mapper("n", "", "l") + +mapper("n", "gd", ":vs | lua vim.lsp.buf.definition()") -- open defn in a new vsplit + +if no_plugins then return end + +local telescope_builtin = require("telescope.builtin") + +mapper("n", "", telescope_builtin.find_files) -- search all files, respecting .gitignore if one exists \ No newline at end of file diff --git a/nvim/lua/dwl/plugin-conf/completion.lua b/nvim/lua/dwl/plugin-conf/completion.lua new file mode 100644 index 0000000..06b5b9f --- /dev/null +++ b/nvim/lua/dwl/plugin-conf/completion.lua @@ -0,0 +1,48 @@ +local cmp = require("cmp") +local cmp_autopairs = require('nvim-autopairs.completion.cmp') +if not cmp then return end + +cmp.setup({ + snippet = { + expand = function(args) vim.fn["vsnip#anonymous"](args.body) end, + }, + sources = cmp.config.sources({ + { name = "vsnip" }, + { name = "nvim_lua" }, + { name = "nvim_lsp", max_item_count = 30 }, -- tsserver likes to send back _everything_ + { name = "nvim_lsp_signature_help" }, + { name = "path" }, + { name = "buffer", keyword_length = 3 }, -- don't complete from buffer right away + }), + mapping = cmp.mapping.preset.insert({ + [""] = cmp.mapping.scroll_docs(-4), + [""] = cmp.mapping.scroll_docs(4), + [""] = cmp.mapping.complete({ reason = cmp.ContextReason.Manual }), + [""] = cmp.mapping.close(), + [""] = cmp.mapping.confirm({ + behavior = cmp.ConfirmBehavior.Insert, + select = true, -- use first result if none explicitly selected + }), + -- [""] = cmp.mapping.select_next_item({ behavior = cmp.SelectBehavior.Select }), + -- [""] = cmp.mapping.select_prev_item({ behavior = cmp.SelectBehavior.Select }), + }), + preselect = cmp.PreselectMode.None, + formatting = { + -- Show where the completion opts are coming from + format = require("lspkind").cmp_format({ + with_text = true, + menu = { + vsnip = "[vsnip]", + nvim_lua = "[nvim]", + nvim_lsp = "[LSP]", + path = "[path]", + buffer = "[buffer]", + nvim_lsp_signature_help = "[param]", + }, + }), + }, + experimental = { + native_menu = false, + ghost_text = true, + }, +}) \ No newline at end of file diff --git a/nvim/lua/dwl/plugin-conf/tokyonight.lua b/nvim/lua/dwl/plugin-conf/tokyonight.lua new file mode 100644 index 0000000..84b2c29 --- /dev/null +++ b/nvim/lua/dwl/plugin-conf/tokyonight.lua @@ -0,0 +1,44 @@ +local tn = require("tokyonight") + +tn.setup({ + style = "night", + -- transparent = false, + terminal_colors = true, + styles = { + comments = { italic = true }, + -- strings = { italic = true }, + }, + -- on_highlights = function(hl, c) + -- local prompt = "#2d3149" + -- -- borderless telescope + -- hl.TelescopeNormal = { + -- bg = c.bg_dark, + -- fg = c.fg_dark, + -- } + -- hl.TelescopeBorder = { + -- bg = c.bg_dark, + -- fg = c.bg_dark, + -- } + -- hl.TelescopePromptNormal = { + -- bg = prompt, + -- } + -- hl.TelescopePromptBorder = { + -- bg = prompt, + -- fg = prompt, + -- } + -- hl.TelescopePromptTitle = { + -- bg = prompt, + -- fg = prompt, + -- } + -- hl.TelescopePreviewTitle = { + -- bg = c.bg_dark, + -- fg = c.bg_dark, + -- } + -- hl.TelescopeResultsTitle = { + -- bg = c.bg_dark, + -- fg = c.bg_dark, + -- } + -- end, + -- sidebars = { "qf", "help", "aerial", "packer" }, +}) +vim.cmd("colorscheme tokyonight-night") \ No newline at end of file diff --git a/nvim/lua/dwl/plugins.lua b/nvim/lua/dwl/plugins.lua new file mode 100644 index 0000000..3085d46 --- /dev/null +++ b/nvim/lua/dwl/plugins.lua @@ -0,0 +1,94 @@ +-- Bootstrap packer if necessary +local install_path = vim.fn.stdpath("data") .. "/site/pack/packer/start/packer.nvim" +local packer_bootstrap = false +-- local lsp_filetypes = require("ag.lsp_config").lsp_filetypes + +if vim.fn.empty(vim.fn.glob(install_path)) > 0 then + packer_bootstrap = vim.fn.system({ "git", "clone", "https://github.com/wbthomason/packer.nvim", install_path }) +end + +-- Init setup +vim.cmd("packadd packer.nvim") -- load packer +local packer = require("packer") + +packer.init({ + auto_reload_compiled = true, +}) + +packer.startup(function(use) + -- Strictly required + use("wbthomason/packer.nvim") + use("nvim-lua/plenary.nvim") -- utility functions + + -- Essentials + use({ + "nvim-telescope/telescope.nvim", -- fuzzy find ALL the things + -- config = function() require("dwl.plugin-conf.telescope") end, + }) + use({ + "windwp/nvim-ts-autotag", -- auto close html tags + ft = { "html", "tsx", "typescriptreact", "javascriptreact" } + }) + use({ + "windwp/nvim-autopairs", -- auto close sybmols + config = function() + require("nvim-autopairs").setup({ + map_cr = true, -- send closing symbol to its own line + check_ts = true, -- use treesitter + }) + end, + disable_filetype = { "TelescopePrompt", "fugitive" }, + }) + + -- Colourschemes + use({ + "folke/tokyonight.nvim", + config = function() require("dwl.plugin-conf.tokyonight") end, + }) + use("lukas-reineke/indent-blankline.nvim") + + -- LSP & Treesitter + use("neovim/nvim-lspconfig") -- basic configurations for LSP client + use("jose-elias-alvarez/null-ls.nvim") -- bridge between LSP client and external formatters/linters, not full fledged language servers + use({ + "nvim-treesitter/nvim-treesitter", -- treesitter + run = ":TSUpdate", + }) + + -- Nice to have + use("tpope/vim-commentary") -- commenting + use("tpope/vim-surround") -- surround + use("tpope/vim-fugitive") -- git + use({ + "jose-elias-alvarez/nvim-lsp-ts-utils", -- helpers for typescript development + ft = { + "typescript", + "typescriptreact", + "typescript.tsx", + "javascript", + "javascriptreact", + "javascript.jsx", + }, + }) + use("JoosepAlviste/nvim-ts-context-commentstring") + use({ + "hrsh7th/nvim-cmp", -- autocomplete + requires = { + -- completion sources + "hrsh7th/cmp-nvim-lsp", + "hrsh7th/cmp-nvim-lsp-signature-help", + "hrsh7th/cmp-nvim-lua", + "hrsh7th/cmp-buffer", + "hrsh7th/cmp-vsnip", + "hrsh7th/cmp-path", + -- complements + "onsails/lspkind-nvim", -- add the nice source + completion item kind to the menu + }, + config = function() require("dwl.plugin-conf.completion") end, + module = "cmp", + }) + + if packer_bootstrap then packer.sync() end +end) + +return packer_bootstrap \ No newline at end of file diff --git a/nvim/lua/dwl/treesitter.lua b/nvim/lua/dwl/treesitter.lua new file mode 100644 index 0000000..f93d49b --- /dev/null +++ b/nvim/lua/dwl/treesitter.lua @@ -0,0 +1,95 @@ +-- vim.opt.foldmethod = "expr" -- use function to determine folds +-- vim.opt.foldexpr = "nvim_treesitter#foldexpr()" -- use treesitter for folding + +require("nvim-treesitter.configs").setup({ + -- either "all" or a list of languages + ensure_installed = { + "javascript", + "jsonc", + "comment", + "jsdoc", + "tsx", + "html", + "vue", + "typescript", + -- "python", + "regex", + "bash", + -- "lua", + "css", + "scss", + "yaml", + }, + highlight = { + -- false will disable the whole extension + enable = true, + }, + indent = { + enable = false, -- buggy :/ + }, + -- custom text objects + -- textobjects = { + -- -- change/delete/select in function or class + -- select = { + -- enable = true, + -- lookahead = true, + -- keymaps = { + -- ["af"] = "@function.outer", + -- ["if"] = "@function.inner", + -- ["ac"] = "@class.outer", + -- ["ic"] = "@class.inner", + -- }, + -- }, + -- -- easily move to next function/class + -- move = { + -- enable = true, + -- set_jumps = true, -- track in jumplist (, ) + -- goto_next_start = { + -- ["]]"] = "@function.outer", + -- ["))"] = "@class.outer", + -- }, + -- goto_next_end = { + -- ["[]"] = "@function.outer", + -- ["()"] = "@class.outer", + -- }, + -- goto_previous_start = { + -- ["[["] = "@function.outer", + -- ["(("] = "@class.outer", + -- }, + -- goto_previous_end = { + -- ["]["] = "@function.outer", + -- [")("] = "@class.outer", + -- }, + -- }, + -- -- peek definitions from LSP + -- lsp_interop = { + -- enable = true, + -- border = "single", + -- peek_definition_code = { + -- ["pf"] = "@function.outer", + -- ["pc"] = "@class.outer", + -- }, + -- }, + -- swap = { + -- enable = true, + -- swap_next = { + -- ["l"] = "@parameter.inner", + -- }, + -- swap_previous = { + -- ["h"] = "@parameter.outer", + -- }, + -- }, + -- }, + context_commentstring = { + enable = true, + enable_autocmd = false, + }, + rainbow = { + enable = true, + extended_mode = true, -- Also highlight non-bracket delimiters like html tags + }, + autotag = { + enable = true, + filetypes = { "html", "tsx", "typescriptreact", "javascriptreact" }, + }, +}) \ No newline at end of file