diff --git a/init.lua b/init.lua index 54824ce1..0b3804b5 100644 --- a/init.lua +++ b/init.lua @@ -1,30 +1,30 @@ vim.loader.enable() vim.g.base46_cache = vim.fn.stdpath("data") .. "/nvchad/base46/" +vim.g.mapleader = " " -require("settings") -require("settings.options") -require("settings.autocmd") -require("plugins") - -vim.api.nvim_create_autocmd("User", { - group = vim.api.nvim_create_augroup("LazyVim", { clear = true }), - pattern = "VeryLazy", - callback = function() - require("settings.keymap") - end, -}) - -for name, icon in pairs(dots.UI.icons.LSP.diagnostics) do - name = "DiagnosticSign" .. name - vim.fn.sign_define(name, { text = icon, texthl = name, numhl = "" }) +-- bootstrap lazy and all plugins +local lazypath = vim.fn.stdpath("data") .. "/lazy/lazy.nvim" + +if not vim.loop.fs_stat(lazypath) then + local repo = "https://github.com/folke/lazy.nvim.git" + vim.fn.system({ "git", "clone", "--filter=blob:none", repo, "--branch=stable", lazypath }) end --- https://www.reddit.com/r/neovim/comments/1ayx62p/config_for_diagnostics/ -vim.diagnostic.config({ - virtual_text = { - source = "if_many", - }, -}) +vim.opt.rtp:prepend(lazypath) + +require("settings") + +require("lazy").setup({ + { import = "plugins.specs" }, + dots.languages.enable, +}, require("configs.lazy")) dofile(vim.g.base46_cache .. "defaults") dofile(vim.g.base46_cache .. "statusline") + +require("settings.options") +require("settings.autocmd") + +vim.schedule(function() + require("settings.keymap") +end) diff --git a/lazy-lock.json b/lazy-lock.json index 9f64824b..ddf02f68 100644 --- a/lazy-lock.json +++ b/lazy-lock.json @@ -1,49 +1,52 @@ { - "Comment.nvim": { "branch": "master", "commit": "0236521ea582747b58869cb72f70ccfa967d2e89" }, - "LuaSnip": { "branch": "master", "commit": "b152822e1a4bafb6bdf11a16cc26525cbd95ee00" }, - "actions-preview.nvim": { "branch": "master", "commit": "ceb6e06d1c8c30d8ddfe3afb03cd2c47b08b2798" }, - "base46": { "branch": "v2.5", "commit": "bcc9ed2e88ef55b7e9d50b2f80f6a2d4b8080b1d" }, + "LuaSnip": { "branch": "master", "commit": "ba3ea5bcfd969679f38fefb1bc801cd45524045b" }, + "base46": { "branch": "v2.5", "commit": "bbbdde83001701047b88f4978f05ea43ea4462e1" }, "cmp-buffer": { "branch": "main", "commit": "3022dbc9166796b644a841a02de8dd1cc1d311fa" }, "cmp-cmdline": { "branch": "main", "commit": "d250c63aa13ead745e3a40f61fdd3470efde3923" }, - "cmp-nvim-lsp": { "branch": "main", "commit": "5af77f54de1b16c34b23cba810150689a3a90312" }, + "cmp-nvim-lsp": { "branch": "main", "commit": "39e2eda76828d88b773cc27a3f61d2ad782c922d" }, "cmp-path": { "branch": "main", "commit": "91ff86cd9c29299a64f968ebb45846c485725f23" }, "cmp_luasnip": { "branch": "master", "commit": "05a9ab28b53f71d1aece421ef32fee2cb857a843" }, - "conform.nvim": { "branch": "master", "commit": "12b3995537f52ba2810a9857e8ca256881febbda" }, - "crates.nvim": { "branch": "main", "commit": "f00e11e8282b94f2a2e938d32712c99f0e0bdeb4" }, - "cutlass.nvim": { "branch": "main", "commit": "1ac7e4b53d79410be52a9e464d44c60556282b3e" }, - "dressing.nvim": { "branch": "master", "commit": "5162edb1442a729a885c45455a07e9a89058be2f" }, - "flash.nvim": { "branch": "main", "commit": "7bb4a9c75d1e20cd24185afedeaa11681829ba23" }, - "friendly-snippets": { "branch": "main", "commit": "fa36367422da5a38560892e3db6d090a635d9d41" }, - "grapple.nvim": { "branch": "main", "commit": "493f174a1ace3f2d55ba2191129e43b3875b9124" }, - "indent-blankline.nvim": { "branch": "master", "commit": "3d08501caef2329aba5121b753e903904088f7e6" }, - "lazy.nvim": { "branch": "main", "commit": "d3974346b6cef2116c8e7b08423256a834cb7cbc" }, - "mini.ai": { "branch": "main", "commit": "55e9b7217f29e62f734e239bfeed5731a065d801" }, - "mini.clue": { "branch": "main", "commit": "bde26d6f142eee03ea63015e73b6ac984d49a382" }, - "mini.diff": { "branch": "main", "commit": "10cc9d370737b8b8c8d996fc537394635da0a4b1" }, - "mini.files": { "branch": "main", "commit": "17684f78d0499f11e54fc980838cfef3cf5c7c72" }, - "mini.indentscope": { "branch": "main", "commit": "a8274b6ea2d868198d27bd91a31ed5ea3a6a5744" }, - "mini.operators": { "branch": "main", "commit": "2edc808e32fbf3e0d4759bdef26a7a143a19f509" }, - "mini.surround": { "branch": "main", "commit": "0f528eb2e1bab420c0569d9e52615144c51db920" }, - "noice.nvim": { "branch": "main", "commit": "f4decbc7a80229ccc9f86026b74bdcf0c39e38a7" }, - "nui.nvim": { "branch": "main", "commit": "274fa89a9b4bed746647c2917091902f882509ec" }, - "nvim-cmp": { "branch": "main", "commit": "8f3c541407e691af6163e2447f3af1bd6e17f9a3" }, - "nvim-lightbulb": { "branch": "master", "commit": "8f00b89dd1b1dbde16872bee5fbcee2e58c9b8e9" }, - "nvim-lint": { "branch": "master", "commit": "861a04313501563bb1b11f125ae9b7237a517b9b" }, - "nvim-lspconfig": { "branch": "master", "commit": "aa5f4f4ee10b2688fb37fa46215672441d5cd5d9" }, - "nvim-notify": { "branch": "master", "commit": "5371f4bfc1f6d3adf4fe9d62cd3a9d44356bfd15" }, - "nvim-spectre": { "branch": "master", "commit": "4651801ba37a9407b7257287aec45b6653ffc5e9" }, - "nvim-treesitter": { "branch": "master", "commit": "4e21361e15b1d4147830c5fe571556eb1b14e6f9" }, - "nvim-treesitter-textobjects": { "branch": "master", "commit": "23b820146956b3b681c19e10d3a8bc0cbd9a1d4c" }, - "nvim-ts-context-commentstring": { "branch": "main", "commit": "a6382f744f584bbf71d0a563af789af7190aabda" }, - "nvim-web-devicons": { "branch": "master", "commit": "475fbcfcb6ee7c35aa33a6b6207ebd4032791d87" }, - "plenary.nvim": { "branch": "master", "commit": "08e301982b9a057110ede7a735dd1b5285eb341f" }, - "smart-open.nvim": { "branch": "main", "commit": "028bb71d20e8212da3514bf6dabfb17038d81ee4" }, + "conform.nvim": { "branch": "master", "commit": "c26dadf8a47a547768d1048a0d698ecec33494ce" }, + "dressing.nvim": { "branch": "master", "commit": "6741f1062d3dc6e4755367a7e9b347b553623f04" }, + "flash.nvim": { "branch": "main", "commit": "43f67935d388fbb540f8b40e8cbfd80de54f978a" }, + "friendly-snippets": { "branch": "main", "commit": "682157939e57bd6a2c86277dfd4d6fbfce63dbac" }, + "gitsigns.nvim": { "branch": "main", "commit": "fa42613096ebfa5fee1ea87d70f8625ab9685d01" }, + "indent-blankline.nvim": { "branch": "master", "commit": "4288ce8128a52650e401dda42fd7651a6038f262" }, + "lazy.nvim": { "branch": "main", "commit": "aa1c9572aa1916e582f9b9c3d43e272b4f23b326" }, + "lazydev.nvim": { "branch": "main", "commit": "78d8a11fbd02ad4eafa07dd8a43a959a69fb3bf8" }, + "lspkind.nvim": { "branch": "master", "commit": "1735dd5a5054c1fb7feaf8e8658dbab925f4f0cf" }, + "luvit-meta": { "branch": "main", "commit": "ce76f6f6cdc9201523a5875a4471dcfe0186eb60" }, + "mini.ai": { "branch": "main", "commit": "ebf806de0292ef89b2756cfb0b55040901d1c441" }, + "mini.clue": { "branch": "main", "commit": "c3eaa29d7e875b3a80b4db4067a04726646ce2db" }, + "mini.diff": { "branch": "main", "commit": "9d451672f2f4f8613c859618b5a7a5bf0c4cfa08" }, + "mini.extra": { "branch": "main", "commit": "2a3dc0293fbbe5a27d54957ed149cbdf4f2ddbbf" }, + "mini.files": { "branch": "main", "commit": "34602e87159c3b0e270da103f37a2860bbfd62bd" }, + "mini.git": { "branch": "main", "commit": "54220269adaf9788175b05877f406dfaba68df09" }, + "mini.hipatterns": { "branch": "main", "commit": "5d28a7e3f399de64c4dbf71f8c6c3b633d986f15" }, + "mini.move": { "branch": "main", "commit": "0977d909000510b9d3c16981e16580b8433c8697" }, + "mini.notify": { "branch": "main", "commit": "08aa3be5b99234715bf8d2e56504dccea8a0e212" }, + "mini.operators": { "branch": "main", "commit": "76ac9104d9773927053ea4eb12fc78ccbb5be813" }, + "mini.splitjoin": { "branch": "main", "commit": "6e0c320c2c3a9cc4beb0db9284f3ee5888371f3a" }, + "mini.surround": { "branch": "main", "commit": "af280fc18792b4d142aab4c1638a8949a38ff33a" }, + "mini.visits": { "branch": "main", "commit": "ba562001b033943f2f0ee943f0d0f1ee621aa90f" }, + "noice.nvim": { "branch": "main", "commit": "03c6a75661e68012e30b0ed81f050358b1e2233c" }, + "nui.nvim": { "branch": "main", "commit": "61574ce6e60c815b0a0c4b5655b8486ba58089a1" }, + "nvim-cmp": { "branch": "main", "commit": "a110e12d0b58eefcf5b771f533fc2cf3050680ac" }, + "nvim-lint": { "branch": "master", "commit": "941fa1220a61797a51f3af9ec6b7d74c8c7367ce" }, + "nvim-lspconfig": { "branch": "master", "commit": "9c9eb07fecc578e25e28db8dc9002b43fff2ed79" }, + "nvim-spectre": { "branch": "master", "commit": "49fae98ef2bfa8342522b337892992e3495065d5" }, + "nvim-treesitter": { "branch": "main", "commit": "fece55077cd7d6f6e79e0deb4397db248e2f5817" }, + "nvim-treesitter-textobjects": { "branch": "main", "commit": "cd8fd01677e0cfe9dc2c715f305d653269232c1a" }, + "nvim-various-textobjs": { "branch": "main", "commit": "bde0481460bfaf0833bd5df7213e6bddcf9b0d8e" }, + "nvim-web-devicons": { "branch": "master", "commit": "c0cfc1738361b5da1cd0a962dd6f774cc444f856" }, + "plenary.nvim": { "branch": "master", "commit": "a3e3bc82a3f95c5ed0d7201546d5d2c19b20d683" }, + "smart-open.nvim": { "branch": "main", "commit": "f4e39e9a1b05a6b82b1182a013677acc44b27abb" }, "sqlite.lua": { "branch": "master", "commit": "d0ffd703b56d090d213b497ed4eb840495f14a11" }, "telescope-fzy-native.nvim": { "branch": "master", "commit": "282f069504515eec762ab6d6c89903377252bf5b" }, - "telescope.nvim": { "branch": "master", "commit": "fac83a556e7b710dc31433dec727361ca062dbe9" }, - "treesj": { "branch": "main", "commit": "e1e82ab4237619d342c7102c9f13d4b9833bfd39" }, - "ui": { "branch": "v2.5", "commit": "9c16efc915346c7bde5288ad94f0ea40a7267d31" }, - "ultimate-autopair.nvim": { "branch": "v0.6", "commit": "6ecf7461d44513af89f8257f057fcc99e9297612" }, + "telescope.nvim": { "branch": "master", "commit": "61a4a615366c470a4e9ca8f8b45718b6b92af73f" }, + "ts-comments.nvim": { "branch": "main", "commit": "c075b4ee00f6e111b44bf99a8cfd5a4cfce9258a" }, + "ui": { "branch": "v2.5", "commit": "a44793fc405d11edc40a694ca9687a36b9dae503" }, + "ultimate-autopair.nvim": { "branch": "v0.6", "commit": "035d92eab05ac1390afef7204e3fcad9a50fa443" }, "vscode-svelte-snippets": { "branch": "master", "commit": "564ac3300bfeda01ff0bf6b89152cef43f85a4ce" }, - "yanky.nvim": { "branch": "main", "commit": "7c5cbf0122ff2dfbb6a92f14885894f65949cc8b" } + "yanky.nvim": { "branch": "main", "commit": "73215b77d22ebb179cef98e7e1235825431d10e4" } } \ No newline at end of file diff --git a/lua/asyncedd/cowboy.lua b/lua/asyncedd/cowboy.lua deleted file mode 100644 index fcd23732..00000000 --- a/lua/asyncedd/cowboy.lua +++ /dev/null @@ -1,37 +0,0 @@ -return function() - ---@type table? - local id - local ok = true - for _, key in ipairs({ "h", "j", "k", "l", "+", "-" }) do - local count = 0 - local timer = assert(vim.loop.new_timer()) - local map = key - vim.keymap.set("n", key, function() - if vim.v.count > 0 then - count = 0 - end - if key == "j" or key == "k" then - map = vim.v.count == 0 and "g" .. key or key - end - if count >= 10 then - ok, id = pcall(vim.notify, "Hold it Cowboy!", vim.log.levels.WARN, { - icon = "🤠", - replace = id, - keep = function() - return count >= 10 - end, - }) - if not ok then - id = nil - return map - end - else - count = count + 1 - timer:start(2000, 0, function() - count = 0 - end) - return map - end - end, { expr = true, silent = true }) - end -end diff --git a/lua/chadrc.lua b/lua/chadrc.lua index 25f7ea6a..757a726c 100644 --- a/lua/chadrc.lua +++ b/lua/chadrc.lua @@ -1,7 +1,9 @@ +---@type ChadrcConfig local M = {} +local utils = require("nvchad.stl.utils") M.ui = { - theme = "onedark", + theme = "everblush", statusline = { order = { "mode", @@ -12,6 +14,37 @@ M.ui = { "cwd", "cursor", }, + modules = { + git = function() + local git_status = vim.b[utils.stbufnr()].minigit_summary_string or "" + + local summary = vim.b[utils.stbufnr()].minigit_summary + local branch_name = (summary ~= nil and summary.head_name) and (" " .. git_status) or "" + + summary = vim.b.minidiff_summary + return "%#St_gitIcons# " + .. branch_name + .. ( + summary ~= nil + and " " .. ((summary.add ~= nil and summary.add > 0) and dots.UI.icons.Git.added .. summary.add or "") .. ((summary.change ~= nil and summary.change > 0) and dots.UI.icons.Git.changed .. summary.change or "") .. ((summary.delete ~= nil and summary.delete > 0) and dots.UI.icons.Git.remove .. summary.delete or "") + or "" + ) + end, + }, + }, + hl_override = { + DiffAdd = { fg = "green" }, + DiffModified = { fg = "yellow" }, + + FloatBorder = { fg = "darker_black", bg = "darker_black" }, + NormalFloat = { bg = "darker_black" }, + }, + hl_add = { + MiniDiffSignAdd = { fg = "green" }, + MiniDiffSignChange = { fg = "yellow" }, + MiniDiffSignDelete = { fg = "red" }, + + MiniNotifyNormal = { link = "Normal" }, }, } diff --git a/lua/configs/conform.lua b/lua/configs/conform.lua new file mode 100644 index 00000000..50d3f91c --- /dev/null +++ b/lua/configs/conform.lua @@ -0,0 +1,18 @@ +local options = { + format_on_save = { timeout_ms = 500, lsp_fallback = true }, + formatters_by_ft = { + c = { "clang_format" }, + javascript = { "prettierd" }, + typescript = { "prettierd" }, + css = { "prettierd" }, + html = { "prettierd" }, + fish = { "fish_indent" }, + nix = { "nixfmt" }, + markdown = { { "prettierd", "prettier" } }, + lua = { "stylua" }, + svelte = { { "prettierd", "prettier" } }, + python = { "black" }, + }, +} + +return options diff --git a/lua/configs/hipatterns.lua b/lua/configs/hipatterns.lua new file mode 100644 index 00000000..39b88291 --- /dev/null +++ b/lua/configs/hipatterns.lua @@ -0,0 +1,7 @@ +local hi = require("mini.hipatterns") + +return { + highlighters = { + hex_color = hi.gen_highlighter.hex_color(), + }, +} diff --git a/lua/configs/lazy.lua b/lua/configs/lazy.lua new file mode 100644 index 00000000..99b047bf --- /dev/null +++ b/lua/configs/lazy.lua @@ -0,0 +1,50 @@ +return { + defaults = { lazy = true }, + install = { colorscheme = { "nvchad", "habamax" } }, + + ui = { + icons = { + ft = "", + lazy = "󰂠 ", + loaded = "", + not_loaded = "", + }, + }, + + performance = { + rtp = { + disabled_plugins = { + "2html_plugin", + "tohtml", + "getscript", + "getscriptPlugin", + "gzip", + "logipat", + "netrw", + "netrwPlugin", + "netrwSettings", + "netrwFileHandlers", + "matchit", + "tar", + "tarPlugin", + "rrhelper", + "spellfile_plugin", + "vimball", + "vimballPlugin", + "zip", + "zipPlugin", + "tutor", + "rplugin", + "syntax", + "synmenu", + "optwin", + "compiler", + "bugreport", + "ftplugin", + }, + }, + }, + change_detection = { + notify = false, + }, +} diff --git a/lua/configs/lspconfig.lua b/lua/configs/lspconfig.lua new file mode 100644 index 00000000..a4565468 --- /dev/null +++ b/lua/configs/lspconfig.lua @@ -0,0 +1,225 @@ +local conf = require("nvconfig").ui.lsp +local map = vim.keymap.set +local on_attach = function(client, bufnr) + local function opts(desc) + return { buffer = bufnr, desc = "LSP " .. desc } + end + + map("n", "gD", vim.lsp.buf.declaration, opts("Go to declaration")) + map("n", "gd", vim.lsp.buf.definition, opts("Go to definition")) + map("n", "gi", vim.lsp.buf.implementation, opts("Go to implementation")) + map("n", "sh", vim.lsp.buf.signature_help, opts("Show signature help")) + map("n", "wa", vim.lsp.buf.add_workspace_folder, opts("Add workspace folder")) + map("n", "wr", vim.lsp.buf.remove_workspace_folder, opts("Remove workspace folder")) + + map("n", "wl", function() + print(vim.inspect(vim.lsp.buf.list_workspace_folders())) + end, opts("List workspace folders")) + + map("n", "D", vim.lsp.buf.type_definition, opts("Go to type definition")) + + map("n", "ra", function() + require("nvchad.lsp.renamer")() + end, opts("NvRenamer")) + + map({ "n", "v" }, "ca", vim.lsp.buf.code_action, opts("Code action")) + map("n", "gr", vim.lsp.buf.references, opts("Show references")) + + -- setup signature popup + if conf.signature and client.server_capabilities.signatureHelpProvider then + require("nvchad.lsp.signature").setup(client, bufnr) + end +end + +local on_init = function(client, _) + if client.supports_method("textDocument/semanticTokens") then + client.server_capabilities.semanticTokensProvider = nil + end + + if conf.inlay_hints then + vim.b.inlay_hints_enabled = true + vim.lsp.inlay_hint.enable(true) + vim.api.nvim_create_autocmd("InsertEnter", { + callback = function() + vim.lsp.inlay_hint.enable(false) + end, + }) + vim.api.nvim_create_autocmd("InsertLeave", { + callback = function() + vim.lsp.inlay_hint.enable(vim.b.inlay_hints_enabled or false) + end, + }) + end +end + +local capabilities = vim.lsp.protocol.make_client_capabilities() + +capabilities.textDocument.completion.completionItem = { + documentationFormat = { "markdown", "plaintext" }, + snippetSupport = true, + preselectSupport = true, + insertReplaceSupport = true, + labelDetailsSupport = true, + deprecatedSupport = true, + commitCharactersSupport = true, + tagSupport = { valueSet = { 1 } }, + resolveSupport = { + properties = { + "documentation", + "detail", + "additionalTextEdits", + }, + }, +} + +local lspconfig = require("lspconfig") + +local servers = { + "basedpyright", + -- "clangd", + -- "svelte", + -- "emmet_ls", + -- "tailwindcss", + -- "marksman", +} + +for _, lsp in ipairs(servers) do + lspconfig[lsp].setup({ + on_attach = on_attach, + on_init = on_init, + capabilities = capabilities, + }) +end + +require("lspconfig")["nil_ls"].setup({ + on_attach = on_attach, + on_init = on_init, + capabilities = capabilities, + + settings = { + ["nil"] = { + nix = { flake = { autoArchive = true } }, + }, + }, +}) + +require("lspconfig")["nixd"].setup({ + on_attach = on_attach, + on_init = function(client, _) + on_init(client, _) + + client.server_capabilities.semanticTokensProvider = nil + end, + capabilities = capabilities, +}) + +require("lspconfig")["markdown_oxide"].setup({ + on_attach = function(client, bufnr) + on_attach(client, bufnr) + + vim.api.nvim_create_autocmd({ "TextChanged", "InsertLeave", "CursorHold", "LspAttach" }, { + buffer = bufnr, + callback = vim.lsp.codelens.refresh, + }) + vim.api.nvim_exec_autocmds("User", { pattern = "LspAttached" }) + + -- setup Markdown Oxide daily note commands + if client.name == "markdown_oxide" then + vim.api.nvim_create_user_command("Daily", function(args) + local input = args.args + + vim.lsp.buf.execute_command({ command = "jump", arguments = { input } }) + end, { desc = "Open daily note", nargs = "*" }) + end + end, + on_init = on_init, + capabilities = vim.tbl_deep_extend("force", capabilities, { + workspace = { + didChangeWatchedFiles = { + dynamicRegistration = true, + }, + }, + }), +}) + +require("lspconfig")["rust_analyzer"].setup({ + capabilities = capabilities, + on_attach = on_attach, + on_init = on_init, + settings = { + ["rust-analyzer"] = { + cargo = { + allFeatures = true, + loadOutDirsFromCheck = true, + runBuildScripts = true, + }, + check = { + command = "clippy", + allFeatures = true, + extraArgs = { + "--", + "-W clippy::pedantic", + "-W clippy::nursery", + "-W clippy::unwrap_used", + "-W clippy::expect_used", + }, + }, + procMacro = { + enable = true, + ignored = { + ["async-trait"] = { "async_trait" }, + ["napi-derive"] = { "napi" }, + ["async-recursion"] = { "async_recursion" }, + }, + }, + }, + }, +}) + +require("lspconfig")["lua_ls"].setup({ + capabilities = capabilities, + on_attach = on_attach, + on_init = on_init, + settings = { + Lua = { + hint = { + enable = true, + arrayIndex = "Disable", + }, + runtime = { + pathStrict = true, + }, + completion = { + callSnippet = "Both", + }, + diagnostics = { + globals = { + "vim", + }, + }, + workspace = { + maxPreload = 100000, + preloadFileSize = 10000, + checkThirdParty = false, + }, + }, + }, +}) + +require("lspconfig")["cssls"].setup({ + capabilities = capabilities, + cmd = { "css-languageserver", "--stdio" }, + on_attach = on_attach, + on_init = on_init, +}) + +require("lspconfig")["ruff_lsp"].setup({ + capabilities = capabilities, + on_attach = function(client, bufnr) + on_attach(client, bufnr) + + -- Disable hover in favor of Pyright + client.server_capabilities.hoverProvider = false + end, + on_init = on_init, +}) diff --git a/lua/nvconfig.lua b/lua/nvconfig.lua index 6e51525a..b57ae913 100644 --- a/lua/nvconfig.lua +++ b/lua/nvconfig.lua @@ -66,6 +66,7 @@ M.ui = { lsp = { signature = true, semantic_tokens = false, + inlay_hints = true, }, term = { diff --git a/lua/plugins/configs/ui/notify.lua b/lua/plugins/configs/ui/notify.lua deleted file mode 100644 index 94cb9c23..00000000 --- a/lua/plugins/configs/ui/notify.lua +++ /dev/null @@ -1,55 +0,0 @@ -local api = vim.api -local stages = require("notify.stages.fade_in_slide_out")("top_down") -local base = require("notify.render.base") -return { - render = function(bufnr, notif, highlights, config) - local max_message_width = math.max(math.max(unpack(vim.tbl_map(function(line) - return vim.fn.strchars(line) - end, notif.message)))) - local title = notif.title[1] - local title_accum = vim.str_utfindex(title) - - local title_buffer = - string.rep(" ", (math.max(max_message_width, title_accum, config.minimum_width()) - title_accum) / 2) - - local namespace = base.namespace() - - api.nvim_buf_set_lines(bufnr, 0, 1, false, { "", "" }) - api.nvim_buf_set_extmark(bufnr, namespace, 0, 0, { - virt_text = { - { title_buffer .. notif.icon .. " " .. title .. title_buffer, highlights.title }, - }, - virt_text_win_col = 0, - priority = 10, - }) - api.nvim_buf_set_extmark(bufnr, namespace, 1, 0, { - virt_text = { - { - string.rep("━", math.max(max_message_width, title_accum, config.minimum_width())), - highlights.border, - }, - }, - virt_text_win_col = 0, - priority = 10, - }) - api.nvim_buf_set_lines(bufnr, 2, -1, false, notif.message) - - api.nvim_buf_set_extmark(bufnr, namespace, 2, 0, { - hl_group = highlights.body, - end_line = 1 + #notif.message, - end_col = #notif.message[#notif.message], - priority = 50, - }) - end, - stages = { - function(...) - local opts = stages[1](...) - if opts then - opts.row = opts.row + 1 - end - return opts - end, - unpack(stages, 2), - }, - fps = 60, -} diff --git a/lua/plugins/init.lua b/lua/plugins/init.lua index 8fab385e..4f794c25 100644 --- a/lua/plugins/init.lua +++ b/lua/plugins/init.lua @@ -14,27 +14,4 @@ vim.opt.rtp:prepend(lazypath) require("lazy").setup({ { import = "plugins.specs" }, dots.languages.enable, - dots.goodies.enable, -}, { - defaults = { - lazy = true, - }, - install = { - colorscheme = { "nvchad", "habamax" }, - }, - performance = { - rtp = { - disabled_plugins = { - "gzip", - "netrwPlugin", - "tarPlugin", - "tohtml", - "zipPlugin", - "tutor", - }, - }, - }, - change_detection = { - notify = false, - }, -}) +}, require("configs.lazy")) diff --git a/lua/plugins/specs/coding.lua b/lua/plugins/specs/coding.lua index 08290882..dc99f995 100644 --- a/lua/plugins/specs/coding.lua +++ b/lua/plugins/specs/coding.lua @@ -42,7 +42,14 @@ return { end, }, sources = cmp.config.sources({ - { name = "nvim_lsp" }, + { + name = "nvim_lsp", + option = { + markdown_oxide = { + keyword_pattern = [[\(\k\| \|\/\|#\)\+]], + }, + }, + }, { name = "luasnip" }, { name = "path" }, { name = "crates" }, @@ -85,12 +92,20 @@ return { end end, { "i", "s" }), [""] = cmp.mapping.confirm({ select = true }), + [""] = cmp.mapping.confirm({ select = false }), }), formatting = { fields = { "kind", "abbr", "menu" }, - format = function(_, vim_item) - local item = vim_item.kind - vim_item.kind = dots.UI.icons.LSP.kind[item] + format = function(entry, vim_item) + local kind = require("lspkind").cmp_format({ + mode = "symbol_text", + maxwidth = 50, + ellipsis_char = "...", + })(entry, vim_item) + -- vim_item.kind = dots.UI.icons.LSP.kind[item] + local strings = vim.split(kind.kind, "%s", { trimempty = true }) + kind.kind = (strings[1] or "") + kind.concat = kind.abbr return vim_item end, @@ -112,6 +127,7 @@ return { "hrsh7th/cmp-path", "L3MON4D3/LuaSnip", "saadparwaiz1/cmp_luasnip", + "onsails/lspkind.nvim", }, event = "InsertEnter", cmd = "CmpStatus", @@ -135,7 +151,7 @@ return { }) end, dependencies = { - "hrsh7th/nvim-cmp", + "nvim-cmp", "hrsh7th/cmp-path", "hrsh7th/cmp-buffer", }, diff --git a/lua/plugins/specs/editor.lua b/lua/plugins/specs/editor.lua index 3dd6ea0b..f4a98216 100644 --- a/lua/plugins/specs/editor.lua +++ b/lua/plugins/specs/editor.lua @@ -1,24 +1,86 @@ +local function patch() + local parsers = require("nvim-treesitter.parsers") + parsers.get_parser_configs = setmetatable({}, { + __call = function() + return parsers + end, + }) +end + return { { "nvim-treesitter/nvim-treesitter", - opts = { - ensure_installed = { "c", "lua", "vim", "vimdoc", "query" }, - auto_install = true, - highlight = { - enable = true, - }, - indent = { - enable = true, - }, - }, + version = false, -- last release is way too old and doesn't work on Windows + branch = "main", + build = ":TSUpdate", + cmd = {}, + opts = function() + patch() + return { + ensure_installed = { + "c", + "lua", + "vim", + "vimdoc", + "query", + "gitcommit", + "gitignore", + "git_config", + "git_rebase", + "git_attributes", + "nix", + "css", + "ninja", + "rst", + "python", + "nix", + }, + highlight = { enable = true, use_languagetree = true }, + -- indent = { enable = true }, + } + end, config = function(_, opts) dofile(vim.g.base46_cache .. "syntax") dofile(vim.g.base46_cache .. "treesitter") - require("nvim-treesitter.configs").setup(opts) + local function norm(ensure) + return ensure == nil and {} or type(ensure) == "string" and { ensure } or ensure + end + + ---@generic T + ---@param list T[] + ---@return T[] + local function dedup(list) + local ret = {} + local seen = {} + for _, v in ipairs(list) do + if not seen[v] then + table.insert(ret, v) + seen[v] = true + end + end + return ret + end + + opts.ensure_install = dedup(vim.list_extend(norm(opts.ensure_install), norm(opts.ensure_installed))) + require("nvim-treesitter").setup(opts) + patch() + + -- backwards compatibility with the old treesitter config for indent + if vim.tbl_get(opts, "indent", "enable") then + vim.bo.indentexpr = "v:lua.require'nvim-treesitter'.indentexpr()" + end + + -- backwards compatibility with the old treesitter config for highlight + if vim.tbl_get(opts, "highlight", "enable") then + vim.api.nvim_create_autocmd("FileType", { + callback = function() + pcall(vim.treesitter.start) + end, + }) + end end, - priority = 1000, - event = { "BufReadPost", "User FilePost" }, + event = { "BufReadPost", "BufNewFile" }, }, { "folke/flash.nvim", @@ -54,46 +116,9 @@ return { "?", }, }, - { - "numToStr/Comment.nvim", - opts = function() - return { - pre_hook = require("ts_context_commentstring.integrations.comment_nvim").create_pre_hook(), - } - end, - keys = { - { "gc", mode = { "x", "n" } }, - { "gb", mode = { "x", "n" } }, - }, - dependencies = { - { - "JoosepAlviste/nvim-ts-context-commentstring", - opts = { - context_commentstring = { - enable = true, - }, - }, - dependencies = { - "nvim-treesitter/nvim-treesitter", - }, - }, - }, - }, { "echasnovski/mini.diff", - event = "User FilePost", - -- opts = { - -- signs = dots.UI.icons.Gitsigns, - -- on_attach = function() - -- local gs = require("gitsigns") - -- - -- local map = vim.keymap.set - -- - -- -- stylua: ignore start - -- map("n", "]h", gs.next_hunk, { desc = "Next Hunk" }) - -- map("n", "[h", gs.prev_hunk, { desc= "Prev Hunk" }) - -- end, - -- }, + event = "User LazyFile", opts = { view = { style = "sign", @@ -106,46 +131,24 @@ return { end, }, { - "Wansmer/treesj", + "lewis6991/gitsigns.nvim", opts = { - use_default_keymaps = false, - max_join_length = 1000, - }, - keys = { - { "gS", "lua require('treesj').toggle()", desc = "TreeSJ - toggle" }, + signcolumn = false, + current_line_blame = true, }, + event = "VeryLazy", + }, + { + "echasnovski/mini-git", + opts = true, + name = "mini.git", + event = "User LazyFile", + }, + { + "echasnovski/mini.splitjoin", + opts = true, + keys = { "gS" }, }, - -- { - -- "kylechui/nvim-surround", - -- opts = { - -- keymaps = { - -- insert = "m", - -- insert_line = "M", - -- normal = "ms", - -- normal_cur = "mss", - -- normal_line = "mS", - -- normal_cur_line = "mSS", - -- visual = "M", - -- visual_line = "gM", - -- delete = "md", - -- change = "mc", - -- change_line = "mS", - -- }, - -- }, - -- keys = { - -- { "m", mode = "i" }, - -- { "M", mode = "i" }, - -- "ms", - -- "mss", - -- "mS", - -- "mSS", - -- { "M", mode = "x" }, - -- { "gM", mode = "x" }, - -- "md", - -- "mc", - -- "mS", - -- }, - -- }, { "echasnovski/mini.surround", opts = { @@ -178,24 +181,163 @@ return { "echasnovski/mini.ai", opts = function() local ai = require("mini.ai") + + local gen_ai_spec = require("mini.extra").gen_ai_spec return { n_lines = 500, custom_textobjects = { - f = ai.gen_spec.treesitter({ a = "@function.outer", i = "@function.inner" }, {}), + F = ai.gen_spec.treesitter({ a = "@function.outer", i = "@function.inner" }, {}), + -- i = gen_ai_spec.indent(), }, } end, dependencies = { - "nvim-treesitter/nvim-treesitter-textobjects", - init = function() - require("lazy.core.loader").disable_rtp_plugin("nvim-treesitter-textobjects") - end, + { + "nvim-treesitter/nvim-treesitter-textobjects", + branch = "main", + dependencies = { + { "echasnovski/mini.extra", opts = true }, + }, + }, }, keys = { { "i", mode = { "x", "o" } }, { "a", mode = { "x", "o" } }, }, }, + { + "chrisgrieser/nvim-various-textobjs", + keys = { + { + "gG", + function() + require("various-textobjs").entireBuffer() + end, + mode = { "x", "o" }, + }, + { + "ii", + function() + if vim.fn.indent(".") == 0 then + require("various-textobjs").entireBuffer() + else + require("various-textobjs").indentation("inner", "inner") + end + end, + mode = { "x", "o" }, + desc = "in an indent block", + }, + { + "ai", + function() + require("various-textobjs").indentation("outer", "inner") + end, + mode = { "x", "o" }, + desc = "around an indent block", + }, + { + "iI", + function() + require("various-textobjs").indentation("inner", "inner") + end, + mode = { "x", "o" }, + desc = "in an indent block", + }, + { + "aI", + function() + require("various-textobjs").indentation("outer", "outer") + end, + mode = { "x", "o" }, + desc = "around an indent block", + }, + { + "n", + function() + require("various-textobjs").nearEoL() + end, + mode = { "x", "o" }, + desc = "to the eol, excluding the last char", + }, + { + "gn", + function() + require("various-textobjs").diagnostic() + end, + mode = { "x", "o" }, + desc = "next diagnostics", + }, + { -- delete surrounding indentation + "dsi", + function() + -- select outer indentation + require("various-textobjs").indentation("outer", "outer") + + -- plugin only switches to visual mode when a textobj has been found + local indentationFound = vim.fn.mode():find("V") + if not indentationFound then + return + end + + -- dedent indentation + vim.cmd.normal({ "<", bang = true }) + + -- delete surrounding lines + local endBorderLn = vim.api.nvim_buf_get_mark(0, ">")[1] + local startBorderLn = vim.api.nvim_buf_get_mark(0, "<")[1] + vim.cmd(tostring(endBorderLn) .. " delete") -- delete end first so line index is not shifted + vim.cmd(tostring(startBorderLn) .. " delete") + end, + desc = "delete surrounding indent", + }, + { -- yank surrounding inner indentation + "ysii", -- `ysi` would conflict with `ysib` and other textobs + function() + local startPos = vim.api.nvim_win_get_cursor(0) + + -- identify start- and end-border + require("various-textobjs").indentation("outer", "outer") + local indentationFound = vim.fn.mode():find("V") + if not indentationFound then + return + end + vim.cmd.normal({ "V", bang = true }) -- leave visual mode so the `'<` `'>` marks are set + + -- copy them into the + register + local startLn = vim.api.nvim_buf_get_mark(0, "<")[1] - 1 + local endLn = vim.api.nvim_buf_get_mark(0, ">")[1] - 1 + local startLine = vim.api.nvim_buf_get_lines(0, startLn, startLn + 1, false)[1] + local endLine = vim.api.nvim_buf_get_lines(0, endLn, endLn + 1, false)[1] + vim.fn.setreg("+", startLine .. "\n" .. endLine .. "\n") + + -- highlight yanked text + local ns = vim.api.nvim_create_namespace("ysi") + vim.highlight.range(0, ns, "IncSearch", { startLn, 0 }, { startLn, -1 }) + vim.highlight.range(0, ns, "IncSearch", { endLn, 0 }, { endLn, -1 }) + vim.defer_fn(function() + vim.api.nvim_buf_clear_namespace(0, ns, 0, -1) + end, 1000) + + -- restore cursor position + vim.api.nvim_win_set_cursor(0, startPos) + end, + desc = "pank surrounding indent", + }, + { + "rp", + "lua require('various-textobjs').restOfParagraph()", + mode = { "o", "x" }, + desc = "rest of paragraph", + }, + { + "ri", + "lua require('various-textobjs').restOfIndentation()", + mode = { "o", "x" }, + desc = "rest of indentation", + }, + { "rg", "G", mode = { "o", "x" }, desc = "rest of buffer" }, + }, + }, { "echasnovski/mini.operators", opts = true, @@ -238,17 +380,30 @@ return { }, }, { - "gbprod/cutlass.nvim", - opts = { - exclude = { "ns", "nS", "or", "oR", "xR" }, - }, + "echasnovski/mini.move", + opts = true, keys = { - { "c", mode = { "n", "x", "o" } }, - { "C", mode = { "n", "x", "o" } }, - { "d", mode = { "n", "x", "o" } }, - { "D", mode = { "n", "x", "o" } }, - "x", - "X", + { + "", + mode = { "n", "x" }, + }, + { + "", + mode = { "n", "x" }, + }, + { + "", + mode = { "n", "x" }, + }, + { + "", + mode = { "n", "x" }, + }, }, }, + { + "folke/ts-comments.nvim", + opts = {}, + event = "VeryLazy", + }, } diff --git a/lua/plugins/specs/goodies/telescope/diagnostics.lua b/lua/plugins/specs/goodies/telescope/diagnostics.lua deleted file mode 100644 index 5b2e08e2..00000000 --- a/lua/plugins/specs/goodies/telescope/diagnostics.lua +++ /dev/null @@ -1,17 +0,0 @@ -return { - { - "nvim-telescope/telescope.nvim", - optional = true, - opts = { - pickers = { - diagnostics = { - theme = "ivy", - initial_mode = "normal", - layout_config = { - preview_cutoff = 9999, - }, - }, - }, - }, - }, -} diff --git a/lua/plugins/specs/languages/c.lua b/lua/plugins/specs/languages/c.lua deleted file mode 100644 index 8673fc7f..00000000 --- a/lua/plugins/specs/languages/c.lua +++ /dev/null @@ -1,10 +0,0 @@ -return { - { - "stevearc/conform.nvim", - opts = { - formatters_by_ft = { - c = { "clang_format" }, - }, - }, - }, -} diff --git a/lua/plugins/specs/languages/css.lua b/lua/plugins/specs/languages/css.lua deleted file mode 100644 index f925cddf..00000000 --- a/lua/plugins/specs/languages/css.lua +++ /dev/null @@ -1,10 +0,0 @@ -return { - { - "stevearc/conform.nvim", - opts = { - formatters_by_ft = { - css = { { "prettierd", "prettier" } }, - }, - }, - }, -} diff --git a/lua/plugins/specs/languages/fish.lua b/lua/plugins/specs/languages/fish.lua deleted file mode 100644 index 5b4f0288..00000000 --- a/lua/plugins/specs/languages/fish.lua +++ /dev/null @@ -1,10 +0,0 @@ -return { - { - "stevearc/conform.nvim", - opts = { - formatters_by_ft = { - fish = { "fish_indent" }, - }, - }, - }, -} diff --git a/lua/plugins/specs/languages/javascript.lua b/lua/plugins/specs/languages/javascript.lua deleted file mode 100644 index 28a4604c..00000000 --- a/lua/plugins/specs/languages/javascript.lua +++ /dev/null @@ -1,10 +0,0 @@ -return { - { - "conform.nvim", - opts = { - formatters_by_ft = { - javascript = { "prettierd" }, - }, - }, - }, -} diff --git a/lua/plugins/specs/languages/lua.lua b/lua/plugins/specs/languages/lua.lua index b9f7077a..e1320666 100644 --- a/lua/plugins/specs/languages/lua.lua +++ b/lua/plugins/specs/languages/lua.lua @@ -1,10 +1,43 @@ return { { - "stevearc/conform.nvim", + "folke/lazydev.nvim", + init = function() + vim.api.nvim_create_autocmd("User", { + group = vim.api.nvim_create_augroup("LoadLazyFile", { clear = true }), + pattern = "LazyFile", + callback = function() + local function load_lazydev() + if not require("lazy.core.config").plugins["lazydev.nvim"]._.loaded then + require("lazy").load({ plugins = "lazydev.nvim" }) + end + end + vim.api.nvim_create_autocmd("FileType", { + pattern = { "*.lua" }, + callback = load_lazydev, + }) + if vim.bo.filetype == "lua" then + load_lazydev() + end + end, + }) + end, opts = { - formatters_by_ft = { - lua = { "stylua" }, + library = { + "ui/nvchad_types", + { path = "luvit-meta/library", words = { "vim%.uv" } }, + "lazy.nvim", }, }, }, + { "Bilal2453/luvit-meta", lazy = true }, -- optional `vim.uv` typings + { -- optional completion source for require statements and module annotations + "nvim-cmp", + opts = function(_, opts) + opts.sources = opts.sources or {} + table.insert(opts.sources, { + name = "lazydev", + group_index = 0, -- set group index to 0 to skip loading LuaLS completions + }) + end, + }, } diff --git a/lua/plugins/specs/languages/markdown.lua b/lua/plugins/specs/languages/markdown.lua deleted file mode 100644 index 716dddc0..00000000 --- a/lua/plugins/specs/languages/markdown.lua +++ /dev/null @@ -1,10 +0,0 @@ -return { - { - "stevearc/conform.nvim", - opts = { - formatters_by_ft = { - markdown = { { "prettierd", "prettier" } }, - }, - }, - }, -} diff --git a/lua/plugins/specs/languages/nix.lua b/lua/plugins/specs/languages/nix.lua deleted file mode 100644 index 7e8bd3c7..00000000 --- a/lua/plugins/specs/languages/nix.lua +++ /dev/null @@ -1,29 +0,0 @@ -return { - -- { - -- "neovim/nvim-lspconfig", - -- optional = true, - -- opts = { - -- servers = { - -- ["nil_ls"] = { - -- ["nil"] = {}, - -- }, - -- }, - -- }, - -- }, - { - "nvim-treesitter/nvim-treesitter", - opts = function(_, opts) - table.insert(opts.ensure_installed, { - "nix", - }) - end, - }, - { - "stevearc/conform.nvim", - opts = { - formatters_by_ft = { - nix = { "alejandra" }, - }, - }, - }, -} diff --git a/lua/plugins/specs/languages/rust.lua b/lua/plugins/specs/languages/rust.lua deleted file mode 100644 index cb4d707c..00000000 --- a/lua/plugins/specs/languages/rust.lua +++ /dev/null @@ -1,17 +0,0 @@ -return { - { - "Saecki/crates.nvim", - event = { "BufRead Cargo.toml" }, - dependencies = { "nvim-lua/plenary.nvim" }, - opts = true, - }, - { - "stevearc/conform.nvim", - optional = true, - opts = { - formatters_by_ft = { - rust = { "rustfmt" }, - }, - }, - }, -} diff --git a/lua/plugins/specs/languages/svelte.lua b/lua/plugins/specs/languages/svelte.lua deleted file mode 100644 index a81dd220..00000000 --- a/lua/plugins/specs/languages/svelte.lua +++ /dev/null @@ -1,25 +0,0 @@ -return { - { - "nvim-treesitter", - optional = true, - opts = function(_, opts) - table.insert(opts.ensure_installed, { - "svelte", - "html", - "css", - "scss", - "javascript", - "typescript", - "rust", - }) - end, - }, - { - "stevearc/conform.nvim", - opts = { - formatters_by_ft = { - svelte = { { "prettierd", "prettier" } }, - }, - }, - }, -} diff --git a/lua/plugins/specs/lsp.lua b/lua/plugins/specs/lsp.lua index b667de95..0be128b6 100644 --- a/lua/plugins/specs/lsp.lua +++ b/lua/plugins/specs/lsp.lua @@ -1,126 +1,19 @@ return { { "neovim/nvim-lspconfig", - event = "User FilePost", - config = function(_, opts) + event = "User LazyFile", + config = function() dofile(vim.g.base46_cache .. "lsp") - local inlay_hint = vim.lsp.buf.inlay_hint or vim.lsp.inlay_hint - - if inlay_hint then - vim.api.nvim_create_autocmd("LspAttach", { - callback = function(args) - local client = vim.lsp.get_client_by_id(args.data.client_id) - if client and client.server_capabilities.inlayHintProvider then - inlay_hint.enable(true) - end - end, - }) - end - - local capabilities = vim.lsp.protocol.make_client_capabilities() - - capabilities.textDocument.completion.completionItem = { - documentationFormat = { "markdown", "plaintext" }, - snippetSupport = true, - preselectSupport = true, - insertReplaceSupport = true, - labelDetailsSupport = true, - deprecatedSupport = true, - commitCharactersSupport = true, - tagSupport = { valueSet = { 1 } }, - resolveSupport = { - properties = { - "documentation", - "detail", - "additionalTextEdits", - }, - }, - } - - require("lspconfig")["rust_analyzer"].setup({ - capabilities = capabilities, - settings = { - ["rust-analyzer"] = { - cargo = { - allFeatures = true, - loadOutDirsFromCheck = true, - runBuildScripts = true, - }, - check = { - command = "clippy", - allFeatures = true, - extraArgs = { - "--", - "-W clippy::pedantic", - "-W clippy::nursery", - "-W clippy::unwrap_used", - "-W clippy::expect_used", - }, - }, - procMacro = { - enable = true, - ignored = { - ["async-trait"] = { "async_trait" }, - ["napi-derive"] = { "napi" }, - ["async-recursion"] = { "async_recursion" }, - }, - }, - }, - }, - }) - - require("lspconfig")["nil_ls"].setup({ capabilities = capabilities }) - require("lspconfig")["lua_ls"].setup({ - capabilities = capabilities, - settings = { - Lua = { - hint = { - enable = true, - arrayIndex = "Disable", - }, - runtime = { - pathStrict = true, - }, - completion = { - callSnippet = "Both", - }, - diagnostics = { - globals = { - "vim", - }, - }, - workspace = { - library = { - [vim.fn.expand("$VIMRUNTIME/lua")] = true, - [vim.fn.expand("$VIMRUNTIME/lua/vim/lsp")] = true, - }, - maxPreload = 100000, - preloadFileSize = 10000, - checkThirdParty = false, - }, - }, - }, - }) - - require("lspconfig")["clangd"].setup({ capabilities = capabilities }) - require("lspconfig")["svelte"].setup({ capabilities = capabilities }) - require("lspconfig")["emmet_ls"].setup({ capabilities = capabilities }) - require("lspconfig")["tailwindcss"].setup({ capabilities = capabilities }) - require("lspconfig")["taplo"].setup({ capabilities = capabilities }) - require("lspconfig")["cssls"].setup({ - capabilities = capabilities, - cmd = { "css-languageserver", "--stdio" }, - }) - require("lspconfig")["marksman"].setup({ capabilities = capabilities }) - require("lspconfig")["hls"].setup({ capabilities = capabilities }) + require("configs.lspconfig") + require("nvchad.lsp") end, }, { "stevearc/conform.nvim", event = { "BufWritePre" }, - opts = { - format_on_save = { timeout_ms = 500, lsp_fallback = true }, - }, + opts = function() + return require("configs.conform") + end, init = function() vim.opt.formatexpr = "v:lua.require'conform'.formatexpr()" end, @@ -141,28 +34,4 @@ return { end, event = "LspAttach", }, - { - "aznhe21/actions-preview.nvim", - opts = function() - return { - diff = { - algorithm = "histogram", - }, - telescope = require("telescope.themes").get_cursor(), - } - end, - keys = { - { "ca", 'lua require("actions-preview").code_actions()', desc = "Code action: open menu" }, - }, - }, - { - "kosayoda/nvim-lightbulb", - opts = { - priority = 40, - autocmd = { - enabled = true, - }, - }, - event = "LspAttach", - }, } diff --git a/lua/plugins/specs/tools.lua b/lua/plugins/specs/tools.lua index edf8462e..3c74245d 100644 --- a/lua/plugins/specs/tools.lua +++ b/lua/plugins/specs/tools.lua @@ -52,7 +52,12 @@ return { "danielfalk/smart-open.nvim", dependencies = { "kkharji/sqlite.lua", - "nvim-telescope/telescope-fzy-native.nvim", + { + "nvim-telescope/telescope-fzy-native.nvim", + config = function() + require("telescope").load_extension("fzy_native") + end, + }, }, config = function() require("telescope").load_extension("smart_open") @@ -65,6 +70,7 @@ return { "lua require('telescope').extensions.smart_open.smart_open({ cwd_only = true, filename_first = false })", desc = "telescope: find_files", }, + { "fb", "Telescope buffers", desc = "telescope: buffers" }, { "fg", "Telescope live_grep", desc = "telescope: live_grep" }, { "f;", "Telescope resume", desc = "telescope: resume" }, { "fx", "Telescope diagnostics", desc = "telescope: diagnostics" }, @@ -135,36 +141,15 @@ return { end, }, { - "cbochs/grapple.nvim", - opts = { - win_opts = { - border = "solid", - }, - }, + "echasnovski/mini.visits", + opts = true, keys = { { - "ga", - "Grapple toggle", - desc = "Grapple: Toggle", - }, - { - "gt", - "Grapple open_tags", - desc = "Grapple: Open Tags", - }, - { - "gs", - "Grapple open_scopes", - desc = "Grapple: Open scopes", - }, - { - "gl", - "Grapple open_loaded", - desc = "Grapple: Open loaded", + "pp", + function() + require("mini.visits").select_path() + end, }, }, - cmd = { - "Grapple", - }, }, } diff --git a/lua/plugins/specs/ui.lua b/lua/plugins/specs/ui.lua index 815d8ff9..5b372b08 100644 --- a/lua/plugins/specs/ui.lua +++ b/lua/plugins/specs/ui.lua @@ -17,7 +17,7 @@ return { }, { "lukas-reineke/indent-blankline.nvim", - event = "User FilePost", + event = "User LazyFile", opts = { indent = { highlight = "IblChar" }, scope = { highlight = "IblScopeChar" }, @@ -32,16 +32,6 @@ return { dofile(vim.g.base46_cache .. "blankline") end, }, - { - "echasnovski/mini.indentscope", - opts = { - symbol = "", - }, - keys = { - { "ai", mode = { "x", "o" } }, - { "ii", mode = { "x", "o" } }, - }, - }, { "nvim-tree/nvim-web-devicons", opts = function() @@ -52,57 +42,6 @@ return { require("nvim-web-devicons").setup(opts) end, }, - { - "rcarriga/nvim-notify", - opts = function() - return require("plugins.configs.ui.notify") - end, - config = function() - vim.notify = require("notify") - end, - init = function() - vim.notify = function(...) - if not require("lazy.core.config").plugins["nvim-notify"]._.loaded then - require("lazy").load({ plugins = "nvim-notify" }) - end - require("notify")(...) - end - end, - }, - { - "folke/noice.nvim", - opts = { - lsp = { - override = { - ["vim.lsp.util.convert_input_to_markdown_lines"] = true, - ["vim.lsp.util.stylize_markdown"] = true, - ["cmp.entry.get_documentation"] = true, - }, - }, - presets = { - bottom_search = true, - command_palette = true, - long_message_to_split = true, - inc_rename = false, - lsp_doc_border = false, - }, - cmdline = { - view = "cmdline", - }, - views = { - mini = { - win_options = { - winblend = 0, - }, - }, - }, - }, - event = "VeryLazy", - dependencies = { - "MunifTanjim/nui.nvim", - "rcarriga/nvim-notify", - }, - }, -- CREDITS TO: https://www.lazyvim.org/plugins/ui#dressingnvim { "stevearc/dressing.nvim", @@ -119,4 +58,49 @@ return { end end, }, + { + "echasnovski/mini.hipatterns", + event = "User LazyFile", + opts = function() + return require("configs.hipatterns") + end, + config = function(_, opts) + require("mini.hipatterns").setup(opts) + + vim.defer_fn(function() + require("mini.hipatterns").enable() + end, 0) + end, + }, + { + "folke/noice.nvim", + event = "VeryLazy", + config = function() + require("noice").setup({ + lsp = { + hover = { + enabled = false, + }, + override = { + ["vim.lsp.util.convert_input_to_markdown_lines"] = true, + ["vim.lsp.util.stylize_markdown"] = true, + ["cmp.entry.get_documentation"] = true, + }, + signature = { enabled = false }, + }, + notify = { view = "mini" }, + cmdline = { view = "cmdline" }, + presets = { + bottom_search = true, -- use a classic bottom cmdline for search + command_palette = false, -- position the cmdline and popupmenu together + long_message_to_split = true, -- long messages will be sent to a split + inc_rename = false, -- enables an input dialog for inc-rename.nvim + lsp_doc_border = false, -- add a border to hover docs and signature help + }, + }) + end, + dependencies = { + "MunifTanjim/nui.nvim", + }, + }, } diff --git a/lua/settings/autocmd.lua b/lua/settings/autocmd.lua index 916d8591..8c5a362f 100644 --- a/lua/settings/autocmd.lua +++ b/lua/settings/autocmd.lua @@ -38,33 +38,6 @@ autocmd({ "BufWritePre" }, { end, }) --- thx to nvchad --- user event that loads after UIEnter + only if file buf is there -vim.api.nvim_create_autocmd({ "UIEnter", "BufReadPost", "BufNewFile" }, { - group = vim.api.nvim_create_augroup("DotsFilePost", { clear = true }), - callback = function(args) - local file = vim.api.nvim_buf_get_name(args.buf) - local buftype = vim.api.nvim_get_option_value("buftype", { buf = args.buf }) - - if not vim.g.ui_entered and args.event == "UIEnter" then - vim.g.ui_entered = true - end - - if file ~= "" and buftype ~= "nofile" and vim.g.ui_entered then - vim.api.nvim_exec_autocmds("User", { pattern = "FilePost", modeline = false }) - vim.api.nvim_del_augroup_by_name("DotsFilePost") - - vim.schedule(function() - vim.api.nvim_exec_autocmds("FileType", {}) - - if vim.g.editorconfig then - require("editorconfig").config(args.buf) - end - end) - end - end, -}) - -- reload some chadrc options on-save autocmd("BufWritePost", { pattern = vim.tbl_map(function(path) @@ -79,24 +52,38 @@ autocmd("BufWritePost", { require("plenary.reload").reload_module("nvconfig") require("plenary.reload").reload_module("base46") + require("plenary.reload").reload_module("nvchad") require("plenary.reload").reload_module(module) - local config = require("nvconfig") + require("nvchad") - -- statusline - if config.ui.statusline.theme ~= "custom" then - require("plenary.reload").reload_module("nvchad.stl.utils") - require("plenary.reload").reload_module("nvchad.stl." .. config.ui.statusline.theme) - vim.opt.statusline = "%!v:lua.require('nvchad.stl." .. config.ui.statusline.theme .. "')()" - end + require("base46").load_all_highlights() + -- vim.cmd("redraw!") + end, +}) - -- tabufline - if config.ui.tabufline.enabled then - require("plenary.reload").reload_module("nvchad.tabufline.modules") - vim.opt.tabline = "%!v:lua.require('nvchad.tabufline.modules')()" +-- user event that loads after UIEnter + only if file buf is there +autocmd({ "UIEnter", "BufReadPost", "BufNewFile" }, { + group = vim.api.nvim_create_augroup("NvLazyFile", { clear = true }), + callback = function(args) + local file = vim.api.nvim_buf_get_name(args.buf) + local buftype = vim.api.nvim_get_option_value("buftype", { buf = args.buf }) + + if not vim.g.ui_entered and args.event == "UIEnter" then + vim.g.ui_entered = true end - require("base46").load_all_highlights() - -- vim.cmd("redraw!") + if file ~= "" and buftype ~= "nofile" and vim.g.ui_entered then + vim.api.nvim_exec_autocmds("User", { pattern = "LazyFile", modeline = false }) + vim.api.nvim_del_augroup_by_name("NvLazyFile") + + vim.schedule(function() + vim.api.nvim_exec_autocmds("FileType", {}) + + if vim.g.editorconfig then + require("editorconfig").config(args.buf) + end + end, 0) + end end, }) diff --git a/lua/settings/init.lua b/lua/settings/init.lua index 3bca923a..32bad009 100644 --- a/lua/settings/init.lua +++ b/lua/settings/init.lua @@ -49,9 +49,9 @@ M.UI = { unsaved_others = "○ ", }, Git = { - added = " ", - remove = " ", - changed = "󰣕 ", + added = " ", + changed = " ", + remove = " ", }, Gitsigns = { add = "▎", @@ -64,25 +64,7 @@ M.UI = { M.languages = { enable = { -- Use this to enable all language support. - -- { import = "plugins.specs.languages" }, - { import = "plugins.specs.languages.lua" }, - { import = "plugins.specs.languages.svelte" }, - { import = "plugins.specs.languages.rust" }, - { import = "plugins.specs.languages.markdown" }, - { import = "plugins.specs.languages.css" }, - { import = "plugins.specs.languages.nix" }, - { import = "plugins.specs.languages.javascript" }, - -- { import = "plugins.specs.languages.dot" }, - -- { import = "plugins.specs.languages.c" }, - -- { import = "plugins.specs.languages.fish" }, - -- { import = "plugins.specs.languages.haskell" }, - -- { import = "plugins.specs.languages.toml" }, - }, -} - -M.goodies = { - enable = { - { import = "plugins.specs.goodies.telescope.diagnostics" }, + { import = "plugins.specs.languages" }, }, } diff --git a/lua/settings/keymap.lua b/lua/settings/keymap.lua index cc0d507b..79578dae 100644 --- a/lua/settings/keymap.lua +++ b/lua/settings/keymap.lua @@ -30,15 +30,6 @@ map( { expr = true, replace_keycodes = false, desc = "Visually select changed text" } ) -map({ "x", "o" }, "gG", function() - vim.api.nvim_win_set_cursor(0, { 1, 0 }) - if not vim.fn.mode():find("V") ~= nil then - vim.cmd("normal! V") - end - vim.cmd("normal! o") - vim.api.nvim_win_set_cursor(0, { vim.fn.line("$"), 0 }) -end) - map("n", "[d", function() vim.diagnostic.goto_prev() end, { desc = "Prev diagnostic" }) @@ -64,11 +55,6 @@ map("n", "x", function() require("nvchad.tabufline").close_buffer() end, { desc = "Buffer Close" }) --- Comment -map("n", "/", function() - require("Comment.api").toggle.linewise.current() -end, { desc = "Comment Toggle" }) - for i = 1, 9, 1 do vim.keymap.set("n", string.format("", i), function() vim.api.nvim_set_current_buf(vim.t.bufs[i]) diff --git a/lua/settings/options.lua b/lua/settings/options.lua index 3c5c82de..bf9b4281 100644 --- a/lua/settings/options.lua +++ b/lua/settings/options.lua @@ -10,6 +10,7 @@ o.relativenumber = true -- Tabs o.shiftwidth = 2 o.tabstop = 2 +o.expandtab = true o.undofile = true o.undodir = vim.fn.stdpath("data") .. "/undo//" @@ -27,18 +28,27 @@ o.clipboard = "unnamedplus" o.signcolumn = "yes:1" -vim.g.mapleader = " " - -- Statusline o.cmdheight = 0 o.laststatus = 3 -- Folds -o.foldcolumn = "1" +o.fillchars = { + foldopen = "", + foldclose = "", + fold = " ", + foldsep = " ", + diff = "╱", + eob = " ", +} o.foldlevel = 99 -o.foldlevelstart = 99 -o.foldenable = true + +o.foldmethod = "expr" +o.foldexpr = "v:lua.require'utils.ui'.foldexpr()" +o.foldtext = "" +o.fillchars = "fold: " +o.statuscolumn = [[%!v:lua.require'utils.ui'.statuscolumn()]] -- Scrolloff @@ -48,7 +58,6 @@ o.scrolloff = 15 o.ignorecase = true o.smartcase = true -o.pumblend = 10 -- Popup blend o.pumheight = 10 -- Maximum number of entries in a popup -- Sessions diff --git a/lua/utils/intro.lua b/lua/utils/intro.lua deleted file mode 100644 index 5c7d5af0..00000000 --- a/lua/utils/intro.lua +++ /dev/null @@ -1,456 +0,0 @@ --- Credits 2 https://gist.github.com/GnikDroy/62556534324f9dc9192f7bba5a88cc43 - -if vim.fn.argc() ~= 0 or #vim.api.nvim_list_wins() ~= 1 then - return -end -vim.opt.shortmess:remove("I") -- Enable default startscreen -local WIDTH = vim.api.nvim_win_get_width(0) -local HEIGHT = vim.api.nvim_win_get_height(0) -if WIDTH < 120 or HEIGHT < 40 then - return -end -- Bail if screen space is at a premium - -vim.api.nvim_set_hl(0, "NvimGreen", { fg = 7054142, default = true }) -vim.api.nvim_set_hl(0, "NvimBlue", { fg = 3054811, default = true }) - -local function shuffle(tbl) - for i = #tbl, 2, -1 do - local j = math.random(i) - tbl[i], tbl[j] = tbl[j], tbl[i] - end - return tbl -end - -local function get_highlight_range(line, pattern) - local results = {} - local start = 1 - while start <= #line do - local s, e = string.find(line, pattern, start) - if e == nil then - return results - end - table.insert(results, { s, e }) - start = e + 1 - end - return results -end - ----@class EphemeralWidget ----@field opts EphemeralWidgetOpts ----@field win number? ----@field buf number? -local EphemeralWidget = {} -EphemeralWidget.__index = EphemeralWidget - ----@class EphemeralWidgetOpts ----@field label string ----@field win_opts table? ----@field lines string[] ----@field highlights table - --- Constructor ----@param opts EphemeralWidgetOpts ----@return EphemeralWidget ----@nodiscard -function EphemeralWidget.new(opts) - local widget = setmetatable({}, EphemeralWidget) - widget.opts = opts - return widget -end - -function EphemeralWidget:render() - local buf = vim.api.nvim_create_buf(false, true) - local win = vim.api.nvim_open_win(buf, false, self.opts.win_opts) - self.buf = buf - self.win = win - vim.wo[win].winhl = "Normal:NONE,EndOfBuffer:NONE" - vim.wo[win].foldenable = false - - vim.api.nvim_buf_set_lines(buf, 0, -1, true, self.opts.lines) - - local ns = vim.api.nvim_create_namespace(self.opts.label) - - for col, line in ipairs(self.opts.lines) do - for _, pattern_hl_pair in ipairs(self.opts.highlights) do - for _, range in ipairs(get_highlight_range(line, pattern_hl_pair[1])) do - vim.api.nvim_buf_add_highlight(buf, ns, pattern_hl_pair[2], col - 1, range[1] - 1, range[2]) - end - end - end - - local augroup = vim.api.nvim_create_augroup(self.opts.label, {}) - - local function cleanup() - if vim.api.nvim_win_is_valid(win) then - vim.api.nvim_win_close(win, true) - end - if vim.api.nvim_buf_is_valid(buf) then - vim.api.nvim_buf_clear_namespace(buf, ns, 0, -1) - vim.api.nvim_buf_delete(buf, { force = true }) - end - vim.on_key(nil, ns) - vim.api.nvim_clear_autocmds({ group = self.opts.label }) - vim.api.nvim_del_augroup_by_id(augroup) - end - - vim.on_key(cleanup, ns) - vim.api.nvim_create_autocmd("VimResized", { group = augroup, callback = cleanup }) -end - -local intro_fmt = [[ -NVIM v%s - -Nvim is open source and freely distributable -https://neovim.io/#chat - -type :help nvim if you are new! -type :checkhealth to optimize Nvim -type :q to exit -type :help for help - -type :help news to see changes in v%s - -Become a registered Vim user! -type :help register for information]] - -local ver = vim.version() - -local ver_str_min = string.format("%d.%d", ver.major, ver.minor) -local intro = vim.split(string.format(intro_fmt, tostring(ver), ver_str_min), "\n") - -local intro_win_width = vim.iter(intro):fold(0, function(acc, line) - return math.max(acc, #line) -end) -intro = vim - .iter(intro) - :map(function(line) - return string.rep(" ", math.ceil((intro_win_width - #line) / 2)) .. line - end) - :totable() -- Center all lines - -EphemeralWidget.new({ - label = "intro", - lines = intro, - win_opts = { - relative = "win", - zindex = 25, - focusable = false, - style = "minimal", - col = (WIDTH - intro_win_width) * 0.5, - row = (HEIGHT - #intro) * 0.5, - width = intro_win_width, - height = #intro, - }, - highlights = { - { "NVIM", "NvimGreen" }, - { "v[0-9]+[0-9.a-zA-z-+]+", "NvimGreen" }, - { "https://neovim.io/#chat", "Underlined" }, - { ":%a+", "NvimBlue" }, - { "<.*>", "NvimGreen" }, - { "if you are new!", "DiagnosticOk" }, - { "to exit", "DiagnosticError" }, - }, -}):render() - -local sysinfo_fmt = [[ -SYSTEM INFO -Hostname │ %s -OS │ %s %s -Memory │ %d Gib -Processor │ %s]] -local hostname = vim.uv.os_gethostname() -local os_ = vim.uv.os_uname() -local mem_gigs = vim.uv.get_total_memory() / 1024 / 1024 / 1024 -local cpu_info = vim.uv.cpu_info() - -local sysinfo = - vim.split(string.format(sysinfo_fmt, hostname, os_.machine, os_.sysname, mem_gigs, cpu_info[1].model), "\n") - -local sysinfo_win_width = vim.iter(sysinfo):fold(0, function(acc, line) - return math.max(acc, vim.api.nvim_strwidth(line)) -end) - -EphemeralWidget.new({ - label = "sysinfo", - lines = sysinfo, - win_opts = { - relative = "win", - zindex = 25, - focusable = false, - style = "minimal", - width = sysinfo_win_width, - height = #sysinfo, - anchor = "SW", - row = HEIGHT - 1, - col = 1, - }, - highlights = { - { "^.*$", "LineNr" }, - { "^SYSTEM INFO$", "NvimGreen" }, - { "^.*│", "NvimBlue" }, - }, -}):render() - -local function parse_keywords_in_section(lines) - local keywords = {} - for _, line in ipairs(lines) do - for w in string.gmatch(line, "|(%S+%(%))|") do - if #w > 40 then -- truncate long function names - w = w:sub(1, 40) .. ".." - end - keywords[#keywords + 1] = w - end - -- You can parse other stuff like option values enclosed in '' - -- I don't care enough to do this - end - return shuffle(keywords) -- Shuffle here to avoid same news sections -end - -local function parse_news() - local lines = {} - for line in io.lines(vim.env.VIMRUNTIME .. "/doc/news.txt") do - lines[#lines + 1] = line - end - - -- Don't want to write a parser for news - -- Perhaps I can do this with treesitter later? - local section_labels = { - "BREAKING CHANGES", - "NEW FEATURES", - "CHANGED FEATURES", - "REMOVED FEATURES", - "DEPRECATIONS", - } - local sections = {} - local current_section = nil - for _, line in ipairs(lines) do - if string.find(line, string.rep("=", 10)) ~= nil then - current_section = nil - end - if current_section ~= nil then - if sections[current_section] == nil then - sections[current_section] = {} - end - table.insert(sections[current_section], line) - end - for _, label in ipairs(section_labels) do - if string.find(line, label) ~= nil then - current_section = label - end - end - end - return sections -end - -local news_fmt = [[ -WHAT'S NEW IN v%s? - -New Features -%s - -Breaking changes -%s - -Deprecations -%s]] - -local keywords = {} -for section, lines in pairs(parse_news()) do - keywords[section] = vim.iter(parse_keywords_in_section(lines)):take(7):totable() -end - -local news = vim.split( - string.format( - news_fmt, - ver_str_min, - table.concat(keywords["NEW FEATURES"], "\n"), - table.concat(keywords["BREAKING CHANGES"], "\n"), - table.concat(keywords["DEPRECATIONS"], "\n") - ), - "\n" -) - -local news_win_width = vim.iter(news):fold(0, function(acc, line) - return math.max(acc, vim.api.nvim_strwidth(line)) -end) - -EphemeralWidget.new({ - label = "news", - lines = news, - win_opts = { - relative = "win", - zindex = 25, - focusable = false, - style = "minimal", - width = news_win_width, - height = HEIGHT - 7, - anchor = "NW", - row = 1, - col = 2, - }, - highlights = { - { "^.*$", "LineNr" }, - { "^WHAT'S NEW IN.*$", "NvimGreen" }, - { "^New Features$", "DiagnosticOk" }, - { "^Breaking changes$", "DiagnosticWarn" }, - { "^Deprecations$", "DiagnosticError" }, - }, -}):render() - -local keyboard_fmt = [[ - Keyboard ❤️ Neovim -╭───┬───┬───┬───┬───┬───┬───┬───┬───┬───╮ -│ Q │ W │ E │ R │ T │ Y │ U │ I │ O │ P │ -╰┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴╮ - │ A │ S │ D │ F │ G │ ← │ ↓ │ ↑ │ → │ ; │ - ╰┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──╯ - │ Z │ X │ C │  │ B │  │ M │ < │ > │ - ╰───┴───┴───┴───┴───┴───┴───╯───┴───╯]] - -local keyboard = vim.split(keyboard_fmt, "\n") - -local keyboard_win_width = vim.iter(keyboard):fold(0, function(acc, line) - return math.max(acc, vim.api.nvim_strwidth(line)) -end) - -local keyboard_widget = EphemeralWidget.new({ - label = "keyboard", - lines = keyboard, - win_opts = { - relative = "win", - style = "minimal", - zindex = 25, - focusable = false, - width = keyboard_win_width, - height = #keyboard, - anchor = "SE", - row = HEIGHT - 1, - col = WIDTH - 1, - }, - highlights = { - { "^.*$", "LineNr" }, - { "[A-Z;<>]", "NvimBlue" }, - { "", "NvimGreen" }, - { "", "NvimGreen" }, - { "←", "NvimGreen" }, - { "↑", "NvimGreen" }, - { "↓", "NvimGreen" }, - { "→", "NvimGreen" }, - { "Neo", "NvimGreen" }, - { "vim", "NvimBlue" }, - { "b", "NvimGreen" }, - }, -}) - -keyboard_widget:render() -vim.wo[keyboard_widget.win].winblend = 50 - -local tools_fmt = [[ -CLI & TOOLCHAINS - -C compiler │ %s - git │ %s - node │ %s - ripgrep │ %s - fd │ %s -]] - -local compiler_present = vim.iter({ "cc", "gcc", "clang", "cl", "zig" }):fold(false, function(acc, exe) - return vim.fn.executable(exe) == 1 or acc -end) -local tools = vim.split( - string.format( - tools_fmt, - compiler_present and "" or "󰅙", - vim.fn.executable("git") == 1 and "" or "󰅙", - vim.fn.executable("node") == 1 and "" or "󰅙", - vim.fn.executable("rg") == 1 and "" or "󰅙", - vim.fn.executable("fd") == 1 and "" or "󰅙" - ), - "\n" -) - -local tools_win_width = vim.iter(tools):fold(0, function(acc, line) - return math.max(acc, vim.api.nvim_strwidth(line)) -end) - -EphemeralWidget.new({ - label = "tools", - lines = tools, - win_opts = { - relative = "win", - style = "minimal", - zindex = 25, - focusable = false, - width = tools_win_width, - height = #tools, - anchor = "NE", - row = 2, - col = WIDTH - 1, - }, - highlights = { - { "^.*$", "LineNr" }, - { "CLI & TOOLCHAINS", "NvimBlue" }, - { "│ $", "DiagnosticOk" }, - { "│ 󰅙$", "DiagnosticError" }, - }, -}):render() - -local features_fmt = [[ - TREESITTER & PLUGINS - - Treesitter ABI │ %d - Scripts Loaded │ %d - - - - - VIM OPTIONS - - mapleader │ [%s] - vim.opt.backup │ %s -vim.opt.swapfile │ %s -vim.opt.autoread │ %s -]] - -local features = vim.split( - string.format( - features_fmt, - vim.treesitter.language_version, - #vim.fn.getscriptinfo(), - vim.g.mapleader, -- keytrans looks ugly - vim.o.backup and "" or "󰅙", - vim.o.swapfile and "" or "󰅙", - vim.o.autoread and "" or "󰅙" - ), - "\n" -) - -local features_win_width = vim.iter(features):fold(0, function(acc, line) - return math.max(acc, vim.api.nvim_strwidth(line)) -end) - -EphemeralWidget.new({ - label = "features", - lines = features, - win_opts = { - relative = "win", - style = "minimal", - zindex = 25, - focusable = false, - width = features_win_width, - height = #features, - anchor = "NE", - row = math.floor((HEIGHT - #features) / 2), - col = WIDTH - 1, - }, - highlights = { - { "^.*$", "LineNr" }, - { "│ %d+", "DiagnosticWarn" }, - { "│ %[.*$", "DiagnosticWarn" }, - { "│%s+$", "DiagnosticOk" }, - { "│%s+󰅙$", "DiagnosticError" }, - { "TREESITTER & PLUGINS", "NvimBlue" }, - { "VIM OPTIONS", "NvimBlue" }, - }, -}):render() diff --git a/lua/utils/mini/git.lua b/lua/utils/mini/git.lua new file mode 100644 index 00000000..04ee369d --- /dev/null +++ b/lua/utils/mini/git.lua @@ -0,0 +1,68 @@ +local function is_valid_git_repo(buf_id) + -- Check if it's a valid buffer + local path = vim.api.nvim_buf_get_name(buf_id) + if path == "" or vim.fn.filereadable(path) ~= 1 then + return false + end + + -- Check if the current directory is a Git repository + if vim.fn.isdirectory(".git") == 0 then + return false + end + + return true +end + +local branch_cache = {} + +-- Function to clear the Git branch cache +local function clear_git_branch_cache() + -- Clear by doing an empty table :) + branch_cache = {} +end + +-- Autocommand to clear the Git branch cache when the directory changes +vim.api.nvim_create_autocmd("DirChanged", { + callback = clear_git_branch_cache, +}) + +local function update_git_branch(data) + if not is_valid_git_repo(data.buf) then + return + end + + -- Check if branch is already cached + local cached_branch = branch_cache[data.buf] + if cached_branch then + vim.b.git_branch = cached_branch + return + end + + local stdout = vim.uv.new_pipe(false) + local handle, pid + handle, pid = vim.uv.spawn( + "git", + { + args = { "-C", vim.fn.expand("%:p:h"), "branch", "--show-current" }, + stdio = { nil, stdout, nil }, + }, + vim.schedule_wrap(function(code, signal) + if code == 0 then + stdout:read_start(function(err, content) + if content then + vim.b.git_branch = content:gsub("\n", "") -- Remove newline character + branch_cache[data.buf] = vim.b.git_branch -- Cache the branch name + stdout:close() + end + end) + else + stdout:close() + end + end) + ) +end + +-- Call this function when the buffer is opened in a window +vim.api.nvim_create_autocmd("BufWinEnter", { + callback = update_git_branch, +}) diff --git a/lua/utils/ui.lua b/lua/utils/ui.lua new file mode 100644 index 00000000..91339ca7 --- /dev/null +++ b/lua/utils/ui.lua @@ -0,0 +1,211 @@ +---@class lazyvim.util.ui +local M = {} + +---@alias Sign {name:string, text:string, texthl:string, priority:number} + +-- Returns a list of regular and extmark signs sorted by priority (low to high) +---@return Sign[] +---@param buf number +---@param lnum number +function M.get_signs(buf, lnum) + -- Get regular signs + ---@type Sign[] + local signs = {} + + if vim.fn.has("nvim-0.10") == 0 then + -- Only needed for Neovim <0.10 + -- Newer versions include legacy signs in nvim_buf_get_extmarks + for _, sign in ipairs(vim.fn.sign_getplaced(buf, { group = "*", lnum = lnum })[1].signs) do + local ret = vim.fn.sign_getdefined(sign.name)[1] --[[@as Sign]] + if ret then + ret.priority = sign.priority + signs[#signs + 1] = ret + end + end + end + + -- Get extmark signs + local extmarks = vim.api.nvim_buf_get_extmarks( + buf, + -1, + { lnum - 1, 0 }, + { lnum - 1, -1 }, + { details = true, type = "sign" } + ) + for _, extmark in pairs(extmarks) do + signs[#signs + 1] = { + name = extmark[4].sign_hl_group or "", + text = extmark[4].sign_text, + texthl = extmark[4].sign_hl_group, + priority = extmark[4].priority, + } + end + + -- Sort by priority + table.sort(signs, function(a, b) + return (a.priority or 0) < (b.priority or 0) + end) + + return signs +end + +---@return Sign? +---@param buf number +---@param lnum number +function M.get_mark(buf, lnum) + local marks = vim.fn.getmarklist(buf) + vim.list_extend(marks, vim.fn.getmarklist()) + for _, mark in ipairs(marks) do + if mark.pos[1] == buf and mark.pos[2] == lnum and mark.mark:match("[a-zA-Z]") then + return { text = mark.mark:sub(2), texthl = "DiagnosticHint" } + end + end +end + +---@param sign? Sign +---@param len? number +function M.icon(sign, len) + sign = sign or {} + len = len or 2 + local text = vim.fn.strcharpart(sign.text or "", 0, len) ---@type string + text = text .. string.rep(" ", len - vim.fn.strchars(text)) + return sign.texthl and ("%#" .. sign.texthl .. "#" .. text .. "%*") or text +end + +function M.foldtext() + local ok = pcall(vim.treesitter.get_parser, vim.api.nvim_get_current_buf()) + local ret = ok and vim.treesitter.foldtext and vim.treesitter.foldtext() + if not ret or type(ret) == "string" then + ret = { { vim.api.nvim_buf_get_lines(0, vim.v.lnum - 1, vim.v.lnum, false)[1], {} } } + end + table.insert(ret, { " " .. require("lazyvim.config").icons.misc.dots }) + + if not vim.treesitter.foldtext then + return table.concat( + vim.tbl_map(function(line) + return line[1] + end, ret), + " " + ) + end + return ret +end + +function M.statuscolumn() + local win = vim.g.statusline_winid + local buf = vim.api.nvim_win_get_buf(win) + local is_file = vim.bo[buf].buftype == "" + local show_signs = vim.wo[win].signcolumn ~= "no" + + local components = { "", "", "" } -- left, middle, right + + if show_signs then + ---@type Sign?,Sign?,Sign? + local left, right, fold + for _, s in ipairs(M.get_signs(buf, vim.v.lnum)) do + if s.name and (s.name:find("GitSign") or s.name:find("MiniDiffSign")) then + right = s + else + left = s + end + end + if vim.v.virtnum ~= 0 then + left = nil + end + vim.api.nvim_win_call(win, function() + if vim.fn.foldclosed(vim.v.lnum) >= 0 then + fold = { text = vim.opt.fillchars:get().foldclose or "", texthl = "Folded" } + end + end) + -- Left: mark or non-git sign + components[1] = M.icon(M.get_mark(buf, vim.v.lnum) or left) + -- Right: fold icon or git sign (only if file) + components[3] = is_file and M.icon(fold or right) or "" + end + + -- Numbers in Neovim are weird + -- They show when either number or relativenumber is true + local is_num = vim.wo[win].number + local is_relnum = vim.wo[win].relativenumber + if (is_num or is_relnum) and vim.v.virtnum == 0 then + if vim.v.relnum == 0 then + components[2] = is_num and "%l" or "%r" -- the current line + else + components[2] = is_relnum and "%r" or "%l" -- other lines + end + components[2] = "%=" .. components[2] .. " " -- right align + end + + if vim.v.virtnum ~= 0 then + components[2] = "%= " + end + + return table.concat(components, "") +end + +---@return {fg?:string}? +function M.fg(name) + local color = M.color(name) + return color and { fg = color } or nil +end + +---@param name string +---@param bg? boolean +---@return string? +function M.color(name, bg) + ---@type {foreground?:number}? + ---@diagnostic disable-next-line: deprecated + local hl = vim.api.nvim_get_hl and vim.api.nvim_get_hl(0, { name = name, link = false }) + or vim.api.nvim_get_hl_by_name(name, true) + ---@diagnostic disable-next-line: undefined-field + ---@type string? + local color = nil + if hl then + if bg then + color = hl.bg or hl.background + else + color = hl.fg or hl.foreground + end + end + return color and string.format("#%06x", color) or nil +end + +M.skip_foldexpr = {} ---@type table +local skip_check = assert(vim.uv.new_check()) + +function M.foldexpr() + local buf = vim.api.nvim_get_current_buf() + + -- still in the same tick and no parser + if M.skip_foldexpr[buf] then + return "0" + end + + -- don't use treesitter folds for non-file buffers + if vim.bo[buf].buftype ~= "" then + return "0" + end + + -- as long as we don't have a filetype, don't bother + -- checking if treesitter is available (it won't) + if vim.bo[buf].filetype == "" then + return "0" + end + + local ok = pcall(vim.treesitter.get_parser, buf) + + if ok then + return vim.treesitter.foldexpr() + end + + -- no parser available, so mark it as skip + -- in the next tick, all skip marks will be reset + M.skip_foldexpr[buf] = true + skip_check:start(function() + M.skip_foldexpr = {} + skip_check:stop() + end) + return "0" +end + +return M