diff --git a/after/ftplugin/c.lua b/after/ftplugin/c.lua index e07a653..7415461 100644 --- a/after/ftplugin/c.lua +++ b/after/ftplugin/c.lua @@ -1,5 +1,5 @@ -local map_local = core.misc.map_local +local map_local, lz = core.misc.map_local, core.misc.lz -- sort #includes <> (very jank) -- TODO: rewrite in a semi-sane way -map_local("n", "cri", "mz/^#include.*<.*>$ggVGN:sort`zdelm z:nohlsearch:echo") +map_local("n", "cri", lz "mz/^#include.*<.*>$ggVGN:sort`zdelm z:nohlsearch:echo") diff --git a/after/ftplugin/dap-float.lua b/after/ftplugin/dap-float.lua index 2a52dea..eb2bb95 100644 --- a/after/ftplugin/dap-float.lua +++ b/after/ftplugin/dap-float.lua @@ -1 +1 @@ -core.misc.map("n", "q", "q") +core.misc.map_local("n", "q", "q") diff --git a/after/ftplugin/java.lua b/after/ftplugin/java.lua index 31c9ee6..272a593 100644 --- a/after/ftplugin/java.lua +++ b/after/ftplugin/java.lua @@ -1,6 +1,3 @@ --- FIXME: the following error is emmitted when starting up jdtls: --- ERROR No LSP client found that supports vscode.java.resolveMainClass - local map, auto = core.misc.map, core.misc.auto local ok, jdtls = pcall(require, "jdtls") @@ -73,10 +70,9 @@ local config = { dap.adapters.java = nil -- remove any old java adapters jdtls.setup_dap({ hotcodereplace = "auto" }) - require("jdtls.dap").setup_dap_main_class_configs() end, - -- don"t print out status messages + -- don't print out status messages handlers = { ["language/status"] = function() end }, diff --git a/after/ftplugin/netrw.lua b/after/ftplugin/netrw.lua index 3f29c3b..6954608 100644 --- a/after/ftplugin/netrw.lua +++ b/after/ftplugin/netrw.lua @@ -2,7 +2,7 @@ local map_local = core.misc.map_local map_local("n", "h", "-", { noremap = false, remap = true }) -- Go up a directory map_local("n", "l", "", { noremap = false, remap = true }) -- Go down a directory / open a file -map_local("n", ".", "gh", { noremap = false, remap = true }) -- Toggle hidden files +map_local("n", "g.", "gh", { noremap = false, remap = true }) -- Toggle hidden files map_local("n", "P", "z", { noremap = false, remap = true }) -- Close preview window -- Close netrw only if it isn't the last window diff --git a/after/lsp/basedpyright.lua b/after/lsp/basedpyright.lua deleted file mode 100644 index fec634c..0000000 --- a/after/lsp/basedpyright.lua +++ /dev/null @@ -1,9 +0,0 @@ -local map = core.misc.map - -return { - on_attach = function(_, bufnr) - -- add some basedpyright specific mappings - local opts = { buffer = bufnr } - map("n", "cri", "PyrightOrganizeImports", opts) - end, -} diff --git a/after/lsp/clangd.lua b/after/lsp/clangd.lua index a827324..ed7af06 100644 --- a/after/lsp/clangd.lua +++ b/after/lsp/clangd.lua @@ -1,12 +1,4 @@ -local map = core.misc.map - return { - on_attach = function(_, bufnr) - -- add some clangd specific mappings - local opts = { buffer = bufnr } - map("n", "o", "ClangdSwitchSourceHeader", opts) - end, - cmd = { "clangd", "--background-index", diff --git a/after/lsp/lua_ls.lua b/after/lsp/lua_ls.lua index 23f0dc6..00bfe12 100644 --- a/after/lsp/lua_ls.lua +++ b/after/lsp/lua_ls.lua @@ -11,14 +11,14 @@ return { enable = false }, workspace = { - checkThirdParty = true, + checkThirdParty = "ApplyInMemory", library = { - vim.env.VIMRUNTIME + vim.env.VIMRUNTIME, + "${3rd}/luv/library" } } } }, - root_markers = { ".luarc.json", ".luarc.jsonc", ".luacheckrc", ".stylua.toml", "stylua.toml", "selene.toml", "selene.yml", "README.md" } } diff --git a/after/plugin/colorscheme.lua b/after/plugin/colorscheme.lua index 039f926..833184d 100644 --- a/after/plugin/colorscheme.lua +++ b/after/plugin/colorscheme.lua @@ -1,5 +1,5 @@ if vim.fn.has("termguicolors") and not os.getenv("TERM") ~= "linux" then - vim.cmd("colorscheme mellow") + vim.cmd("colo mellow") else - vim.cmd("colorscheme default") + vim.cmd("colo default") end diff --git a/extras/c.sh b/extras/c.sh deleted file mode 100644 index e1ce6ee..0000000 --- a/extras/c.sh +++ /dev/null @@ -1,3 +0,0 @@ -# TODO: -# add something to check if we need to run bear again to update -# clangd build options diff --git a/lua/conf/autos.lua b/lua/conf/autos.lua index ceb669c..b622141 100644 --- a/lua/conf/autos.lua +++ b/lua/conf/autos.lua @@ -1,6 +1,6 @@ local auto, augroup = core.misc.auto, core.misc.augroup --- auto commands which interact with bufferes without modifying them +-- auto commands which interact with buffers without modifying them local bufcheck = augroup("bufcheck") -- auto commands which modify things on the filesystem local fsmod = augroup("fsmod") @@ -11,14 +11,6 @@ auto("FocusGained", { command = "checktime" }) -auto("TextYankPost", { - group = bufcheck, - desc = "Highlight on yank.", - callback = function() - vim.highlight.on_yank { timeout = 250 } - end -}) - auto("BufRead", { group = bufcheck, desc = "Return to the last place the buffer was closed in.", @@ -38,14 +30,4 @@ auto("BufWritePre", { end }) -auto("BufWritePre", { - group = fsmod, - desc = "Basically mkdir -p.", - callback = function(ctx) - if ctx.match:match("^%w%w+://") then return end - local dir = vim.fn.fnamemodify(ctx.file, ":p:h") - vim.fn.mkdir(dir, "p") - end -}) - core.color.setup_termbg_sync() diff --git a/lua/conf/binds.lua b/lua/conf/binds.lua index 94540d8..dd4a88b 100644 --- a/lua/conf/binds.lua +++ b/lua/conf/binds.lua @@ -1,64 +1,49 @@ -local map = core.misc.map +local map, lz = core.misc.map, core.misc.lz +local function feedkeys(keys) + vim.api.nvim_feedkeys( + vim.api.nvim_replace_termcodes(keys, true, false, true), + "n", true) +end -- vim binds vim.g.mapleader = " " -- set leader key map("x", "p", [["_dP]], { desc = "Greatest remap of all time." }) map("n", "", ":nohlsearch:echo", { desc = "Clear search." }) --- move selected text up/down -map("v", "", ":m '<-2gv=gv", { desc = "Move selected text up." }) -map("v", "", ":m '>+1gv=gv", { desc = "Move selected text down." }) -- the cursor STAYS IN THE MIDDLE -map("n", "", "mzJ`zdelm z") -- when combining lines -map("n", "n", "nzzzv") -- when searching -map("n", "N", "Nzzzv") -map("n", "", "zz") -- half page jumping -map("n", "", "zz") +map("n", "", lz "mzJ`zdelm z") -- when combining lines +map("n", "n", lz "nzzzv") -- when searching +map("n", "N", lz "Nzzzv") +map("n", "", lz "zz") -- half page jumping +map("n", "", lz "zz") -map({ "n", "i" }, "", "") - -map("n", "x", function() -- execute order 111 - local fn = vim.fn.expand("%:p") - if vim.fn.getftype(fn) == "file" then - local perm = vim.fn.getfperm(fn) - if string.match(perm, "x", 3) then - vim.notify("Removed executable flags") - vim.fn.setfperm(fn, string.sub(fn, 1, 2).."-"..string.sub(fn, 4, 5).."-" - ..string.sub(fn, 7, 8).."-") - else - vim.notify("Add executable flags") - vim.fn.setfperm(fn, string.sub(fn, 1, 2).."x"..string.sub(fn, 4, 5).."x" - ..string.sub(fn, 7, 8).."x") - end - else - vim.notify("File doesn't exist") - end -end, { desc = "toggle executable flag of the file" }) - --- good spell suggestion ui --- (stolen from https://github.com/neovim/neovim/pull/25833) -vim.keymap.set("n", "z=", function() - local spell_on_choice = vim.schedule_wrap(function(_, idx) - if type(idx) == "number" then - vim.cmd("normal! "..idx.."z=") - end - end) - - if vim.v.count > 0 then - spell_on_choice(nil, vim.v.count) - return - end - local cword = vim.fn.expand("") - local prompt = "Change "..vim.inspect(cword).." to:" - vim.ui.select(vim.fn.spellsuggest(cword, vim.o.lines), { prompt = prompt }, - spell_on_choice) -end, { desc = "Shows spelling suggestions" }) +-- trigger completion menu +-- (stolen from https://gist.github.com/MariaSolOs/2e44a86f569323c478e5a078d0cf98cc) +map("i", "", function() + -- if the completion menu is already visible just go to the next item + if vim.fn.pumvisible() ~= 0 then + feedkeys("") + else + if #vim.lsp.get_clients({ bufnr = 0 }) > 0 then + vim.lsp.completion.get() + else + if vim.bo.omnifunc == "" then + feedkeys("") + else + feedkeys("") + end + end + end +end, { desc = "Trigger/select next completion" }) +map("i", "", "", { desc = "Trigger spell completion" }) +map("n", "", lz "se spellease nospell", { desc = "Trigger spell completion" }) -- quickfix map("n", "", "cnext") map("n", "", "cprev") map("n", "", "cclose") +map("n", "", "cope") -- man pages map("n", "", "Man") diff --git a/lua/conf/opts.lua b/lua/conf/opts.lua index ce0dddf..b35ca4c 100644 --- a/lua/conf/opts.lua +++ b/lua/conf/opts.lua @@ -1,84 +1,47 @@ --- color stuff -if vim.fn.has("termguicolors") then - vim.opt.termguicolors = true -end - -- make .h files default to c code vim.filetype.add({ extension = { h = "c", }, }) -- numbers -vim.opt.number = true -vim.opt.relativenumber = true +vim.o.nu = true +vim.o.rnu = true -- buffer -vim.opt.scrolloff = 5 -vim.opt.wrap = true -- wraping lines -vim.opt.linebreak = true -- fix where line is wraped -vim.opt.cursorline = true -vim.opt.colorcolumn = { 80 } +vim.o.lbr = true -- fix where line is wraped +vim.o.cul = true +vim.o.cc = "80" -- indents + tabs local tabwidth = 2 -vim.opt.expandtab = true -vim.opt.smarttab = true -vim.opt.cindent = true -vim.opt.autoindent = true -vim.opt.tabstop = tabwidth -vim.opt.shiftwidth = tabwidth -vim.opt.softtabstop = tabwidth +vim.o.ts = tabwidth +vim.o.sw = tabwidth +vim.o.sts = -1 -- Schedule the setting after `UiEnter` because it can increase startup-time. -- (yoinked from kickstart.nvim) vim.schedule(function() - vim.opt.clipboard = "unnamedplus" -- system clipboard + vim.o.cb = "unnamedplus" -- system clipboard end) -vim.opt.updatetime = 200 - -- file saving -vim.opt.swapfile = false -vim.opt.undofile = true -vim.opt.confirm = true +vim.o.swf = false +vim.o.udf = true -- searching -vim.opt.ignorecase = true -vim.opt.smartcase = true -vim.opt.wrapscan = true -vim.opt.showmatch = true -vim.opt.incsearch = true +vim.o.ic = true -- wild menus -vim.opt.wildoptions = "pum" -vim.opt.pumblend = 3 -vim.opt.pumheight = 20 +vim.o.ph = 20 +vim.o.wic = true +vim.o.wop = "fuzzy,pum,tagfile" -vim.opt.wildignorecase = true -vim.opt.wildignore = "*.o" +-- completion +vim.o.cot = "menu,menuone,noinsert,fuzzy,popup" +vim.o.cia = "kind,abbr,menu" --- netrw -vim.g.netrw_banner = 0 -vim.g.netrw_winsize = 30 -vim.g.netrw_liststyle = 1 -vim.g.netrw_sizestyle = "H" -vim.g.netrw_hide = 1 - --- border (this doesn't actually do anything within vim, I'm just setting it --- here so it's easy to find) -vim.g.border_style = "solid" - -do -- folding - vim.opt.foldmethod = "syntax" - vim.opt.foldlevelstart = 99 - vim.opt.foldlevel = 99 - vim.opt.foldenable = true - vim.o.fillchars = "fold: ,eob: " - - vim.opt.foldtext = "v:lua.core.folding()" -end +-- make windows look nice +vim.o.winborder = "solid" do -- statusline - local last_bufnr, i = 1, 1 - --- status line ---@return string out formatted status line function _G.Status() --- get the percentage through the file @@ -101,64 +64,9 @@ do -- statusline return percent.."%%" end - --- get the number of lsp servers - ---@return string out the formatted number of servers - local function lsp_servers() - local out, nclients, hi - local hi_groups = { "@boolean", "@constant", "@keyword", "@number" } - - -- get the number of clients - nclients = #vim.lsp.get_clients({ bufnr = 0 }) - - -- set the client display - out = "λ"..nclients - if nclients > 0 then - local bufnr = vim.api.nvim_win_get_buf(0) - if bufnr ~= last_bufnr then - last_bufnr = bufnr - i = i + 1 - if i > #hi_groups then - i = 1 - end - end - - hi = "%#"..hi_groups[i].."#" - out = hi..out.."%#StatusLine#" - end - - return out - end - - --- get git status information - ---@return string out git status information or nothing - local function gitsigns() - local reset = "%#StatusLine#" - local hl = reset - local lil_guy = "o/" - - ---@type table - local status = vim.b.gitsigns_status_dict - if not status then - return "" - end - - if status.removed and status.removed > 0 then - hl = "%#GitSignsDelete#" - lil_guy = "" - elseif status.changed and status.changed > 0 then - hl = "%#GitSignsChange#" - lil_guy = "o7" - elseif status.added and status.added > 0 then - hl = "%#GitSignsAdd#" - lil_guy = "\\o/" - end - - return hl..lil_guy..reset - end - -- this is my statusline: -- - -- opts.lua [+] o/ λ1 163,61-60 88% + -- opts.lua [+] λ1 163,61-60 88% -- return table.concat { "%t", -- file name @@ -167,10 +75,8 @@ do -- statusline "%r", -- readonly flag "%=", -- seperate left and right side - -- print out git status information in the form of a lil guy - gitsigns(), " ", -- print out the number of lsp clients attached with nice colors :) - lsp_servers(), " ", + "λ"..#vim.lsp.get_clients({ bufnr = 0 }), " ", "%<", -- we can start truncating here (I want to keep the file name) "%l,%c%V", -- line, column-virtual column @@ -178,6 +84,6 @@ do -- statusline " "..percentage() -- percentage through the buffer } end - vim.opt.statusline = "%!v:lua.Status()" - vim.opt.laststatus = 3 + vim.o.stl = "%!v:lua.Status()" + vim.o.ls = 3 end diff --git a/lua/conf/plugins/cmp.lua b/lua/conf/plugins/cmp.lua deleted file mode 100644 index 954b191..0000000 --- a/lua/conf/plugins/cmp.lua +++ /dev/null @@ -1,129 +0,0 @@ -return { "Saghen/blink.cmp", - branch = "v1.*", - reqs = { - "xzbdmw/colorful-menu.nvim", - "L3MON4D3/LuaSnip" - }, - config = function() - vim.cmd("!cargo build --release") - end, - lazy = dep_short.auto("InsertEnter"), - load = function() - local colormenu = require("colorful-menu") - require("blink.cmp").setup { - keymap = { - preset = "none", -- I don't like the default documentation scroll binds - [""] = { "select_and_accept" }, - [""] = { "select_next", "fallback_to_mappings" }, - [""] = { "select_prev", "fallback_to_mappings" }, - - [""] = { "scroll_documentation_up", "fallback" }, - [""] = { "scroll_documentation_down", "fallback" } - }, - - completion = { - menu = { - scrollbar = false, - border = vim.g.border_style, - draw = { - columns = { - { "kind_icon" }, - { "label", "label_description", gap = 1 }, - { "kind" } - }, - - -- blink.cmp should not take this much damn work to make it look - -- semi-decent - components = { - -- we replace the kind icon with the an icon for the source - kind_icon = { - text = function(ctx) - local menu_icon = { - "?", -- fallback - lsp = "λ", - snippets = "%", - buffer = "@", - path = "#", - cmdline = "$" - } - - local icon = menu_icon[ctx.source_id] - if icon == nil then - icon = menu_icon[1] - end - - return icon - end, - highlight = function(_) - return { { group = "CmpItemMenu" } } - end - }, - label = { - text = function(ctx) - return colormenu.blink_components_text(ctx) - end, - highlight = function(ctx) - return colormenu.blink_components_highlight(ctx) - end - }, - kind = { - -- these highlights are technically for nvim-cmp, but they're - -- built into my colorscheme so I don"t mind using them here - highlight = function(ctx) - return { - { group = "CmpItemKind"..ctx.kind, priority = 20000 } - } - end - } - } - } - }, - - ghost_text = { - enabled = true - }, - - -- documentation should show up immediately - documentation = { - auto_show = true, - auto_show_delay_ms = 0, - window = { - border = vim.g.border_style - } - } - }, - - -- I like the default command line completion - cmdline = { - enabled = false - }, - - -- signature support is necessary - signature = { - enabled = true, - window = { - border = vim.g.border_style - } - }, - - -- TODO: find a way to make my fancy luasnip snippets with multiple - -- triggers not look stupid e.g. "fn\|main" for a function that could - -- be triggered by fn or main - snippets = { - preset = "luasnip" - }, - - sources = { - default = { "lsp", "path", "snippets", "buffer" } - }, - - fuzzy = { - implementation = "prefer_rust_with_warning", - sorts = { - "score", - "sort_text" - } - } - } - end -} diff --git a/lua/conf/plugins/dap.lua b/lua/conf/plugins/dap.lua index a682e54..575acee 100644 --- a/lua/conf/plugins/dap.lua +++ b/lua/conf/plugins/dap.lua @@ -40,7 +40,6 @@ return { "nvim-telescope/telescope.nvim" }, deps = "theHamsta/nvim-dap-virtual-text", - disable = not vim.fn.has("nvim-0.9.5"), branch = "0.10.0", lazy = function(load) load:keymap("n", "ec") diff --git a/lua/conf/plugins/gitsigns.lua b/lua/conf/plugins/gitsigns.lua deleted file mode 100644 index cd91d8e..0000000 --- a/lua/conf/plugins/gitsigns.lua +++ /dev/null @@ -1,88 +0,0 @@ -local map = core.misc.map - -return { "lewis6991/gitsigns.nvim", - disable = not vim.fn.has("nvim-0.9.0"), - lazy = function(load) - load:auto({ "BufEnter", "BufNew" }, { - callback = function() - local paths = vim.fs.find({ ".git", }, { upward = true }) - if #paths > 0 then - load:cleanup() - end - end - }) - load:cmd("Gitsigns") - end, - load = function() - local gs = require("gitsigns") - - gs.setup { - signs = { - add = { text = "│" }, - change = { text = "│" }, - delete = { text = "-" }, - topdelete = { text = "‾" }, - changedelete = { text = "~" }, - untracked = { text = "┆" } - }, - - signcolumn = true, - numhl = false, - linehl = false, - word_diff = false, - - watch_gitdir = { - interval = 1000, - follow_files = true - }, - - attach_to_untracked = true, - current_line_blame_formatter = ", - ", - - preview_config = { border = vim.g.border_style }, - - on_attach = function(bufnr) - local opts = { buffer = bufnr } - - -- Navigation - map("n", "]c", function() - if vim.wo.diff then - return "]c" - end - vim.schedule(function() gs.next_hunk() end) - return "" - end, { expr = true, buffer = bufnr }) - - map("n", "[c", function() - if vim.wo.diff then - return "[c" - end - vim.schedule(function() gs.prev_hunk() end) - return "" - end, { expr = true, buffer = bufnr }) - - -- Actions - map("n", "hs", gs.stage_hunk, opts) - map("n", "hr", gs.reset_hunk, opts) - map("v", "hs", function() - gs.stage_hunk { vim.fn.line("."), vim.fn.line("v") } - end, opts) - map("v", "hr", function() - gs.reset_hunk { vim.fn.line("."), vim.fn.line("v") } - end, opts) - map("n", "hS", gs.stage_buffer, opts) - map("n", "hu", gs.undo_stage_hunk, opts) - map("n", "hR", gs.reset_buffer, opts) - map("n", "hp", gs.preview_hunk, opts) - map("n", "hb", function() gs.blame_line { full=true } end, opts) - map("n", "tb", gs.toggle_current_line_blame, opts) - map("n", "hd", gs.diffthis, opts) - map("n", "hD", function() gs.diffthis("~") end, opts) - map("n", "td", gs.toggle_deleted, opts) - - -- Text object - map({ "o", "x" }, "ih", ":Gitsigns select_hunk", opts) - end - } - end -} diff --git a/lua/conf/plugins/lsp.lua b/lua/conf/plugins/lsp.lua index 51f4b3a..630d7a6 100644 --- a/lua/conf/plugins/lsp.lua +++ b/lua/conf/plugins/lsp.lua @@ -2,7 +2,6 @@ local nonels_augroup = core.misc.augroup("nullls formatting") return { { "neovim/nvim-lspconfig", - disable = not vim.fn.has("nvim-0.10.0"), reqs = { "mason-org/mason.nvim", "mason-org/mason-lspconfig.nvim" @@ -20,7 +19,6 @@ return { -- python "basedpyright", - "mypy", "black", "debugpy" } @@ -29,79 +27,22 @@ return { }, { "mason-org/mason.nvim", - disable = not vim.fn.has("nvim-0.7.0"), load = function() - local mason = require("mason") - - mason.setup { + require("mason").setup { ui = { - border = vim.g.border_style, - width = 0.8, - height = 0.9, - + -- not sure why these are nerdfont icons by default icons = { package_installed = "+", package_pending = "?", package_uninstalled = "x" } - }, - keymaps = { - toggle_package_expand = "", - install_package = "i", - update_package = "u", - check_package_version = "c", - update_all_packages = "U", - check_outdated_packages = "C", - uninstall_package = "r", - cancel_installation = "", - apply_language_filter = "" - } - } - end - }, - - { "j-hui/fidget.nvim", - disable = not vim.fn.has("nvim-0.9.0"), - branch = "v1.*", - lazy = dep_short.auto("LspAttach"), - load = function() - local notification_defaults = require("fidget.notification").default_config - notification_defaults["icon"] = "" - - require("fidget").setup { - progress = { - display = { - progress_icon = { - pattern = "line", - period = 1 - }, - done_icon = ":)" - } - }, - notification = { - filter = vim.log.levels.DEBUG, - override_vim_notify = true, - configs = { - default = notification_defaults - }, - view = { - icon_separator = " ", - group_separator = "---", - group_separator_hl = "Comment" - }, - window = { - zindex = 44, - relative = "editor" - } } } end }, { "mfussenegger/nvim-jdtls", - disable = not vim.fn.has("nvim-0.6.0"), - reqs = "mfussenegger/nvim-dap", - lazy = dep_short.ft("java") + reqs = "mfussenegger/nvim-dap" }, { "nvimtools/none-ls.nvim", @@ -111,11 +52,11 @@ return { null_ls.setup { sources = { - null_ls.builtins.formatting.black, + null_ls.builtins.formatting.black }, on_attach = function(client, bufnr) - if client.supports_method("textDocument/formatting") then + if client:supports_method("textDocument/formatting") then vim.api.nvim_clear_autocmds({ group = nonels_augroup, buffer = bufnr diff --git a/lua/conf/plugins/luasnip.lua b/lua/conf/plugins/luasnip.lua index a81b54d..f66a105 100644 --- a/lua/conf/plugins/luasnip.lua +++ b/lua/conf/plugins/luasnip.lua @@ -1,75 +1,45 @@ -local map, auto = core.misc.map, core.misc.auto +local map = core.misc.map return { "L3MON4D3/LuaSnip", - branch = "v2.*", - disable = not vim.fn.has("nvim-0.7.0"), - config = function() - vim.cmd("make install_jsregexp") - end, - lazy = function(load) - load:keymap({"i", "s"}, "") - load:keymap({"i", "s"}, "") - load:keymap({"i", "s"}, "") - load:keymap({"i", "s"}, "") - end, - load = function() - local luasnip = require("luasnip") - local types = require("luasnip.util.types") + branch = "v2.*", + config = function() + vim.cmd("make install_jsregexp") + end, + lazy = function(load) + load:keymap({"i", "s"}, "") + load:keymap({"i", "s"}, "") + load:keymap({"i", "s"}, "") + load:keymap({"i", "s"}, "") + end, + load = function() + local ls = require("luasnip") + vim.snippet.expand = ls.lsp_expand - luasnip.config.set_config { - history = true, -- return back into snippet - enable_autosnippets = true, + ls.config.setup { + keep_roots = true, + link_roots = true, + link_children = true, + exit_roots = not true + } - -- update on text insert and cursor hold - updateevents = { "TextChanged", "TextChangedI", "CursorHold" }, - ext_opts = { - [types.choiceNode] = { - active = { - virt_text = {{ "?", "@boolean" }} - } - } - } - } + map({"i", "s"}, "", ls.expand) + map({"i", "s"}, "", function() ls.jump(1) end) + map({"i", "s"}, "", function() ls.jump(-1) end) + map({"i", "s"}, "", function() + if ls.choice_active() then + ls.change_choice(1) + end + end) - map({"i", "s"}, "", function() - if luasnip.choice_active() then - luasnip.change_choice(1) - end - end) + -- collect all snippets and add them + for _, file in ipairs(vim.api.nvim_get_runtime_file("lua/snippets/*.lua", + true)) do + local fn = file:gsub("^.*/", ""):gsub("%.lua$", "") - map({"i", "s"}, "", function() - if luasnip.expandable() then - luasnip.expand() - end - end) - - map({"i", "s"}, "", function() - if luasnip.jumpable(1) then - luasnip.jump(1) - end - end) - - map({"i", "s"}, "", function() - if luasnip.jumpable(-1) then - luasnip.jump(-1) - end - end) - - -- collect all snippets and add them when in the correct file type - for _, file in ipairs(vim.api.nvim_get_runtime_file("lua/snippets/*.lua", - true)) do - local fn = file:gsub("^.*/", ""):gsub("%.lua$", "") - - auto("FileType", { - pattern = fn, - once = true, - callback = function() - local ret = require("snippets."..fn) - if type(ret) ~= "boolean" then - luasnip.add_snippets(fn, ret, { key = fn }) - end - end - }) - end - end + local ret = require("snippets."..fn) + if type(ret) ~= "boolean" then + ls.add_snippets(fn, ret, { key = fn }) + end + end + end } diff --git a/lua/conf/plugins/mellow.lua b/lua/conf/plugins/mellow.lua index fe799fa..1c5c76b 100644 --- a/lua/conf/plugins/mellow.lua +++ b/lua/conf/plugins/mellow.lua @@ -1,5 +1,4 @@ return { "mellow-theme/mellow.nvim", - disable = not vim.fn.has("nvim-0.8.0"), reqs = "nvim-treesitter/nvim-treesitter", load = function() vim.g.mellow_variant = "dark" @@ -21,6 +20,15 @@ return { "mellow-theme/mellow.nvim", ["NormalFloat"] = { fg = c.fg, bg = "#111111" }, ["FloatBorder"] = { link = "NormalFloat" }, + -- Make pmenu look good + ["Pmenu"] = { link = "NormalFloat" }, + ["PmenuSel"] = { link = "Normal" }, + ["PmenuKind"] = { link = "@constant" }, + ["PmenuKindSel"] = { + fg = core.color.copyhl("Comment").fg, + bold = true + }, + -- make diagnostics have an undercurl ["DiagnosticUnderlineError"] = { fg = c.red, undercurl = true }, ["DiagnosticUnderlineWarn"] = { fg = c.yellow, undercurl = true }, @@ -28,13 +36,6 @@ return { "mellow-theme/mellow.nvim", ["DiagnosticUnderlineHint"] = { fg = c.cyan, undercurl = true }, ["DiagnosticHint"] = { fg = c.cyan }, -- revert - -- make blink actually look nice - ["BlinkCmpMenu"] = { link = "NormalFloat" }, - ["BlinkCmpMenuBorder"] = { link = "BlinkCmpMenu" }, - ["BlinkCmpMenuSelection"] = { bg = c.gray01 }, - ["BlinkCmpLabelDeprecated"] = { link = "CmpItemAbbrDeprecated" }, - ["BlinkCmpLabelMatch"] = { link = "NormalFloat" }, -- reverted - -- telescope styling so I can see when coding outside (real) ["TelescopeResultsNormal"] = { bg = c.bg_dark }, ["TelescopeResultsBorder"] = { link = "TelescopeResultsNormal" }, diff --git a/lua/conf/plugins/oil.lua b/lua/conf/plugins/oil.lua index 321b620..f712010 100644 --- a/lua/conf/plugins/oil.lua +++ b/lua/conf/plugins/oil.lua @@ -1,51 +1,5 @@ local map = core.misc.map --- helper function to parse output -local function parse_output(proc) - local result = proc:wait() - local ret = {} - if result.code == 0 then - for line in vim.gsplit(result.stdout, "\n", { - plain = true, trimempty = true }) do - -- Remove trailing slash - line = line:gsub("/$", "") - ret[line] = true - end - end - return ret -end - --- build git status cache -local function new_git_status() - return setmetatable({}, { - __index = function(self, key) - local ignore_proc = vim.system( - { "git", "ls-files", "--ignored", "--exclude-standard", "--others", - "--directory" }, - { - cwd = key, - text = true, - } - ) - local tracked_proc = vim.system({ "git", "ls-tree", "HEAD", - "--name-only" }, - { - cwd = key, - text = true, - } - ) - local ret = { - ignored = parse_output(ignore_proc), - tracked = parse_output(tracked_proc), - } - - rawset(self, key, ret) - return ret - end, - }) -end -local git_status = new_git_status() - local permission_hlgroups = { ["-"] = "NonText", ["r"] = "DiagnosticSignWarn", @@ -53,190 +7,34 @@ local permission_hlgroups = { ["x"] = "DiagnosticSignOk", } -return { - { "stevearc/oil.nvim", - disable = not vim.fn.has("nvim-0.8.0"), - lazy = dep_short.keymap("n", "-"), - load = function() - -- Clear git status cache on refresh - local refresh = require("oil.actions").refresh - local orig_refresh = refresh.callback - refresh.callback = function(...) - git_status = new_git_status() - orig_refresh(...) - end - - require("oil").setup { - -- ID is automatically added at the beginning, and name at the end - -- See :help oil-columns - columns = { - { - "permissions", - highlight = function(permission_str) - local hls = {} - for i = 1, #permission_str do - local char = permission_str:sub(i, i) - table.insert(hls, { permission_hlgroups[char], i - 1, i }) - end - return hls - end, - }, - { "size", highlight = "@number" } - }, - - -- Window-local options to use for oil buffers - win_options = { - number = false, - relativenumber = false, - wrap = false, - signcolumn = "yes:2", - cursorcolumn = false, - foldcolumn = "0", - spell = false, - list = false, - conceallevel = 3, - concealcursor = "nvic" - }, - - -- Send deleted files to the trash instead of permanently deleting them (:help oil-trash) - delete_to_trash = false, - - -- Skip the confirmation popup for simple operations (:help oil.skip_confirm_for_simple_edits) - skip_confirm_for_simple_edits = false, - - -- Selecting a new/moved/renamed file or directory will prompt you to save changes first - -- (:help prompt_save_on_select_new_entry) - prompt_save_on_select_new_entry = true, - - -- Oil will automatically delete hidden buffers after this delay - -- You can set the delay to false to disable cleanup entirely - -- Note that the cleanup process only starts when none of the oil buffers are currently displayed - cleanup_delay_ms = 2000, - lsp_file_methods = { - -- Enable or disable LSP file operations - enabled = true, - -- Time to wait for LSP file operations to complete before skipping - timeout_ms = 1000, - -- Set to true to autosave buffers that are updated with LSP willRenameFiles - -- Set to "unmodified" to only save unmodified buffers - autosave_changes = "unmodified" - }, - - -- Constrain the cursor to the editable parts of the oil buffer - -- Set to `false` to disable, or "name" to keep it on the file names - constrain_cursor = "editable", - - -- Set to true to watch the filesystem for changes and reload oil - watch_for_changes = false, - - -- Keymaps in oil buffer. Can be any value that `vim.keymap.set` accepts OR a table of keymap - -- options with a `callback` (e.g. { callback = function() ... end, desc = "", mode = "n" }) - -- Additionally, if it is a string that matches "actions.", - -- it will use the mapping at require("oil.actions"). - -- Set to `false` to remove a keymap - -- See :help oil-actions for a list of all available actions - keymaps = { - ["g?"] = { "actions.show_help", mode = "n" }, - [""] = "actions.refresh", - [""] = "actions.select", - ["-"] = { "actions.parent", mode = "n" }, - ["_"] = { "actions.open_cwd", mode = "n" }, - ["`"] = { "actions.cd", mode = "n" }, - ["~"] = { "actions.cd", opts = { scope = "tab" }, mode = "n" }, - ["gs"] = { "actions.change_sort", mode = "n" }, - ["gx"] = "actions.open_external", - ["g."] = { "actions.toggle_hidden", mode = "n" }, - ["g\\"] = { "actions.toggle_trash", mode = "n" } - }, - - view_options = { - -- Show files and directories that start with "." - show_hidden = false, - - -- This function defines what is considered a "hidden" file - is_hidden_file = function(name, bufnr) - local dir = require("oil").get_current_dir(bufnr) - local is_dotfile = vim.startswith(name, ".") and name ~= ".." - -- if no local directory (e.g. for ssh connections), just hide dotfiles - if not dir then - return is_dotfile +return { "stevearc/oil.nvim", + lazy = dep_short.keymap("n", "-"), + load = function() + require("oil").setup { + -- ID is automatically added at the beginning, and name at the end + -- See :help oil-columns + columns = { + { + "permissions", + highlight = function(permission_str) + local hls = {} + for i = 1, #permission_str do + local char = permission_str:sub(i, i) + table.insert(hls, { permission_hlgroups[char], i - 1, i }) end - -- dotfiles are considered hidden unless tracked - if is_dotfile then - return not git_status[dir].tracked[name] - end - end, - - -- This function defines what will never be shown, even when `show_hidden` is set - is_always_hidden = function(name, bufnr) - return false - end, - - -- Sort file names with numbers in a more intuitive order for humans. - -- Can be "fast", true, or false. "fast" will turn it off for large directories. - natural_order = "fast", - - -- Sort file and directory names case insensitive - case_insensitive = false, - - sort = { - -- sort order can be "asc" or "desc" - -- see :help oil-columns to see which columns are sortable - { "type", "asc" }, - { "name", "asc" }, - }, - - -- Customize the highlight group for the file name - highlight_filename = function(entry, is_hidden, is_link_target, is_link_orphan) - return nil + return hls end, }, + { "size", highlight = "@number" } + }, - -- Configuration for the floating window in oil.open_float - float = { - border = vim.g.border_style - }, + -- fix the damn border + confirmation = { border = vim.o.winborder }, + progress = { border = vim.o.winborder }, + ssh = { border = vim.o.winborder }, + keymaps_help = { border = vim.o.winborder } + } - -- Configuration for the floating action confirmation window - confirmation = { - border = vim.g.border_style - }, - -- Configuration for the floating progress window - progress = { - border = vim.g.border_style - }, - -- Configuration for the floating SSH window - ssh = { - border = vim.g.border_style - }, - -- Configuration for the floating keymaps help window - keymaps_help = { - border = vim.g.border_style - } - } - - map("n", "-", "Oil") - end - }, - - { "refractalize/oil-git-status.nvim", - reqs = "stevearc/oil.nvim", - lazy = dep_short.plugin("stevearc/oil.nvim"), - load = function() - require("oil-git-status").setup { - symbols = { -- customize the symbols that appear in the git status columns - index = { - ["A"] = "+", - ["D"] = "-", - ["M"] = "~", - }, - working_tree = { - ["A"] = "+", - ["D"] = "-", - ["M"] = "~", - } - } - } - end - } + map("n", "-", "Oil") + end } diff --git a/lua/conf/plugins/telescope.lua b/lua/conf/plugins/telescope.lua index 1859ccd..4d732bc 100644 --- a/lua/conf/plugins/telescope.lua +++ b/lua/conf/plugins/telescope.lua @@ -21,14 +21,8 @@ local function telebuilt_picker(fn) end return { "nvim-telescope/telescope.nvim", - disable = not vim.fn.has("nvim-0.9.0"), reqs = { - { "nvim-lua/plenary.nvim", - -- lazy = function(load) - -- load:cmd("PlenaryBustedDirectory") - -- load:cmd("PlenaryBustedFile") - -- end - }, + "nvim-lua/plenary.nvim", { "nvim-telescope/telescope-fzf-native.nvim", config = function() vim.cmd("make") @@ -40,11 +34,8 @@ return { "nvim-telescope/telescope.nvim", lazy = function(load) load:cmd("Telescope") load:keymap("n", "f") - load:keymap("n", "o") load:keymap("n", "s") load:keymap("n", "i") - load:keymap("n", "l") - load:keymap("n", ";") load:keymap("n", "tc") load:keymap("n", "tp") end, @@ -52,35 +43,86 @@ return { "nvim-telescope/telescope.nvim", load = function() local telescope = require("telescope") local actions = require("telescope.actions") + local action_state = require("telescope.actions.state") + + local function send_limited_to_qflist_and_open(prompt_bufnr) + local picker = action_state.get_current_picker(prompt_bufnr) + local entries = {} + local max_items = 100 + local count = 0 + + for entry in picker.manager:iter() do + if count >= max_items then + break + end + + local filename = entry.path or entry.filename or entry.value + local text = entry.text or entry.value + if not text then + if type(entry.value) == "table" then + text = entry.value.text + else + text = entry.value + end + end + + local pattern + if not entry.lnum then + if type(entry.display) == "string" then + pattern = entry.display + elseif type(entry.ordinal) == "string" then + pattern = entry.ordinal + elseif type(text) == "string" then + pattern = text + else + entry.lnum = 1 + end + end + + if filename then + table.insert(entries, { + filename = filename, + text = text, + lnum = entry.lnum, + col = entry.col, + + -- we try and put a pattern in based on the info we receive from + -- telescope so that the qf list takes us to the correct place + pattern = pattern + }) + count = count + 1 + end + end + + if #entries > 0 then + -- make sure errors get suppressed. I don't care + pcall(vim.fn.setqflist, {}, " ", { + title = "Telescope Limited Results", + items = entries + }) + end + + actions.select_default(prompt_bufnr) + end telescope.setup { defaults = { - borderchars = { - prompt = { " ", " ", " ", " ", " ", " ", " ", " " }, - results = { " ", " ", " ", " ", " ", " ", " ", " " }, - preview = { " ", " ", " ", " ", " ", " ", " ", " " }, - }, - winblend = 0, - layout_strategy = "horizontal", - sorting_strategy = "descending", - scroll_strategy = "limit", - layout_config = { - horizontal = { - height = 20, - prompt_position = "bottom", - anchor = "N", - } - }, + layout_strategy = "bottom_pane", + borderchars = { " ", " ", " ", " ", " ", " ", " ", " " }, mappings = { i = { [""] = actions.close, [""] = actions.move_selection_next, [""] = actions.move_selection_previous, - [""] = actions.preview_scrolling_up, - [""] = actions.preview_scrolling_down, + [""] = send_limited_to_qflist_and_open, } } }, + pickers = { + colorscheme = { + enable_preview = true + } + }, extensions = { fzf = {} } @@ -95,17 +137,10 @@ return { "nvim-telescope/telescope.nvim", map("n", "f", telebuilt_picker(telebuilt.find_files), { desc = "Find files." }) - map("n", "o", telebuilt.oldfiles, { desc = "Find old." }) map("n", "s", telebuilt_picker(telebuilt.live_grep), { desc = "Find strings." }) map("n", "i", telebuilt.help_tags, { desc = "find help tags." }) - map("n", "l", telebuilt.lsp_document_symbols, { - desc = "Find symbols." - }) - map("n", ";", telebuilt.lsp_workspace_symbols, { - desc = "Find Workspace symbols." - }) -- find over specific directories map("n", "tc", function() @@ -116,12 +151,5 @@ return { "nvim-telescope/telescope.nvim", cwd = vim.fs.joinpath(vim.fn.stdpath("data"), "site/pack/deps/opt") } end, { desc = "find files in plugin directory" }) - - -- enable previewing in the default colorscheme switcher - telebuilt.colorscheme = function() - require("telescope.builtin.__internal").colorscheme { - enable_preview = true - } - end end } diff --git a/lua/conf/plugins/treesitter.lua b/lua/conf/plugins/treesitter.lua index 18bc158..335c914 100644 --- a/lua/conf/plugins/treesitter.lua +++ b/lua/conf/plugins/treesitter.lua @@ -1,8 +1,7 @@ -local map, auto = core.misc.map, core.misc.auto +local map = core.misc.map return { { "nvim-treesitter/nvim-treesitter", - disable = not vim.fn.has("nvim-0.10.0"), config = function() vim.cmd("TSUpdate") end, diff --git a/lua/core/folding.lua b/lua/core/folding.lua deleted file mode 100644 index 6c278fe..0000000 --- a/lua/core/folding.lua +++ /dev/null @@ -1,124 +0,0 @@ ---- Stolen from: https://github.com/Wansmer/nvim-config/blob/main/lua/modules/foldtext.lua ---- modified for my use ---- ----@module Foldtext ----Based on https://www.reddit.com/r/neovim/comments/16sqyjz/finally_we_can_have_highlighted_folds/ ----Updated with vim.treesitter._fold.foldtext() - - -local function parse_line(linenr) - local bufnr = vim.api.nvim_get_current_buf() - - local line = vim.api.nvim_buf_get_lines(bufnr, linenr - 1, linenr, false)[1] - if not line then - return nil - end - - -- get a parser TODO: remove the pcall once nvim 0.12 hits and the function no - -- longer raises an error - local ok, parser = pcall(vim.treesitter.get_parser, bufnr) - if not ok or not parser then - return nil - end - - -- get a query from the parser - local query = vim.treesitter.query.get(parser:lang(), "highlights") - if not query then - return nil - end - - -- parse the current line - local tree = parser:parse({ linenr - 1, linenr })[1] - local result = {} - local line_pos = 0 - - for id, node, metadata in query:iter_captures(tree:root(), 0, linenr - 1, linenr) do - local name = query.captures[id] - local start_row, start_col, end_row, end_col = node:range() - - local priority = tonumber(metadata.priority or vim.highlight.priorities.treesitter) - - if start_row == linenr - 1 and end_row == linenr - 1 then - -- check for characters ignored by treesitter - if start_col > line_pos then - table.insert(result, { - line:sub(line_pos + 1, start_col), - { { "Folded", priority } }, - range = { line_pos, start_col }, - }) - end - line_pos = end_col - - local text = line:sub(start_col + 1, end_col) - table.insert(result, { text, { { "@" .. name, priority } }, range = { start_col, end_col } }) - end - end - - local i = 1 - while i <= #result do - -- find first capture that is not in current range and apply highlights on the way - local j = i + 1 - while j <= #result and result[j].range[1] >= result[i].range[1] and result[j].range[2] <= result[i].range[2] do - for k, v in ipairs(result[i][2]) do - if not vim.tbl_contains(result[j][2], v) then - table.insert(result[j][2], k, v) - end - end - j = j + 1 - end - - -- remove the parent capture if it is split into children - if j > i + 1 then - table.remove(result, i) - else - -- highlights need to be sorted by priority, on equal prio, the deeper nested capture (earlier - -- in list) should be considered higher prio - if #result[i][2] > 1 then - table.sort(result[i][2], function(a, b) - return a[2] < b[2] - end) - end - - result[i][2] = vim.tbl_map(function(tbl) - return tbl[1] - end, result[i][2]) - result[i] = { result[i][1], result[i][2] } - - i = i + 1 - end - end - - return result -end - ---- create a string of highlighted text for folds ----@return table|string -local function HighlightedFoldtext() - local result = parse_line(vim.v.foldstart) - if not result then - return vim.fn.foldtext() - end - - table.insert(result, { - " ... ", - "LspCodeLens", - }) - - local result2 = parse_line(vim.v.foldend) - if result2 then - local first = result2[1] - result2[1] = { vim.trim(first[1]), first[2] } - for _, item in ipairs(result2) do - table.insert(result, item) - end - end - - table.insert(result, { - " "..(vim.v.foldend - vim.v.foldstart + 1).." Lines Folded ", - "LspCodeLens", - }) - - return result -end - -return HighlightedFoldtext diff --git a/lua/core/init.lua b/lua/core/init.lua index c0b3aea..2f47744 100644 --- a/lua/core/init.lua +++ b/lua/core/init.lua @@ -29,7 +29,6 @@ end local M = { misc = require("core.misc"), - folding = require("core.folding"), lsp = require("core.lsp"), color = require("core.color"), snippets = vim.fs.joinpath(vim.fn.stdpath("config"), "lua/core/snippets.lua"), diff --git a/lua/core/lsp.lua b/lua/core/lsp.lua deleted file mode 100644 index e94b0c8..0000000 --- a/lua/core/lsp.lua +++ /dev/null @@ -1,99 +0,0 @@ -local misc = require("core.misc") -local map, auto = misc.map, misc.auto -local popup_opts, hover_opts, signature_opts, list_opts, location_opts - -local function on_list(opts) - vim.fn.setqflist({}, "r", opts) - if #opts.items > 1 then - vim.cmd.copen() - - -- get to the closest reference to the cursor (likely the one gr or gd was - -- called on) - local closest, distance = 1, false - for i, item in ipairs(opts.items) do - if item.filename and vim.fn.expand("%:p") == item.filename then - local lnum = vim.api.nvim_win_get_cursor(0)[1] - if item.lnum then - local new_distance = math.abs(lnum - item.lnum) - if not distance or new_distance < distance then - distance = new_distance - closest = i - end - end - end - - vim.cmd(".cc! "..closest) - end - else - vim.cmd(".cc! 1") - end -end - --- disable the default keybinds (they're bad) -for _, bind in ipairs({ "grn", "gra", "gri", "grr" }) do - pcall(vim.keymap.del, "n", bind) -end - -local M = {} - ---- setup vim lsp options -function M.setup() - -- options for different lsp functions - popup_opts = { border = vim.g.border_style } - hover_opts = vim.tbl_deep_extend("force", popup_opts, {}) - signature_opts = vim.tbl_deep_extend("force", popup_opts, {}) - list_opts = { on_list = on_list } - location_opts = vim.tbl_deep_extend("force", list_opts, {}) - - -- confgiure lsp - vim.diagnostic.config { - virtual_text = false, - virtual_lines = { - current_line = true - }, - update_in_insert = false, - underline = true, - severity_sort = true, - signs = { - text = { - [vim.diagnostic.severity.ERROR] = "x", - [vim.diagnostic.severity.WARN] = "!", - [vim.diagnostic.severity.INFO] = "i", - [vim.diagnostic.severity.HINT] = "h" - } - } - } - - -- set default capabilities and attach function - vim.lsp.config['*'] = { - capabilities = vim.lsp.protocol.make_client_capabilities() - } - - -- make my attach function always run - auto("LspAttach", { - callback = function(event) - local opts = { buffer = event.buf, nowait = true } - - -- LSP actions - map("n", "K", function() vim.lsp.buf.hover(hover_opts) end, opts) - map("n", "gd", function() vim.lsp.buf.definition(location_opts) end, opts) - map("n", "gD", function() vim.lsp.buf.declaration(location_opts) end, opts) - map("n", "gi", function() vim.lsp.buf.implementation(location_opts) end, opts) - map("n", "gy", function() vim.lsp.buf.type_definition(location_opts) end, opts) - map("n", "gr", function() vim.lsp.buf.references(nil, list_opts) end, opts) - map("n", "", function() vim.lsp.buf.signature_help(signature_opts) end, opts) - map("n", { "r", "" }, vim.lsp.buf.rename, opts) - map("n", { "gA", "" }, vim.lsp.buf.code_action, opts) - - -- Diagnostics - map("n", "[d", function() - vim.diagnostic.jump({ count = -1 }) - end, opts) - map("n", "]d", function() - vim.diagnostic.jump({ count = 1 }) - end, opts) - end - }) -end - -return M diff --git a/lua/core/lsp/binds.lua b/lua/core/lsp/binds.lua new file mode 100644 index 0000000..2cdc6ca --- /dev/null +++ b/lua/core/lsp/binds.lua @@ -0,0 +1,65 @@ +local misc = require("core.misc") +local map, auto = misc.map, misc.auto + +local function on_list(opts) + vim.fn.setqflist({}, "r", opts) + if #opts.items > 1 then + vim.cmd.copen() + + -- get to the closest reference to the cursor (likely the one gr or gd was + -- called on) + local closest, distance = 1, false + for i, item in ipairs(opts.items) do + if item.filename and vim.fn.expand("%:p") == item.filename then + local lnum = vim.api.nvim_win_get_cursor(0)[1] + if item.lnum then + local new_distance = math.abs(lnum - item.lnum) + if not distance or new_distance < distance then + distance = new_distance + closest = i + end + end + end + + vim.cmd(".cc! "..closest) + end + else + vim.cmd(".cc! 1") + end +end + +-- disable the default keybinds (they're bad) +for _, bind in ipairs({ "grn", "gra", "gri", "grr" }) do + pcall(vim.keymap.del, "n", bind) +end + +local group = misc.augroup("lsp.bind") +auto("LspAttach", { + group = group, + callback = function(ctx) + local list_opts = { on_list = on_list } + local opts = { buffer = ctx.buf, nowait = true } + + -- LSP actions + map("n", "K", vim.lsp.buf.hover, opts) + map("n", "gd", function() vim.lsp.buf.definition(list_opts) end, opts) + map("n", "gD", function() vim.lsp.buf.declaration(list_opts) end, opts) + map("n", "gi", function() vim.lsp.buf.implementation(list_opts) end, opts) + map("n", "gy", function() vim.lsp.buf.type_definition(list_opts) end, opts) + map("n", "gr", function() vim.lsp.buf.references(nil, list_opts) end, opts) + map("n", "", vim.lsp.buf.signature_help, opts) + map("n", { "r", "" }, vim.lsp.buf.rename, opts) + map("n", { "gA", "" }, vim.lsp.buf.code_action, opts) + + -- Diagnostics + map("n", "[d", function() + vim.diagnostic.jump({ count = -1 }) + end, opts) + map("n", "]d", function() + vim.diagnostic.jump({ count = 1 }) + end, opts) + + -- formatting + map("n", "c", vim.lsp.buf.format) + end +}) diff --git a/lua/core/lsp/completion.lua b/lua/core/lsp/completion.lua new file mode 100644 index 0000000..22eaed0 --- /dev/null +++ b/lua/core/lsp/completion.lua @@ -0,0 +1,178 @@ +-- stolen from https://github.com/glepnir/nvim with some modifications by me + +--- add char to list of triggerable chars +---@param list table list of chars +---@param char number|string char to add +local function add_to_client(list, char) + local c + + if type(char) == "string" then + c = char + elseif type(char) == "number" then + c = string.char(char) + end + if not table.contains(list, c) then + table.insert(list, c) + end +end + +local misc = require("core.misc") +local auto = misc.auto + +local competion_group = misc.augroup("lsp.completion") + +-- configure the lsp completion menu +auto("LspAttach", { + group = competion_group, + callback = function(ctx) + local client = vim.lsp.get_client_by_id(ctx.data.client_id) + if not client or not client:supports_method("textDocument/completion") then + return + end + + -- Make completion menu appear whenever you type something. + local c = client.server_capabilities.completionProvider.triggerCharacters + if c then + for i = 32, 126 do + add_to_client(c, string.char(i)) + end + end + + vim.lsp.completion.enable(true, client.id, ctx.buf, { + autotrigger = true, + convert = function(item) + local kind = vim.lsp.protocol.CompletionItemKind[item.kind] or 'u' + return { + abbr = item.label:gsub('%b()', ''), + kind = kind:sub(1, 1):lower(), + menu = '' + } + end + }) + end +}) + +-- attempt to style the completion documentation popup +auto("CompleteChanged", { + group = competion_group, + callback = function() + local info = vim.fn.complete_info({ "selected" }) + if info.preview_bufnr and vim.bo[info.preview_bufnr].filetype == "" then + vim.bo[info.preview_bufnr].filetype = "markdown" + vim.wo[info.preview_winid].conceallevel = 2 + vim.wo[info.preview_winid].concealcursor = "niv" + end + end +}) + +-- Add snippet support to lsp clients who don't do it for us. Currently this +-- only supports function calls. +-- +-- there's a very good chance this will give us problems for languages who do +-- not follow the c-style function call style +auto("CompleteDonePre", { + group = competion_group, + callback = function() + local item = vim.tbl_get( + vim.v.completed_item, + "user_data", + "nvim", + "lsp", + "completion_item" + ) + if not item then + return + end + + -- if the item isn't a snippet then we might want to create a snippet + if item.label and item.kind and item.insertTextFormat then + if item.insertTextFormat ~= 2 and item.kind == 3 then + local n_complete_item = vim.v.completed_item + + -- attempt to modify the function args to create a snippet + local paren1 = string.find(item.label, "%(") + if not paren1 then + return + end + + -- try and create a snippet from a function call + local i = 1 + local text = "" + local l_paren = paren1 + local next, is_paren + while not is_paren do + -- find the next token + next = string.find(item.label, "%,", l_paren + 1) + if not next then + next = string.find(item.label, "%)", l_paren + 1) + if not next then + return + end + is_paren = true + end + + -- concat text + if text == "" then + -- start the snippet + text = string.sub(item.label, 0, l_paren).."${"..i..":" + else + -- continue the snippet + text = text.."}, ".."${"..i..":" + end + + do -- add the content of the argument to the snippet + -- we need to account for cases in which the developer uses spaces + -- between their commas and code + local is_space = string.sub(item.label, l_paren + 1, l_paren + 1) + local plus = is_space == " " and 2 or 1 + + text = text..string.sub(item.label, l_paren + plus, next - 1) + end + + -- increment + l_paren = next + i = i + 1 + end + -- end the snippet + text = text.."})" + + n_complete_item.user_data.nvim.lsp.completion_item.insertText = text + n_complete_item.user_data.nvim.lsp.completion_item.insertTextFormat = 2 + vim.v.completed_item = n_complete_item + end + end + end +}) + +-- show the signature help when inside a function call +auto("CompleteDone", { + group = competion_group, + callback = function(ctx) + -- make sure there's an lsp client, and make sure the lsp client supports + -- textDocument/signatureHelp + local client = vim.lsp.get_clients({ bufnr = ctx.buf })[0] + if not client or not client[0]:supports_method("textDocument/signatureHelp") then + return + end + + -- show the signature help + local item = vim.tbl_get( + vim.v.completed_item, + "user_data", + "nvim", + "lsp", + "completion_item" + ) + if not item then + return + end + + -- show signature help when the completion is a function + if item.kind == 3 and (item.textEdit ~= nil or item.insertText ~= nil) then + vim.schedule(function() + vim.lsp.buf.signature_help() + end) + end + end, + desc = "Auto show signature help when completion is done" +}) diff --git a/lua/core/lsp/init.lua b/lua/core/lsp/init.lua new file mode 100644 index 0000000..5e0b1e9 --- /dev/null +++ b/lua/core/lsp/init.lua @@ -0,0 +1,33 @@ +local M = {} + +--- setup vim lsp options +function M.setup() + -- confgiure lsp + vim.diagnostic.config { + virtual_text = false, + virtual_lines = { + current_line = true + }, + update_in_insert = false, + underline = true, + severity_sort = true, + signs = { + text = { + [vim.diagnostic.severity.ERROR] = "x", + [vim.diagnostic.severity.WARN] = "!", + [vim.diagnostic.severity.INFO] = "i", + [vim.diagnostic.severity.HINT] = "h" + } + } + } + + -- set default capabilities and attach function + vim.lsp.config['*'] = { + capabilities = vim.lsp.protocol.make_client_capabilities() + } + + require("core.lsp.binds") + require("core.lsp.completion") +end + +return M diff --git a/lua/core/misc.lua b/lua/core/misc.lua index 24378b4..7e419f3 100644 --- a/lua/core/misc.lua +++ b/lua/core/misc.lua @@ -59,16 +59,27 @@ end --- extend vim.api.nvim_create_autocmd ---@param event string|table event or events ---@param opts vim.api.keyset.create_autocmd options +---@return integer function M.auto(event, opts) - vim.api.nvim_create_autocmd(event, opts) + return vim.api.nvim_create_autocmd(event, opts) end --- extend auto group ---@param name string name of the autogroup ---@param opts table? table of options +---@return integer function M.augroup(name, opts) opts = opts or {} - vim.api.nvim_create_augroup(name, opts) + return vim.api.nvim_create_augroup(name, opts) +end + +--- Make an action lazy. This is mostly useful for keybinds which do a lot and +--- you want to make sure the screen doesn't flash +---@param txt string the action +---@return string lazified +---@nodiscard +function M.lz(txt) + return "se lz"..txt.."se lz!" end --- extend vim.api.nvim_set_hl diff --git a/lua/snippets/norg.lua b/lua/snippets/norg.lua deleted file mode 100644 index afe4c49..0000000 --- a/lua/snippets/norg.lua +++ /dev/null @@ -1,24 +0,0 @@ -dofile(core.snippets) - -return { - -- header level 1, usually this has the same name as the file - s("h1", { - t("* "), - c(1, { - f(file_name, {}), - i(1, "header") - }) - }), - - -- link snippet - s("link", { - t("{"), - c(1, { - sn(nil, { t({":$/"}), i(1, "path to file"), t(":") }), - i(1, "https://example.com") - }), - t("}["), - i(2, "description"), - t("]") - }) -}