]> git.rmz.io Git - dotfiles.git/commitdiff
Merge branch 'remove-lazyvim'
authorSamir Benmendil <me@rmz.io>
Sun, 2 Mar 2025 16:28:57 +0000 (16:28 +0000)
committerSamir Benmendil <me@rmz.io>
Sun, 2 Mar 2025 16:28:57 +0000 (16:28 +0000)
47 files changed:
nvim/init.lua
nvim/lua/config/autocmds.lua
nvim/lua/config/init.lua [new file with mode: 0644]
nvim/lua/config/keymaps.lua
nvim/lua/config/lazy.lua
nvim/lua/config/options.lua
nvim/lua/plugins/blink.lua [new file with mode: 0644]
nvim/lua/plugins/coding.lua
nvim/lua/plugins/colorscheme.lua
nvim/lua/plugins/core.lua
nvim/lua/plugins/dap.lua
nvim/lua/plugins/editor.lua
nvim/lua/plugins/formatter.lua [new file with mode: 0644]
nvim/lua/plugins/init.lua [new file with mode: 0644]
nvim/lua/plugins/lang/cmake.lua [new file with mode: 0644]
nvim/lua/plugins/lang/cpp.lua
nvim/lua/plugins/lang/docker.lua [new file with mode: 0644]
nvim/lua/plugins/lang/git.lua [new file with mode: 0644]
nvim/lua/plugins/lang/go.lua [new file with mode: 0644]
nvim/lua/plugins/lang/haskell.lua [new file with mode: 0644]
nvim/lua/plugins/lang/json.lua [new file with mode: 0644]
nvim/lua/plugins/lang/markdown.lua [new file with mode: 0644]
nvim/lua/plugins/lang/nix.lua [new file with mode: 0644]
nvim/lua/plugins/lang/nlua.lua [new file with mode: 0644]
nvim/lua/plugins/lang/python.lua
nvim/lua/plugins/lang/ruby.lua [new file with mode: 0644]
nvim/lua/plugins/lang/rust.lua [new file with mode: 0644]
nvim/lua/plugins/lang/tex.lua [new file with mode: 0644]
nvim/lua/plugins/lang/toml.lua [new file with mode: 0644]
nvim/lua/plugins/lang/yaml.lua [new file with mode: 0644]
nvim/lua/plugins/lint.lua [new file with mode: 0644]
nvim/lua/plugins/lsp.lua [deleted file]
nvim/lua/plugins/lsp/init.lua [new file with mode: 0644]
nvim/lua/plugins/lsp/keymaps.lua [new file with mode: 0644]
nvim/lua/plugins/nvim-treesitter.lua [deleted file]
nvim/lua/plugins/picker.lua [new file with mode: 0644]
nvim/lua/plugins/snacks.lua [new file with mode: 0644]
nvim/lua/plugins/test.lua
nvim/lua/plugins/treesitter.lua [new file with mode: 0644]
nvim/lua/plugins/ui.lua
nvim/lua/rmz/util/init.lua [new file with mode: 0644]
nvim/lua/rmz/util/lazy.lua [new file with mode: 0644]
nvim/lua/rmz/util/lsp.lua [new file with mode: 0644]
nvim/lua/rmz/util/ui.lua [new file with mode: 0644]
nvim/snippets/all.lua [moved from nvim/lua/snippets/all.lua with 100% similarity]
nvim/snippets/all.snippets [new file with mode: 0644]
vim/vimrc

index ffbd39547b2567c91210a152f29c0aa6f6526783..13a0be54886f00ab9ed7f318deb8431a6df7a5c2 100644 (file)
@@ -4,6 +4,6 @@ vim.cmd([[ source $XDG_CONFIG_HOME/vim/vimrc ]])
 -- TODO: review if I want this for some buffers
 vim.g.autoformat = false
 
--- bootstrap lazy.nvim, LazyVim and your plugins
-package.loaded["lazyvim.config.options"] = true
-require("config.lazy")
+_G.rmz = require("rmz.util")
+
+require("config")
index 2e26068707031595e744abedeaa0a4a7570afd50..596f65dc1a383ba15db756c18960374b203ad62e 100644 (file)
@@ -1,14 +1,52 @@
--- Autocmds are automatically loaded on the VeryLazy event
+-- Autocmds are automatically loaded by config.init
 
 local function augroup(name)
-  return vim.api.nvim_create_augroup("lazyvim_" .. name, { clear = true })
+  return vim.api.nvim_create_augroup("rmz_" .. name, { clear = true })
 end
 
+-- Check if we need to reload the file when it changed
+vim.api.nvim_create_autocmd({ "FocusGained", "TermClose", "TermLeave" }, {
+  group = augroup("checktime"),
+  callback = function()
+    if vim.o.buftype ~= "nofile" then
+      vim.cmd("checktime")
+    end
+  end,
+})
+
 -- Highlight on yank
 vim.api.nvim_create_autocmd("TextYankPost", {
   group = augroup("highlight_yank"),
   callback = function()
-    vim.highlight.on_yank()
+    (vim.hl or vim.highlight).on_yank()
+  end,
+})
+
+-- resize splits if window got resized
+vim.api.nvim_create_autocmd({ "VimResized" }, {
+  group = augroup("resize_splits"),
+  callback = function()
+    local current_tab = vim.fn.tabpagenr()
+    vim.cmd("tabdo wincmd =")
+    vim.cmd("tabnext " .. current_tab)
+  end,
+})
+
+-- go to last loc when opening a buffer
+vim.api.nvim_create_autocmd("BufReadPost", {
+  group = augroup("last_loc"),
+  callback = function(event)
+    local exclude = { "gitcommit" }
+    local buf = event.buf
+    if vim.tbl_contains(exclude, vim.bo[buf].filetype) or vim.b[buf].rmz_last_loc then
+      return
+    end
+    vim.b[buf].rmz_last_loc = true
+    local mark = vim.api.nvim_buf_get_mark(buf, '"')
+    local lcount = vim.api.nvim_buf_line_count(buf)
+    if mark[1] > 0 and mark[1] <= lcount then
+      pcall(vim.api.nvim_win_set_cursor, 0, mark)
+    end
   end,
 })
 
@@ -16,10 +54,11 @@ vim.api.nvim_create_autocmd("TextYankPost", {
 vim.api.nvim_create_autocmd("FileType", {
   group = augroup("close_with_q"),
   pattern = {
-    "PlenaryTestPopup",
+    "checkhealth",
+    "dbout",
+    "gitsigns-blame",
     "help",
     "lspinfo",
-    "man",
     "notify",
     "qf",
     "spectre_panel",
@@ -28,6 +67,33 @@ vim.api.nvim_create_autocmd("FileType", {
   },
   callback = function(event)
     vim.bo[event.buf].buflisted = false
-    vim.keymap.set("n", "q", "<cmd>close<cr>", { buffer = event.buf, silent = true })
+    vim.schedule(function()
+      vim.keymap.set("n", "q", function()
+        vim.cmd("close")
+        pcall(vim.api.nvim_buf_delete, event.buf, { force = true })
+      end, {
+        buffer = event.buf,
+        silent = true,
+        desc = "Quit buffer",
+      })
+    end)
+  end,
+})
+
+-- make it easier to close man-files when opened inline
+vim.api.nvim_create_autocmd("FileType", {
+  group = augroup("man_unlisted"),
+  pattern = { "man" },
+  callback = function(event)
+    vim.bo[event.buf].buflisted = false
+  end,
+})
+
+-- Fix conceallevel for json files
+vim.api.nvim_create_autocmd({ "FileType" }, {
+  group = augroup("json_conceal"),
+  pattern = { "json", "jsonc", "json5" },
+  callback = function()
+    vim.opt_local.conceallevel = 0
   end,
 })
diff --git a/nvim/lua/config/init.lua b/nvim/lua/config/init.lua
new file mode 100644 (file)
index 0000000..e9ad2fd
--- /dev/null
@@ -0,0 +1,12 @@
+require("config.lazy")
+require("config.options")
+require("config.autocmds")
+
+local group = vim.api.nvim_create_augroup("Init", { clear = true })
+vim.api.nvim_create_autocmd("User", {
+  group = group,
+  pattern = "VeryLazy",
+  callback = function()
+    require("config.keymaps")
+  end,
+})
index fc3ba2f2e6809cd104baec00eb399c2873d612ac..fbe320c0247c7ed25dc1a79eb1ff4818a12c179f 100644 (file)
@@ -1,60 +1,75 @@
 -- Keymaps are automatically loaded on the VeryLazy event
--- NOTE: Default LazyVim keys are not loaded automatically, review upstream keymas occasionnaly.
--- ~/.local/share/nvim/lazy/LazyVim/lua/lazyvim/config/keymaps.lua
 
-local Util = require("lazyvim.util")
+local map = vim.keymap.set
+
+-- better up/down
+map({ "n", "x" }, "j",      "v:count == 0 ? 'gj' : 'j'", { desc = "Down", expr = true, silent = true })
+map({ "n", "x" }, "<Down>", "v:count == 0 ? 'gj' : 'j'", { desc = "Down", expr = true, silent = true })
+map({ "n", "x" }, "k",      "v:count == 0 ? 'gk' : 'k'", { desc = "Up",   expr = true, silent = true })
+map({ "n", "x" }, "<Up>",   "v:count == 0 ? 'gk' : 'k'", { desc = "Up",   expr = true, silent = true })
+
+-- Move to window using the <ctrl> hjkl keys
+map("n", "<C-h>", "<C-w>W", { desc = "Go to Prev Window",  remap = true })
+map("n", "<C-l>", "<C-w>w", { desc = "Go to Next Window",  remap = true })
+map("n", "<C-j>", "<C-w>j", { desc = "Go to Lower Window", remap = true })
+map("n", "<C-k>", "<C-w>k", { desc = "Go to Upper Window", remap = true })
 
 -- Resize window using <ctrl> arrow keys
 -- TODO: this is cool, but should also support a number
-vim.keymap.set("n", "<C-Up>", "<cmd>resize +2<cr>", { desc = "Increase window height" })
-vim.keymap.set("n", "<C-Down>", "<cmd>resize -2<cr>", { desc = "Decrease window height" })
-vim.keymap.set("n", "<C-Left>", "<cmd>vertical resize -2<cr>", { desc = "Decrease window width" })
-vim.keymap.set("n", "<C-Right>", "<cmd>vertical resize +2<cr>", { desc = "Increase window width" })
+map("n", "<C-Up>",    "<cmd>resize +2<cr>",          { desc = "Increase Window Height" })
+map("n", "<C-Down>",  "<cmd>resize -2<cr>",          { desc = "Decrease Window Height" })
+map("n", "<C-Left>",  "<cmd>vertical resize -2<cr>", { desc = "Decrease Window Width" })
+map("n", "<C-Right>", "<cmd>vertical resize +2<cr>", { desc = "Increase Window Width" })
 
 -- Move Lines
-vim.keymap.set("n", "<A-j>", "<cmd>m .+1<cr>==", { desc = "Move down" })
-vim.keymap.set("n", "<A-k>", "<cmd>m .-2<cr>==", { desc = "Move up" })
--- NOTE: this triggers with <esc-j> when I'm too quick at doing "go to normal mode then move line"
-vim.keymap.set("i", "<A-j>", "<esc><cmd>m .+1<cr>==gi", { desc = "Move down" })
-vim.keymap.set("i", "<A-k>", "<esc><cmd>m .-2<cr>==gi", { desc = "Move up" })
-vim.keymap.set("v", "<A-j>", ":m '>+1<cr>gv=gv", { desc = "Move down" })
-vim.keymap.set("v", "<A-k>", ":m '<-2<cr>gv=gv", { desc = "Move up" })
+-- NOTE: these trigger with <esc-j> when I'm too quick at doing "go to normal mode then move line"
+map("n", "<A-j>", "<cmd>execute 'move .+' . v:count1<cr>==",                   { desc = "Move Down" })
+map("n", "<A-k>", "<cmd>execute 'move .-' . (v:count1 + 1)<cr>==",             { desc = "Move Up" })
+map("i", "<A-j>", "<esc><cmd>m .+1<cr>==gi",                                   { desc = "Move Down" })
+map("i", "<A-k>", "<esc><cmd>m .-2<cr>==gi",                                   { desc = "Move Up" })
+map("v", "<A-j>", ":<C-u>execute \"'<,'>move '>+\" . v:count1<cr>gv=gv",       { desc = "Move Down" })
+map("v", "<A-k>", ":<C-u>execute \"'<,'>move '<-\" . (v:count1 + 1)<cr>gv=gv", { desc = "Move Up" })
 
 -- buffers
-vim.keymap.set("n", "<S-h>", "<cmd>BufferLineCyclePrev<cr>", { desc = "Prev buffer" })
-vim.keymap.set("n", "<S-l>", "<cmd>BufferLineCycleNext<cr>", { desc = "Next buffer" })
-vim.keymap.set("n", "[b", "<cmd>BufferLineCyclePrev<cr>", { desc = "Prev buffer" })
-vim.keymap.set("n", "]b", "<cmd>BufferLineCycleNext<cr>", { desc = "Next buffer" })
+map("n", "<S-h>", "<cmd>BufferLineCyclePrev<cr>", { desc = "Prev Buffer" })
+map("n", "<S-l>", "<cmd>BufferLineCycleNext<cr>", { desc = "Next Buffer" })
+map("n", "[b",    "<cmd>BufferLineCyclePrev<cr>", { desc = "Prev Buffer" })
+map("n", "]b",    "<cmd>BufferLineCycleNext<cr>", { desc = "Next Buffer" })
 
-vim.keymap.set("n", "<leader>bb", "<cmd>e #<cr>", { desc = "Switch to Other Buffer" })
+map("n", "<leader>bb", "<cmd>e #<cr>", { desc = "Switch to Other Buffer" })
 
--- Clear search with <esc>
-vim.keymap.set({ "i", "n" }, "<esc>", "<cmd>noh<cr><esc>", { desc = "Escape and clear hlsearch" })
+-- Clear search and stop snippet on escape
+map({ "i", "n", "s" }, "<esc>", function()
+  vim.cmd("noh")
+  -- TODO: stop snippet with esc *but don't do it in insert mode*
+  -- require("luasnip").unlink_current()
+  return "<esc>"
+end, { expr = true, desc = "Escape and Clear hlsearch" })
 
 -- Clear search, diff update and redraw
 -- taken from runtime/lua/_editor.lua
-vim.keymap.set(
+map(
   "n",
   "<leader>ur",
   "<Cmd>nohlsearch<Bar>diffupdate<Bar>normal! <C-L><CR>",
-  { desc = "Redraw / clear hlsearch / diff update" }
+  { desc = "Redraw / Clear hlsearch / Diff Update" }
 )
 
-vim.keymap.set({ "n", "x" }, "gw", "*N", { desc = "Search word under cursor" })
+map({ "n", "x" }, "gw", "*N", { desc = "Search word under cursor" })
 
 -- Add undo break-points
-vim.keymap.set("i", ",", ",<c-g>u")
-vim.keymap.set("i", ".", ".<c-g>u")
-vim.keymap.set("i", ";", ";<c-g>u")
+map("i", ",", ",<c-g>u")
+map("i", ".", ".<c-g>u")
+map("i", ";", ";<c-g>u")
+
+--keywordprg
+map("n", "<leader>K", "<cmd>norm! K<cr>", { desc = "Keywordprg" })
 
 -- lazy
-vim.keymap.set("n", "<leader>l", "<cmd>:Lazy<cr>", { desc = "Lazy" })
+map("n", "<leader>l", "<cmd>Lazy<cr>", { desc = "Lazy" })
 
 -- new file
-vim.keymap.set("n", "<leader>fn", "<cmd>enew<cr>", { desc = "New File" })
-
-vim.keymap.set("n", "[q", vim.cmd.cprev, { desc = "Previous quickfix" })
-vim.keymap.set("n", "]q", vim.cmd.cnext, { desc = "Next quickfix" })
+map("n", "<leader>fn", "<cmd>enew<cr>", { desc = "New File" })
 
 -- diagnostic
 local diagnostic_goto = function(next, severity)
@@ -64,38 +79,49 @@ local diagnostic_goto = function(next, severity)
     go({ severity = severity })
   end
 end
-vim.keymap.set("n", "<leader>cd", vim.diagnostic.open_float, { desc = "Line Diagnostics" })
-vim.keymap.set("n", "]d", diagnostic_goto(true), { desc = "Next Diagnostic" })
-vim.keymap.set("n", "[d", diagnostic_goto(false), { desc = "Prev Diagnostic" })
-vim.keymap.set("n", "]e", diagnostic_goto(true, "ERROR"), { desc = "Next Error" })
-vim.keymap.set("n", "[e", diagnostic_goto(false, "ERROR"), { desc = "Prev Error" })
-vim.keymap.set("n", "]w", diagnostic_goto(true, "WARN"), { desc = "Next Warning" })
-vim.keymap.set("n", "[w", diagnostic_goto(false, "WARN"), { desc = "Prev Warning" })
+map("n", "<leader>cd", vim.diagnostic.open_float, { desc = "Line Diagnostics" })
 
--- stylua: ignore start
+map("n", "]d", diagnostic_goto(true),           { desc = "Next Diagnostic" })
+map("n", "[d", diagnostic_goto(false),          { desc = "Prev Diagnostic" })
+map("n", "]e", diagnostic_goto(true,  "ERROR"), { desc = "Next Error" })
+map("n", "[e", diagnostic_goto(false, "ERROR"), { desc = "Prev Error" })
+map("n", "]w", diagnostic_goto(true,  "WARN"),  { desc = "Next Warning" })
+map("n", "[w", diagnostic_goto(false, "WARN"),  { desc = "Prev Warning" })
 
 -- toggle options
-vim.keymap.set("n", "<leader>uf", Util.format.toggle, { desc = "Toggle format on Save" })
-vim.keymap.set("n", "<leader>ud", Snacks.toggle.diagnostics, { desc = "Toggle Diagnostics" })
-local conceallevel = vim.o.conceallevel > 0 and vim.o.conceallevel or 3
-vim.keymap.set("n", "<leader>uc", function() Snacks.toggle("conceallevel", false, {0, conceallevel}) end, { desc = "Toggle Conceal" })
+Snacks.toggle.option("spell", { name = "Spelling" }):map("<leader>us")
+Snacks.toggle.option("wrap", { name = "Wrap" }):map("<leader>uw")
+Snacks.toggle.option("relativenumber", { name = "Relative Number" }):map("<leader>uL")
+Snacks.toggle.diagnostics():map("<leader>ud")
+Snacks.toggle.line_number():map("<leader>ul")
+Snacks.toggle.option("conceallevel", { off = 0, on = vim.o.conceallevel > 0 and vim.o.conceallevel or 2, name = "Conceal Level" }):map("<leader>uc")
+Snacks.toggle.option("showtabline", { off = 0, on = vim.o.showtabline > 0 and vim.o.showtabline or 2, name = "Tabline" }):map("<leader>uA")
+Snacks.toggle.treesitter():map("<leader>uT")
+Snacks.toggle.option("background", { off = "light", on = "dark" , name = "Dark Background" }):map("<leader>ub")
+Snacks.toggle.dim():map("<leader>uD")
+Snacks.toggle.animate():map("<leader>ua")
+Snacks.toggle.indent():map("<leader>ug")
+Snacks.toggle.scroll():map("<leader>uS")
+Snacks.toggle.profiler():map("<leader>dpp")
+Snacks.toggle.profiler_highlights():map("<leader>dph")
+
+if vim.lsp.inlay_hint then
+  Snacks.toggle.inlay_hints():map("<leader>uh")
+end
+
+map({ "n", "x" }, "<leader>gB", function() Snacks.gitbrowse() end, { desc = "Git Browse (open)" })
+map({"n", "x" }, "<leader>gY", function()
+  Snacks.gitbrowse({ open = function(url) vim.fn.setreg("+", url) end, notify = false })
+end, { desc = "Git Browse (copy)" })
 
 -- highlights under cursor
-if vim.fn.has("nvim-0.9.0") == 1 then
-  vim.keymap.set("n", "<leader>ui", vim.show_pos, { desc = "Inspect Pos" })
-end
+map("n", "<leader>ui", vim.show_pos, { desc = "Inspect Pos" })
+map("n", "<leader>uI", "<cmd>InspectTree<cr>", { desc = "Inspect Tree" })
 
 -- floating terminal
 -- TODO: I prefer a split buffer for terminal, need to review how to make this more vim-like
-local lazyterm = function() LazyVim.terminal(nil, { cwd = LazyVim.root() }) end
-vim.keymap.set("n", "<leader>ft", lazyterm, { desc = "Terminal (Root Dir)" })
-vim.keymap.set("n", "<leader>fT", function() LazyVim.terminal() end, { desc = "Terminal (cwd)" })
+map("n", "<c-/>",      function() Snacks.terminal() end, { desc = "Terminal (cmd)" })
 
 -- Terminal Mappings
-vim.keymap.set("t", "<esc><esc>", "<c-\\><c-n>", { desc = "Enter Normal Mode" })
-vim.keymap.set("t", "<C-h>", "<cmd>wincmd h<cr>", { desc = "Go to Left Window" })
-vim.keymap.set("t", "<C-j>", "<cmd>wincmd j<cr>", { desc = "Go to Lower Window" })
-vim.keymap.set("t", "<C-k>", "<cmd>wincmd k<cr>", { desc = "Go to Upper Window" })
-vim.keymap.set("t", "<C-l>", "<cmd>wincmd l<cr>", { desc = "Go to Right Window" })
-vim.keymap.set("t", "<C-/>", "<cmd>close<cr>", { desc = "Hide Terminal" })
-vim.keymap.set("t", "<c-_>", "<cmd>close<cr>", { desc = "which_key_ignore" })
+map("t", "<esc><esc>", "<c-\\><c-n>",  { desc = "Enter Normal Mode" })
+map("t", "<C-/>", "<cmd>close<cr>",    { desc = "Hide Terminal" })
index b88ded792028797144efd3f99717f75117af767e..226c16d5b00da6c818a0a26b51171fd7d320e9cb 100644 (file)
@@ -1,35 +1,21 @@
 local lazypath = vim.fn.stdpath("data") .. "/lazy/lazy.nvim"
 if not vim.loop.fs_stat(lazypath) then
   -- bootstrap lazy.nvim
-  -- stylua: ignore
   vim.fn.system({ "git", "clone", "--filter=blob:none", "https://github.com/folke/lazy.nvim.git", "--branch=stable", lazypath })
 end
 vim.opt.rtp:prepend(vim.env.LAZY or lazypath)
 
 require("lazy").setup({
   spec = {
-    -- add LazyVim and import its plugins
-    { "LazyVim/LazyVim", import = "lazyvim.plugins" },
-    -- import any extras modules here
-    -- { import = "lazyvim.plugins.extras.lang.typescript" },
-    -- { import = "lazyvim.plugins.extras.lang.json" },
-    -- { import = "lazyvim.plugins.extras.ui.mini-animate" },
-    -- import/override with your plugins
     { import = "plugins" },
     { import = "plugins.lang" },
   },
   defaults = {
-    -- By default, only LazyVim plugins will be lazy-loaded. Your custom plugins will load during startup.
-    -- If you know what you're doing, you can set this to `true` to have all your custom plugins lazy-loaded by default.
     lazy = false,
-    -- It's recommended to leave version=false for now, since a lot the plugin that support versioning,
-    -- have outdated releases, which may break your Neovim install.
     version = false, -- always use the latest git commit
-    -- version = "*", -- try installing the latest stable version for plugins that support semver
   },
-  install = { colorscheme = { "tokyonight", "habamax" } },
+  install = { colorscheme = { "onenord", "habamax" } },
   checker = {
-    -- automatically check for plugin updates
     enabled = true,
     notify = false,
   },
index cd18d69a3fe0a8ba64e52cde528373caff935a7b..aeaca61d63544aa9a3cd28b6bc604a4d647ec73a 100644 (file)
@@ -2,6 +2,16 @@
 
 local opt = vim.opt
 
+opt.fillchars = {
+  foldopen = "",
+  foldclose = "",
+  fold = " ",
+  foldsep = " ",
+  eob = " ",
+  diff = "⣿",
+  vert = "│",
+}
+
 vim.g.man_hardwrap = 1
 vim.env.MANWIDTH = 80
 
@@ -16,13 +26,10 @@ opt.pumheight = 10 -- Maximum number of entries in a popup
 opt.showmode = false -- Dont show mode since we have a statusline
 opt.signcolumn = "yes" -- Always show the signcolumn, otherwise it would shift the text each time
 opt.updatetime = 200 -- Save swap file and trigger CursorHold
-if vim.fn.has("nvim-0.9.0") == 1 then
-  opt.splitkeep = "screen"
-  opt.shortmess:append({ C = true })
-end
+opt.splitkeep = "screen"
+opt.shortmess:append({ C = true })
+opt.foldmethod = "expr"
+opt.foldexpr = "v:lua.require'rmz.util'.foldexpr()"
+
 -- do not let markdown plugin change indent
 vim.g.markdown_recommended_style = 0
-
-vim.g.lazyvim_picker = "telescope"
-
-vim.g.snacks_animate = false
diff --git a/nvim/lua/plugins/blink.lua b/nvim/lua/plugins/blink.lua
new file mode 100644 (file)
index 0000000..e98ae95
--- /dev/null
@@ -0,0 +1,78 @@
+return {
+  {
+    "saghen/blink.cmp",
+    version = "*",
+    -- build = "cargo build --release",
+    dependencies = {
+      "rafamadriz/friendly-snippets",
+    },
+    -- NOTE: not described in upstream install docs
+    event = "InsertEnter",
+
+    ---@module 'blink.cmp'
+    ---@type blink.cmp.Config
+    opts = {
+      completion = {
+        menu = { draw = { treesitter = { "lsp" }, }, },
+        documentation = {
+          auto_show = true,
+          auto_show_delay_ms = 200,
+        },
+        ghost_text = {
+          enabled = true,
+        },
+      },
+
+      cmdline = {
+        enabled = false,
+      },
+      sources = {
+        default = { "lsp", "path", "snippets", "buffer" },
+      },
+      snippets = {
+        preset = "luasnip",
+      },
+
+      keymap = {
+        preset = "enter",
+        ["<C-y>"] = { "select_and_accept" },
+      },
+    },
+    opts_extend = { "sources.default", },
+  },
+
+  -- add icons
+  {
+    "saghen/blink.cmp",
+    opts = function(_, opts)
+      opts.appearance = opts.appearance or {}
+      opts.appearance.kind_icons = vim.tbl_extend("force", opts.appearance.kind_icons or {}, rmz.ui.icons.kinds)
+    end,
+  },
+
+  -- lazydev
+  {
+    "saghen/blink.cmp",
+    opts = {
+      sources = {
+        -- add lazydev to your completion providers
+        default = { "lazydev" },
+        providers = {
+          lazydev = {
+            name = "LazyDev",
+            module = "lazydev.integrations.blink",
+            score_offset = 100, -- show at a higher priority than lsp
+          },
+        },
+      },
+    },
+  },
+  -- catppuccin support
+  {
+    "catppuccin",
+    optional = true,
+    opts = {
+      integrations = { blink_cmp = true },
+    },
+  },
+}
index 131fc4acd874948c4d19f94aeeaa5948e7c7f66b..77d49557b73989443648b733a9a2ac86792eb5bb 100644 (file)
----@type LazyPluginSpec
+---@type LazySpec
 return {
   -- snippets
-  {
-    "L3MON4D3/LuaSnip",
-    -- disable luasnip bindings for <tab> and <s-tab>
+  { "l3mon4d3/luasnip",
+    build = "make install_jsregexp", -- optional
     dependencies = {
-      {
-        "honza/vim-snippets",
-        config = function()
-          require("luasnip.loaders.from_snipmate").lazy_load()
-          require("luasnip.loaders.from_lua").load({ paths = vim.fn.stdpath("config") .. "/lua/snippets" })
-        end,
-      },
+      { "honza/vim-snippets", },
     },
+    config = function()
+      local snippets = vim.fn.stdpath("config").."/snippets"
+      require("luasnip.loaders.from_snipmate").load({ paths = { snippets }})
+      require("luasnip.loaders.from_lua").load({ paths = { snippets }})
+    end,
     keys = function()
       return {}
     end,
     opts = {
+      history = true,
+      delete_check_events = "TextChanged",
       store_selection_keys = "<Tab>",
     },
   },
 
-  -- auto completion
-  {
-    "hrsh7th/nvim-cmp",
-    version = false, -- last release is way too old
-    event = "InsertEnter",
-    dependencies = {
-      "hrsh7th/cmp-nvim-lsp",
-      "hrsh7th/cmp-buffer",
-      "hrsh7th/cmp-path",
-      "saadparwaiz1/cmp_luasnip",
+  { "echasnovski/mini.pairs",
+    event = "VeryLazy",
+    opts = {
+      modes = { insert = true, command = true, terminal = false },
+      -- skip autopair when next character is one of these
+      skip_next = [=[[%w%%%'%[%"%.%`%$]]=],
+      -- skip autopair when the cursor is inside these treesitter nodes
+      skip_ts = { "string" },
+      -- skip autopair when next character is closing pair
+      -- and there are more closing pairs than opening pairs
+      skip_unbalanced = true,
+      -- better deal with markdown code blocks
+      markdown = true,
     },
-    ---@param opts cmp.ConfigSchema
-    opts = function(_, opts)
-      local has_words_before = function()
-        unpack = unpack or table.unpack
-        local line, col = unpack(vim.api.nvim_win_get_cursor(0))
-        return col ~= 0 and vim.api.nvim_buf_get_lines(0, line - 1, line, true)[1]:sub(col, col):match("%s") == nil
-      end
-
-      local cmp = require("cmp")
-      local luasnip = require("luasnip")
-
-      local upstream_format = opts.formatting.format
-      opts.formatting.format = function(entry, vim_item)
-        vim_item = upstream_format(entry, vim_item)
-        local menu = {
-          nvim_lsp = "[lsp]",
-          luasnip = "[snip]",
-          buffer = "[buf]",
-          path = "[path]",
-        }
-        vim_item.menu = menu[entry.source.name]
-        return vim_item
-      end
+    config = function(_, opts)
+      Snacks.toggle({
+        name = "Mini Pairs",
+        get = function()
+          return not vim.g.minipairs_disable
+        end,
+        set = function(state)
+          vim.g.minipairs_disable = not state
+        end,
+      }):map("<leader>up")
 
-      opts.completion = vim.tbl_extend("force", opts.completion, {
-        completeopt = "menu,menuone,noselect",
-      })
-      -- TODO: review if I want to keep any of LazyVim's mappings
-      opts.mapping = {
-        -- lazyvims
-        ["<C-n>"] = cmp.mapping.select_next_item({ behavior = cmp.SelectBehavior.Insert }),
-        ["<C-p>"] = cmp.mapping.select_prev_item({ behavior = cmp.SelectBehavior.Insert }),
-        ["<C-b>"] = cmp.mapping.scroll_docs(-4),
-        ["<C-f>"] = cmp.mapping.scroll_docs(4),
-        ["<C-e>"] = cmp.mapping.abort(),
-        ["<C-Space>"] = cmp.mapping.complete(),
-        -- mine
-        ["<Tab>"] = cmp.mapping(function(fallback)
-          if cmp.visible() then
-            cmp.select_next_item()
-          elseif luasnip.expand_or_jumpable() then
-            luasnip.expand_or_jump()
-          elseif has_words_before() then
-            cmp.complete()
-          else
-            fallback()
+      local pairs = require("mini.pairs")
+      pairs.setup(opts)
+      local open = pairs.open
+      --- Custom open command with extensions from LazyVim
+      ---@diagnostic disable-next-line: duplicate-set-field
+      pairs.open = function(pair, neigh_pattern)
+        if vim.fn.getcmdline() ~= "" then
+          return open(pair, neigh_pattern)
+        end
+        local o, c = pair:sub(1, 1), pair:sub(2, 2)
+        local line = vim.api.nvim_get_current_line()
+        local cursor = vim.api.nvim_win_get_cursor(0)
+        local next = line:sub(cursor[2] + 1, cursor[2] + 1)
+        local before = line:sub(1, cursor[2])
+        -- don't add fourth ` in markdown ```
+        if opts.markdown and o == "`" and vim.bo.filetype == "markdown" and before:match("^%s*``") then
+          return "`\n```" .. vim.api.nvim_replace_termcodes("<up>", true, true, true)
+        end
+        if opts.skip_next and next ~= "" and next:match(opts.skip_next) then
+          return o
+        end
+        if opts.skip_ts and #opts.skip_ts > 0 then
+          local ok, captures = pcall(vim.treesitter.get_captures_at_pos, 0, cursor[1] - 1, math.max(cursor[2] - 1, 0))
+          for _, capture in ipairs(ok and captures or {}) do
+            if vim.tbl_contains(opts.skip_ts, capture.capture) then
+              return o
+            end
           end
-        end, { "i", "s" }),
-        ["<S-Tab>"] = cmp.mapping(function(fallback)
-          if cmp.visible() then
-            cmp.select_prev_item()
-          elseif luasnip.jumpable(-1) then
-            luasnip.jump(-1)
-          else
-            fallback()
+        end
+        if opts.skip_unbalanced and next == c and c ~= o then
+          local _, count_open = line:gsub(vim.pesc(pair:sub(1, 1)), "")
+          local _, count_close = line:gsub(vim.pesc(pair:sub(2, 2)), "")
+          if count_close > count_open then
+            return o
           end
-        end, { "i", "s" }),
-      }
+        end
+        return open(pair, neigh_pattern)
+      end
     end,
   },
 
-  -- auto pairs
-  {
-    "echasnovski/mini.pairs",
-  },
-
-  -- surround
-  {
-    "echasnovski/mini.surround",
+  { "echasnovski/mini.surround",
     keys = function()
       -- HACK: use function to disable merging with LazyVim's keys definition
       return {
@@ -131,20 +118,117 @@ return {
       vim.keymap.set("x", "S", [[:<C-u>lua MiniSurround.add('visual')<CR>]], { silent = true })
     end,
   },
-  -- comments
-  {
-    "numToStr/Comment.nvim",
+
+  { "echasnovski/mini.ai",
+    -- TODO: port vim text objects over
+    event = "VeryLazy",
+    opts = function()
+      local ai = require("mini.ai")
+      return {
+        n_lines = 500,
+        custom_textobjects = {
+          o = ai.gen_spec.treesitter({ -- code block
+            a = { "@block.outer", "@conditional.outer", "@loop.outer" },
+            i = { "@block.inner", "@conditional.inner", "@loop.inner" },
+          }),
+          f = ai.gen_spec.treesitter({ a = "@function.outer", i = "@function.inner" }), -- function
+          c = ai.gen_spec.treesitter({ a = "@class.outer", i = "@class.inner" }), -- class
+          t = { "<([%p%w]-)%f[^<%w][^<>]->.-</%1>", "^<.->().*()</[^/]->$" }, -- tags
+          d = { "%f[%d]%d+" }, -- digits
+          e = { -- Word with case
+            { "%u[%l%d]+%f[^%l%d]", "%f[%S][%l%d]+%f[^%l%d]", "%f[%P][%l%d]+%f[^%l%d]", "^[%l%d]+%f[^%l%d]" },
+            "^().*()$",
+          },
+          u = ai.gen_spec.function_call(), -- u for "Usage"
+          U = ai.gen_spec.function_call({ name_pattern = "[%w_]" }), -- without dot in function name
+        },
+      }
+    end,
+  },
+  { "numToStr/Comment.nvim",
+    dependencies = {
+      { "JoosepAlviste/nvim-ts-context-commentstring",  -- nested language commenting (f.ex markdown code blocks)
+        opts = { enable_autocmd = false, },
+      }
+    },
+    opts = function(_, opts)
+      local tscci = require('ts_context_commentstring.integrations.comment_nvim')
+      vim.tbl_deep_extend('force', opts, {
+        toggler = {
+          line = "gcc",
+          block = "gbb",
+        },
+        mappings = {
+          basic = true,
+          extra = true,
+        },
+        pre_hook = tscci.create_pre_hook()
+      })
+      return opts
+    end,
+  },
+  { "danymat/neogen",  -- Generate annotations like doxygen
+    cmd = "Neogen",
+    keys = {
+      { "<leader>cn", function() require("neogen").generate() end, desc = "Generate Annotations (Neogen)", },
+    },
     opts = {
-      toggler = {
-        line = "gcc",
-        block = "gbb",
+      snippet_engine = "luasnip",
+    },
+  },
+  { "folke/lazydev.nvim",
+    ft = "lua",
+    cmd = "LazyDev",
+    opts = {
+      library = {
+        { path = "${3rd}/luv/library", words = { "vim%.uv" } },
+        { path = "snacks.nvim", words = { "Snacks" } },
+        { path = "lazy.nvim", words = { "LazySpec" } },
       },
-      mappings = {
-        basic = true,
-        extra = true,
+    },
+  },
+  { "gbprod/yanky.nvim", enabled = false, -- better yank/paste
+    -- TODO: integrate?
+    -- I'm not entirely convinced, it doesn't provide functionality like vim-peekaboo, 
+    -- maybe it can supplement it though?
+    -- Also, see issues on OSC52: https://github.com/gbprod/yanky.nvim/issues/213
+    recommended = true,
+    desc = "Better Yank/Paste",
+    event = "LazyFile",
+    opts = {
+      highlight = { timer = 150 },
+    },
+    keys = {
+      {
+        "<leader>p",
+        function() vim.cmd([[YankyRingHistory]]) end,
+        mode = { "n", "x" },
+        desc = "Open Yank History",
       },
+      -- stylua: ignore
+      { "y", "<Plug>(YankyYank)", mode = { "n", "x" }, desc = "Yank Text" },
+      { "p", "<Plug>(YankyPutAfter)", mode = { "n", "x" }, desc = "Put Text After Cursor" },
+      { "P", "<Plug>(YankyPutBefore)", mode = { "n", "x" }, desc = "Put Text Before Cursor" },
+      { "gp", "<Plug>(YankyGPutAfter)", mode = { "n", "x" }, desc = "Put Text After Selection" },
+      { "gP", "<Plug>(YankyGPutBefore)", mode = { "n", "x" }, desc = "Put Text Before Selection" },
+      { "[y", "<Plug>(YankyCycleForward)", desc = "Cycle Forward Through Yank History" },
+      { "]y", "<Plug>(YankyCycleBackward)", desc = "Cycle Backward Through Yank History" },
+      { "]p", "<Plug>(YankyPutIndentAfterLinewise)", desc = "Put Indented After Cursor (Linewise)" },
+      { "[p", "<Plug>(YankyPutIndentBeforeLinewise)", desc = "Put Indented Before Cursor (Linewise)" },
+      { "]P", "<Plug>(YankyPutIndentAfterLinewise)", desc = "Put Indented After Cursor (Linewise)" },
+      { "[P", "<Plug>(YankyPutIndentBeforeLinewise)", desc = "Put Indented Before Cursor (Linewise)" },
+      { ">p", "<Plug>(YankyPutIndentAfterShiftRight)", desc = "Put and Indent Right" },
+      { "<p", "<Plug>(YankyPutIndentAfterShiftLeft)", desc = "Put and Indent Left" },
+      { ">P", "<Plug>(YankyPutIndentBeforeShiftRight)", desc = "Put Before and Indent Right" },
+      { "<P", "<Plug>(YankyPutIndentBeforeShiftLeft)", desc = "Put Before and Indent Left" },
+      { "=p", "<Plug>(YankyPutAfterFilter)", desc = "Put After Applying a Filter" },
+      { "=P", "<Plug>(YankyPutBeforeFilter)", desc = "Put Before Applying a Filter" },
     },
   },
-  { "JoosepAlviste/nvim-ts-context-commentstring", enabled = false },
-  { "echasnovski/mini.comment", enabled = false },
+
+  { "andrewferrier/debugprint.nvim",
+    dependencies = { "nvim-treesitter" },
+    -- TODO: setup debugprint (or maybe not)
+    opts = { }
+  }
 }
index 8e1ae25dd2ba222b4a7290f274135b6a866315b7..873902e503fcafc94167ae4167a5d412d21ad654 100644 (file)
@@ -1,83 +1,77 @@
----@type LazyPluginSpec
+---@type LazySpec
 return {
-  {
-    "LazyVim",
-    opts = { colorscheme = "onenord" },
-    dependencies = { "onenord.nvim" },
-  },
-  {
-    -- this meta plugin can be used to install all colorschemes to test with telescope
-    name = "colorschemes",
-    dir = "",
-    lazy = true,
-    dependencies = {
-      {
-        -- requires too much configuration to make look good
-        "rmehri01/onenord.nvim",
-        opts = function(_, opts)
-          local colors = require("onenord.colors").load()
-          opts = vim.tbl_extend("force", opts, {
-            custom_highlights = {
-              ["@parameter"] = { fg = colors.fg },
-              ["@namespace"] = { fg = colors.fg },
-              ["@type"] = { fg = colors.fg },
-              ["@variable.builtin"] = { fg = colors.fg },
-            },
-          })
-          return opts
-        end,
-      },
-      { "folke/tokyonight.nvim" },
-      {
-        "catppuccin/nvim",
-        name = "catppuccin",
-        opts = {
-          color_overrides = {
-            -- https://github.com/catppuccin/nvim/discussions/323#discussioncomment-5760383
-            mocha = {
-              rosewater = "#BF616A",
-              flamingo = "#BF616A",
-              pink = "#B48EAD",
-              mauve = "#B48EAD",
-              red = "#BF616A",
-              maroon = "#BF616A",
-              peach = "#D08770",
-              yellow = "#EBCB8B",
-              green = "#A3BE8C",
-              teal = "#88c0d0",
-              sky = "#88c0d0",
-              sapphire = "#88c0d0",
-              blue = "#81a1c1",
-              lavender = "#81a1c1",
-              text = "#ECEFF4",
-              subtext1 = "#E5E9F0",
-              subtext0 = "#D8DEE9",
-              overlay2 = "#8d9196",
-              overlay1 = "#81858b",
-              overlay0 = "#4C566A",
-              surface2 = "#434C5E",
-              surface1 = "#3B4252",
-              surface0 = "#292e39",
-              base = "#242933",
-              mantle = "#20242d",
-              crust = "#1c2028",
-            },
-          },
+  { "rmehri01/onenord.nvim",
+    lazy = false,
+    priority = 1000,
+    opts = function(_, opts)
+      local colors = require("onenord.colors").load()
+      opts = vim.tbl_extend("force", opts, {
+        custom_highlights = {
+          ["@parameter"] = { fg = colors.fg },
+          ["@namespace"] = { fg = colors.fg },
+          ["@type"] = { fg = colors.fg },
+          ["@variable.builtin"] = { fg = colors.fg },
         },
-      },
-      {
-        "shaunsingh/nord.nvim",
-        dev = true,
-        init = function()
-          vim.g.nord_contrats = true
-          vim.g.nord_borders = true
-          vim.g.nord_bold = false
-          vim.g.nord_uniform_diff_background = false
-          vim.g.nord_disable_background = false
-        end,
-      },
-      -- conflicts with above
-      -- { "gbprod/nord.nvim"},
-    },
+      })
+      return opts
+    end,
   },
+  -- FIXME: Find a way to lazy load all colorschemes when invoking the picker
+  -- https://github.com/folke/lazy.nvim/discussions/1167
+  -- { name = "colorschemes",
+  --   -- this meta plugin can be used to install all colorschemes to test with a picker
+  --   dir = "",  -- NOTE: empty dir no longer works
+  --   lazy = true,
+  --   dependencies = {
+  --     {
+  --       "catppuccin/nvim",
+  --       name = "catppuccin",
+  --       opts = {
+  --         color_overrides = {
+  --           -- https://github.com/catppuccin/nvim/discussions/323#discussioncomment-5760383
+  --           mocha = {
+  --             rosewater = "#BF616A",
+  --             flamingo = "#BF616A",
+  --             pink = "#B48EAD",
+  --             mauve = "#B48EAD",
+  --             red = "#BF616A",
+  --             maroon = "#BF616A",
+  --             peach = "#D08770",
+  --             yellow = "#EBCB8B",
+  --             green = "#A3BE8C",
+  --             teal = "#88c0d0",
+  --             sky = "#88c0d0",
+  --             sapphire = "#88c0d0",
+  --             blue = "#81a1c1",
+  --             lavender = "#81a1c1",
+  --             text = "#ECEFF4",
+  --             subtext1 = "#E5E9F0",
+  --             subtext0 = "#D8DEE9",
+  --             overlay2 = "#8d9196",
+  --             overlay1 = "#81858b",
+  --             overlay0 = "#4C566A",
+  --             surface2 = "#434C5E",
+  --             surface1 = "#3B4252",
+  --             surface0 = "#292e39",
+  --             base = "#242933",
+  --             mantle = "#20242d",
+  --             crust = "#1c2028",
+  --           },
+  --         },
+  --       },
+  --     },
+  --     {
+  --       "shaunsingh/nord.nvim",
+  --       init = function()
+  --         vim.g.nord_contrats = true
+  --         vim.g.nord_borders = true
+  --         vim.g.nord_bold = false
+  --         vim.g.nord_uniform_diff_background = false
+  --         vim.g.nord_disable_background = false
+  --       end,
+  --     },
+  --     -- conflicts with above
+  --     -- { "gbprod/nord.nvim"},
+  --   },
+  -- },
 }
index b3f49a209ec339c012368624f4d3d1873bb258c6..acec5987535750b70ac614e84da177a33aada708 100644 (file)
@@ -1,18 +1,13 @@
----@type LazyPluginSpec
+---@type LazySpec
 return {
-  {
-    "LazyVim/LazyVim",
-    opts = {
-      defaults = {
-        autocmds = false,
-        options = false,
-        keymaps = false,
-      },
-    },
-  },
-  {
-    "vhyrro/luarocks.nvim",
+  { "vhyrro/luarocks.nvim",
     priority = 1000,
     config = true,
+  },
+  { "dstein64/vim-startuptime",
+    cmd = "StartupTime",
+    config = function()
+      vim.g.startuptime_tries = 10
+    end,
   }
 }
index 8657ab85fcb1b34888e03c879f724bec39a8769d..46840f749f89225fada1cc43a1f398259dc191a3 100644 (file)
----@param config {args?:string[]|fun():string[]?}
+---@param config {type?:string, args?:string[]|fun():string[]?}
 local function get_args(config)
-  local args = type(config.args) == "function" and (config.args() or {}) or config.args or {}
+  local args = type(config.args) == "function" and (config.args() or {}) or config.args or {} --[[@as string[] | string ]]
+  local args_str = type(args) == "table" and table.concat(args, " ") or args --[[@as string]]
+
   config = vim.deepcopy(config)
   ---@cast args string[]
   config.args = function()
-    local new_args = vim.fn.input("Run with args: ", table.concat(args, " ")) --[[@as string]]
-    return vim.split(vim.fn.expand(new_args) --[[@as string]], " ")
+    local new_args = vim.fn.expand(vim.fn.input("Run with args: ", args_str)) --[[@as string]]
+    return require("dap.utils").splitstr(new_args)
   end
   return config
 end
 
 return {
-  "mfussenegger/nvim-dap",
-
-  dependencies = {
-    -- fancy UI for the debugger
-    {
+  { "mfussenegger/nvim-dap",
+    dependencies = {
       "rcarriga/nvim-dap-ui",
-      -- stylua: ignore
-      keys = {
-        { "<leader>du", function() require("dapui").toggle({ }) end, desc = "Dap UI" },
-        { "<leader>de", function() require("dapui").eval() end, desc = "Eval", mode = {"n", "v"} },
+      { "theHamsta/nvim-dap-virtual-text", -- virtual text for the debugger
+        opts = {},
       },
-      opts = {},
-      config = function(_, opts)
-        local dap = require("dap")
-        local dapui = require("dapui")
-        dapui.setup(opts)
-        dap.listeners.after.event_initialized["dapui_config"] = function()
-          dapui.open({})
-        end
-      end,
     },
 
-    -- virtual text for the debugger
-    {
-      "theHamsta/nvim-dap-virtual-text",
-      opts = {},
+    -- stylua: ignore
+    keys = {
+      { "<leader>dB", function() require("dap").set_breakpoint(vim.fn.input('Breakpoint condition: ')) end, desc = "Breakpoint Condition" },
+      { "<leader>db", function() require("dap").toggle_breakpoint() end, desc = "Toggle Breakpoint" },
+      { "<leader>dc", function() require("dap").continue() end, desc = "Run/Continue" },
+      { "<leader>da", function() require("dap").continue({ before = get_args }) end, desc = "Run with Args" },
+      { "<leader>dC", function() require("dap").run_to_cursor() end, desc = "Run to Cursor" },
+      { "<C-T>", function() require("dap").run_to_cursor() end, desc = "Run to Cursor" },
+      { "<leader>dg", function() require("dap").goto_() end, desc = "Go to Line (No Execute)" },
+      { "<leader>di", function() require("dap").step_into() end, desc = "Step Into" },
+      { "<C-S>", function() require("dap").step_into() end, desc = "Step Into" },
+      { "<leader>dj", function() require("dap").down() end, desc = "Down" },
+      { "<leader>dk", function() require("dap").up() end, desc = "Up" },
+      { "<leader>dl", function() require("dap").run_last() end, desc = "Run Last" },
+      { "<leader>do", function() require("dap").step_out() end, desc = "Step Out" },
+      { "<C-F>", function() require("dap").step_out() end, desc = "Step Over" },
+      { "<leader>dO", function() require("dap").step_over() end, desc = "Step Over" },
+      { "<C-N>", function() require("dap").step_over() end, desc = "Step Over" },
+      { "<leader>dP", function() require("dap").pause() end, desc = "Pause" },
+      { "<leader>dr", function() require("dap").repl.toggle() end, desc = "Toggle REPL" },
+      { "<leader>ds", function() require("dap").session() end, desc = "Session" },
+      { "<leader>dt", function() require("dap").terminate() end, desc = "Terminate" },
+      { "<leader>dw", function() require("dap.ui.widgets").hover() end, desc = "Widgets" },
     },
 
-    -- which key integration
-    {
-      "folke/which-key.nvim",
-      opts = {
-        defaults = {
-          ["<leader>d"] = { name = "+debug" },
-        },
-      },
-    },
+    config = function()
+      -- load mason-nvim-dap here, after all adapters have been setup
+      require("mason-nvim-dap").setup(rmz.lazy.opts("mason-nvim-dap.nvim"))
 
-    -- mason.nvim integration
-    {
-      "jay-babu/mason-nvim-dap.nvim",
-      dependencies = "mason.nvim",
-      cmd = { "DapInstall", "DapUninstall" },
-      opts = {
-        -- Makes a best effort to setup the various debuggers with
-        -- reasonable debug configurations
-        automatic_installation = true,
+      vim.api.nvim_set_hl(0, "DapStoppedLine", { default = true, link = "Visual" })
 
-        -- You can provide additional configuration to the handlers,
-        -- see mason-nvim-dap README for more information
-        handlers = {},
-      },
-    },
-    {
-      "jbyuki/one-small-step-for-vimkind",
-      -- stylua: ignore
-      keys = {
-        { "<leader>daL", function() require("osv").launch({ port = 8086 }) end, desc = "Adapter Lua Server" },
-        { "<leader>dal", function() require("osv").run_this() end, desc = "Adapter Lua" },
-      },
-      config = function()
-        local dap = require("dap")
-        dap.adapters.nlua = function(callback, config)
-          local adapter = {
-            type = "server",
-            host = config.host or "127.0.0.1",
-            port = config.port or 8086,
-          }
-          if config.start_neovim then
-            local dap_run = dap.run
-            dap.run = function(c)
-              adapter.port = c.port
-              adapter.host = c.host
-            end
-            require("osv").run_this()
-            dap.run = dap_run
-          end
-          callback(adapter)
-        end
-        dap.configurations.lua = {
-          {
-            type = "nlua",
-            request = "attach",
-            name = "Run this file",
-            start_neovim = {},
-          },
-          {
-            type = "nlua",
-            request = "attach",
-            name = "Attach to running Neovim instance (port 8086)",
-            port = 8086,
-          },
-        }
-      end,
+      for name, sign in pairs(rmz.ui.icons.dap) do
+        sign = type(sign) == "table" and sign or { sign }  ---@cast sign table
+        vim.fn.sign_define(
+          "Dap" .. name,
+          { text = sign[1], texthl = sign[2] or "DiagnosticInfo", linehl = sign[3], numhl = sign[3] }
+        )
+      end
+
+      -- setup dap config by VsCode launch.json file
+      local vscode = require("dap.ext.vscode")
+      local json = require("plenary.json")
+      vscode.json_decode = function(str)
+        return vim.json.decode(json.json_strip_comments(str))
+      end
+    end,
+  },
+  { "mason.nvim",
+    opts = {
+        log_level = vim.log.levels.TRACE,
+    }
+  },
+  { "rcarriga/nvim-dap-ui", -- fancy UI for the debugger
+    dependencies = { "nvim-neotest/nvim-nio" },
+    -- stylua: ignore
+    keys = {
+      { "<leader>du", function() require("dapui").toggle({ }) end, desc = "Dap UI" },
+      { "<leader>de", function() require("dapui").eval() end, desc = "Eval", mode = {"n", "v"} },
     },
+    opts = {},
+    config = function(_, opts)
+      local dap = require("dap")
+      local dapui = require("dapui")
+      dapui.setup(opts)
+      dap.listeners.after.event_initialized["dapui_config"] = function()
+        dapui.open({})
+      end
+    end,
   },
-
-  -- stylua: ignore
-  keys = {
-    { "<leader>dB", function() require("dap").set_breakpoint(vim.fn.input('Breakpoint condition: ')) end, desc = "Breakpoint Condition" },
-    { "<leader>db", function() require("dap").toggle_breakpoint() end, desc = "Toggle Breakpoint" },
-    { "<leader>dc", function() require("dap").continue() end, desc = "Continue" },
-    { "<leader>da", function() require("dap").continue({ before = get_args }) end, desc = "Run with Args" },
-    { "<leader>dC", function() require("dap").run_to_cursor() end, desc = "Run to Cursor" },
-    { "<C-T>", function() require("dap").run_to_cursor() end, desc = "Run to Cursor" },
-    { "<leader>dg", function() require("dap").goto_() end, desc = "Go to line (no execute)" },
-    { "<leader>di", function() require("dap").step_into() end, desc = "Step Into" },
-    { "<C-S>", function() require("dap").step_into() end, desc = "Step Into" },
-    { "<leader>dj", function() require("dap").down() end, desc = "Down" },
-    { "<leader>dk", function() require("dap").up() end, desc = "Up" },
-    { "<leader>dl", function() require("dap").run_last() end, desc = "Run Last" },
-    { "<leader>do", function() require("dap").step_out() end, desc = "Step Out" },
-    { "<C-F>", function() require("dap").step_out() end, desc = "Step Over" },
-    { "<leader>dO", function() require("dap").step_over() end, desc = "Step Over" },
-    { "<C-N>", function() require("dap").step_over() end, desc = "Step Over" },
-    { "<leader>dp", function() require("dap").pause() end, desc = "Pause" },
-    { "<leader>dr", function() require("dap").repl.toggle() end, desc = "Toggle REPL" },
-    { "<leader>ds", function() require("dap").session() end, desc = "Session" },
-    { "<leader>dt", function() require("dap").terminate() end, desc = "Terminate" },
-    { "<leader>dw", function() require("dap.ui.widgets").hover() end, desc = "Widgets" },
+  -- mason.nvim integration
+  { "jay-babu/mason-nvim-dap.nvim",
+    dependencies = "mason.nvim",
+    cmd = { "DapInstall", "DapUninstall" },
+    opts_extend = { "ensure_installed" },
+    opts = {
+      automatic_installation = true,
+      handlers = {},
+      ensure_installed = { },
+    },
+    -- mason-nvim-dap is loaded when nvim-dap loads
+    config = function() end,
   },
-
-  config = function()
-    local Config = require("lazyvim.config")
-    vim.api.nvim_set_hl(0, "DapStoppedLine", { default = true, link = "Visual" })
-
-    for name, sign in pairs(Config.icons.dap) do
-      sign = type(sign) == "table" and sign or { sign }
-      vim.fn.sign_define(
-        "Dap" .. name,
-        { text = sign[1], texthl = sign[2] or "DiagnosticInfo", linehl = sign[3], numhl = sign[3] }
-      )
-    end
-  end,
 }
index 0407b47953fe5586329cc8b25bb6ac782c11b1ae..1e94ab0bc0a7b6e0362f71a349e54fc82e045d7c 100644 (file)
@@ -1,97 +1,6 @@
----@type LazyPluginSpec
+---@type LazySpec
 return {
-  {
-    "nvim-telescope/telescope.nvim",
-    keys = {
-      { "<leader>fF", LazyVim.pick("files", { cwd = false }), desc = "Find Files (cwd)" },
-      -- from lazyvim
-      { "<leader>,", "<cmd>Telescope buffers show_all_buffers=true<cr>", desc = "Switch Buffer" },
-      { "<leader>/", LazyVim.pick("live_grep"), desc = "Grep (root dir)" },
-      { "<leader>:", "<cmd>Telescope command_history<cr>", desc = "Command History" },
-      { "<leader><space>", LazyVim.pick("files"), desc = "Find Files (root dir)" },
-      { "<leader><space>", false },
-      -- find
-      { "<leader>fb", "<cmd>Telescope buffers sort_lastused=true<CR>", desc = "Buffers" },
-      -- { "<leader>ff", LazyVim.pick("files"), desc = "Find Files (root dir)" },
-      { "<leader>ff", false }, -- fswitch
-      { "<leader>fF", LazyVim.pick("files", { cwd = false }), desc = "Find Files (cwd)" },
-      { "<leader>fr", "<cmd>Telescope oldfiles<cr>", desc = "Recent" },
-      { "<leader>fR", LazyVim.pick("oldfiles", { cwd = vim.loop.cwd() }), desc = "Recent (cwd)" },
-      -- git
-      -- { "<leader>gc", "<cmd>Telescope git_commits<CR>", desc = "commits" },
-      { "<leader>gc", false },
-      -- { "<leader>gs", "<cmd>Telescope git_status<CR>", desc = "status" },
-      { "<leader>gs", false },
-      -- search
-      { "<leader>sa", "<cmd>Telescope autocommands<cr>", desc = "Auto Commands" },
-      { "<leader>sb", "<cmd>Telescope current_buffer_fuzzy_find<cr>", desc = "Buffer" },
-      { "<leader>sc", "<cmd>Telescope command_history<cr>", desc = "Command History" },
-      { "<leader>sC", "<cmd>Telescope commands<cr>", desc = "Commands" },
-      { "<leader>sd", "<cmd>Telescope diagnostics bufnr=0<cr>", desc = "Document diagnostics" },
-      { "<leader>sD", "<cmd>Telescope diagnostics<cr>", desc = "Workspace diagnostics" },
-      { "<leader>sg", LazyVim.pick("live_grep"), desc = "Grep (root dir)" },
-      { "<leader>sG", LazyVim.pick("live_grep", { cwd = false }), desc = "Grep (cwd)" },
-      { "<leader>sh", "<cmd>Telescope help_tags<cr>", desc = "Help Pages" },
-      { "<leader>sH", "<cmd>Telescope highlights<cr>", desc = "Search Highlight Groups" },
-      { "<leader>sk", "<cmd>Telescope keymaps<cr>", desc = "Key Maps" },
-      { "<leader>sM", "<cmd>Telescope man_pages<cr>", desc = "Man Pages" },
-      { "<leader>sm", "<cmd>Telescope marks<cr>", desc = "Jump to Mark" },
-      { "<leader>so", "<cmd>Telescope vim_options<cr>", desc = "Options" },
-      { "<leader>sR", "<cmd>Telescope resume<cr>", desc = "Resume" },
-      { "<leader>sw", LazyVim.pick("grep_string"), desc = "Word (root dir)" },
-      { "<leader>sW", LazyVim.pick("grep_string", { cwd = false }), desc = "Word (cwd)" },
-      { "<leader>uC", LazyVim.pick("colorscheme", { enable_preview = true }), desc = "Colorscheme with preview" },
-      -- {
-      --   "<leader>ss",
-      --   LazyVim.pick("lsp_document_symbols", {
-      --     symbols = {
-      --       "Class",
-      --       "Function",
-      --       "Method",
-      --       "Constructor",
-      --       "Interface",
-      --       "Module",
-      --       "Struct",
-      --       "Trait",
-      --       "Field",
-      --       "Property",
-      --     },
-      --   }),
-      --   desc = "Goto Symbol",
-      -- },
-      { "<leader>ss", false }, -- use for snippets below
-      {
-        "<leader>sS",
-        LazyVim.pick("lsp_dynamic_workspace_symbols", {
-          symbols = {
-            "Class",
-            "Function",
-            "Method",
-            "Constructor",
-            "Interface",
-            "Module",
-            "Struct",
-            "Trait",
-            "Field",
-            "Property",
-          },
-        }),
-        desc = "Goto Symbol (Workspace)",
-      },
-    },
-  },
-  {
-    "benfowler/telescope-luasnip.nvim",
-    dependencies = {
-      "telescope.nvim",
-    },
-    config = function()
-      require("telescope").load_extension("luasnip")
-    end,
-    keys = { { "<leader>ss", "<cmd>Telescope luasnip<cr>", desc = "Snippets" } },
-  },
-  {
-    "stevearc/oil.nvim",
+  { "stevearc/oil.nvim",
     opts = {
       keymaps = {
         ["g?"] = "actions.show_help",
@@ -117,9 +26,6 @@ return {
   { "folke/trouble.nvim",
     cmd = { "Trouble" },
     opts = {
-      keys = {
-        ["<space><space>"] = "fold_toggle",
-      },
       modes = {
         lsp = {
           win = { position = "right" },
@@ -164,40 +70,140 @@ return {
     },
   },
   { "folke/todo-comments.nvim",
-    cmd = { "TodoTrouble", "TodoTelescope" },
-    event = "LazyFile",
+    -- Finds and lists all of the TODO, HACK, BUG, etc comment
+    -- in your project and loads them into a browsable list.
+    cmd = { "TodoTrouble"},
+    event = { "BufReadPost", "BufNewFile", "BufWritePre" },
     -- stylua: ignore
     keys = {
       { "]t", function() require("todo-comments").jump_next() end, desc = "Next Todo Comment" },
       { "[t", function() require("todo-comments").jump_prev() end, desc = "Previous Todo Comment" },
       { "<leader>xt", "<cmd>Trouble todo toggle<cr>", desc = "Todo (Trouble)" },
       { "<leader>xT", "<cmd>Trouble todo toggle filter = {tag = {TODO,FIX,FIXME}}<cr>", desc = "Todo/Fix/Fixme (Trouble)" },
-      { "<leader>st", "<cmd>TodoTelescope<cr>", desc = "Todo" },
-      { "<leader>sT", "<cmd>TodoTelescope keywords=TODO,FIX,FIXME<cr>", desc = "Todo/Fix/Fixme" },
     },
+    opts = {}
   },
-  {
-    "neo-tree.nvim",
-    enabled = false,
-    lazy = false,
-    opts = {
-      filesystem = {
-        -- TODO: review these
-        bind_to_cwd = false,
-        follow_current_file = {
-          enabled = false,
-        },
-      },
-    },
-    keys = function()
-      local NeoTree = function(args)
-        return function()
-          require("neo-tree.command").execute(args)
-        end
-      end
+  { "echasnovski/mini.hipatterns",  -- highlight hex colours and other matched words
+    event = { "BufReadPost", "BufNewFile", "BufWritePre" },
+    opts = function()
+      local hi = require("mini.hipatterns")
       return {
-        { "<leader>fe", NeoTree({ toggle = true, dir = vim.loop.cwd() }) },
+        highlighters = {
+          hex_color = hi.gen_highlighter.hex_color({ priority = 2000 }),
+        },
       }
     end,
   },
+  { "folke/flash.nvim",
+    -- Flash enhances the built-in search functionality by showing labels
+    -- at the end of each match, letting you quickly jump to a specific
+    -- location.
+    event = "VeryLazy",
+    vscode = true,
+    ---@type Flash.Config
+    opts = {},
+    -- stylua: ignore
+    keys = {
+      { "s", mode = { "n", "x", "o" }, function() require("flash").jump() end, desc = "Flash" },
+      { "S", mode = { "n", "o", "x" }, function() require("flash").treesitter() end, desc = "Flash Treesitter" },
+      { "r", mode = "o", function() require("flash").remote() end, desc = "Remote Flash" },
+      { "R", mode = { "o", "x" }, function() require("flash").treesitter_search() end, desc = "Treesitter Search" },
+      { "<c-s>", mode = { "c" }, function() require("flash").toggle() end, desc = "Toggle Flash Search" },
+    },
+  },
+  { "lewis6991/gitsigns.nvim",
+    -- git signs highlights text that has changed since the list
+    -- git commit, and also lets you interactively stage & unstage
+    -- hunks in a commit.
+    event = { "BufReadPost", "BufNewFile", "BufWritePre" },
+    opts = {
+      signs = {
+        add = { text = "▎" },
+        change = { text = "▎" },
+        delete = { text = "" },
+        topdelete = { text = "" },
+        changedelete = { text = "▎" },
+        untracked = { text = "▎" },
+      },
+      signs_staged = {
+        add = { text = "▎" },
+        change = { text = "▎" },
+        delete = { text = "" },
+        topdelete = { text = "" },
+        changedelete = { text = "▎" },
+      },
+      on_attach = function(buffer)
+        local gs = package.loaded.gitsigns
+
+        local function map(mode, l, r, desc)
+          vim.keymap.set(mode, l, r, { buffer = buffer, desc = desc })
+        end
+
+        -- stylua: ignore start
+        map("n", "]h", function()
+          if vim.wo.diff then
+            vim.cmd.normal({ "]c", bang = true })
+          else
+            gs.nav_hunk("next")
+          end
+        end, "Next Hunk")
+        map("n", "[h", function()
+          if vim.wo.diff then
+            vim.cmd.normal({ "[c", bang = true })
+          else
+            gs.nav_hunk("prev")
+          end
+        end, "Prev Hunk")
+        map("n", "]H", function() gs.nav_hunk("last") end, "Last Hunk")
+        map("n", "[H", function() gs.nav_hunk("first") end, "First Hunk")
+        map({ "n", "v" }, "<leader>ghs", ":Gitsigns stage_hunk<CR>", "Stage Hunk")
+        map({ "n", "v" }, "<leader>ghr", ":Gitsigns reset_hunk<CR>", "Reset Hunk")
+        map("n", "<leader>ghS", gs.stage_buffer, "Stage Buffer")
+        map("n", "<leader>ghu", gs.undo_stage_hunk, "Undo Stage Hunk")
+        map("n", "<leader>ghR", gs.reset_buffer, "Reset Buffer")
+        map("n", "<leader>ghp", gs.preview_hunk_inline, "Preview Hunk Inline")
+        map("n", "<leader>ghb", function() gs.blame_line({ full = true }) end, "Blame Line")
+        map("n", "<leader>ghB", function() gs.blame() end, "Blame Buffer")
+        map("n", "<leader>ghd", gs.diffthis, "Diff This")
+        map("n", "<leader>ghD", function() gs.diffthis("~") end, "Diff This ~")
+        map({ "o", "x" }, "ih", ":<C-U>Gitsigns select_hunk<CR>", "GitSigns Select Hunk")
+        Snacks.toggle({
+          name = "Git Signs",
+          get = function()
+            return require("gitsigns.config").config.signcolumn
+          end,
+          set = function(state)
+            require("gitsigns").toggle_signs(state)
+          end,
+        }):map("<leader>uG")
+      end,
+    },
+  },
+
+  -- TODO: currently unused plugins, check and enable/remove
+  { "MagicDuck/grug-far.nvim", enabled = false,
+    -- search/replace in multiple files
+    opts = { headerMaxWidth = 80 },
+    cmd = "GrugFar",
+    keys = {
+      {
+        "<leader>sr",
+        function()
+          local grug = require("grug-far")
+          local ext = vim.bo.buftype == "" and vim.fn.expand("%:e")
+          grug.open({
+            transient = true,
+            prefills = {
+              filesFilter = ext and ext ~= "" and "*." .. ext or nil,
+            },
+          })
+        end,
+        mode = { "n", "v" },
+        desc = "Search and Replace",
+      },
+    },
+  },
+  { "aymericbeaumet/vim-symlink",
+    dependencies = { "moll/vim-bbye" }, -- NOTE: Snacks.buddelete also provides this
+  },
 }
diff --git a/nvim/lua/plugins/formatter.lua b/nvim/lua/plugins/formatter.lua
new file mode 100644 (file)
index 0000000..2dd44ab
--- /dev/null
@@ -0,0 +1,47 @@
+--- TODO: add toggle for format on save
+--- https://github.com/stevearc/conform.nvim/blob/master/doc/recipes.md#command-to-toggle-format-on-save
+--- previous keymap was <leader>uf
+
+---@type LazySpec
+return {
+  { "stevearc/conform.nvim",
+    dependencies = { "mason.nvim" },
+    lazy = true,
+    cmd = "ConformInfo",
+    keys = {
+      {"<leader>cf", function() require("conform").format({ async = true }) end, mode = "", desc = "Format buffer" },
+      {
+        "<leader>cF",
+        function()
+          require("conform").format({ formatters = { "injected" }, timeout_ms = 3000 })
+        end,
+        mode = { "n", "v" },
+        desc = "Format Injected Langs",
+      },
+    },
+    ---@module "conform"
+    ---@type conform.setupOpts
+    opts = {
+      default_format_opts = {
+        timeout_ms = 3000,
+        async = false, -- not recommended to change
+        quiet = false, -- not recommended to change
+        lsp_format = "fallback", -- not recommended to change
+      },
+      formatters_by_ft = {
+        lua = { "stylua" },
+        fish = { "fish_indent" },
+        sh = { "shfmt" },
+      },
+      -- The options you set here will be merged with the builtin formatters.
+      -- You can also define any custom formatters here.
+      ---@type table<string, conform.FormatterConfigOverride|fun(bufnr: integer): nil|conform.FormatterConfigOverride>
+      formatters = {
+        injected = { options = { ignore_errors = true } },
+      },
+    },
+    init = function ()
+      vim.opt.formatexpr = "v:lua.require'conform'.formatexpr()"
+    end,
+  },
+}
diff --git a/nvim/lua/plugins/init.lua b/nvim/lua/plugins/init.lua
new file mode 100644 (file)
index 0000000..c21defb
--- /dev/null
@@ -0,0 +1,4 @@
+return {
+  { "folke/lazy.nvim", version = "*" },
+  { "folke/snacks.nvim", priority = 1000, lazy = false },
+}
diff --git a/nvim/lua/plugins/lang/cmake.lua b/nvim/lua/plugins/lang/cmake.lua
new file mode 100644 (file)
index 0000000..2e76835
--- /dev/null
@@ -0,0 +1,60 @@
+return {
+  {
+    "nvim-treesitter/nvim-treesitter",
+    opts = { ensure_installed = { "cmake" } },
+  },
+  {
+    "nvimtools/none-ls.nvim",
+    optional = true,
+    opts = function(_, opts)
+      local nls = require("null-ls")
+      opts.sources = vim.list_extend(opts.sources or {}, {
+        nls.builtins.diagnostics.cmake_lint,
+      })
+    end,
+  },
+  {
+    "mfussenegger/nvim-lint",
+    optional = true,
+    opts = {
+      linters_by_ft = {
+        cmake = { "cmakelint" },
+      },
+    },
+  },
+  {
+    "mason.nvim",
+    opts = { ensure_installed = { "cmakelang", "cmakelint" } },
+  },
+  {
+    "neovim/nvim-lspconfig",
+    opts = {
+      servers = {
+        neocmake = {},
+      },
+    },
+  },
+  {
+    "Civitasv/cmake-tools.nvim",
+    lazy = true,
+    init = function()
+      local loaded = false
+      local function check()
+        local cwd = vim.uv.cwd()
+        if vim.fn.filereadable(cwd .. "/CMakeLists.txt") == 1 then
+          require("lazy").load({ plugins = { "cmake-tools.nvim" } })
+          loaded = true
+        end
+      end
+      check()
+      vim.api.nvim_create_autocmd("DirChanged", {
+        callback = function()
+          if not loaded then
+            check()
+          end
+        end,
+      })
+    end,
+    opts = {},
+  },
+}
index ff6624ef3a216ad5f4e6d3e9638bf9d178d77613..d3153dbdeb892f94bcc28f10b40f49278e19f75d 100644 (file)
@@ -2,11 +2,7 @@ return {
   -- Add C/C++ to treesitter
   {
     "nvim-treesitter/nvim-treesitter",
-    opts = function(_, opts)
-      if type(opts.ensure_installed) == "table" then
-        vim.list_extend(opts.ensure_installed, { "c", "cpp" })
-      end
-    end,
+    opts = { ensure_installed = { "c", "cpp" } },
   },
 
   {
@@ -48,7 +44,7 @@ return {
         -- Ensure mason installs the server
         clangd = {
           keys = {
-            { "<leader>cR", "<cmd>ClangdSwitchSourceHeader<cr>", desc = "Switch Source/Header (C/C++)" },
+            { "<leader>ch", "<cmd>ClangdSwitchSourceHeader<cr>", desc = "Switch Source/Header (C/C++)" },
           },
           root_dir = function(fname)
             return require("lspconfig.util").root_pattern( "compile_commands.json", "compile_flags.txt")(fname)
@@ -84,31 +80,24 @@ return {
       },
       setup = {
         clangd = function(_, opts)
-          local clangd_ext_opts = require("lazyvim.util").opts("clangd_extensions.nvim")
+          local clangd_ext_opts = rmz.lazy.opts("clangd_extensions.nvim")
           require("clangd_extensions").setup(vim.tbl_deep_extend("force", clangd_ext_opts or {}, { server = opts }))
           return false
         end,
       },
     },
   },
-
-  {
-    "nvim-cmp",
-    opts = function(_, opts)
-      table.insert(opts.sorting.comparators, 1, require("clangd_extensions.cmp_scores"))
-    end,
-  },
-
-  {
-    "mfussenegger/nvim-dap",
+  -- { "blink.cmp",
+  --   opts = function(_, opts)
+  --     -- TODO: make sure this works
+  --     table.insert(opts.fuzzy.sorts, 1, require("clangd_extensions.cmp_scores"))
+  --   end,
+  -- },
+  { "mfussenegger/nvim-dap",
     dependencies = {
       -- Ensure C/C++ debugger is installed
       "williamboman/mason.nvim",
-      opts = function(_, opts)
-        if type(opts.ensure_installed) == "table" then
-          vim.list_extend(opts.ensure_installed, { "codelldb" })
-        end
-      end,
+      opts = { ensure_installed = { "codelldb" } },
     },
     opts = function()
       local dap = require("dap")
@@ -141,7 +130,7 @@ return {
             type = "codelldb",
             request = "attach",
             name = "Attach to process",
-            processId = require("dap.utils").pick_process,
+            pid = require("dap.utils").pick_process,
             cwd = "${workspaceFolder}",
           },
         }
diff --git a/nvim/lua/plugins/lang/docker.lua b/nvim/lua/plugins/lang/docker.lua
new file mode 100644 (file)
index 0000000..e375fa4
--- /dev/null
@@ -0,0 +1,38 @@
+return {
+  {
+    "nvim-treesitter/nvim-treesitter",
+    opts = { ensure_installed = { "dockerfile" } },
+  },
+  {
+    "mason.nvim",
+    opts = { ensure_installed = { "hadolint" } },
+  },
+  {
+    "nvimtools/none-ls.nvim",
+    optional = true,
+    opts = function(_, opts)
+      local nls = require("null-ls")
+      opts.sources = vim.list_extend(opts.sources or {}, {
+        nls.builtins.diagnostics.hadolint,
+      })
+    end,
+  },
+  {
+    "mfussenegger/nvim-lint",
+    optional = true,
+    opts = {
+      linters_by_ft = {
+        dockerfile = { "hadolint" },
+      },
+    },
+  },
+  {
+    "neovim/nvim-lspconfig",
+    opts = {
+      servers = {
+        dockerls = {},
+        docker_compose_language_service = {},
+      },
+    },
+  },
+}
diff --git a/nvim/lua/plugins/lang/git.lua b/nvim/lua/plugins/lang/git.lua
new file mode 100644 (file)
index 0000000..a45d4da
--- /dev/null
@@ -0,0 +1,19 @@
+return {
+  -- Treesitter git support
+  { "nvim-treesitter/nvim-treesitter",
+    opts = { ensure_installed = { "git_config", "gitcommit", "git_rebase", "gitignore", "gitattributes" } },
+  },
+
+  {
+    "hrsh7th/nvim-cmp",
+    optional = true,
+    dependencies = {
+      { "petertriho/cmp-git", opts = {} },
+    },
+    ---@module 'cmp'
+    ---@param opts cmp.ConfigSchema
+    opts = function(_, opts)
+      table.insert(opts.sources, { name = "git" })
+    end,
+  },
+}
diff --git a/nvim/lua/plugins/lang/go.lua b/nvim/lua/plugins/lang/go.lua
new file mode 100644 (file)
index 0000000..d63a201
--- /dev/null
@@ -0,0 +1,147 @@
+return {
+  {
+    "nvim-treesitter/nvim-treesitter",
+    opts = { ensure_installed = { "go", "gomod", "gowork", "gosum" } },
+  },
+  {
+    "neovim/nvim-lspconfig",
+    opts = {
+      servers = {
+        gopls = {
+          settings = {
+            gopls = {
+              gofumpt = true,
+              codelenses = {
+                gc_details = false,
+                generate = true,
+                regenerate_cgo = true,
+                run_govulncheck = true,
+                test = true,
+                tidy = true,
+                upgrade_dependency = true,
+                vendor = true,
+              },
+              hints = {
+                assignVariableTypes = true,
+                compositeLiteralFields = true,
+                compositeLiteralTypes = true,
+                constantValues = true,
+                functionTypeParameters = true,
+                parameterNames = true,
+                rangeVariableTypes = true,
+              },
+              analyses = {
+                fieldalignment = true,
+                nilness = true,
+                unusedparams = true,
+                unusedwrite = true,
+                useany = true,
+              },
+              usePlaceholders = true,
+              completeUnimported = true,
+              staticcheck = true,
+              directoryFilters = { "-.git", "-.vscode", "-.idea", "-.vscode-test", "-node_modules" },
+              semanticTokens = true,
+            },
+          },
+        },
+      },
+      setup = {
+        gopls = function(_, opts)
+          -- workaround for gopls not supporting semanticTokensProvider
+          -- https://github.com/golang/go/issues/54531#issuecomment-1464982242
+          rmz.lsp.on_attach(function(client, _)
+            if not client.server_capabilities.semanticTokensProvider then
+              local semantic = client.config.capabilities.textDocument.semanticTokens
+              client.server_capabilities.semanticTokensProvider = {
+                full = true,
+                legend = {
+                  tokenTypes = semantic.tokenTypes,
+                  tokenModifiers = semantic.tokenModifiers,
+                },
+                range = true,
+              }
+            end
+          end, "gopls")
+          -- end workaround
+        end,
+      },
+    },
+  },
+  -- Ensure Go tools are installed
+  {
+    "williamboman/mason.nvim",
+    opts = { ensure_installed = { "goimports", "gofumpt" } },
+  },
+  {
+    "nvimtools/none-ls.nvim",
+    optional = true,
+    dependencies = {
+      {
+        "williamboman/mason.nvim",
+        opts = { ensure_installed = { "gomodifytags", "impl" } },
+      },
+    },
+    opts = function(_, opts)
+      local nls = require("null-ls")
+      opts.sources = vim.list_extend(opts.sources or {}, {
+        nls.builtins.code_actions.gomodifytags,
+        nls.builtins.code_actions.impl,
+        nls.builtins.formatting.goimports,
+        nls.builtins.formatting.gofumpt,
+      })
+    end,
+  },
+  {
+    "stevearc/conform.nvim",
+    optional = true,
+    opts = {
+      formatters_by_ft = {
+        go = { "goimports", "gofumpt" },
+      },
+    },
+  },
+  {
+    "mfussenegger/nvim-dap",
+    optional = true,
+    dependencies = {
+      {
+        "williamboman/mason.nvim",
+        opts = { ensure_installed = { "delve" } },
+      },
+      {
+        "leoluz/nvim-dap-go",
+        opts = {},
+      },
+    },
+  },
+  {
+    "nvim-neotest/neotest",
+    optional = true,
+    dependencies = {
+      "fredrikaverpil/neotest-golang",
+    },
+    opts = {
+      adapters = {
+        ["neotest-golang"] = {
+          -- Here we can set options for neotest-golang, e.g.
+          -- go_test_args = { "-v", "-race", "-count=1", "-timeout=60s" },
+          dap_go_enabled = true, -- requires leoluz/nvim-dap-go
+        },
+      },
+    },
+  },
+
+  -- Filetype icons
+  {
+    "echasnovski/mini.icons",
+    opts = {
+      file = {
+        [".go-version"] = { glyph = "", hl = "MiniIconsBlue" },
+      },
+      filetype = {
+        gotmpl = { glyph = "󰟓", hl = "MiniIconsGrey" },
+      },
+    },
+  },
+}
diff --git a/nvim/lua/plugins/lang/haskell.lua b/nvim/lua/plugins/lang/haskell.lua
new file mode 100644 (file)
index 0000000..b1c67ff
--- /dev/null
@@ -0,0 +1,89 @@
+return {
+
+  -- Add Haskell to treesitter
+  {
+    "nvim-treesitter/nvim-treesitter",
+    opts = { ensure_installed = { "haskell" } },
+  },
+
+  {
+    "mrcjkb/haskell-tools.nvim",
+    version = "^3",
+    ft = { "haskell", "lhaskell", "cabal", "cabalproject" },
+    dependencies = {
+      { "nvim-telescope/telescope.nvim", optional = true },
+    },
+    config = function()
+      local ok, telescope = pcall(require, "telescope")
+      if ok then
+        telescope.load_extension("ht")
+      end
+    end,
+  },
+
+  {
+    "williamboman/mason.nvim",
+    opts = { ensure_installed = { "haskell-language-server" } },
+  },
+
+  {
+    "mfussenegger/nvim-dap",
+    optional = true,
+    dependencies = {
+      {
+        "williamboman/mason.nvim",
+        opts = { ensure_installed = { "haskell-debug-adapter" } },
+      },
+    },
+  },
+
+  {
+    "nvim-neotest/neotest",
+    optional = true,
+    dependencies = {
+      { "mrcjkb/neotest-haskell" },
+    },
+    opts = {
+      adapters = {
+        ["neotest-haskell"] = {},
+      },
+    },
+  },
+
+  {
+    "mrcjkb/haskell-snippets.nvim",
+    dependencies = { "l3mon4d3/luasnip" },
+    ft = { "haskell", "lhaskell", "cabal", "cabalproject" },
+    config = function()
+      local haskell_snippets = require("haskell-snippets").all
+      require("luasnip").add_snippets("haskell", haskell_snippets, { key = "haskell" })
+    end,
+  },
+
+  {
+    "luc-tielen/telescope_hoogle",
+    ft = { "haskell", "lhaskell", "cabal", "cabalproject" },
+    dependencies = {
+      { "nvim-telescope/telescope.nvim" },
+    },
+    config = function()
+      local ok, telescope = pcall(require, "telescope")
+      if ok then
+        telescope.load_extension("hoogle")
+      end
+    end,
+  },
+
+  -- Make sure lspconfig doesn't start hls,
+  -- as it conflicts with haskell-tools
+  {
+    "neovim/nvim-lspconfig",
+    opts = {
+      setup = {
+        hls = function()
+          return true
+        end,
+      },
+    },
+  },
+}
diff --git a/nvim/lua/plugins/lang/json.lua b/nvim/lua/plugins/lang/json.lua
new file mode 100644 (file)
index 0000000..88acd8c
--- /dev/null
@@ -0,0 +1,39 @@
+return {
+  -- add json to treesitter
+  {
+    "nvim-treesitter/nvim-treesitter",
+    opts = { ensure_installed = { "json5" } },
+  },
+
+  -- yaml schema support
+  {
+    "b0o/SchemaStore.nvim",
+    lazy = true,
+    version = false, -- last release is way too old
+  },
+
+  -- correctly setup lspconfig
+  {
+    "neovim/nvim-lspconfig",
+    opts = {
+      -- make sure mason installs the server
+      servers = {
+        jsonls = {
+          -- lazy-load schemastore when needed
+          on_new_config = function(new_config)
+            new_config.settings.json.schemas = new_config.settings.json.schemas or {}
+            vim.list_extend(new_config.settings.json.schemas, require("schemastore").json.schemas())
+          end,
+          settings = {
+            json = {
+              format = {
+                enable = true,
+              },
+              validate = { enable = true },
+            },
+          },
+        },
+      },
+    },
+  },
+}
diff --git a/nvim/lua/plugins/lang/markdown.lua b/nvim/lua/plugins/lang/markdown.lua
new file mode 100644 (file)
index 0000000..a4862e3
--- /dev/null
@@ -0,0 +1,119 @@
+return {
+  {
+    "stevearc/conform.nvim",
+    optional = true,
+    opts = {
+      formatters = {
+        ["markdown-toc"] = {
+          condition = function(_, ctx)
+            for _, line in ipairs(vim.api.nvim_buf_get_lines(ctx.buf, 0, -1, false)) do
+              if line:find("<!%-%- toc %-%->") then
+                return true
+              end
+            end
+          end,
+        },
+        ["markdownlint-cli2"] = {
+          condition = function(_, ctx)
+            local diag = vim.tbl_filter(function(d)
+              return d.source == "markdownlint"
+            end, vim.diagnostic.get(ctx.buf))
+            return #diag > 0
+          end,
+        },
+      },
+      formatters_by_ft = {
+        ["markdown"] = { "prettier", "markdownlint-cli2", "markdown-toc" },
+        ["markdown.mdx"] = { "prettier", "markdownlint-cli2", "markdown-toc" },
+      },
+    },
+  },
+  {
+    "williamboman/mason.nvim",
+    opts = { ensure_installed = { "markdownlint-cli2", "markdown-toc" } },
+  },
+  {
+    "nvimtools/none-ls.nvim",
+    optional = true,
+    opts = function(_, opts)
+      local nls = require("null-ls")
+      opts.sources = vim.list_extend(opts.sources or {}, {
+        nls.builtins.diagnostics.markdownlint_cli2,
+      })
+    end,
+  },
+  {
+    "mfussenegger/nvim-lint",
+    optional = true,
+    opts = {
+      linters_by_ft = {
+        markdown = { "markdownlint-cli2" },
+      },
+    },
+  },
+  {
+    "neovim/nvim-lspconfig",
+    opts = {
+      servers = {
+        marksman = {},
+      },
+    },
+  },
+
+  -- Markdown preview
+  {
+    "iamcco/markdown-preview.nvim",
+    cmd = { "MarkdownPreviewToggle", "MarkdownPreview", "MarkdownPreviewStop" },
+    build = function()
+      require("lazy").load({ plugins = { "markdown-preview.nvim" } })
+      vim.fn["mkdp#util#install"]()
+    end,
+    keys = {
+      {
+        "<leader>cp",
+        ft = "markdown",
+        "<cmd>MarkdownPreviewToggle<cr>",
+        desc = "Markdown Preview",
+      },
+    },
+    config = function()
+      vim.cmd([[do FileType]])
+    end,
+  },
+
+  {
+    "MeanderingProgrammer/render-markdown.nvim",
+    opts = {
+      code = {
+        sign = false,
+        width = "block",
+        right_pad = 1,
+      },
+      heading = {
+        sign = false,
+        icons = {},
+      },
+      checkbox = {
+        enabled = false,
+      },
+    },
+    ft = { "markdown", "norg", "rmd", "org", "codecompanion" },
+    config = function(_, opts)
+      require("render-markdown").setup(opts)
+      Snacks.toggle({
+        name = "Render Markdown",
+        get = function()
+          return require("render-markdown.state").enabled
+        end,
+        set = function(enabled)
+          local m = require("render-markdown")
+          if enabled then
+            m.enable()
+          else
+            m.disable()
+          end
+        end,
+      }):map("<leader>um")
+    end,
+  },
+}
diff --git a/nvim/lua/plugins/lang/nix.lua b/nvim/lua/plugins/lang/nix.lua
new file mode 100644 (file)
index 0000000..e524602
--- /dev/null
@@ -0,0 +1,19 @@
+return {
+  { "nvim-treesitter/nvim-treesitter",
+    opts = { ensure_installed = { "nix" } },
+  },
+  { "neovim/nvim-lspconfig",
+    opts = {
+      servers = {
+        -- nil_ls = {},  -- FIXME: this causes big CPU usage when tried to be installed and eventually just fails
+      },
+    },
+  },
+  { "stevearc/conform.nvim",
+    opts = {
+      formatters_by_ft = {
+        nix = { "nixfmt" },
+      },
+    },
+  },
+}
diff --git a/nvim/lua/plugins/lang/nlua.lua b/nvim/lua/plugins/lang/nlua.lua
new file mode 100644 (file)
index 0000000..f604b6f
--- /dev/null
@@ -0,0 +1,42 @@
+return {
+  "mfussenegger/nvim-dap",
+  dependencies = {
+    {
+      "jbyuki/one-small-step-for-vimkind",
+      config = function()
+        local dap = require("dap")
+        dap.adapters.nlua = function(callback, conf)
+          local adapter = {
+            type = "server",
+            host = conf.host or "127.0.0.1",
+            port = conf.port or 8086,
+          }
+          if conf.start_neovim then
+            local dap_run = dap.run
+            dap.run = function(c)
+              adapter.port = c.port
+              adapter.host = c.host
+            end
+            require("osv").run_this()
+            dap.run = dap_run
+          end
+          callback(adapter)
+        end
+        dap.configurations.lua = {
+          {
+            type = "nlua",
+            request = "attach",
+            name = "Run this file",
+            start_neovim = {},
+          },
+          {
+            type = "nlua",
+            request = "attach",
+            name = "Attach to running Neovim instance (port = 8086)",
+            port = 8086,
+          },
+        }
+      end,
+    },
+  },
+}
index 899bfb36cdf3da4d9439017f7d0d179576289a1c..09ee671ab8249e474acb4fe06cf090a642100c2c 100644 (file)
@@ -1,65 +1,46 @@
 return {
-  {
-    "nvim-treesitter/nvim-treesitter",
-    opts = function(_, opts)
-      if type(opts.ensure_installed) == "table" then
-        vim.list_extend(opts.ensure_installed, { "ninja", "python", "rst", "toml" })
-      end
-    end,
+  { "nvim-treesitter/nvim-treesitter",
+    opts = { ensure_installed = { "ninja", "rst" } },
   },
-  {
-    "neovim/nvim-lspconfig",
+  { "neovim/nvim-lspconfig",
     opts = {
-      ---@type lspconfig.options
       servers = {
-        pyright = {},
         ruff = {
-          root_dir = function(fname)
-            return require("lspconfig.util").root_pattern("pyproject.toml", "setup.cfg", "ruff.toml")(fname)
-          end,
+          cmd_env = { RUFF_TRACE = "messages" },
+          init_options = {
+            settings = {
+              logLevel = "error",
+            },
+          },
           keys = {
             {
               "<leader>co",
-              function()
-                vim.lsp.buf.code_action({
-                  apply = true,
-                  context = {
-                    only = { "source.organizeImports" },
-                    diagnostics = {},
-                  },
-                })
-              end,
+              rmz.lsp.action["source.organizeImports"],
               desc = "Organize Imports",
             },
           },
         },
-        pylsp = {
-          settings = {
-            pylsp = {
-              plugins = {
-                autopep8 = { enabled = false },
-                flake8 = { enabled = false },
-                mccabe = { enabled = false },
-                pycodestyle = { enabled = false },
-                pydocstyle = { enabled = false },
-                pyflakes = { enabled = false },  -- covered by flake8
-              }
-            }
-          }
-        }
       },
       setup = {
-        ruff_lsp = function()
-          require("lazyvim.util").lsp.on_attach(function(client, _)
-            if client.name == "ruff_lsp" then
-              -- Disable hover in favor of Pyright
-              client.server_capabilities.hoverProvider = false
-            end
-          end)
+        ["ruff"] = function()
+          rmz.lsp.on_attach(function(client, _)
+            -- Disable hover in favor of Pyright
+            client.server_capabilities.hoverProvider = false
+          end, "ruff")
         end,
       },
     },
   },
+  {
+    "neovim/nvim-lspconfig",
+    opts = function(_, opts)
+      local servers = { "pyright", "ruff"}
+      for _, server in ipairs(servers) do
+        opts.servers[server] = opts.servers[server] or {}
+        opts.servers[server].enabled = server == lsp or server == ruff
+      end
+    end,
+  },
   {
     "nvim-neotest/neotest",
     dependencies = {
@@ -76,7 +57,6 @@ return {
     "mfussenegger/nvim-dap",
     dependencies = {
       "mfussenegger/nvim-dap-python",
-      -- stylua: ignore
       keys = {
         { "<leader>dPt", function() require('dap-python').test_method() end, desc = "Debug Method", ft = "python" },
         { "<leader>dPc", function() require('dap-python').test_class() end, desc = "Debug Class", ft = "python" },
@@ -87,22 +67,34 @@ return {
       end,
     },
   },
-  {
-    "linux-cultist/venv-selector.nvim",
+  { "jay-babu/mason-nvim-dap.nvim",
+    opts = {
+      handlers = {
+        python = function() end,
+      },
+      ensure_installed = { "python" },
+    },
+  },
+  { "linux-cultist/venv-selector.nvim", enabled = false,
+    -- TODO needs fd to be installed (I don't know what that is)
+    branch = "regexp", -- Use this branch for the new version
     cmd = "VenvSelect",
-    opts = function(_, opts)
-      if require("lazyvim.util").has("nvim-dap-python") then
-        opts.dap_enabled = true
-      end
-      return vim.tbl_deep_extend("force", opts, {
-        name = {
-          "venv",
-          ".venv",
-          "env",
-          ".env",
+    opts = {
+      settings = {
+        options = {
+          notify_user_on_venv_activation = true,
         },
-      })
+      },
+    },
+    --  Call config for python files and load the cached venv automatically
+    ft = "python",
+    keys = { { "<leader>cv", "<cmd>:VenvSelect<cr>", desc = "Select VirtualEnv", ft = "python" } },
+  },
+  { "hrsh7th/nvim-cmp",
+    optional = true,
+    opts = function(_, opts)
+      opts.auto_brackets = opts.auto_brackets or {}
+      table.insert(opts.auto_brackets, "python")
     end,
-    keys = { { "<leader>cv", "<cmd>:VenvSelect<cr>", desc = "Select VirtualEnv" } },
   },
 }
diff --git a/nvim/lua/plugins/lang/ruby.lua b/nvim/lua/plugins/lang/ruby.lua
new file mode 100644 (file)
index 0000000..d434dcf
--- /dev/null
@@ -0,0 +1,54 @@
+return {
+  { "nvim-treesitter/nvim-treesitter",
+    opts = { ensure_installed = { "ruby" } },
+  },
+  { "neovim/nvim-lspconfig",
+    ---@class PluginLspOpts
+    opts = {
+      ---@type lspconfig.options
+      servers = {
+        ruby_lsp = { enabled = true, },
+        rubocop = { enabled = true, },
+      },
+    },
+  },
+  { "williamboman/mason.nvim",
+    opts = { ensure_installed = { "erb-formatter", "erb-lint" } },
+  },
+  {
+    "mfussenegger/nvim-dap",
+    dependencies = {
+      "suketa/nvim-dap-ruby",
+      config = function()
+        require("dap-ruby").setup()
+      end,
+    },
+  },
+  { "stevearc/conform.nvim",
+    opts = {
+      formatters_by_ft = {
+        ruby = { "rubocop" },
+        eruby = { "erb_format" },
+      },
+    },
+  },
+  { "nvim-neotest/neotest",
+    dependencies = {
+      "olimorris/neotest-rspec",
+    },
+    opts = {
+      adapters = {
+        ["neotest-rspec"] = {
+          -- NOTE: By default neotest-rspec uses the system wide rspec gem instead of the one through bundler
+          -- rspec_cmd = function()
+          --   return vim.tbl_flatten({
+          --     "bundle",
+          --     "exec",
+          --     "rspec",
+          --   })
+          -- end,
+        },
+      },
+    },
+  },
+}
diff --git a/nvim/lua/plugins/lang/rust.lua b/nvim/lua/plugins/lang/rust.lua
new file mode 100644 (file)
index 0000000..97f9718
--- /dev/null
@@ -0,0 +1,117 @@
+return {
+  { "Saecki/crates.nvim",
+    event = { "BufRead Cargo.toml" },
+    opts = {
+      completion = {
+        crates = {
+          enabled = true,
+        },
+      },
+      lsp = {
+        enabled = true,
+        actions = true,
+        completion = true,
+        hover = true,
+      },
+    },
+  },
+  { "nvim-treesitter/nvim-treesitter",
+    opts = { ensure_installed = { "rust", "ron" } },
+  },
+  { "williamboman/mason.nvim",
+    optional = true,
+    opts = function(_, opts)
+      opts.ensure_installed = opts.ensure_installed or {}
+      vim.list_extend(opts.ensure_installed, { "codelldb" })
+    end,
+  },
+  { "mrcjkb/rustaceanvim",
+    version = vim.fn.has("nvim-0.10.0") == 0 and "^4" or false,
+    ft = { "rust" },
+    opts = {
+      server = {
+        on_attach = function(_, bufnr)
+          vim.keymap.set("n", "<leader>cR", function()
+            vim.cmd.RustLsp("codeAction")
+          end, { desc = "Code Action", buffer = bufnr })
+          vim.keymap.set("n", "<leader>dr", function()
+            vim.cmd.RustLsp("debuggables")
+          end, { desc = "Rust Debuggables", buffer = bufnr })
+        end,
+        default_settings = {
+          -- rust-analyzer language server configuration
+          ["rust-analyzer"] = {
+            cargo = {
+              allFeatures = true,
+              loadOutDirsFromCheck = true,
+              buildScripts = {
+                enable = true,
+              },
+            },
+            -- Add clippy lints for Rust if using rust-analyzer
+            checkOnSave = true,
+            -- Enable diagnostics if using rust-analyzer
+            diagnostics = {
+              enable = true,
+            },
+            procMacro = {
+              enable = true,
+              ignored = {
+                ["async-trait"] = { "async_trait" },
+                ["napi-derive"] = { "napi" },
+                ["async-recursion"] = { "async_recursion" },
+              },
+            },
+            files = {
+              excludeDirs = {
+                ".direnv",
+                ".git",
+                ".github",
+                ".gitlab",
+                "bin",
+                "node_modules",
+                "target",
+                "venv",
+                ".venv",
+              },
+            },
+          },
+        },
+      },
+    },
+    config = function(_, opts)
+      local package_path = require("mason-registry").get_package("codelldb"):get_install_path()
+      local codelldb = package_path .. "/extension/adapter/codelldb"
+      local library_path = package_path .. "/extension/lldb/lib/liblldb.dylib"
+      local uname = io.popen("uname"):read("*l")
+      if uname == "Linux" then
+        library_path = package_path .. "/extension/lldb/lib/liblldb.so"
+      end
+      opts.dap = {
+        adapter = require("rustaceanvim.config").get_codelldb_adapter(codelldb, library_path),
+      }
+      vim.g.rustaceanvim = vim.tbl_deep_extend("keep", vim.g.rustaceanvim or {}, opts or {})
+      if vim.fn.executable("rust-analyzer") == 0 then
+        rmz.lazy.error(
+          "**rust-analyzer** not found in PATH, please install it.\nhttps://rust-analyzer.github.io/",
+          { title = "rustaceanvim" }
+        )
+      end
+    end,
+  },
+  { "neovim/nvim-lspconfig",
+    opts = {
+      servers = {
+        rust_analyzer = { enabled = false },  -- rustaceanvim is used instead
+      },
+    },
+  },
+  { "nvim-neotest/neotest",
+    optional = true,
+    opts = {
+      adapters = {
+        ["rustaceanvim.neotest"] = {},
+      },
+    },
+  },
+}
diff --git a/nvim/lua/plugins/lang/tex.lua b/nvim/lua/plugins/lang/tex.lua
new file mode 100644 (file)
index 0000000..0d0fdb4
--- /dev/null
@@ -0,0 +1,44 @@
+return {
+  -- Add BibTeX/LaTeX to treesitter
+  {
+    "nvim-treesitter/nvim-treesitter",
+    opts = function(_, opts)
+      opts.highlight = opts.highlight or {}
+      if type(opts.ensure_installed) == "table" then
+        vim.list_extend(opts.ensure_installed, { "bibtex" })
+      end
+      if type(opts.highlight.disable) == "table" then
+        vim.list_extend(opts.highlight.disable, { "latex" })
+      else
+        opts.highlight.disable = { "latex" }
+      end
+    end,
+  },
+
+  {
+    "lervag/vimtex",
+    lazy = false, -- lazy-loading will disable inverse search
+    config = function()
+      vim.g.vimtex_mappings_disable = { ["n"] = { "K" } } -- disable `K` as it conflicts with LSP hover
+      vim.g.vimtex_quickfix_method = vim.fn.executable("pplatex") == 1 and "pplatex" or "latexlog"
+    end,
+    keys = {
+      { "<localLeader>l", "", desc = "+vimtex", ft = "tex" },
+    },
+  },
+
+  -- Correctly setup lspconfig for LaTeX 🚀
+  {
+    "neovim/nvim-lspconfig",
+    optional = true,
+    opts = {
+      servers = {
+        texlab = {
+          keys = {
+            { "<Leader>K", "<plug>(vimtex-doc-package)", desc = "Vimtex Docs", silent = true },
+          },
+        },
+      },
+    },
+  },
+}
diff --git a/nvim/lua/plugins/lang/toml.lua b/nvim/lua/plugins/lang/toml.lua
new file mode 100644 (file)
index 0000000..9020962
--- /dev/null
@@ -0,0 +1,8 @@
+return {
+  "neovim/nvim-lspconfig",
+  opts = {
+    servers = {
+      taplo = {},
+    },
+  },
+}
diff --git a/nvim/lua/plugins/lang/yaml.lua b/nvim/lua/plugins/lang/yaml.lua
new file mode 100644 (file)
index 0000000..977590f
--- /dev/null
@@ -0,0 +1,64 @@
+return {
+  -- yaml schema support
+  {
+    "b0o/SchemaStore.nvim",
+    lazy = true,
+    version = false, -- last release is way too old
+  },
+
+  -- correctly setup lspconfig
+  {
+    "neovim/nvim-lspconfig",
+    opts = {
+      -- make sure mason installs the server
+      servers = {
+        yamlls = {
+          -- Have to add this for yamlls to understand that we support line folding
+          capabilities = {
+            textDocument = {
+              foldingRange = {
+                dynamicRegistration = false,
+                lineFoldingOnly = true,
+              },
+            },
+          },
+          -- lazy-load schemastore when needed
+          on_new_config = function(new_config)
+            new_config.settings.yaml.schemas = vim.tbl_deep_extend(
+              "force",
+              new_config.settings.yaml.schemas or {},
+              require("schemastore").yaml.schemas()
+            )
+          end,
+          settings = {
+            redhat = { telemetry = { enabled = false } },
+            yaml = {
+              keyOrdering = false,
+              format = {
+                enable = true,
+              },
+              validate = true,
+              schemaStore = {
+                -- Must disable built-in schemaStore support to use
+                -- schemas from SchemaStore.nvim plugin
+                enable = false,
+                -- Avoid TypeError: Cannot read properties of undefined (reading 'length')
+                url = "",
+              },
+            },
+          },
+        },
+      },
+      setup = {
+        yamlls = function()
+          -- Neovim < 0.10 does not have dynamic registration for formatting
+          if vim.fn.has("nvim-0.10") == 0 then
+            rmz.lsp.on_attach(function(client, _)
+              client.server_capabilities.documentFormattingProvider = true
+            end, "yamlls")
+          end
+        end,
+      },
+    },
+  },
+}
diff --git a/nvim/lua/plugins/lint.lua b/nvim/lua/plugins/lint.lua
new file mode 100644 (file)
index 0000000..0184577
--- /dev/null
@@ -0,0 +1,35 @@
+local M = {}
+
+return {
+  { "mfussenegger/nvim-lint",
+    event = { "BufReadPost", "BufNewFile", "BufWritePre" },
+    opts = {
+      -- Event to trigger linters
+      events = { "BufWritePost", "BufReadPost", "InsertLeave" },
+      linters_by_ft = { },
+      -- NOTE: LazyVim had an extension to support global and fallback linters,
+      -- and conditionally enable a linter
+    },
+    config = function(_, opts)
+      function M.debounce(ms, fn)
+        local timer = vim.uv.new_timer()
+        return function(...)
+          local argv = { ... }
+          timer:start(ms, 0, function()
+            timer:stop()
+            vim.schedule_wrap(fn)(unpack(argv))
+          end)
+        end
+      end
+
+      local lint = require('lint')
+      function M.lint()
+        lint.try_lint()
+      end
+      vim.api.nvim_create_autocmd(opts.events, {
+        group = vim.api.nvim_create_augroup("nvim-lint", { clear = true }),
+        callback = M.debounce(100, M.lint),
+      })
+    end,
+  },
+}
diff --git a/nvim/lua/plugins/lsp.lua b/nvim/lua/plugins/lsp.lua
deleted file mode 100644 (file)
index d020443..0000000
+++ /dev/null
@@ -1,123 +0,0 @@
-return {
-  -- lspconfig
-  {
-    "neovim/nvim-lspconfig",
-    ---@class PluginLspOpts
-    opts = function()
-      local keys = require("lazyvim.plugins.lsp.keymaps").get()
-      -- TODO: setup a new mapping for this
-      -- { "gr", "<cmd>Telescope lsp_references<cr>", desc = "References" },
-      keys[#keys+1] = { "gr", false }
-
-      return {
-        diagnostics = {
-          underline = true,
-          update_in_insert = false,
-          virtual_text = {
-            spacing = 4,
-            source = "if_mani",
-            prefix = "●",
-          },
-          severity_sort = true,
-          signs = {
-            text = {
-              [vim.diagnostic.severity.ERROR] = " ",
-              [vim.diagnostic.severity.WARN]  = " ",
-              [vim.diagnostic.severity.HINT]  = " ",
-              [vim.diagnostic.severity.INFO]  = " ",
-            },
-          },
-        },
-        inlay_hints = { enabled = false, },
-        codelens = { enabled = false, },
-        document_highlight = { enabled = true, },
-        capabilities = {
-          workspace = {
-            fileOperations = {
-              didRename = true,
-              willRename = true,
-            },
-          },
-        },
-        format = {
-          formatting_options = nil,
-          timeout_ms = nil,
-        },
-        -- Automatically format on save
-        -- autoformat = false,
-        -- LSP Server Settings
-        ---@type lspconfig.options
-        servers = {
-          lua_ls = {
-            settings = {
-              Lua = {
-                workspace = { checkThirdParty = false, },
-                codeLens = { enable = true, },
-                completion = { callSnippet = "Replace", },
-                doc = { privateName = { "^_" }, },
-                hint = {
-                  enable = true,
-                  setType = false,
-                  paramType = true,
-                  paramName = "Disable",
-                  semicolon = "Disable",
-                  arrayIndex = "Disable",
-                },
-                diagnostics = {
-                  disable = { "missing-fields", },
-                },
-              },
-            },
-          },
-          -- Add clangd extensions
-          -- https://github.com/p00f/clangd_extensions.nvim
-        },
-        -- you can do any additional lsp server setup here
-        -- return true if you don't want this server to be setup with lspconfig
-        ---@type table<string, fun(server:string, opts:_.lspconfig.options):boolean?>
-        setup = {
-          -- example to setup with typescript.nvim
-          -- tsserver = function(_, opts)
-          --   require("typescript").setup({ server = opts })
-          --   return true
-          -- end,
-          -- Specify * to use this function as a fallback for any server
-          -- ["*"] = function(server, opts) end,
-        },
-      }
-    end,
-  },
-
-  -- cmdline tools and lsp servers
-  {
-
-    "williamboman/mason.nvim",
-    cmd = "Mason",
-    keys = { { "<leader>cm", "<cmd>Mason<cr>", desc = "Mason" } },
-    opts = {
-      ensure_installed = {
-        "stylua",
-        "shfmt",
-        -- "flake8",
-      },
-    },
-    ---@param opts MasonSettings | {ensure_installed: string[]}
-    config = function(_, opts)
-      require("mason").setup(opts)
-      local mr = require("mason-registry")
-      local function ensure_installed()
-        for _, tool in ipairs(opts.ensure_installed) do
-          local p = mr.get_package(tool)
-          if not p:is_installed() then
-            p:install()
-          end
-        end
-      end
-      if mr.refresh then
-        mr.refresh(ensure_installed)
-      else
-        ensure_installed()
-      end
-    end,
-  },
-}
diff --git a/nvim/lua/plugins/lsp/init.lua b/nvim/lua/plugins/lsp/init.lua
new file mode 100644 (file)
index 0000000..132c412
--- /dev/null
@@ -0,0 +1,172 @@
+return {
+  { "neovim/nvim-lspconfig",
+    event = { "BufReadPost", "BufNewFile", "BufWritePre" },
+    dependencies = {
+      "mason.nvim",
+      { "williamboman/mason-lspconfig.nvim", config = function() end }, -- don't configure yet
+    },
+    ---@class PluginLspOpts
+    opts = {
+      ---@type vim.diagnostic.Opts
+      diagnostics = {
+        underline = true,
+        update_in_insert = false,
+        virtual_text = {
+          spacing = 4,
+          source = "if_many",
+          prefix = "●",
+        },
+        severity_sort = true,
+        signs = {
+          text = {
+            [vim.diagnostic.severity.ERROR] = " ",
+            [vim.diagnostic.severity.WARN]  = " ",
+            [vim.diagnostic.severity.HINT]  = " ",
+            [vim.diagnostic.severity.INFO]  = " ",
+          },
+        },
+      },
+      inlay_hints = { enabled = false, },
+      codelens = { enabled = false, },
+      document_highlight = { enabled = true, },
+      capabilities = {
+        workspace = {
+          fileOperations = {
+            didRename = true,
+            willRename = true,
+          },
+        },
+      },
+      format = {
+        formatting_options = nil,
+        timeout_ms = nil,
+      },
+      -- LSP Server Settings
+      ---@type lspconfig.options
+      servers = {
+        lua_ls = {
+          settings = {
+            Lua = {
+              workspace = { checkThirdParty = false, },
+              codeLens = { enable = true, },
+              completion = { callSnippet = "Replace", },
+              doc = { privateName = { "^_" }, },
+              hint = {
+                enable = true,
+                setType = false,
+                paramType = true,
+                paramName = "Disable",
+                semicolon = "Disable",
+                arrayIndex = "Disable",
+              },
+              diagnostics = {
+                disable = { "missing-fields", },
+              },
+            },
+          },
+        },
+        -- TODO: Add clangd extensions
+        -- https://github.com/p00f/clangd_extensions.nvim
+      },
+      -- you can do any additional lsp server setup here
+      -- return true if you don't want this server to be setup with lspconfig
+      ---@type table<string, fun(server:string, opts:_.lspconfig.options):boolean?>
+      setup = {
+        -- example to setup with typescript.nvim
+        -- tsserver = function(_, opts)
+        --   require("typescript").setup({ server = opts })
+        --   return true
+        -- end,
+        -- Specify * to use this function as a fallback for any server
+        -- ["*"] = function(server, opts) end,
+      },
+    },
+    ---@param opts PluginLspOpts
+    config = function(_, opts)
+      local lspconfig = require('lspconfig')
+      for server, config in pairs(opts.servers) do
+        local capabilities = vim.tbl_deep_extend("force",
+          vim.lsp.protocol.make_client_capabilities() or {},
+          require('blink.cmp').get_lsp_capabilities() or {},
+          config.capabilities or {}
+        )
+        config.capabilities = capabilities
+        lspconfig[server].setup(config)
+      end
+
+      -- setup keymaps
+      rmz.lsp.on_attach(function(client, buffer)
+        require("plugins.lsp.keymaps").on_attach(client, buffer)
+      end)
+
+      rmz.lsp.setup()
+      rmz.lsp.on_dynamic_capability(require("plugins.lsp.keymaps").on_attach)
+      -- TODO: should vim.diagnostics be condigured directly?
+      vim.diagnostic.config(vim.deepcopy(opts.diagnostics))
+
+      -- get all the servers that are available through mason-lspconfig
+      local mlsp = require("mason-lspconfig")
+      -- TODO: use mason-lspconfig.get_available_servers()?
+      local all_mslp_servers = vim.tbl_keys(require("mason-lspconfig.mappings.server").lspconfig_to_package)
+
+      local ensure_installed = {} ---@type string[]
+      for server, server_opts in pairs(opts.servers) do
+        if server_opts then
+          server_opts = server_opts == true and {} or server_opts
+          if server_opts.enabled ~= false then
+            -- run manual setup if mason=false or if this is a server that cannot be installed with mason-lspconfig
+            if server_opts.mason == false or not vim.tbl_contains(all_mslp_servers, server) then
+              require("lspconfig")[server].setup(server_opts)
+            else
+              ensure_installed[#ensure_installed + 1] = server
+            end
+          end
+        end
+      end
+
+      mlsp.setup({
+        ensure_installed = vim.tbl_deep_extend(
+          "force",
+          ensure_installed,
+          rmz.lazy.opts("mason-lspconfig.nvim").ensure_installed or {}
+        ),
+        handlers = { setup },
+      })
+    end
+  },
+  { "williamboman/mason.nvim",
+    cmd = "Mason",
+    keys = { { "<leader>cm", "<cmd>Mason<cr>", desc = "Mason" } },
+    build = ":MasonUpdate",
+    opts_extend = { "ensure_installed" },
+    opts = {
+      ensure_installed = {
+        "stylua",
+        "shfmt",
+      },
+    },
+    ---@param opts MasonSettings | {ensure_installed: string[]}
+    config = function(_, opts)
+      require("mason").setup(opts)
+      local mr = require("mason-registry")
+      mr:on("package:install:success", function()
+        vim.defer_fn(function()
+          -- trigger FileType event to possibly load this newly installed LSP server
+          require("lazy.core.handler.event").trigger({
+            event = "FileType",
+            buf = vim.api.nvim_get_current_buf(),
+          })
+        end, 100)
+      end)
+
+      mr.refresh(function()
+        for _, tool in ipairs(opts.ensure_installed) do
+          local p = mr.get_package(tool)
+          if not p:is_installed() then
+            p:install()
+          end
+        end
+      end)
+    end,
+  },
+}
diff --git a/nvim/lua/plugins/lsp/keymaps.lua b/nvim/lua/plugins/lsp/keymaps.lua
new file mode 100644 (file)
index 0000000..42e210b
--- /dev/null
@@ -0,0 +1,99 @@
+local M = {}
+
+---@type LazyKeysLspSpec[]|nil
+M._keys = nil
+
+---@alias LazyKeysLspSpec LazyKeysSpec|{has?:string|string[], cond?:fun():boolean}
+---@alias LazyKeysLsp LazyKeys|{has?:string|string[], cond?:fun():boolean}
+
+---@return LazyKeysLspSpec[]
+function M.get()
+  if M._keys then
+    return M._keys
+  end
+    -- stylua: ignore
+    M._keys =  {
+      { "<leader>cl", "<cmd>LspInfo<cr>", desc = "Lsp Info" },
+      { "gd", vim.lsp.buf.definition, desc = "Goto Definition", has = "definition" },
+      -- { "gr", vim.lsp.buf.references, desc = "References", nowait = true },
+      { "gI", vim.lsp.buf.implementation, desc = "Goto Implementation" },
+      { "gy", vim.lsp.buf.type_definition, desc = "Goto T[y]pe Definition" },
+      { "gD", vim.lsp.buf.declaration, desc = "Goto Declaration" },
+      { "K", function() return vim.lsp.buf.hover() end, desc = "Hover" },
+      { "gK", function() return vim.lsp.buf.signature_help() end, desc = "Signature Help", has = "signatureHelp" },
+      { "<c-k>", function() return vim.lsp.buf.signature_help() end, mode = "i", desc = "Signature Help", has = "signatureHelp" },
+      { "<leader>ca", vim.lsp.buf.code_action, desc = "Code Action", mode = { "n", "v" }, has = "codeAction" },
+      { "<leader>cc", vim.lsp.codelens.run, desc = "Run Codelens", mode = { "n", "v" }, has = "codeLens" },
+      { "<leader>cC", vim.lsp.codelens.refresh, desc = "Refresh & Display Codelens", mode = { "n" }, has = "codeLens" },
+      { "<leader>cR", function() Snacks.rename.rename_file() end, desc = "Rename File", mode ={"n"}, has = { "workspace/didRenameFiles", "workspace/willRenameFiles" } },
+      { "<leader>cr", vim.lsp.buf.rename, desc = "Rename", has = "rename" },
+      { "<leader>cA", rmz.lsp.action.source, desc = "Source Action", has = "codeAction" },
+      { "]]", function() Snacks.words.jump(vim.v.count1) end, has = "documentHighlight",
+        desc = "Next Reference", cond = function() return Snacks.words.is_enabled() end },
+      { "[[", function() Snacks.words.jump(-vim.v.count1) end, has = "documentHighlight",
+        desc = "Prev Reference", cond = function() return Snacks.words.is_enabled() end },
+      { "<a-n>", function() Snacks.words.jump(vim.v.count1, true) end, has = "documentHighlight",
+        desc = "Next Reference", cond = function() return Snacks.words.is_enabled() end },
+      { "<a-p>", function() Snacks.words.jump(-vim.v.count1, true) end, has = "documentHighlight",
+        desc = "Prev Reference", cond = function() return Snacks.words.is_enabled() end },
+    }
+
+  return M._keys
+end
+
+---@param method string|string[]
+function M.has(buffer, method)
+  if type(method) == "table" then
+    for _, m in ipairs(method) do
+      if M.has(buffer, m) then
+        return true
+      end
+    end
+    return false
+  end
+  method = method:find("/") and method or "textDocument/" .. method
+  local clients = rmz.lsp.get_clients({ bufnr = buffer })
+  for _, client in ipairs(clients) do
+    if client.supports_method(method) then
+      return true
+    end
+  end
+  return false
+end
+
+---@return LazyKeysLsp[]
+function M.resolve(buffer)
+  local Keys = require("lazy.core.handler.keys")
+  if not Keys.resolve then
+    return {}
+  end
+  local spec = vim.tbl_extend("force", {}, M.get())
+  local opts = rmz.lazy.opts("nvim-lspconfig")
+  local clients = rmz.lsp.get_clients({ bufnr = buffer })
+  for _, client in ipairs(clients) do
+    local maps = opts.servers[client.name] and opts.servers[client.name].keys or {}
+    vim.list_extend(spec, maps)
+  end
+  return Keys.resolve(spec)
+end
+
+function M.on_attach(_, buffer)
+  local Keys = require("lazy.core.handler.keys")
+  local keymaps = M.resolve(buffer)
+
+  for _, keys in pairs(keymaps) do
+    local has = not keys.has or M.has(buffer, keys.has)
+    local cond = not (keys.cond == false or ((type(keys.cond) == "function") and not keys.cond()))
+
+    if has and cond then
+      local opts = Keys.opts(keys)
+      opts.cond = nil
+      opts.has = nil
+      opts.silent = opts.silent ~= false
+      opts.buffer = buffer
+      vim.keymap.set(keys.mode or "n", keys.lhs, keys.rhs, opts)
+    end
+  end
+end
+
+return M
diff --git a/nvim/lua/plugins/nvim-treesitter.lua b/nvim/lua/plugins/nvim-treesitter.lua
deleted file mode 100644 (file)
index 8b87f09..0000000
+++ /dev/null
@@ -1,23 +0,0 @@
-return {
-  -- add more treesitter parsers
-  {
-    "nvim-treesitter/nvim-treesitter",
-    opts = {
-      -- overwrites the settings from LazyVim
-      ensure_installed = {
-        "bash",
-        "c",
-        "html",
-        "json",
-        "lua",
-        "markdown",
-        "markdown_inline",
-        "python",
-        "regex",
-        "vim",
-        "vimdoc",
-        "yaml",
-      },
-    },
-  },
-}
diff --git a/nvim/lua/plugins/picker.lua b/nvim/lua/plugins/picker.lua
new file mode 100644 (file)
index 0000000..3878e03
--- /dev/null
@@ -0,0 +1,128 @@
+---@type LazySpec
+return {
+  desc = "Fast and modern file picker",
+  { "folke/snacks.nvim",
+    opts = {
+      picker = {
+        win = {
+          input = {
+            keys = {
+              ["<c-t>"] = { "trouble_open", mode = { "n", "i" }, },
+            },
+          },
+        },
+        actions = {
+          actions = require("trouble.sources.snacks").actions,
+        },
+      },
+    },
+    -- stylua: ignore
+    keys = {
+      { "<leader>,", function() Snacks.picker.buffers() end, desc = "Buffers" },
+      { "<leader>/", function() Snacks.picker.grep() end, desc = "Grep" },
+      { "<leader>:", function() Snacks.picker.command_history() end, desc = "Command History" },
+      { "<leader>n", function() Snacks.picker.notifications() end, desc = "Notification History" },
+      -- find
+      { "<leader>fb", function() Snacks.picker.buffers() end, desc = "Buffers" },
+      { "<leader>fB", function() Snacks.picker.buffers({ hidden = true, nofile = true }) end, desc = "Buffers (all)" },
+      { "<leader>fc", function() Snacks.picker.files({ cwd = vim.fn.stdpath("config") }) end, desc = "Find Config File" },
+      { "<leader>fF", function() Snacks.picker.files() end, desc = "Find Files" },
+      { "<leader>fg", function() Snacks.picker.git_files() end, desc = "Find Files (git-files)" },
+      -- TODO: swap fr and fR ?
+      { "<leader>fr", function() Snacks.picker.recent() end, desc = "Recent" },
+      { "<leader>fR", function() Snacks.picker.recent({ filter = { cwd = true }}) end, desc = "Recent (cwd)" },
+      { "<leader>fp", function() Snacks.picker.projects() end, desc = "Projects" },
+      -- git
+      -- { "<leader>gc", function() Snacks.picker.git_log() end, desc = "Git Log" },
+      -- { "<leader>gd", function() Snacks.picker.git_diff() end, desc = "Git Diff (hunks)" },
+      -- { "<leader>gs", function() Snacks.picker.git_status() end, desc = "Git Status" },
+      -- Grep
+      { "<leader>sb", function() Snacks.picker.lines() end, desc = "Buffer Lines" },
+      { "<leader>sB", function() Snacks.picker.grep_buffers() end, desc = "Grep Open Buffers" },
+      { "<leader>sg", function() Snacks.picker.grep() end, desc = "Grep" },
+      { "<leader>sp", function() Snacks.picker.lazy() end, desc = "Search for Plugin Spec" },
+      { "<leader>sw", function() Snacks.picker.grep_word() end, desc = "Visual selection or word", mode = { "n", "x" } },
+      -- search
+      { '<leader>s"', function() Snacks.picker.registers() end, desc = "Registers" },
+      { "<leader>sa", function() Snacks.picker.autocmds() end, desc = "Autocmds" },
+      { "<leader>sc", function() Snacks.picker.command_history() end, desc = "Command History" },
+      { "<leader>sC", function() Snacks.picker.commands() end, desc = "Commands" },
+      { "<leader>sd", function() Snacks.picker.diagnostics() end, desc = "Diagnostics" },
+      { "<leader>sh", function() Snacks.picker.help() end, desc = "Help Pages" },
+      { "<leader>sH", function() Snacks.picker.highlights() end, desc = "Highlights" },
+      { "<leader>si", function() Snacks.picker.icons() end, desc = "Icons" },
+      { "<leader>sj", function() Snacks.picker.jumps() end, desc = "Jumps" },
+      { "<leader>sk", function() Snacks.picker.keymaps() end, desc = "Keymaps" },
+      { "<leader>sl", function() Snacks.picker.loclist() end, desc = "Location List" },
+      { "<leader>sM", function() Snacks.picker.man() end, desc = "Man Pages" },
+      { "<leader>sm", function() Snacks.picker.marks() end, desc = "Marks" },
+      { "<leader>sR", function() Snacks.picker.resume() end, desc = "Resume" },
+      { "<leader>sq", function() Snacks.picker.qflist() end, desc = "Quickfix List" },
+      { "<leader>su", function() Snacks.picker.undo() end, desc = "Undotree" },
+      -- ui
+      { "<leader>uC", function() Snacks.picker.colorschemes() end, desc = "Colorschemes" },
+    },
+  },
+  { "neovim/nvim-lspconfig",
+    opts = function()
+      local Keys = require("plugins.lsp.keymaps").get()
+      -- stylua: ignore
+      vim.list_extend(Keys, {
+        { "gd", function() Snacks.picker.lsp_definitions() end, desc = "Goto Definition", has = "definition" },
+        -- { "gr", function() Snacks.picker.lsp_references() end, nowait = true, desc = "References" },
+        { "gI", function() Snacks.picker.lsp_implementations() end, desc = "Goto Implementation" },
+        { "gy", function() Snacks.picker.lsp_type_definitions() end, desc = "Goto T[y]pe Definition" },
+        { "<leader>ss", function() Snacks.picker.lsp_symbols({ filter = rmz.lsp.kind_filter }) end, desc = "LSP Symbols", has = "documentSymbol" },
+        { "<leader>sS", function() Snacks.picker.lsp_workspace_symbols({ filter = rmz.lsp.kind_filter }) end, desc = "LSP Workspace Symbols", has = "workspace/symbols" },
+      })
+    end,
+  },
+  { "folke/todo-comments.nvim",
+    optional = true,
+    -- stylua: ignore
+    keys = {
+      { "<leader>st", function() Snacks.picker.todo_comments() end, desc = "Todo" },
+      { "<leader>sT", function () Snacks.picker.todo_comments({ keywords = { "TODO", "FIX", "FIXME" } }) end, desc = "Todo/Fix/Fixme" },
+    },
+  },
+  { "folke/flash.nvim",
+    -- TODO: verify if I want to keep this
+    specs = {
+      {
+        "folke/snacks.nvim",
+        opts = {
+          picker = {
+            win = {
+              input = {
+                keys = {
+                  ["<a-s>"] = { "flash", mode = { "n", "i" } },
+                  ["s"] = { "flash" },
+                },
+              },
+            },
+            actions = {
+              flash = function(picker)
+                require("flash").jump({
+                  pattern = "^",
+                  label = { after = { 0, 0 } },
+                  search = {
+                    mode = "search",
+                    exclude = {
+                      function(win)
+                        return vim.bo[vim.api.nvim_win_get_buf(win)].filetype ~= "snacks_picker_list"
+                      end,
+                    },
+                  },
+                  action = function(match)
+                    local idx = picker.list:row2idx(match.pos[1])
+                    picker.list:_move(idx, true, true)
+                  end,
+                })
+              end,
+            },
+          },
+        },
+      },
+    },
+  },
+}
diff --git a/nvim/lua/plugins/snacks.lua b/nvim/lua/plugins/snacks.lua
new file mode 100644 (file)
index 0000000..89eec46
--- /dev/null
@@ -0,0 +1,81 @@
+-- Terminal Mappings
+local function term_nav(dir)
+  ---@param self snacks.terminal
+  return function(self)
+    return self:is_floating() and "<c-" .. dir .. ">" or vim.schedule(function()
+      vim.cmd.wincmd(dir)
+    end)
+  end
+end
+
+return {
+  { "folke/snacks.nvim",
+    -- stylua: ignore
+    keys = {
+      -- Snacks Scratch
+      { "<leader>.",  function() Snacks.scratch() end, desc = "Toggle Scratch Buffer" },
+      { "<leader>S",  function() Snacks.scratch.select() end, desc = "Select Scratch Buffer" },
+      { "<leader>dps", function() Snacks.profiler.scratch() end, desc = "Profiler Scratch Buffer" },
+    },
+    opts = {
+      bigfile = { enabled = true },
+      indent = { enabled = true },
+      input = { enabled = true },  -- NOTE: seems unecessary
+      quickfile = { enabled = true },  -- TODO: review if needed
+      scope = { enabled = true },
+      scroll = { enabled = false },  -- fuck this!
+      statuscolumn = { enabled = true },
+      terminal = {
+        win = {
+          keys = {
+            nav_h = { "<C-h>", term_nav("W"), desc = "Go to Prev Window", expr = true, mode = "t" },
+            nav_j = { "<C-j>", term_nav("j"), desc = "Go to Lower Window", expr = true, mode = "t" },
+            nav_k = { "<C-k>", term_nav("k"), desc = "Go to Upper Window", expr = true, mode = "t" },
+            nav_l = { "<C-l>", term_nav("w"), desc = "Go to Next Window", expr = true, mode = "t" },
+          },
+        },
+      },
+      dashboard = {
+        preset = {
+          -- TODO: replace header
+          header = [[
+          ██╗      █████╗ ██╗   ██╗███████╗██╗   ██╗██╗   ██╗██╗███╗   ███╗          Z
+          ██║     ██╔══██╗██║   ██║╚══███╔╝╚██╗ ██╔╝██║   ██║██║████╗ ████║      Z    
+          ██║     ██║  ██║██║   ██║  ███╔╝  ╚████╔╝ ██║   ██║██║██╔████╔██║   z       
+          ██║     ██║  ██║██║   ██║ ███╔╝    ╚██╔╝  ╚██╗ ██╔╝██║██║╚██╔╝██║ z         
+          ███████╗╚█████╔╝╚██████╔╝███████╗   ██║    ╚████╔╝ ██║██║ ╚═╝ ██║           
+          ╚══════╝ ╚════╝  ╚═════╝ ╚══════╝   ╚═╝     ╚═══╝  ╚═╝╚═╝     ╚═╝           ]],
+          -- stylua: ignore
+          ---@type snacks.dashboard.Item[]
+          keys = {
+            { icon = " ", key = "f", desc = "Find File", action = ":lua Snacks.dashboard.pick('files')" },
+            { icon = " ", key = "n", desc = "New File", action = ":ene | startinsert" },
+            { icon = " ", key = "g", desc = "Find Text", action = ":lua Snacks.dashboard.pick('live_grep')" },
+            { icon = " ", key = "r", desc = "Recent Files", action = ":lua Snacks.dashboard.pick('oldfiles')" },
+            { icon = " ", key = "c", desc = "Config", action = ":lua Snacks.dashboard.pick('files', {cwd = vim.fn.stdpath('config')})" },
+            { icon = " ", key = "s", desc = "Restore Session", section = "session" },
+            { icon = " ", key = "x", desc = "Lazy Extras", action = ":LazyExtras" },
+            { icon = "󰒲 ", key = "l", desc = "Lazy", action = ":Lazy" },
+          },
+        },
+      },
+    },
+  },
+  { "folke/snacks.nvim",
+    opts = {
+      notifier = { enabled = true },
+    },
+    -- stylua: ignore
+    keys = {
+      -- TODO: review after picking picker (ha)
+      { "<leader>n", function()
+        if Snacks.config.picker and Snacks.config.picker.enabled then
+          Snacks.picker.notifications()
+        else
+          Snacks.notifier.show_history()
+        end
+      end, desc = "Notification History" },
+      { "<leader>un", function() Snacks.notifier.hide() end, desc = "Dismiss All Notifications" },
+    },
+  }
+}
index e4bc07c0f9d2bd6af57647bee3d48342a248806e..9ed3fc498be53ff5f5addb2565fbaf400c2ae2f3 100644 (file)
@@ -1,22 +1,15 @@
 return {
-  {
-    "folke/which-key.nvim",
-    opts = {
-      defaults = { ["<leader>t"] = { name = "+test" }, },
-    },
-  },
-  {
-    "nvim-neotest/neotest",
+  { "nvim-neotest/neotest",
+    dependencies = { "nvim-neotest/nvim-nio" },
     opts = {
+      adapters = {},
       status = { virtual_text = true },
       output = { open_on_run = true },
       quickfix = {
         open = function()
-          if require("lazyvim.util").has("trouble.nvim") then
-            require("trouble").open({ mode = "quickfix", focus = false })
-          else
-            vim.cmd("copen")
-          end
+          -- TODO: review if I'd prefer to just use quickfix here
+          --    vim.cmd("copen")
+          require("trouble").open({ mode = "quickfix", focus = false })
         end,
       },
     },
@@ -32,37 +25,36 @@ return {
         },
       }, neotest_ns)
 
-      if require("lazyvim.util").has("trouble.nvim") then
-        opts.consumers = opts.consumers or {}
-        -- Refresh and auto close trouble after running tests
-        ---@type neotest.Consumer
-        opts.consumers.trouble = function(client)
-          client.listeners.results = function(adapter_id, results, partial)
-            if partial then
-              return
-            end
-            local tree = assert(client:get_position(nil, { adapter = adapter_id }))
+      opts.consumers = opts.consumers or {}
+      -- Refresh and auto close trouble after running tests
+      ---@type neotest.Consumer
+      opts.consumers.trouble = function(client)
+        client.listeners.results = function(adapter_id, results, partial)
+          if partial then
+            return
+          end
+          local tree = assert(client:get_position(nil, { adapter = adapter_id }))
 
-            local failed = 0
-            for pos_id, result in pairs(results) do
-              if result.status == "failed" and tree:get_key(pos_id) then
-                failed = failed + 1
-              end
+          local failed = 0
+          for pos_id, result in pairs(results) do
+            if result.status == "failed" and tree:get_key(pos_id) then
+              failed = failed + 1
             end
-            vim.schedule(function()
-              local trouble = require("trouble")
-              if trouble.is_open() then
-                trouble.refresh()
-                if failed == 0 then
-                  trouble.close()
-                end
-              end
-            end)
           end
-          return {}
+          vim.schedule(function()
+            local trouble = require("trouble")
+            if trouble.is_open() then
+              trouble.refresh()
+              if failed == 0 then
+                trouble.close()
+              end
+            end
+          end)
         end
+        return {}
       end
 
+      -- NOTE: support setting up test adapters in lang
       if opts.adapters then
         local adapters = {}
         for name, config in pairs(opts.adapters or {}) do
@@ -77,8 +69,11 @@ return {
               local meta = getmetatable(adapter)
               if adapter.setup then
                 adapter.setup(config)
+              elseif adapter.adapter then
+                adapter.adapter(config)
+                adapter = adapter.adapter
               elseif meta and meta.__call then
-                adapter(config)
+                adapter = adapter(config)
               else
                 error("Adapter " .. name .. " does not support setup")
               end
@@ -93,13 +88,16 @@ return {
     end,
     -- stylua: ignore
     keys = {
+      {"<leader>t", "", desc = "+test"},
       { "<leader>tt", function() require("neotest").run.run(vim.fn.expand("%")) end, desc = "Run File" },
       { "<leader>tT", function() require("neotest").run.run(vim.loop.cwd()) end, desc = "Run All Test Files" },
       { "<leader>tr", function() require("neotest").run.run() end, desc = "Run Nearest" },
+      { "<leader>tl", function() require("neotest").run.run_last() end, desc = "Run Last" },
       { "<leader>ts", function() require("neotest").summary.toggle() end, desc = "Toggle Summary" },
       { "<leader>to", function() require("neotest").output.open({ enter = true, auto_close = true }) end, desc = "Show Output" },
       { "<leader>tO", function() require("neotest").output_panel.toggle() end, desc = "Toggle Output Panel" },
       { "<leader>tS", function() require("neotest").run.stop() end, desc = "Stop" },
+      { "<leader>tw", function() require("neotest").watch.toggle(vim.fn.expand("%")) end, desc = "Toggle Watch" },
     },
   },
   {
diff --git a/nvim/lua/plugins/treesitter.lua b/nvim/lua/plugins/treesitter.lua
new file mode 100644 (file)
index 0000000..5ffa798
--- /dev/null
@@ -0,0 +1,113 @@
+return {
+  { "nvim-treesitter/nvim-treesitter",
+    dependencies = { "nvim-treesitter/nvim-treesitter-textobjects" },
+    build = ":TSUpdate",
+    event = { "BufReadPost", "BufNewFile", "BufWritePre" , "VeryLazy" },
+    lazy = vim.fn.argc(-1) == 0, -- load treesitter early when opening a file from the cmdline
+    init = function(plugin)
+      -- PERF: add nvim-treesitter queries to the rtp and it's custom query predicates early
+      -- This is needed because a bunch of plugins no longer `require("nvim-treesitter")`, which
+      -- no longer trigger the **nvim-treesitter** module to be loaded in time.
+      -- Luckily, the only things that those plugins need are the custom queries, which we make available
+      -- during startup.
+      require("lazy.core.loader").add_to_rtp(plugin)
+      require("nvim-treesitter.query_predicates")
+    end,
+    cmd = { "TSUpdateSync", "TSUpdate", "TSInstall" },
+    keys = {
+      { "<c-space>", desc = "Increment Selection" },
+      { "<bs>", desc = "Decrement Selection", mode = "x" },
+    },
+    opts_extend = { "ensure_installed" },
+    ---@type TSConfig
+    ---@diagnostic disable-next-line: missing-fields
+    opts = {
+      highlight = { enable = true },
+      indent = { enable = true },
+      ensure_installed = {
+        "bash",
+        "c",
+        "diff",
+        "git_config",
+        "git_rebase",
+        "gitattributes",
+        "gitcommit",
+        "gitignore",
+        "html",
+        "javascript",
+        "jsdoc",
+        "json",
+        "jsonc",
+        "lua",
+        "luadoc",
+        "luap",
+        "markdown",
+        "markdown_inline",
+        "printf",
+        "python",
+        "query",
+        "regex",
+        "toml",
+        "tsx",
+        "typescript",
+        "vim",
+        "vimdoc",
+        "xml",
+        "yaml",
+      },
+      incremental_selection = {
+        enable = true,
+        keymaps = {
+          init_selection = "<C-space>",
+          node_incremental = "<C-space>",
+          scope_incremental = false,
+          node_decremental = "<bs>",
+        },
+      },
+      textobjects = {
+        move = {
+          enable = true,
+          goto_next_start = { ["]f"] = "@function.outer", ["]c"] = "@class.outer", ["]a"] = "@parameter.inner" },
+          goto_next_end = { ["]F"] = "@function.outer", ["]C"] = "@class.outer", ["]A"] = "@parameter.inner" },
+          goto_previous_start = { ["[f"] = "@function.outer", ["[c"] = "@class.outer", ["[a"] = "@parameter.inner" },
+          goto_previous_end = { ["[F"] = "@function.outer", ["[C"] = "@class.outer", ["[A"] = "@parameter.inner" },
+        },
+      },
+    },
+    ---@param opts TSConfig
+    config = function(_, opts)
+      -- make sure extra langs are not duplicated
+      opts.ensure_installed = rmz.dedup(opts.ensure_installed)
+
+      local configs = require("nvim-treesitter.configs")
+      configs.setup(opts)
+
+      -- When in diff mode, we want to use the default
+      -- vim text objects c & C instead of the treesitter ones.
+      local move = require("nvim-treesitter.textobjects.move") ---@type table<string,fun(...)>
+      for name, fn in pairs(move) do
+        if name:find("goto") == 1 then
+          move[name] = function(q, ...)
+            if not vim.wo.diff then return fn(q, ...) end
+
+            local config = configs.get_module("textobjects.move")[name] ---@type table<string,string>
+            for key, query in pairs(config or {}) do
+              if q == query and key:find("[%]%[][cC]") then
+                vim.cmd("normal! " .. key)
+                return
+              end
+            end
+          end
+        end
+      end
+    end,
+  },
+
+  -- Automatically add closing tags for HTML and JSX
+  {
+    "windwp/nvim-ts-autotag",
+    event = { "BufReadPost", "BufNewFile", "BufWritePre" },
+    opts = {},
+  },
+}
+
index 0cb899a94543e3e288d1efb5425b0b785603c121..8e52958f400bc38cee86cf17a846fc9c60f8dc84 100644 (file)
@@ -1,10 +1,91 @@
----@type LazyPluginSpec
+local M = {}
+
+---@param component any -- actually a lualine.component
+---@param text string
+---@param hl_group? string
+---@return string
+function M.format(component, text, hl_group)
+  text = text:gsub("%%", "%%%%")
+  if not hl_group or hl_group == "" then
+    return text
+  end
+  --- hl_cache is added here, not modified
+  ---@type table<string, string>
+  component.hl_cache = component.hl_cache or {}
+  local lualine_hl_group = component.hl_cache[hl_group]
+  if not lualine_hl_group then
+    local utils = require("lualine.utils.utils")
+    ---@type string[]
+    local gui = vim.tbl_filter(function(x) return x end, {
+      utils.extract_highlight_colors(hl_group, "bold") and "bold",
+      utils.extract_highlight_colors(hl_group, "italic") and "italic",
+    })
+
+    lualine_hl_group = component:create_hl({
+      fg = utils.extract_highlight_colors(hl_group, "fg"),
+      gui = #gui > 0 and table.concat(gui, ",") or nil,
+    }, "LV_" .. hl_group) --[[@as string]]
+    component.hl_cache[hl_group] = lualine_hl_group
+  end
+  return component:format_hl(lualine_hl_group) .. text .. component:get_default_hl()
+end
+
+function M.pretty_path()
+  return function(self)
+    local opts = {
+      directory_hl = "",
+      filename_hl = "Bold",
+      length = 3,
+      modified_hl = "MatchParen",  -- hl group when file is modified
+      modified_sign = "",
+      readonly_icon = " 󰌾 ",
+    }
+
+    local path = vim.fn.expand("%:p") --[[@as string]]
+
+    if path == "" then
+      return ""
+    end
+
+    path = require("lazy.core.util").norm(path)
+    local cwd = vim.uv.cwd()
+
+    if path:find(cwd, 1, true) == 1 then
+      path = path:sub(#cwd + 2)
+    end
+
+    local sep = package.config:sub(1, 1)
+    local parts = vim.split(path, "[\\/]")
+
+    if opts.length == 0 then
+      parts = parts
+    elseif #parts > opts.length then
+      parts = { parts[1], "…", unpack(parts, #parts - opts.length + 2, #parts) }
+    end
+
+    if vim.bo.modified then
+      parts[#parts] = parts[#parts] .. opts.modified_sign
+      parts[#parts] = M.format(self, parts[#parts], opts.modified_hl)
+    else
+      parts[#parts] = M.format(self, parts[#parts], opts.filename_hl)
+    end
+
+    local dir = ""
+    if #parts > 1 then
+      dir = table.concat({ unpack(parts, 1, #parts - 1) }, sep)
+      dir = M.format(self, dir .. sep, opts.directory_hl)
+    end
+
+    local readonly = ""
+    if vim.bo.readonly then
+      readonly = M.format(self, opts.readonly_icon, opts.modified_hl)
+    end
+    return dir .. parts[#parts] .. readonly
+  end
+end
+
+---@type LazySpec
 return {
-  -- disabled plugins {{{
-  { "folke/which-key.nvim",
-    enabled = false,
-  },
-  -- }}}
   { 'echasnovski/mini.clue',
     -- NOTE: this caused some issue with unterminated mappings, i.e. <L>gc when there 
     -- is also <L>gcc. It would simply terminate early and not allow for next mapping.
@@ -33,63 +114,50 @@ return {
       },
     },
   },
-  {
-    "nvim-notify",
-  },
-  {
-    "bufferline.nvim",
+  { "akinsho/bufferline.nvim",
+    event = "VeryLazy",
+    keys = {
+      { "<leader>bp", "<Cmd>BufferLineTogglePin<CR>", desc = "Toggle Pin" },
+      { "<leader>bP", "<Cmd>BufferLineGroupClose ungrouped<CR>", desc = "Delete Non-Pinned Buffers" },
+      { "<leader>br", "<Cmd>BufferLineCloseRight<CR>", desc = "Delete Buffers to the Right" },
+      { "<leader>bl", "<Cmd>BufferLineCloseLeft<CR>", desc = "Delete Buffers to the Left" },
+      { "<S-h>", "<cmd>BufferLineCyclePrev<cr>", desc = "Prev Buffer" },
+      { "<S-l>", "<cmd>BufferLineCycleNext<cr>", desc = "Next Buffer" },
+      { "[b", "<cmd>BufferLineCyclePrev<cr>", desc = "Prev Buffer" },
+      { "]b", "<cmd>BufferLineCycleNext<cr>", desc = "Next Buffer" },
+      { "[B", "<cmd>BufferLineMovePrev<cr>", desc = "Move buffer prev" },
+      { "]B", "<cmd>BufferLineMoveNext<cr>", desc = "Move buffer next" },
+    },
     ---@type BufferlineConfig
     opts = {
       options = {
+        close_command = function(n) Snacks.bufdelete(n) end,
+        right_mouse_command = function(n) Snacks.bufdelete(n) end,
+        diagnostics = "nvim_lsp",
         always_show_bufferline = false,
-      },
-    },
-  },
-  {
-    "stevearc/dressing.nvim",
-    lazy = true,
-    opts = {
-      input = {
-        start_in_insert = false,
-        insert_only = false,
-      },
-    },
-  },
-  {
-    "noice.nvim",
-    enabled = false,
-    ---@type NoiceConfig
-    opts = {
-      presets = {
-        command_palette = false, -- don't position the cmdline and popupmenu together
-        lsp_doc_border = true,
-        long_message_to_split = true,
-      },
-      cmdline = {
-        view = "cmdline",
-      },
-      routes = {
-        { -- send file written messages to mini
-          filter = {
-            event = "msg_show",
-            kind = "",
-            find = "%[w%]",
+        diagnostics_indicator = function(_, _, diag)
+          local icons = rmz.ui.icons.diagnostics
+          local ret = (diag.error and icons.Error .. diag.error .. " " or "")
+            .. (diag.warning and icons.Warn .. diag.warning or "")
+          return vim.trim(ret)
+        end,
+        offsets = {
+          {
+            filetype = "man",
+            text = "Man page",
+            highlight = "Directory",
+            text_align = "left",
           },
-          opts = { skip = true },
         },
+        ---@param opts bufferline.IconFetcherOpts
+        get_element_icon = function(opts)
+          return rmz.ui.icons.ft[opts.filetype]
+        end,
       },
     },
-    config = function(_, opts)
-      -- ensure [w] is written to msg_show so we can match it
-      vim.opt.shortmess:append("w")
-      vim.opt.shortmess:remove("W")
-
-      require("noice").setup(opts)
-    end,
   },
-  {
-    "lualine.nvim",
-    --TODO: Things that were in vim but are missing
+  { "nvim-lualine/lualine.nvim",
+    -- TODO: Things that were in vim but are missing
     -- - git line add/mod/del ar next to branch name rather on right
     -- - one status line per splits
     --   - maybe a single one is OK too?
@@ -97,98 +165,193 @@ return {
     --   - unix/dos eof markers
     --     - really I only want to know if it's not unix
     --   - filetype in text form. It's quite important to glance this quickly
-  },
-  {
-    "indent-blankline.nvim",
-  },
-  {
-    "echasnovski/mini.indentscope",
-    version = false, -- wait till new 0.7.0 release to put it back on semver
-    event = "LazyFile",
-    opts = function (_, opts)
-      return {
-        draw = {
-          animation = require("mini.indentscope").gen_animation.linear({ duration = 10 })
-        }
-      }
+    event = "VeryLazy",
+    init = function()
+      vim.g.lualine_laststatus = vim.o.laststatus
+      if vim.fn.argc(-1) > 0 then
+        -- set an empty statusline till lualine loads
+        vim.o.statusline = " "
+      else
+        -- hide the statusline on the starter page
+        vim.o.laststatus = 0
+      end
     end,
-  },
-  {
-    "nvimdev/dashboard-nvim",
-  -- TODO: create cool dashboard header
-  -- generate logo from text here:
-  -- https://patorjk.com/software/taag/#p=testall&v=0&f=Computer&t=NEOVIM
-  -- Can also use use `chafa` and aplha.term to generate text from cli, see
-  -- https://github.com/goolord/alpha-nvim/discussions/16#discussioncomment-4915947
-  -- https://github.com/goolord/alpha-nvim/discussions/16#discussioncomment-5065731
-  -- To add orgmode agenda button in alpha
-  -- dashboard.button("a", "󰕪 " .. " View Agenda", ":lua require('orgmode').action('agenda.agenda')<CR>"),
     opts = function()
-      local logo = [[
-           ██╗      █████╗ ███████╗██╗   ██╗██╗   ██╗██╗███╗   ███╗          Z
-           ██║     ██╔══██╗╚══███╔╝╚██╗ ██╔╝██║   ██║██║████╗ ████║      Z    
-           ██║     ███████║  ███╔╝  ╚████╔╝ ██║   ██║██║██╔████╔██║   z       
-           ██║     ██╔══██║ ███╔╝    ╚██╔╝  ╚██╗ ██╔╝██║██║╚██╔╝██║ z         
-           ███████╗██║  ██║███████╗   ██║    ╚████╔╝ ██║██║ ╚═╝ ██║           
-           ╚══════╝╚═╝  ╚═╝╚══════╝   ╚═╝     ╚═══╝  ╚═╝╚═╝     ╚═╝           
-  ]]
+      -- PERF: we don't need this lualine require madness 🤷
+      local lualine_require = require("lualine_require")
+      lualine_require.require = require
+
+      local icons = rmz.ui.icons
 
-      logo = string.rep("\n", 8) .. logo .. "\n\n"
+      vim.o.laststatus = vim.g.lualine_laststatus
 
       local opts = {
-        theme = "doom",
-        hide = {
-          -- this is taken care of by lualine
-          -- enabling this messes up the actual laststatus setting after loading a file
-          statusline = false,
+        options = {
+          theme = "auto",
+          globalstatus = vim.o.laststatus == 3,
+          disabled_filetypes = { statusline = { "dashboard", "alpha", "ministarter", "snacks_dashboard" } },
         },
-        config = {
-          header = vim.split(logo, "\n"),
-          -- stylua: ignore
-          center = {
-            { action = [[lua require('orgmode').action('agenda.agenda')]],         desc = " View Agenda",     icon = "󰕪 ", key = "a" },
-            { action = "Telescope find_files",                                     desc = " Find file",       icon = " ", key = "f" },
-            { action = "ene | startinsert",                                        desc = " New file",        icon = " ", key = "n" },
-            { action = "Telescope oldfiles",                                       desc = " Recent files",    icon = " ", key = "r" },
-            { action = [[lua require("lazyvim.util").telescope.config_files()()]], desc = " Config",          icon = " ", key = "c" },
-            { action = 'lua require("persistence").load()',                        desc = " Restore Session", icon = " ", key = "s" },
-            { action = "LazyExtras",                                               desc = " Lazy Extras",     icon = " ", key = "x" },
-            { action = "Lazy",                                                     desc = " Lazy",            icon = "󰒲 ", key = "l" },
+        sections = {
+          lualine_a = { "mode" },
+          lualine_b = { "branch" },
+
+          lualine_c = {
+            {
+              "diagnostics",
+              symbols = {
+                error = icons.diagnostics.Error,
+                warn = icons.diagnostics.Warn,
+                info = icons.diagnostics.Info,
+                hint = icons.diagnostics.Hint,
+              },
+            },
+            { "filetype", icon_only = true, separator = "", padding = { left = 1, right = 0 } },
+            { M.pretty_path() },
+          },
+          lualine_x = {
+            Snacks.profiler.status(),
+            -- stylua: ignore
+            {
+              function() return "  " .. require("dap").status() end,
+              cond = function() return package.loaded["dap"] and require("dap").status() ~= "" end,
+              color = function() return { fg = Snacks.util.color("Debug") } end,
+            },
+            -- stylua: ignore
+            {
+              require("lazy.status").updates,
+              cond = require("lazy.status").has_updates,
+              color = function() return { fg = Snacks.util.color("Special") } end,
+            },
+            {
+              "diff",
+              symbols = {
+                added = icons.git.added,
+                modified = icons.git.modified,
+                removed = icons.git.removed,
+              },
+              source = function()
+                local gitsigns = vim.b.gitsigns_status_dict
+                if gitsigns then
+                  return {
+                    added = gitsigns.added,
+                    modified = gitsigns.changed,
+                    removed = gitsigns.removed,
+                  }
+                end
+              end,
+            },
+          },
+          lualine_y = {
+            { "progress", separator = " ", padding = { left = 1, right = 0 } },
+            { "location", padding = { left = 0, right = 1 } },
+          },
+          lualine_z = {
+            function()
+              return " " .. os.date("%R")
+            end,
           },
-          footer = function()
-            local stats = require("lazy").stats()
-            local ms = (math.floor(stats.startuptime * 100 + 0.5) / 100)
-            return { "⚡ Neovim loaded " .. stats.loaded .. "/" .. stats.count .. " plugins in " .. ms .. "ms" }
-          end,
         },
+        inactive_sections = {
+          lualine_c = {
+            { "filetype", icon_only = true, separator = "", padding = { left = 1, right = 0 } },
+            { M.pretty_path() },
+          },
+        },
+        extensions = { "neo-tree", "lazy", "fzf" },
       }
 
-      for _, button in ipairs(opts.config.center) do
-        button.desc = button.desc .. string.rep(" ", 43 - #button.desc)
-        button.key_format = "  %s"
-      end
-
-      -- close Lazy and re-open when the dashboard is ready
-      if vim.o.filetype == "lazy" then
-        vim.cmd.close()
-        vim.api.nvim_create_autocmd("User", {
-          pattern = "DashboardLoaded",
-          callback = function()
-            require("lazy").show()
-          end,
-        })
-      end
+      local trouble = require("trouble")
+      local symbols = trouble.statusline({
+        mode = "symbols",
+        groups = {},
+        title = false,
+        filter = { range = true },
+        format = "{kind_icon}{symbol.name:Normal}",
+        hl_group = "lualine_c_normal",
+      })
+      table.insert(opts.sections.lualine_c, {
+        symbols and symbols.get,
+        cond = function()
+          return vim.b.trouble_lualine ~= false and symbols.has()
+        end,
+      })
 
       return opts
-    end
+    end,
   },
   {
-    "SmiteshP/nvim-navic",
+    "echasnovski/mini.icons",
+    lazy = true,
+    opts = {
+      file = {
+        [".keep"] = { glyph = "󰊢", hl = "MiniIconsGrey" },
+        ["devcontainer.json"] = { glyph = "", hl = "MiniIconsAzure" },
+      },
+      filetype = {
+        dotenv = { glyph = "", hl = "MiniIconsYellow" },
+      },
+    },
+    init = function()
+      -- TODO: try without this
+      -- see :h MiniIcons.mock_nvim_web_devicons()
+      package.preload["nvim-web-devicons"] = function()
+        require("mini.icons").mock_nvim_web_devicons()
+        return package.loaded["nvim-web-devicons"]
+      end
+    end,
   },
-  {
-    "nvim-web-devicons",
+  { "MunifTanjim/nui.nvim", lazy = true },
+  { "stevearc/dressing.nvim",
+    enabled = false,  -- replaced by snacks.input
+    lazy = true,
+    opts = {
+      input = {
+        start_in_insert = false,
+        insert_only = false,
+      },
+    },
   },
-  {
-    "nui.nvim",
+  { "indent-blankline.nvim",
+    enabled = false,  -- replaced by snacks.indent
+  },
+  { "echasnovski/mini.indentscope",
+    enabled = false,  -- replaced by snacks.indent
+    version = false, -- wait till new 0.7.0 release to put it back on semver
+    event = { "BufReadPost", "BufNewFile", "BufWritePre" },
+    opts = function (_, opts)
+      return {
+        draw = {
+          animation = require("mini.indentscope").gen_animation.linear({ duration = 10 })
+        }
+      }
+    end,
+  },
+  { "SmiteshP/nvim-navic",
+    lazy = true,
+    init = function()
+      vim.g.navic_silence = true
+      rmz.lsp.on_attach(function(client, buffer)
+        if client.supports_method("textDocument/documentSymbol") then
+          require("nvim-navic").attach(client, buffer)
+        end
+      end)
+    end,
+    opts = function()
+      return {
+        separator = " ",
+        highlight = true,
+        depth_limit = 5,
+        icons = rmz.ui.icons.kinds,
+        lazy_update_context = true,
+      }
+    end,
+  },
+  { "nvim-lualine/lualine.nvim",
+    optional = true,
+    opts = function(_, opts)
+      if not vim.g.trouble_lualine then
+        table.insert(opts.sections.lualine_c, { "navic", color_correction = "dynamic" })
+      end
+    end,
   },
 }
diff --git a/nvim/lua/rmz/util/init.lua b/nvim/lua/rmz/util/init.lua
new file mode 100644 (file)
index 0000000..abf0c21
--- /dev/null
@@ -0,0 +1,41 @@
+---@class rmz.util
+local M = {
+  ui  = require("rmz.util.ui"),
+  lazy = require("rmz.util.lazy"),
+  lsp = require("rmz.util.lsp"),
+}
+
+--- Deduplicates a list.
+---@generic T
+---@param list T[]
+---@return T[]
+function M.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
+
+function M.foldexpr()
+  local buf = vim.api.nvim_get_current_buf()
+  if vim.b[buf].ts_folds == nil then
+    -- 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
+    if vim.bo[buf].filetype:find("dashboard") then
+      vim.b[buf].ts_folds = false
+    else
+      vim.b[buf].ts_folds = pcall(vim.treesitter.get_parser, buf)
+    end
+  end
+  return vim.b[buf].ts_folds and vim.treesitter.foldexpr() or "0"
+end
+
+return M
diff --git a/nvim/lua/rmz/util/lazy.lua b/nvim/lua/rmz/util/lazy.lua
new file mode 100644 (file)
index 0000000..81a5534
--- /dev/null
@@ -0,0 +1,28 @@
+---@class rmz.util.lazy
+local M = {}
+
+---@param name string
+function M.get_plugin(name)
+  return require("lazy.core.config").spec.plugins[name]
+end
+
+---@param name string
+function M.opts(name)
+  local plugin = M.get_plugin(name)
+  if not plugin then
+    return {}
+  end
+  local Plugin = require("lazy.core.plugin")
+  return Plugin.values(plugin, "opts", false)
+end
+
+for _, level in ipairs({ "info", "warn", "error" }) do
+  M[level] = function(msg, opts)
+    opts = opts or {}
+    opts.title = opts.title or "RmZ"
+    local Util = require("lazy.core.util")
+    return Util[level](msg, opts)
+  end
+end
+
+return M
diff --git a/nvim/lua/rmz/util/lsp.lua b/nvim/lua/rmz/util/lsp.lua
new file mode 100644 (file)
index 0000000..662781c
--- /dev/null
@@ -0,0 +1,206 @@
+-- Absorbed from LazyVim
+-- TODO: review, understand and adapt
+---@class rmz.util.lsp
+local M = {}
+
+---@alias lsp.Client.filter {id?: number, bufnr?: number, name?: string, method?: string, filter?:fun(client: lsp.Client):boolean}
+
+M.kind_filter = {
+  default = {
+    "Class",
+    "Constructor",
+    "Enum",
+    "Field",
+    "Function",
+    "Interface",
+    "Method",
+    "Module",
+    "Namespace",
+    "Package",
+    "Property",
+    "Struct",
+    "Trait",
+  },
+  markdown = false,
+  help = false,
+  -- you can specify a different filter for each filetype
+  lua = {
+    "Class",
+    "Constructor",
+    "Enum",
+    "Field",
+    "Function",
+    "Interface",
+    "Method",
+    "Module",
+    "Namespace",
+    -- "Package", -- remove package since luals uses it for control flow structures
+    "Property",
+    "Struct",
+    "Trait",
+  },
+}
+
+---@param opts? lsp.Client.filter
+function M.get_clients(opts)
+  local ret = {} ---@type vim.lsp.Client[]
+  if vim.lsp.get_clients then
+    ret = vim.lsp.get_clients(opts)
+  else
+    ---@diagnostic disable-next-line: deprecated
+    ret = vim.lsp.get_active_clients(opts)
+    if opts and opts.method then
+      ---@param client vim.lsp.Client
+      ret = vim.tbl_filter(function(client)
+        return client.supports_method(opts.method, { bufnr = opts.bufnr })
+      end, ret)
+    end
+  end
+  return opts and opts.filter and vim.tbl_filter(opts.filter, ret) or ret
+end
+
+---@param on_attach fun(client:vim.lsp.Client, buffer)
+---@param name? string
+function M.on_attach(on_attach, name)
+  return vim.api.nvim_create_autocmd("LspAttach", {
+    callback = function(args)
+      local buffer = args.buf ---@type number
+      local client = vim.lsp.get_client_by_id(args.data.client_id)
+      if client and (not name or client.name == name) then
+        return on_attach(client, buffer)
+      end
+    end,
+  })
+end
+
+---@type table<string, table<vim.lsp.Client, table<number, boolean>>>
+M._supports_method = {}
+
+function M.setup()
+  local register_capability = vim.lsp.handlers["client/registerCapability"]
+  vim.lsp.handlers["client/registerCapability"] = function(err, res, ctx)
+    ---@diagnostic disable-next-line: no-unknown
+    local ret = register_capability(err, res, ctx)
+    local client = vim.lsp.get_client_by_id(ctx.client_id)
+    if client then
+      for buffer in pairs(client.attached_buffers) do
+        vim.api.nvim_exec_autocmds("User", {
+          pattern = "LspDynamicCapability",
+          data = { client_id = client.id, buffer = buffer },
+        })
+      end
+    end
+    return ret
+  end
+  M.on_attach(M._check_methods)
+  M.on_dynamic_capability(M._check_methods)
+end
+
+---@param client vim.lsp.Client
+function M._check_methods(client, buffer)
+  -- don't trigger on invalid buffers
+  if not vim.api.nvim_buf_is_valid(buffer) then
+    return
+  end
+  -- don't trigger on non-listed buffers
+  if not vim.bo[buffer].buflisted then
+    return
+  end
+  -- don't trigger on nofile buffers
+  if vim.bo[buffer].buftype == "nofile" then
+    return
+  end
+  for method, clients in pairs(M._supports_method) do
+    clients[client] = clients[client] or {}
+    if not clients[client][buffer] then
+      if client.supports_method and client.supports_method(method, { bufnr = buffer }) then
+        clients[client][buffer] = true
+        vim.api.nvim_exec_autocmds("User", {
+          pattern = "LspSupportsMethod",
+          data = { client_id = client.id, buffer = buffer, method = method },
+        })
+      end
+    end
+  end
+end
+
+---@param fn fun(client:vim.lsp.Client, buffer):boolean?
+---@param opts? {group?: integer}
+function M.on_dynamic_capability(fn, opts)
+  return vim.api.nvim_create_autocmd("User", {
+    pattern = "LspDynamicCapability",
+    group = opts and opts.group or nil,
+    callback = function(args)
+      local client = vim.lsp.get_client_by_id(args.data.client_id)
+      local buffer = args.data.buffer ---@type number
+      if client then
+        return fn(client, buffer)
+      end
+    end,
+  })
+end
+
+---@param method string
+---@param fn fun(client:vim.lsp.Client, buffer)
+function M.on_supports_method(method, fn)
+  M._supports_method[method] = M._supports_method[method] or setmetatable({}, { __mode = "k" })
+  return vim.api.nvim_create_autocmd("User", {
+    pattern = "LspSupportsMethod",
+    callback = function(args)
+      local client = vim.lsp.get_client_by_id(args.data.client_id)
+      local buffer = args.data.buffer ---@type number
+      if client and method == args.data.method then
+        return fn(client, buffer)
+      end
+    end,
+  })
+end
+
+---@return _.lspconfig.options
+function M.get_config(server)
+  local configs = require("lspconfig.configs")
+  return rawget(configs, server)
+end
+
+---@return {default_config:lspconfig.Config}
+function M.get_raw_config(server)
+  local ok, ret = pcall(require, "lspconfig.configs." .. server)
+  if ok then
+    return ret
+  end
+  return require("lspconfig.server_configurations." .. server)
+end
+
+function M.is_enabled(server)
+  local c = M.get_config(server)
+  return c and c.enabled ~= false
+end
+
+---@param server string
+---@param cond fun( root_dir, config): boolean
+function M.disable(server, cond)
+  local util = require("lspconfig.util")
+  local def = M.get_config(server)
+  ---@diagnostic disable-next-line: undefined-field
+  def.document_config.on_new_config = util.add_hook_before(def.document_config.on_new_config, function(config, root_dir)
+    if cond(root_dir, config) then
+      config.enabled = false
+    end
+  end)
+end
+
+M.action = setmetatable({}, {
+  __index = function(_, action)
+    return function()
+      vim.lsp.buf.code_action({
+        apply = true,
+        context = {
+          only = { action },
+          diagnostics = {},
+        },
+      })
+    end
+  end,
+})
+
+return M
diff --git a/nvim/lua/rmz/util/ui.lua b/nvim/lua/rmz/util/ui.lua
new file mode 100644 (file)
index 0000000..024ec05
--- /dev/null
@@ -0,0 +1,72 @@
+local M = {}
+
+-- icons used by other plugins
+M.icons = {
+  misc = {
+    dots = "󰇘",
+  },
+  ft = {
+    octo = "",
+  },
+  dap = {
+    Stopped             = { "󰁕 ", "DiagnosticWarn", "DapStoppedLine" },
+    Breakpoint          = " ",
+    BreakpointCondition = " ",
+    BreakpointRejected  = { " ", "DiagnosticError" },
+    LogPoint            = ".>",
+  },
+  diagnostics = {
+    Error = " ",
+    Warn  = " ",
+    Hint  = " ",
+    Info  = " ",
+  },
+  git = {
+    added    = " ",
+    modified = " ",
+    removed  = " ",
+  },
+  kinds = {
+    Array         = " ",
+    Boolean       = "󰨙 ",
+    Class         = " ",
+    Codeium       = "󰘦 ",
+    Color         = " ",
+    Control       = " ",
+    Collapsed     = " ",
+    Constant      = "󰏿 ",
+    Constructor   = " ",
+    Copilot       = " ",
+    Enum          = " ",
+    EnumMember    = " ",
+    Event         = " ",
+    Field         = " ",
+    File          = " ",
+    Folder        = " ",
+    Function      = "󰊕 ",
+    Interface     = " ",
+    Key           = " ",
+    Keyword       = " ",
+    Method        = "󰊕 ",
+    Module        = " ",
+    Namespace     = "󰦮 ",
+    Null          = " ",
+    Number        = "󰎠 ",
+    Object        = " ",
+    Operator      = " ",
+    Package       = " ",
+    Property      = " ",
+    Reference     = " ",
+    Snippet       = "󱄽 ",
+    String        = " ",
+    Struct        = "󰆼 ",
+    Supermaven    = " ",
+    TabNine       = "󰏚 ",
+    Text          = " ",
+    TypeParameter = " ",
+    Unit          = " ",
+    Value         = " ",
+    Variable      = "󰀫 ",
+  },
+}
+return M
diff --git a/nvim/snippets/all.snippets b/nvim/snippets/all.snippets
new file mode 100644 (file)
index 0000000..1d91cec
--- /dev/null
@@ -0,0 +1,2 @@
+# Add TextMate style snippets here
+# see https://github.com/L3MON4D3/LuaSnip/blob/master/DOC.md#snipmate
index 0c341cb5c64ede5e78244f4b03c5a6d9b6834eff..0a09c8a2a75ffe8b8bf64be0cf29442d1d05cbf7 100644 (file)
--- a/vim/vimrc
+++ b/vim/vimrc
@@ -563,34 +563,37 @@ augroup ft_stdin
     au StdinReadPost * :set buftype=nofile
 augroup END
 
-" Jump to last known cursor position {{{2
-augroup last_loc
+if !has("nvim")
+  " autocmds that already exist in neovim
+  " Jump to last known cursor position {{{2
+  augroup last_loc
+      au!
+      " blacklist certain filetype
+      let blacklist = ['gitcommit']
+      autocmd BufReadPost *
+                  \ if index(blacklist, &ft) < 0 && line("'\"") > 1 && line("'\"") <= line("$") |
+                  \   exe "normal! g`\"" |
+                  \ endif
+  augroup END
+
+  " Check for file modifications automatically {{{2
+  " (current buffer only)
+  " Use :NoAutoChecktime to disable it (uses b:autochecktime)
+  fun! MyAutoCheckTime()
+    " only check timestamp for normal files
+    if &buftype != '' | return | endif
+    if ! exists('b:autochecktime') || b:autochecktime
+      checktime %
+      let b:autochecktime = 1
+    endif
+  endfun
+  augroup MyAutoChecktime
     au!
-    " blacklist certain filetype
-    let blacklist = ['gitcommit']
-    autocmd BufReadPost *
-                \ if index(blacklist, &ft) < 0 && line("'\"") > 1 && line("'\"") <= line("$") |
-                \   exe "normal! g`\"" |
-                \ endif
-augroup END
-
-" Check for file modifications automatically {{{2
-" (current buffer only)
-" Use :NoAutoChecktime to disable it (uses b:autochecktime)
-fun! MyAutoCheckTime()
-  " only check timestamp for normal files
-  if &buftype != '' | return | endif
-  if ! exists('b:autochecktime') || b:autochecktime
-    checktime %
-    let b:autochecktime = 1
-  endif
-endfun
-augroup MyAutoChecktime
-  au!
-  au FocusGained,BufEnter,CursorHold,InsertEnter * call MyAutoCheckTime()
-augroup END
-command! NoAutoChecktime let b:autochecktime=0
-command! ToggleAutoChecktime let b:autochecktime=!get(b:, 'autochecktime', 0) | echom "b:autochecktime:" b:autochecktime
+    au FocusGained,BufEnter,CursorHold,InsertEnter * call MyAutoCheckTime()
+  augroup END
+  command! NoAutoChecktime let b:autochecktime=0
+  command! ToggleAutoChecktime let b:autochecktime=!get(b:, 'autochecktime', 0) | echom "b:autochecktime:" b:autochecktime
+endif
 
 " bindings {{{1