diff --git a/lua/community.lua b/lua/community.lua index 1dc7769..3b4d700 100644 --- a/lua/community.lua +++ b/lua/community.lua @@ -25,6 +25,9 @@ return { { import = "astrocommunity.editing-support.conform-nvim" }, { import = "astrocommunity.lsp.inc-rename-nvim" }, { import = "astrocommunity.lsp.nvim-lsp-file-operations" }, + { import = "astrocommunity.colorscheme.bamboo-nvim" }, { import = "astrocommunity.colorscheme.cyberdream-nvim" }, - { import = "astrocommunity.completion.copilot-vim-cmp" }, + { import = "astrocommunity.colorscheme.gruvbox-baby" }, + { import = "astrocommunity.colorscheme.kanagawa-nvim" }, + { import = "astrocommunity.colorscheme.kanagawa-paper-nvim" }, } diff --git a/lua/config/terminals.lua b/lua/config/terminals.lua index 54bc52e..0addeac 100644 --- a/lua/config/terminals.lua +++ b/lua/config/terminals.lua @@ -65,6 +65,16 @@ function M.setup() vim.api.nvim_buf_set_keymap(term.bufnr, "n", "q", "close", { noremap = true, silent = true }) end, } + -- Mk (make) terminal + local lazydocker = Terminal:new { + cmd = "lazydocker", + hidden = true, + direction = "float", + on_open = function(term) + vim.cmd "startinsert!" + vim.api.nvim_buf_set_keymap(term.bufnr, "n", "q", "close", { noremap = true, silent = true }) + end, + } -- Scratch terminal local scratch = Terminal:new { @@ -80,6 +90,7 @@ function M.setup() M.scooter_toggle = function() scooter:toggle() end M.mk_toggle = function() mk:toggle() end M.lazygit_toggle = function() lazygit:toggle() end + M.lazydocker_toggle = function() lazydocker:toggle() end M.smartCommit_toggle = function() smartCommit:toggle() end M.scratch_toggle = function() scratch:toggle() end end diff --git a/lua/plugins/astrocore.lua b/lua/plugins/astrocore.lua index 076373f..8a44ca4 100644 --- a/lua/plugins/astrocore.lua +++ b/lua/plugins/astrocore.lua @@ -17,567 +17,572 @@ return { ---@type AstroCoreOpts opts = { - sessions = { - -- Configure auto saving - autosave = { - last = true, -- auto save last session - cwd = true, -- auto save session for each working directory - }, - -- Patterns to ignore when saving sessions - ignore = { - dirs = {}, -- working directories to ignore sessions in - filetypes = { "gitcommit", "gitrebase" }, -- filetypes to ignore sessions - buftypes = {}, -- buffer types to ignore sessions - }, - -- Store pinned buffers in session data - before_save = function() - local pinned = {} - for _, buf in ipairs(vim.api.nvim_list_bufs()) do - if vim.api.nvim_buf_is_valid(buf) and vim.api.nvim_buf_get_option(buf, "buflisted") then - local bufname = vim.api.nvim_buf_get_name(buf) - if bufname ~= "" then - -- Check if buffer is pinned using BufferLine's API - local ok, bufferline = pcall(require, "bufferline") - if ok and bufferline.get_elements then - local elements = bufferline.get_elements() - for _, element in ipairs(elements) do - if element.id == buf and element.pinned then - table.insert(pinned, bufname) - break - end + sessions = { + -- Configure auto saving + autosave = { + last = true, -- auto save last session + cwd = true, -- auto save session for each working directory + }, + -- Patterns to ignore when saving sessions + ignore = { + dirs = {}, -- working directories to ignore sessions in + filetypes = { "gitcommit", "gitrebase" }, -- filetypes to ignore sessions + buftypes = {}, -- buffer types to ignore sessions + }, + -- Store pinned buffers in session data + before_save = function() + local pinned = {} + for _, buf in ipairs(vim.api.nvim_list_bufs()) do + if vim.api.nvim_buf_is_valid(buf) and vim.api.nvim_buf_get_option(buf, "buflisted") then + local bufname = vim.api.nvim_buf_get_name(buf) + if bufname ~= "" then + -- Check if buffer is pinned using BufferLine's API + local ok, bufferline = pcall(require, "bufferline") + if ok and bufferline.get_elements then + local elements = bufferline.get_elements() + for _, element in ipairs(elements) do + if element.id == buf and element.pinned then + table.insert(pinned, bufname) + break end end end end end - vim.g.session_pinned_buffers = pinned - end, - -- Restore pinned buffers after session load - after_load = function() - if vim.g.session_pinned_buffers then - vim.defer_fn(function() - for _, bufname in ipairs(vim.g.session_pinned_buffers) do - -- Find the buffer by name - for _, buf in ipairs(vim.api.nvim_list_bufs()) do - if vim.api.nvim_buf_is_valid(buf) and vim.api.nvim_buf_get_name(buf) == bufname then - -- Pin the buffer using BufferLine command - vim.cmd("BufferLineTogglePin " .. buf) - break - end - end - end - vim.g.session_pinned_buffers = nil - end, 100) - end - end, - }, - rooter = { - -- list of detectors in order of prevalence, elements can be: - -- "lsp" : lsp detection - -- string[] : a list of directory patterns to look for - -- fun(bufnr: integer): string|string[] : a function that takes a buffer number and outputs detected roots - detector = { - "lsp", -- highest priority is getting workspace from running language servers - { ".git", "_darcs", ".hg", ".bzr", ".svn" }, -- next check for a version controlled parent directory - { - "package.json", - "lua", - "Cargo.toml", - "Pipfile", - "docs.json", - }, -- lastly check for a file named `main` - }, - -- ignore things from root detection - ignore = { - servers = { - "golangci_lint_ls", - }, -- list of language server names to ignore (Ex. { "efm" }) - dirs = {}, -- list of directory patterns (Ex. { "~/.cargo/*" }) - }, - -- automatically update working directory (update manually with `:AstroRoot`) - autochdir = true, - -- scope of working directory to change ("global"|"tab"|"win") - scope = "global", -- Changed from "win" to "global" to make directory changes apply globally - -- show notification on every working directory change - notify = false, - }, - - -- Configure core features of AstroNvim - features = { - autopairs = true, -- enable autopairs at start - diagnostics_mode = 1, -- diagnostic mode on start (0 = off, 1 = no signs/virtual text, 2 = no virtual text, 3 = on) - highlighturl = true, -- highlight URLs at start - notifications = false, -- enable notifications at start - }, - - -- Diagnostics configuration (for vim.diagnostics.config({...})) when diagnostics are on - diagnostics = { - virtual_text = true, - underline = true, - }, - - -- Autocmds can be configured here - autocmds = { - -- Custom title formatting for ghq repos - custom_title = { - { - event = { "BufEnter", "DirChanged" }, - desc = "Update terminal title with org/repo format", - callback = function() - local filepath = vim.fn.expand "%:p" - local filename = vim.fn.expand "%:t" - - -- If no file is open, try to show just the repo name - if filename == "" then - local cwd = vim.fn.getcwd() - local github_match = cwd:match "github%.com/([^/]+/[^/]+)" - if github_match then - vim.opt.titlestring = github_match - else - vim.opt.titlestring = "Nvim" - end - return - end - - -- Check if path contains github.com (ghq structure) - local github_match = filepath:match "github%.com/([^/]+/[^/]+)" - - if github_match then - -- Format: filename | org/repo - vim.opt.titlestring = string.format("%s | %s", filename, github_match) - else - -- Fallback: filename | Nvim - vim.opt.titlestring = string.format("%s | Nvim", filename) - end - end, - }, - }, - -- Show smart picker on startup - startup_picker = { - { - event = "VimEnter", - desc = "Show smart picker on startup", - callback = function() - -- Skip if opening with arguments - if vim.fn.argc() > 0 then return end - - -- Skip if current buffer has content - local lines = vim.api.nvim_buf_get_lines(0, 0, -1, false) - if #lines > 1 or (#lines == 1 and lines[1] ~= "") then return end - - -- Delay to ensure everything is loaded - vim.defer_fn(function() require("snacks").picker.smart() end, 50) - end, - }, - }, - }, - - -- vim options can be configured here - options = { - opt = { -- vim.opt. - relativenumber = false, -- sets vim.opt.relativenumber - number = true, -- sets vim.opt.number - spell = false, -- sets vim.opt.spell - wrap = true, -- sets vim.opt.wrap - clipboard = "unnamedplus", -- use system clipboard for all operations - title = true, -- enable title string - titlestring = "", -- will be set dynamically by autocommand - laststatus = 0, -- disable statusline (0 = never show) - }, - g = { -- vim.g. - -- configure global vim variables (vim.g) - -- NOTE: `mapleader` and `maplocalleader` must be set in the AstroNvim opts or before `lazy.setup` - -- This can be found in the `lua/lazy_setup.lua` file - }, - }, - -- Mappings can be configured through AstroCore as well. - -- NOTE: keycodes follow the casing in the vimdocs. For example, `` must be capitalized - mappings = { - -- first key is the mode - n = { - [""] = { "suspend", desc = "Suspend nvim (return with 'fg')" }, - ["Q"] = { "wqa", desc = "Save all buffers and quit Neovim" }, - -- navigate buffer tabs - [""] = { "wabd", desc = "Save and close buffer" }, -- Added C-x to save and close buffer - ["F"] = { "za", desc = "Toggle fold under cursor" }, - ["J"] = { function() vim.diagnostic.goto_next() end, desc = "Next diagnostic" }, - ["K"] = { function() vim.diagnostic.goto_prev() end, desc = "Previous diagnostic" }, - ["L"] = { "BufferLineCycleNext", desc = "Next buffer" }, - ["H"] = { "BufferLineCyclePrev", desc = "Previous buffer" }, - -- Window navigation - [""] = { "h", desc = "Navigate to left window" }, - [""] = { "j", desc = "Navigate to bottom window" }, - [""] = { "k", desc = "Navigate to top window" }, - [""] = { "l", desc = "Navigate to right window" }, - [""] = { "Neotree toggle", desc = "Open Explorer" }, - [""] = { "OverseerRun", desc = "Run Overseer" }, - [""] = { - function() require("snacks").picker.smart() end, - desc = "Find files", - }, - ["b"] = { "BufferLinePick", desc = "Pick buffer" }, - ["f"] = { - function() require("snacks").picker.buffers() end, - desc = "Find buffers", - }, - - [""] = { - function() - local current_buffer = vim.api.nvim_get_current_buf() + end + vim.g.session_pinned_buffers = pinned + end, + -- Restore pinned buffers after session load + after_load = function() + if vim.g.session_pinned_buffers then + vim.defer_fn(function() + for _, bufname in ipairs(vim.g.session_pinned_buffers) do + -- Find the buffer by name for _, buf in ipairs(vim.api.nvim_list_bufs()) do - if buf ~= current_buffer then vim.api.nvim_buf_delete(buf, { force = true }) end - end - end, - desc = "Close all buffers except the current one", - }, - ["g"] = { - function() - local groups = { "DEX", "DID", "DWN", "SVC", "Tests", "Actions", "Claude", "Docs", "Config" } - for _, group in ipairs(groups) do - vim.cmd("BufferLineGroupToggle " .. group) - end - end, - desc = "Toggle all buffer groups", - }, - -- Quick group toggles - ["l"] = { - function() require("snacks").picker.lines() end, - desc = "Find in line", - }, - ["1"] = { "BufferLineGroupToggle DEX", desc = "Toggle DEX group" }, - ["2"] = { "BufferLineGroupToggle DID", desc = "Toggle DID group" }, - ["3"] = { "BufferLineGroupToggle DWN", desc = "Toggle DWN group" }, - ["4"] = { "BufferLineGroupToggle SVC", desc = "Toggle SVC group" }, - ["t"] = { "BufferLineGroupToggle Tests", desc = "Toggle Tests group" }, - ["k"] = { "BufferLinePickClose", desc = "Pick buffer to close" }, - ["o"] = { "!gh repo view --web", desc = "Open Repo on Web" }, - [""] = { - function() - require("snacks").terminal("gh dash", { - hidden = true, - auto_close = true, - interactive = true, - }) - end, - desc = "GH Dash", - }, - [""] = { - terminals.smartCommit_toggle, - desc = "SmartCommit Toggle", - }, - [""] = { - terminals.lazygit_toggle, - desc = "Lazygit Toggle", - }, - [""] = { "Octo issue list", desc = "List Issues" }, - [""] = { "Octo label", desc = "Manage Labels" }, - [""] = { "Octo pr list", desc = "List PRs" }, - ["s"] = { "Octo search", desc = "Octo Search" }, - [""] = { "!gh release list", desc = "List Releases" }, - ["d"] = { - function() require("snacks").picker.git_diff() end, - desc = "Search git diffs", - }, - [""] = { - function() require("snacks").picker.git_branches() end, - desc = "Search git branches", - }, - ["vv"] = { "gg0VG$", desc = "Select all contents in buffer" }, - ["T"] = { "gg", desc = "Go to top of file" }, - ["r"] = { - terminals.scooter_toggle, - desc = "Find and replace", - }, - ["d"] = { - function() require("snacks").picker.diagnostics() end, - desc = "Find diagnostics", - }, - ["l"] = { - function() require("snacks").picker.lines() end, - desc = "Find in line", - }, - ["t"] = { - function() require("snacks").picker.lines() end, - desc = "Find in line", - }, - ["w"] = { - function() require("snacks").picker.grep() end, - desc = "Find word", - }, - ["f"] = { - function() require("snacks").picker.git_files { transform = file_filter } end, - desc = "Find files", - }, - ["o"] = { - function() require("snacks").picker.recent() end, - desc = "Find recent files", - }, - ["gc"] = { - function() - local ai_dir = vim.fn.getcwd() .. "/.ai" - -- Check if directory exists - if vim.fn.isdirectory(ai_dir) == 0 then - vim.notify("No .ai directory found in current project", vim.log.levels.WARN) - return - end - -- Use files picker to find AI files - require("snacks").picker.files { - cwd = ai_dir, - transform = file_filter, - } - end, - desc = "Find AI files", - }, - ["p"] = { desc = "Find Package files" }, - ["m"] = { desc = "Find Module files" }, - ["g"] = { - desc = "Find by Group", - }, - ["gw"] = { - function() - local workflows_dir = vim.fn.getcwd() .. "/.github/workflows" - -- Check if directory exists - if vim.fn.isdirectory(workflows_dir) == 0 then - vim.notify("No .github/workflows directory found in current project", vim.log.levels.WARN) - return - end - -- Use files picker to find workflow files - require("snacks").picker.files { - cwd = workflows_dir, - transform = file_filter, - } - end, - desc = "Find GitHub Workflow files", - }, - ["gd"] = { - function() - require("snacks").picker.files { - cmd = "fd", - args = { - "devbox.json|process-compose.yaml|Dockerfile|docker-compose.yaml|compose.yaml", - }, - } - end, - desc = "Find Devbox/Docker files", - }, - ["gm"] = { - function() - require("snacks").picker.files { - cmd = "fd", - args = { - "Makefile", - }, - } - end, - desc = "Find Makefile files", - }, - ["gp"] = { - function() - require("snacks").picker.files { - cmd = "fd", - args = { - "package.json", - }, - } - end, - desc = "Find Package.json files", - }, - - [""] = { function() terminals.scratch_toggle() end, desc = "Open Scratch Terminal" }, - -- AI/Assistant mappings (Avante) - [""] = { nil, desc = "Avante AI" }, - [""] = { "AvanteToggle", desc = "Toggle Avante" }, - ["a"] = { "AvanteAsk", desc = "Ask Avante" }, - ["e"] = { "AvanteEdit", desc = "Edit with Avante" }, - ["r"] = { "AvanteRefresh", desc = "Refresh Avante" }, - ["f"] = { "AvanteFocus", desc = "Focus Avante" }, - ["c"] = { "AvanteChat", desc = "Avante Chat" }, - ["s"] = { "AvanteSwitchProvider", desc = "Switch Provider" }, - ["C"] = { "AvanteClear", desc = "Clear Avante" }, - -- UI Toggles with Snacks - ["u"] = { desc = "UI Toggles" }, - ["ud"] = { - function() require("snacks").toggle.diagnostics():toggle() end, - desc = "Toggle Diagnostics", - }, - ["un"] = { - function() require("snacks").toggle.line_number():toggle() end, - desc = "Toggle Line Numbers", - }, - ["ur"] = { - function() require("snacks").toggle.option("relativenumber"):toggle() end, - desc = "Toggle Relative Numbers", - }, - ["uw"] = { - function() require("snacks").toggle.option("wrap"):toggle() end, - desc = "Toggle Line Wrap", - }, - ["us"] = { - function() require("snacks").toggle.option("spell"):toggle() end, - desc = "Toggle Spelling", - }, - ["ui"] = { - function() require("snacks").toggle.inlay_hints():toggle() end, - desc = "Toggle Inlay Hints", - }, - ["ut"] = { - function() require("snacks").toggle.treesitter():toggle() end, - desc = "Toggle Treesitter", - }, - ["uc"] = { - function() require("snacks").toggle.option("conceallevel", { off = 0, on = 2 }):toggle() end, - desc = "Toggle Conceal", - }, - ["uI"] = { - function() require("snacks").toggle.indent():toggle() end, - desc = "Toggle Indent Guides", - }, - ["uz"] = { - function() require("snacks").toggle.zen():toggle() end, - desc = "Toggle Zen Mode", - }, - ["uZ"] = { - function() require("snacks").toggle.zoom():toggle() end, - desc = "Toggle Zoom", - }, - ["ua"] = { - function() require("snacks").toggle.animate():toggle() end, - desc = "Toggle Animations", - }, - ["uS"] = { - function() require("snacks").toggle.scroll():toggle() end, - desc = "Toggle Smooth Scroll", - }, - ["up"] = { - function() require("snacks").toggle.profiler():toggle() end, - desc = "Toggle Profiler", - }, - ["uh"] = { - function() require("snacks").toggle.profiler_highlights():toggle() end, - desc = "Toggle Profiler Highlights", - }, - ["ux"] = { - function() require("snacks").toggle.dim():toggle() end, - desc = "Toggle Dim Inactive", - }, - ["uf"] = { - function() - vim.g.disable_autoformat = not vim.g.disable_autoformat - local status = vim.g.disable_autoformat and "disabled" or "enabled" - vim.notify("Format on save " .. status, vim.log.levels.INFO) - end, - desc = "Toggle Format on Save", - }, - ["ul"] = { - function() - local new_value = not require("lsp_lines").toggle() - vim.diagnostic.config { virtual_text = new_value } - end, - desc = "Toggle LSP Lines", - }, - }, - i = { - [""] = { "wabd", desc = "Save, close buffer, and return to normal mode" }, - [""] = { "wabd", desc = "Save, close buffer, and return to normal mode" }, -- Added C-x for insert mode - }, - v = { - [""] = { "Neotree toggle", desc = "Open Explorer" }, - [""] = { "wbd", desc = "Save and close buffer" }, - [""] = { "wbd", desc = "Save and close buffer" }, - -- Avante visual mode mappings - [""] = { "AvanteAsk", desc = "Ask Avante with selection" }, - ["e"] = { "AvanteEdit", desc = "Edit selection with Avante" }, - ["r"] = { "AvanteReplace", desc = "Replace with Avante" }, - ["D"] = { - function() - -- Yank the visual selection to register v - vim.cmd 'normal! "vy' - local selection = vim.fn.getreg "v" - - -- Escape special regex characters - local escaped = vim.fn.escape(selection, [[/\.*$^~[]]) - - -- Delete all occurrences in the buffer (e flag suppresses errors if no match) - vim.cmd(string.format([[%%s/%s//ge]], escaped)) - - -- Show notification of what was deleted - vim.notify(string.format("Deleted all occurrences of: %s", selection), vim.log.levels.INFO) - end, - desc = "Delete all occurrences of selected text", - }, - ["R"] = { - function() - -- Yank the visual selection to register v - vim.cmd 'normal! "vy' - local selection = vim.fn.getreg "v" - - -- Escape special regex characters for search pattern - local escaped = vim.fn.escape(selection, [[/\.*$^~[]]) - - -- Show input prompt using snacks.input - require("snacks").input({ - prompt = string.format("Replace '%s' with:", selection), - default = "", - }, function(replacement) - if replacement then - -- Escape special characters for replacement string - local escaped_replacement = vim.fn.escape(replacement, [[/\&~]]) - - -- Replace all occurrences in the buffer - vim.cmd(string.format([[%%s/%s/%s/ge]], escaped, escaped_replacement)) - - -- Show notification - vim.notify(string.format("Replaced '%s' with '%s'", selection, replacement), vim.log.levels.INFO) + if vim.api.nvim_buf_is_valid(buf) and vim.api.nvim_buf_get_name(buf) == bufname then + -- Pin the buffer using BufferLine command + vim.cmd("BufferLineTogglePin " .. buf) + break end - end) - end, - desc = "Replace all occurrences of selected text", - }, - }, - t = { - [""] = { terminals.mk_toggle, desc = "Taskfile Toggle" }, - [""] = { "Neotree toggle", desc = "Open Explorer" }, - -- Paste from system clipboard - [""] = { function() vim.cmd('normal! "+p') end, desc = "Paste from system clipboard" }, - ["f"] = { - function() require("snacks").picker.buffers() end, - desc = "Find buffers", - }, - [""] = { function() terminals.scratch_toggle() end, desc = "Open Scratch Terminal" }, - -- Exit terminal mode and close window - [""] = { - function() - vim.api.nvim_feedkeys(vim.api.nvim_replace_termcodes([[]], true, false, true), "n", false) - vim.cmd "close" - end, - desc = "Exit terminal and close window", - }, - -- Exit terminal mode and close window - [""] = { - function() - vim.api.nvim_feedkeys(vim.api.nvim_replace_termcodes([[h]], true, false, true), "n", false) - end, - desc = "Navigate to left window", - }, - [""] = { - function() - vim.api.nvim_feedkeys(vim.api.nvim_replace_termcodes([[j]], true, false, true), "n", false) - end, - desc = "Navigate to bottom window", - }, - [""] = { - function() - vim.api.nvim_feedkeys(vim.api.nvim_replace_termcodes([[k]], true, false, true), "n", false) - end, - desc = "Navigate to top window", - }, - [""] = { - function() - vim.api.nvim_feedkeys(vim.api.nvim_replace_termcodes([[l]], true, false, true), "n", false) - end, - desc = "Navigate to right window", - }, + end + end + vim.g.session_pinned_buffers = nil + end, 100) + end + end, + }, + rooter = { + -- list of detectors in order of prevalence, elements can be: + -- "lsp" : lsp detection + -- string[] : a list of directory patterns to look for + -- fun(bufnr: integer): string|string[] : a function that takes a buffer number and outputs detected roots + detector = { + "lsp", -- highest priority is getting workspace from running language servers + { ".git", "_darcs", ".hg", ".bzr", ".svn" }, -- next check for a version controlled parent directory + { + "package.json", + "lua", + "Cargo.toml", + "Pipfile", + "docs.json", + }, -- lastly check for a file named `main` + }, + -- ignore things from root detection + ignore = { + servers = { + "golangci_lint_ls", + }, -- list of language server names to ignore (Ex. { "efm" }) + dirs = {}, -- list of directory patterns (Ex. { "~/.cargo/*" }) + }, + -- automatically update working directory (update manually with `:AstroRoot`) + autochdir = true, + -- scope of working directory to change ("global"|"tab"|"win") + scope = "global", -- Changed from "win" to "global" to make directory changes apply globally + -- show notification on every working directory change + notify = false, + }, + + -- Configure core features of AstroNvim + features = { + autopairs = true, -- enable autopairs at start + diagnostics_mode = 1, -- diagnostic mode on start (0 = off, 1 = no signs/virtual text, 2 = no virtual text, 3 = on) + highlighturl = true, -- highlight URLs at start + notifications = false, -- enable notifications at start + }, + + -- Diagnostics configuration (for vim.diagnostics.config({...})) when diagnostics are on + diagnostics = { + virtual_text = true, + underline = true, + }, + + -- Autocmds can be configured here + autocmds = { + -- Custom title formatting for ghq repos + custom_title = { + { + event = { "BufEnter", "DirChanged" }, + desc = "Update terminal title with org/repo format", + callback = function() + local filepath = vim.fn.expand "%:p" + local filename = vim.fn.expand "%:t" + + -- If no file is open, try to show just the repo name + if filename == "" then + local cwd = vim.fn.getcwd() + local github_match = cwd:match "github%.com/([^/]+/[^/]+)" + if github_match then + vim.opt.titlestring = github_match + else + vim.opt.titlestring = "Nvim" + end + return + end + + -- Check if path contains github.com (ghq structure) + local github_match = filepath:match "github%.com/([^/]+/[^/]+)" + + if github_match then + -- Format: filename | org/repo + vim.opt.titlestring = string.format("%s | %s", filename, github_match) + else + -- Fallback: filename | Nvim + vim.opt.titlestring = string.format("%s | Nvim", filename) + end + end, }, }, + -- Show smart picker on startup + startup_picker = { + { + event = "VimEnter", + desc = "Show smart picker on startup", + callback = function() + -- Skip if opening with arguments + if vim.fn.argc() > 0 then return end + + -- Skip if current buffer has content + local lines = vim.api.nvim_buf_get_lines(0, 0, -1, false) + if #lines > 1 or (#lines == 1 and lines[1] ~= "") then return end + + -- Delay to ensure everything is loaded + vim.defer_fn(function() require("snacks").picker.smart() end, 50) + end, + }, + }, + }, + + -- vim options can be configured here + options = { + opt = { -- vim.opt. + relativenumber = false, -- sets vim.opt.relativenumber + number = true, -- sets vim.opt.number + spell = false, -- sets vim.opt.spell + wrap = true, -- sets vim.opt.wrap + clipboard = "unnamedplus", -- use system clipboard for all operations + title = true, -- enable title string + titlestring = "", -- will be set dynamically by autocommand + laststatus = 0, -- disable statusline (0 = never show) + }, + g = { -- vim.g. + -- configure global vim variables (vim.g) + -- NOTE: `mapleader` and `maplocalleader` must be set in the AstroNvim opts or before `lazy.setup` + -- This can be found in the `lua/lazy_setup.lua` file + }, + }, + -- Mappings can be configured through AstroCore as well. + -- NOTE: keycodes follow the casing in the vimdocs. For example, `` must be capitalized + mappings = { + -- first key is the mode + n = { + [""] = { "suspend", desc = "Suspend nvim (return with 'fg')" }, + ["Q"] = { "wqa", desc = "Save all buffers and quit Neovim" }, + -- navigate buffer tabs + [""] = { "wabd", desc = "Save and close buffer" }, -- Added C-x to save and close buffer + ["F"] = { "za", desc = "Toggle fold under cursor" }, + ["J"] = { function() vim.diagnostic.goto_next() end, desc = "Next diagnostic" }, + ["K"] = { function() vim.diagnostic.goto_prev() end, desc = "Previous diagnostic" }, + ["L"] = { "BufferLineCycleNext", desc = "Next buffer" }, + ["H"] = { "BufferLineCyclePrev", desc = "Previous buffer" }, + -- Window navigation + [""] = { "h", desc = "Navigate to left window" }, + [""] = { "j", desc = "Navigate to bottom window" }, + [""] = { "k", desc = "Navigate to top window" }, + [""] = { "l", desc = "Navigate to right window" }, + [""] = { "Neotree toggle", desc = "Open Explorer" }, + [""] = { "OverseerRun", desc = "Run Overseer" }, + [""] = { + function() require("snacks").picker.smart() end, + desc = "Find files", + }, + ["b"] = { "BufferLinePick", desc = "Pick buffer" }, + ["f"] = { + function() require("snacks").picker.buffers() end, + desc = "Find buffers", + }, + + [""] = { + function() + local current_buffer = vim.api.nvim_get_current_buf() + for _, buf in ipairs(vim.api.nvim_list_bufs()) do + if buf ~= current_buffer then vim.api.nvim_buf_delete(buf, { force = true }) end + end + end, + desc = "Close all buffers except the current one", + }, + ["g"] = { + function() + local groups = { "DEX", "DID", "DWN", "SVC", "Tests", "Actions", "Claude", "Docs", "Config" } + for _, group in ipairs(groups) do + vim.cmd("BufferLineGroupToggle " .. group) + end + end, + desc = "Toggle all buffer groups", + }, + -- Quick group toggles + ["l"] = { + function() require("snacks").picker.lines() end, + desc = "Find in line", + }, + ["1"] = { "BufferLineGroupToggle DEX", desc = "Toggle DEX group" }, + ["2"] = { "BufferLineGroupToggle DID", desc = "Toggle DID group" }, + ["3"] = { "BufferLineGroupToggle DWN", desc = "Toggle DWN group" }, + ["4"] = { "BufferLineGroupToggle SVC", desc = "Toggle SVC group" }, + ["t"] = { "BufferLineGroupToggle Tests", desc = "Toggle Tests group" }, + ["k"] = { "BufferLinePickClose", desc = "Pick buffer to close" }, + ["o"] = { "!gh repo view --web", desc = "Open Repo on Web" }, + [""] = { + function() + require("snacks").terminal("gh dash", { + hidden = true, + auto_close = true, + interactive = true, + }) + end, + desc = "GH Dash", + }, + [""] = { + terminals.smartCommit_toggle, + desc = "SmartCommit Toggle", + }, + [""] = { "tabnext", desc = "Next Tab" }, + [""] = { + terminals.lazydocker_toggle, + desc = "Lazydocker Toggle", + }, + [""] = { + terminals.lazygit_toggle, + desc = "Lazygit Toggle", + }, + [""] = { "Octo issue list", desc = "List Issues" }, + [""] = { "Octo label", desc = "Manage Labels" }, + [""] = { "Octo pr list", desc = "List PRs" }, + ["s"] = { "Octo search", desc = "Octo Search" }, + [""] = { "!gh release list", desc = "List Releases" }, + ["d"] = { + function() require("snacks").picker.git_diff() end, + desc = "Search git diffs", + }, + [""] = { + function() require("snacks").picker.git_branches() end, + desc = "Search git branches", + }, + ["vv"] = { "gg0VG$", desc = "Select all contents in buffer" }, + ["T"] = { "gg", desc = "Go to top of file" }, + ["r"] = { + terminals.scooter_toggle, + desc = "Find and replace", + }, + ["d"] = { + function() require("snacks").picker.diagnostics() end, + desc = "Find diagnostics", + }, + ["l"] = { + function() require("snacks").picker.lines() end, + desc = "Find in line", + }, + ["t"] = { + function() require("snacks").picker.lines() end, + desc = "Find in line", + }, + ["w"] = { + function() require("snacks").picker.grep() end, + desc = "Find word", + }, + ["f"] = { + function() require("snacks").picker.git_files { transform = file_filter } end, + desc = "Find files", + }, + ["o"] = { + function() require("snacks").picker.recent() end, + desc = "Find recent files", + }, + ["gc"] = { + function() + local ai_dir = vim.fn.getcwd() .. "/.ai" + -- Check if directory exists + if vim.fn.isdirectory(ai_dir) == 0 then + vim.notify("No .ai directory found in current project", vim.log.levels.WARN) + return + end + -- Use files picker to find AI files + require("snacks").picker.files { + cwd = ai_dir, + transform = file_filter, + } + end, + desc = "Find AI files", + }, + ["p"] = { desc = "Find Package files" }, + ["m"] = { desc = "Find Module files" }, + ["g"] = { + desc = "Find by Group", + }, + ["gw"] = { + function() + local workflows_dir = vim.fn.getcwd() .. "/.github/workflows" + -- Check if directory exists + if vim.fn.isdirectory(workflows_dir) == 0 then + vim.notify("No .github/workflows directory found in current project", vim.log.levels.WARN) + return + end + -- Use files picker to find workflow files + require("snacks").picker.files { + cwd = workflows_dir, + transform = file_filter, + } + end, + desc = "Find GitHub Workflow files", + }, + ["gd"] = { + function() + require("snacks").picker.files { + cmd = "fd", + args = { + "devbox.json|process-compose.yaml|Dockerfile|docker-compose.yaml|compose.yaml", + }, + } + end, + desc = "Find Devbox/Docker files", + }, + ["gm"] = { + function() + require("snacks").picker.files { + cmd = "fd", + args = { + "Makefile", + }, + } + end, + desc = "Find Makefile files", + }, + ["gp"] = { + function() + require("snacks").picker.files { + cmd = "fd", + args = { + "package.json", + }, + } + end, + desc = "Find Package.json files", + }, + + [""] = { function() terminals.scratch_toggle() end, desc = "Open Scratch Terminal" }, + -- AI/Assistant mappings (Avante) + [""] = { nil, desc = "Avante AI" }, + [""] = { "AvanteToggle", desc = "Toggle Avante" }, + ["a"] = { "AvanteAsk", desc = "Ask Avante" }, + ["e"] = { "AvanteEdit", desc = "Edit with Avante" }, + ["r"] = { "AvanteRefresh", desc = "Refresh Avante" }, + ["f"] = { "AvanteFocus", desc = "Focus Avante" }, + ["c"] = { "AvanteChat", desc = "Avante Chat" }, + ["s"] = { "AvanteSwitchProvider", desc = "Switch Provider" }, + ["C"] = { "AvanteClear", desc = "Clear Avante" }, + -- UI Toggles with Snacks + ["u"] = { desc = "UI Toggles" }, + ["ud"] = { + function() require("snacks").toggle.diagnostics():toggle() end, + desc = "Toggle Diagnostics", + }, + ["un"] = { + function() require("snacks").toggle.line_number():toggle() end, + desc = "Toggle Line Numbers", + }, + ["ur"] = { + function() require("snacks").toggle.option("relativenumber"):toggle() end, + desc = "Toggle Relative Numbers", + }, + ["uw"] = { + function() require("snacks").toggle.option("wrap"):toggle() end, + desc = "Toggle Line Wrap", + }, + ["us"] = { + function() require("snacks").toggle.option("spell"):toggle() end, + desc = "Toggle Spelling", + }, + ["ui"] = { + function() require("snacks").toggle.inlay_hints():toggle() end, + desc = "Toggle Inlay Hints", + }, + ["ut"] = { + function() require("snacks").toggle.treesitter():toggle() end, + desc = "Toggle Treesitter", + }, + ["uc"] = { + function() require("snacks").toggle.option("conceallevel", { off = 0, on = 2 }):toggle() end, + desc = "Toggle Conceal", + }, + ["uI"] = { + function() require("snacks").toggle.indent():toggle() end, + desc = "Toggle Indent Guides", + }, + ["uz"] = { + function() require("snacks").toggle.zen():toggle() end, + desc = "Toggle Zen Mode", + }, + ["uZ"] = { + function() require("snacks").toggle.zoom():toggle() end, + desc = "Toggle Zoom", + }, + ["ua"] = { + function() require("snacks").toggle.animate():toggle() end, + desc = "Toggle Animations", + }, + ["uS"] = { + function() require("snacks").toggle.scroll():toggle() end, + desc = "Toggle Smooth Scroll", + }, + ["up"] = { + function() require("snacks").toggle.profiler():toggle() end, + desc = "Toggle Profiler", + }, + ["uh"] = { + function() require("snacks").toggle.profiler_highlights():toggle() end, + desc = "Toggle Profiler Highlights", + }, + ["ux"] = { + function() require("snacks").toggle.dim():toggle() end, + desc = "Toggle Dim Inactive", + }, + ["uf"] = { + function() + vim.g.disable_autoformat = not vim.g.disable_autoformat + local status = vim.g.disable_autoformat and "disabled" or "enabled" + vim.notify("Format on save " .. status, vim.log.levels.INFO) + end, + desc = "Toggle Format on Save", + }, + ["ul"] = { + function() + local new_value = not require("lsp_lines").toggle() + vim.diagnostic.config { virtual_text = new_value } + end, + desc = "Toggle LSP Lines", + }, + }, + i = { + [""] = { "wabd", desc = "Save, close buffer, and return to normal mode" }, + [""] = { "wabd", desc = "Save, close buffer, and return to normal mode" }, -- Added C-x for insert mode + }, + v = { + [""] = { "Neotree toggle", desc = "Open Explorer" }, + [""] = { "wbd", desc = "Save and close buffer" }, + [""] = { "wbd", desc = "Save and close buffer" }, + -- Avante visual mode mappings + [""] = { "AvanteAsk", desc = "Ask Avante with selection" }, + ["e"] = { "AvanteEdit", desc = "Edit selection with Avante" }, + ["r"] = { "AvanteReplace", desc = "Replace with Avante" }, + ["D"] = { + function() + -- Yank the visual selection to register v + vim.cmd 'normal! "vy' + local selection = vim.fn.getreg "v" + + -- Escape special regex characters + local escaped = vim.fn.escape(selection, [[/\.*$^~[]]) + + -- Delete all occurrences in the buffer (e flag suppresses errors if no match) + vim.cmd(string.format([[%%s/%s//ge]], escaped)) + + -- Show notification of what was deleted + vim.notify(string.format("Deleted all occurrences of: %s", selection), vim.log.levels.INFO) + end, + desc = "Delete all occurrences of selected text", + }, + ["R"] = { + function() + -- Yank the visual selection to register v + vim.cmd 'normal! "vy' + local selection = vim.fn.getreg "v" + + -- Escape special regex characters for search pattern + local escaped = vim.fn.escape(selection, [[/\.*$^~[]]) + + -- Show input prompt using snacks.input + require("snacks").input({ + prompt = string.format("Replace '%s' with:", selection), + default = "", + }, function(replacement) + if replacement then + -- Escape special characters for replacement string + local escaped_replacement = vim.fn.escape(replacement, [[/\&~]]) + + -- Replace all occurrences in the buffer + vim.cmd(string.format([[%%s/%s/%s/ge]], escaped, escaped_replacement)) + + -- Show notification + vim.notify(string.format("Replaced '%s' with '%s'", selection, replacement), vim.log.levels.INFO) + end + end) + end, + desc = "Replace all occurrences of selected text", + }, + }, + t = { + [""] = { terminals.mk_toggle, desc = "Taskfile Toggle" }, + [""] = { "Neotree toggle", desc = "Open Explorer" }, + -- Paste from system clipboard + [""] = { function() vim.cmd 'normal! "+p' end, desc = "Paste from system clipboard" }, + ["f"] = { + function() require("snacks").picker.buffers() end, + desc = "Find buffers", + }, + [""] = { function() terminals.scratch_toggle() end, desc = "Open Scratch Terminal" }, + -- Exit terminal mode and close window + [""] = { + function() + vim.api.nvim_feedkeys(vim.api.nvim_replace_termcodes([[]], true, false, true), "n", false) + vim.cmd "close" + end, + desc = "Exit terminal and close window", + }, + -- Exit terminal mode and close window + [""] = { + function() + vim.api.nvim_feedkeys(vim.api.nvim_replace_termcodes([[h]], true, false, true), "n", false) + end, + desc = "Navigate to left window", + }, + [""] = { + function() + vim.api.nvim_feedkeys(vim.api.nvim_replace_termcodes([[j]], true, false, true), "n", false) + end, + desc = "Navigate to bottom window", + }, + [""] = { + function() + vim.api.nvim_feedkeys(vim.api.nvim_replace_termcodes([[k]], true, false, true), "n", false) + end, + desc = "Navigate to top window", + }, + [""] = { + function() + vim.api.nvim_feedkeys(vim.api.nvim_replace_termcodes([[l]], true, false, true), "n", false) + end, + desc = "Navigate to right window", + }, + }, + }, }, } diff --git a/lua/plugins/astroui.lua b/lua/plugins/astroui.lua index f592486..d67aace 100644 --- a/lua/plugins/astroui.lua +++ b/lua/plugins/astroui.lua @@ -13,7 +13,6 @@ return { GitChange = "", GitDelete = "", }, - }, }, {