-- https://neovim.io/doc/user/options.html#options vim.o.autowrite = true vim.o.clipboard = "unnamedplus" vim.o.colorcolumn = "100" vim.o.completeopt = "fuzzy,menuone,noinsert,noselect,popup" vim.o.confirm = true vim.o.ignorecase = true vim.o.inccommand = "split" vim.o.incsearch = true vim.o.mousefocus = true vim.o.scrolloff = 4 vim.o.shortmess = "aoOstTWAIcC" vim.o.sidescrolloff = 4 vim.o.smartcase = true vim.o.smarttab = true vim.o.termguicolors = true vim.o.updatetime = 300 vim.o.wildignorecase = true vim.o.wildmode = "longest,list:longest,full" vim.wo.breakindent = true vim.wo.foldlevel = 99 vim.wo.number = true -- vim.wo.spell = true vim.wo.statusline = "%-F %-r %-m %= %{&fileencoding} | %y | %3.l/%3.L:%3.c" vim.bo.copyindent = true vim.bo.expandtab = true vim.bo.modeline = false vim.bo.shiftwidth = 0 vim.bo.smartindent = true -- tbd: messes with yaml? vim.bo.swapfile = false vim.bo.tabstop = 4 vim.bo.undofile = true -- -- indenting local ft_tab_width = { [2] = { "html", "javascript", "markdown", "toml", "yaml" }, [8] = { "go" }, } for k, v in pairs(ft_tab_width) do vim.api.nvim_create_autocmd("FileType", { pattern = v, callback = function() vim.opt_local.shiftwidth = k vim.opt_local.softtabstop = k vim.opt_local.tabstop = k end, }) end -- -- common typo vim.keymap.set("c", "WQ", "wq", { desc = "write and quit" }) vim.keymap.set("c", "Wq", "wq", { desc = "write and quit" }) -- easier to remember delete without yank vim.keymap.set("v", "s", '"_d', { desc = "delete selection without yank" }) vim.keymap.set("n", "ss", '"_dd', { desc = "delete line without yank" }) -- less shifting vim.keymap.set("n", ";", ":", { silent = true }) -- :W write with sudo vim.api.nvim_create_user_command("W", function() local tmpfilename = os.tmpname() local tmpfile = io.open(tmpfilename, "w") if not tmpfile then vim.api.nvim_echo({ { "failed to open tmp file" }, { tmpfilename } }, false, { err = true }) return end for _, line in ipairs(vim.api.nvim_buf_get_lines(0, 0, -1, false)) do tmpfile:write(line .. "\n") end tmpfile:close() local curfilename = vim.api.nvim_buf_get_name(0) os.execute(string.format("sudo tee %s < %s > /dev/null", curfilename, tmpfilename)) vim.cmd([[ edit! ]]) os.remove(tmpfilename) end, {}) vim.api.nvim_create_autocmd("BufWritePre", { pattern = "*", callback = function() for i, line in ipairs(vim.api.nvim_buf_get_lines(0, 0, -1, false)) do local trimmed = string.gsub(line, "%s+$", "") vim.api.nvim_buf_set_lines(0, i - 1, i, false, { trimmed }) end end, }) vim.api.nvim_create_autocmd("BufWritePre", { pattern = { "*.md" }, command = "%!prettier --parser markdown", }) -- setup remote copy/paste through ssh osc52 if vim.env.SSH_CONNECTION ~= nil then vim.g.clipboard = { name = "osc52clip", copy = { ["+"] = "osc52clip copy", }, paste = { ["+"] = "osc52clip paste", }, } local config_dir = vim.env.XDG_CONFIG_HOME or "~/.config" local bin_dir = config_dir .. "/bin" local osc52clip = io.open(bin_dir .. "/osc52clip", "w") if osc52clip ~= nil then osc52clip:write([[#!/bin/bash : ${TTY:=$((tty || tty /dev/null | grep /dev/)} case $1 in copy) buffer=$(base64) [ -n "$TTY" ] && printf $'\e]52;c;%s\a' "$buffer" > "$TTY" ;; paste) exit 1 ;; esac ]]) osc52clip:close() os.execute("chmod +x " .. bin_dir .. "/osc52clip") end end -- -- lsp configs local cap = vim.lsp.protocol.make_client_capabilities() local cap_ws = cap.workspace if cap_ws ~= nil then cap_ws.didChangeWatchedFiles.dynamicRegistration = true end vim.lsp.config("*", { root_markers = { ".git" }, capabilities = cap }) vim.lsp.config("bash", { -- https://github.com/bash-lsp/bash-language-server cmd = { "bash-language-server", "start" }, filetypes = { "sh", "bash" }, root_markers = nil, }) vim.lsp.enable("bash") vim.lsp.config("buf", { -- https://buf.build/docs/reference/cli/buf/beta/lsp/ -- TODO: compare with https://github.com/coder3101/protols cmd = { "buf", "beta", "lsp", "--timeout=0", "--log-format=text" }, filetypes = { "proto" }, root_markers = { "buf.yaml", ".git" }, }) vim.lsp.enable("buf") vim.lsp.config("css", { -- https://github.com/hrsh7th/vscode-langservers-extracted cmd = { 'vscode-css-language-server', '--stdio' }, filetypes = { "css" }, root_markers = nil, }) vim.lsp.enable("css") vim.lsp.config("cue", { -- https://github.com/cue-lang/cue/wiki/cue-lsp cmd = { "cue", "lsp" }, filetypes = { "cue" }, root_markers = { "cue.mod", ".git" }, }) vim.lsp.enable("cue") vim.lsp.config("docker", { -- https://github.com/rcjsuen/dockerfile-language-server-nodejs cmd = { "docker-langserver", "--stdio" }, filetypes = { "dockerfile" }, root_markers = nil, }) vim.lsp.enable("docker") vim.lsp.config("gopls", { -- https://github.com/golang/tools/tree/master/gopls cmd = { "gopls" }, -- cmd = { "gopls", "-rpc.trace", "-logfile=/home/user/gopls.log" }, filetypes = { "go", "gomod", "gowork", "gotmpl" }, root_markers = { "go.mod", "go.sum", "go.work", ".git" }, settings = { gopls = { gofumpt = true, staticcheck = true, templateExtensions = { "gotmpl" }, vulncheck = "Imports", analyses = { shadow = true, }, }, }, on_init = function(client) local path = client.workspace_folders[1].name if path:find("/sdk/") then -- disable gofumpt when working on Go project repos client.config.settings.gopls.gofumpt = false end end, }) vim.lsp.enable("gopls") vim.lsp.config('json', { -- https://github.com/hrsh7th/vscode-langservers-extracted cmd = { 'vscode-json-language-server', '--stdio' }, filetypes = { "json" }, root_markers = nil, }) vim.lsp.enable("json") vim.lsp.config("html", { -- https://github.com/hrsh7th/vscode-langservers-extracted cmd = { "vscode-html-language-server", "--stdio" }, filetypes = { "html" }, root_markers = nil, }) vim.lsp.enable("html") vim.lsp.config("lua", { -- https://github.com/luals/lua-language-server cmd = { "lua-language-server" }, filetypes = { "lua" }, settings = { Lua = { workspace = { library = { vim.env.VIMRUNTIME, }, }, }, }, on_attach = function(client, bufnr) vim.lsp.completion.enable(true, client.id, bufnr, { autotrigger = true, convert = function(item) return { abbr = item.label:gsub("%b()", "") } end, }) end, }) vim.lsp.enable("lua") vim.lsp.config("markdown", { -- https://github.com/hrsh7th/vscode-langservers-extracted cmd = { "vscode-markdown-language-server", "--stdio" }, filetypes = { "markdown" }, root_markers = nil, }) vim.lsp.enable("markdown") -- get directory name from file path function Dirname(str) return str:match("(.*[/\\])") end vim.lsp.config("terraform", { -- https://github.com/hashicorp/terraform-ls cmd = { "terraform-ls", "serve" }, filetypes = { "terraform" }, root_dir = function(bufnr, cb) local bufpath = vim.api.nvim_buf_get_name(bufnr) local bufdir = Dirname(bufpath) cb(bufdir) end }) vim.lsp.enable("terraform") vim.lsp.config("typos", { -- https://github.com/tekumara/typos-lsp cmd = { "typos-lsp" }, root_markers = nil, }) vim.lsp.enable("typos") vim.lsp.config("yaml", { -- https://github.com/redhat-developer/yaml-language-server cmd = { "yaml-language-server", "--stdio" }, filetypes = { "yaml" }, root_markers = nil, settings = { ['yaml.format.enable'] = true, ['yaml.validate'] = true, ['yaml.hover'] = true, ['yaml.completion'] = true, ['yaml.schemaStore.enable'] = true, }, }) vim.lsp.enable("yaml") vim.api.nvim_create_autocmd("LspAttach", { group = vim.api.nvim_create_augroup("my.lsp", {}), callback = function(args) local client = assert(vim.lsp.get_client_by_id(args.data.client_id)) vim.keymap.set("n", "e", vim.diagnostic.open_float, { desc = "open diagnostic window" }) vim.keymap.set("n", "q", vim.diagnostic.setloclist, { desc = "set diagnostic loclist" }) vim.keymap.set("n", "d", vim.lsp.buf.definition, { silent = true, desc = "go to definition" }) vim.keymap.set("n", "h", vim.lsp.buf.hover, { silent = true, desc = "show hover info" }) vim.keymap.set("n", "i", vim.lsp.buf.implementation, { silent = true, desc = "go to implementation" }) vim.keymap.set("n", "s", vim.lsp.buf.signature_help, { silent = true, desc = "show signature help" }) -- vim.keymap.set('n', 'D', vim.lsp.buf.type_definition, { silent = true, desc = "go to type definition" }) vim.keymap.set("n", "rn", vim.lsp.buf.rename, { silent = true, desc = "rename symbol" }) vim.keymap.set("n", "a", vim.lsp.buf.code_action, { silent = true, desc = "show code actions" }) vim.keymap.set("n", "r", vim.lsp.buf.references, { silent = true, desc = "show references" }) -- Enable auto-completion. Note: Use CTRL-Y to select an item. |complete_CTRL-Y| if client:supports_method("textDocument/completion") then -- Optional: trigger autocompletion on EVERY keypress. May be slow! local chars = {} for i = 32, 126 do table.insert(chars, string.char(i)) end client.server_capabilities.completionProvider.triggerCharacters = chars vim.lsp.completion.enable(true, client.id, args.buf, { autotrigger = true }) vim.keymap.set("i", "", function() return vim.fn.pumvisible() == 1 and '' or '' end, { silent = true, expr = true }) end -- Auto-format ("lint") on save. -- Usually not needed if server supports "textDocument/willSaveWaitUntil". if not client:supports_method("textDocument/willSaveWaitUntil") and client:supports_method("textDocument/formatting") then vim.api.nvim_create_autocmd("BufWritePre", { group = vim.api.nvim_create_augroup("my.lsp", { clear = false }), buffer = args.buf, callback = function() if client.name == "gopls" then vim.lsp.buf.code_action({ bufnr = args.buf, id = client.id, context = { diagnostics = {}, only = { 'source.organizeImports' }, }, apply = true, }) -- vim.lsp.buf.code_action({ bufnr = args.buf, id = client.id, context = { only = { 'source.fixAll' } }, apply = true }) end -- local path = client.workspace_folders[1].name -- if not path:find("/sdk/") then vim.lsp.buf.format({ bufnr = args.buf, id = client.id, timeout_ms = 1000 }) -- end end, }) end end, }) vim.diagnostic.config({ virtual_text = true, -- virtual_lines = true, }) -- -- load plugins local pckr_path = vim.fn.stdpath("data") .. "/pckr/pckr.nvim" if not vim.uv.fs_stat(pckr_path) then vim.fn.system({ "git", "clone", "--filter=blob:none", "https://github.com/lewis6991/pckr.nvim", pckr_path, }) end vim.opt.rtp:prepend(pckr_path) require("pckr").add({ -- colorscheme { "dasupradyumna/midnight.nvim", config = function() vim.cmd.colorscheme("midnight") -- vim.api.nvim_set_hl(0, "goFormatSpecifier", {fg = "#ffffff" }) -- doesn't work vim.api.nvim_set_hl(0, "Normal", { bg = "#000000" }) end, }, -- shared deps { -- generic shared library of lua utils "nvim-lua/plenary.nvim", }, { -- debug highlights with :Telescope highlights "nvim-telescope/telescope.nvim", requires = { "nvim-lua/plenary.nvim" }, }, -- system { -- floating notification windows "rcarriga/nvim-notify", config = function() vim.notify = require("notify") end, }, -- language support -- { -- -- a lot of filetypes, primarily syntax highlighting -- "sheerun/vim-polyglot", -- config_pre = function() -- vim.g.polyglot_disabled = { "cue" } -- end, -- }, { -- cuelang -- fixes tab issues? "jjo/vim-cue", }, -- { -- "terrastruct/d2-vim", -- filetypes = { "d2" }, -- }, { -- treesitter text objects "nvim-treesitter/nvim-treesitter", -- requires = { "neovim/nvim-lspconfig" }, run = ":TSUpdate", config = function() require("nvim-treesitter.configs").setup({ ensure_installed = "all", highlight = { enable = true, disable = { "dockerfile" }, }, indent = { enable = true, }, }) vim.wo.foldmethod = "expr" vim.wo.foldexpr = "v:lua.vim.treesitter.foldexpr()" end, }, -- { -- "ravsii/tree-sitter-d2", -- run = "make nvim-install", -- }, -- automagic { -- pair close insertion "windwp/nvim-autopairs", config = function() require("nvim-autopairs").setup({ check_ts = true, }) end, }, -- keybind reminder { "folke/which-key.nvim", }, -- git integration { -- end of line blame "f-person/git-blame.nvim", }, { -- gutter signs "lewis6991/gitsigns.nvim", config = function() require("gitsigns").setup({ signs = { add = { text = "+" }, change = { text = "~" }, }, }) end, }, { -- link to git host with gl "ruifm/gitlinker.nvim", requires = { "nvim-lua/plenary.nvim" }, config = function() require("gitlinker").setup({ mappings = "gl", callbacks = { ["go.googlesource.com"] = function(url_data) local url = require("gitlinker.hosts").get_base_https_url(url_data) url = url .. "/+/" .. url_data.rev .. "/" .. url_data.file if url_data.lstart then url = url .. "#" .. url_data.lstart end return url end, ["lucid-git"] = function(url_data) url_data.host = "github.com" url_data.repo = "seankhliao/" .. url_data.repo return require("gitlinker.hosts").get_github_type_url(url_data) end, }, }) end, }, -- kitty integration { "mikesmithgh/kitty-scrollback.nvim", config = function() require("kitty-scrollback").setup({ { restore_options = true, keymaps_enabled = false, }, }) end, }, -- extra info { -- colorize #hex "NvChad/nvim-colorizer.lua", config = function() require("colorizer").setup({}) end, }, { "lukas-reineke/indent-blankline.nvim", config = function() local highlight = { "RainbowRed", "RainbowOrange", "RainbowYellow", "RainbowGreen", "RainbowCyan", "RainbowBlue", "RainbowViolet", } local hooks = require("ibl.hooks") -- create the highlight groups in the highlight setup hook, so they are reset -- every time the colorscheme changes hooks.register(hooks.type.HIGHLIGHT_SETUP, function() vim.api.nvim_set_hl(0, "RainbowRed", { fg = "#E06C75" }) vim.api.nvim_set_hl(0, "RainbowOrange", { fg = "#D19A66" }) vim.api.nvim_set_hl(0, "RainbowYellow", { fg = "#E5C07B" }) vim.api.nvim_set_hl(0, "RainbowGreen", { fg = "#98C379" }) vim.api.nvim_set_hl(0, "RainbowCyan", { fg = "#56B6C2" }) vim.api.nvim_set_hl(0, "RainbowBlue", { fg = "#61AFEF" }) vim.api.nvim_set_hl(0, "RainbowViolet", { fg = "#C678DD" }) end) require("ibl").setup({ indent = { highlight = { "RainbowRed", "RainbowOrange", "RainbowYellow", "RainbowGreen", "RainbowCyan", "RainbowBlue", "RainbowViolet", }, }, exclude = { buftypes = { "terminal", "nofile" }, }, scope = { highlight = highlight, }, }) end, }, { -- search hover info "kevinhwang91/nvim-hlslens", -- better search config = function() require("hlslens").setup() vim.keymap.set("n", "n", function() vim.cmd.normal({ "n", bang = true }) require("hlslens").start() end, { silent = true }) vim.keymap.set("n", "N", function() vim.cmd.normal({ "N", bang = true }) require("hlslens").start() end, { silent = true }) end, }, })