636 lines
11 KiB
Lua
636 lines
11 KiB
Lua
return {
|
|
"folke/snacks.nvim",
|
|
priority = 1000,
|
|
lazy = false,
|
|
opts = {
|
|
-- your configuration comes here
|
|
-- or leave it empty to use the default settings
|
|
-- refer to the configuration section below
|
|
bigfile = { enabled = true },
|
|
notifier = { enabled = true },
|
|
quickfile = { enabled = true },
|
|
statuscolumn = { enabled = true },
|
|
words = { enabled = true },
|
|
picker = {},
|
|
explorer = {},
|
|
},
|
|
keys = {
|
|
{
|
|
"<leader>.",
|
|
function()
|
|
Snacks.scratch()
|
|
end,
|
|
desc = "Toggle Scratch Buffer",
|
|
},
|
|
{
|
|
"<leader>S",
|
|
function()
|
|
Snacks.scratch.select()
|
|
end,
|
|
desc = "Select Scratch Buffer",
|
|
},
|
|
{
|
|
"<leader>n",
|
|
function()
|
|
Snacks.notifier.show_history()
|
|
end,
|
|
desc = "Notification History",
|
|
},
|
|
|
|
{
|
|
"<leader>gB",
|
|
function()
|
|
Snacks.gitbrowse()
|
|
end,
|
|
desc = "Git Browse",
|
|
},
|
|
-- {
|
|
-- "<leader>gb",
|
|
-- function()
|
|
-- Snacks.git.blame_line()
|
|
-- end,
|
|
-- desc = "Git Blame Line",
|
|
-- },
|
|
{
|
|
"<leader>gf",
|
|
function()
|
|
Snacks.lazygit.log_file()
|
|
end,
|
|
desc = "Lazygit Current File History",
|
|
},
|
|
{
|
|
"<leader>lg",
|
|
function()
|
|
Snacks.lazygit()
|
|
end,
|
|
desc = "Lazygit",
|
|
},
|
|
{
|
|
"<leader>gl",
|
|
function()
|
|
Snacks.lazygit.log()
|
|
end,
|
|
desc = "Lazygit Log (cwd)",
|
|
},
|
|
{
|
|
"<leader>dn",
|
|
function()
|
|
Snacks.notifier.hide()
|
|
end,
|
|
desc = "Dismiss All Notifications",
|
|
},
|
|
{
|
|
"<c-/>",
|
|
function()
|
|
Snacks.terminal()
|
|
end,
|
|
desc = "Toggle Terminal",
|
|
},
|
|
{
|
|
"<c-_>",
|
|
function()
|
|
Snacks.terminal()
|
|
end,
|
|
desc = "which_key_ignore",
|
|
},
|
|
{
|
|
"]]",
|
|
function()
|
|
Snacks.words.jump(vim.v.count1)
|
|
end,
|
|
desc = "Next Reference",
|
|
mode = { "n", "t" },
|
|
},
|
|
{
|
|
"[[",
|
|
function()
|
|
Snacks.words.jump(-vim.v.count1)
|
|
end,
|
|
desc = "Prev Reference",
|
|
mode = { "n", "t" },
|
|
},
|
|
{
|
|
"<leader>N",
|
|
desc = "Neovim News",
|
|
function()
|
|
Snacks.win({
|
|
file = vim.api.nvim_get_runtime_file("doc/news.txt", false)[1],
|
|
width = 0.6,
|
|
height = 0.6,
|
|
wo = {
|
|
spell = false,
|
|
wrap = false,
|
|
signcolumn = "yes",
|
|
statuscolumn = " ",
|
|
conceallevel = 3,
|
|
},
|
|
})
|
|
end,
|
|
},
|
|
-- Snacks Picker
|
|
-- Top Pickers & Explorer
|
|
{
|
|
"<leader><space>",
|
|
function()
|
|
Snacks.picker.smart()
|
|
end,
|
|
desc = "Smart Find Files",
|
|
},
|
|
{
|
|
"<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",
|
|
},
|
|
{
|
|
"<leader>e",
|
|
function()
|
|
Snacks.explorer()
|
|
end,
|
|
desc = "File Explorer",
|
|
},
|
|
-- find
|
|
{
|
|
"<leader>fb",
|
|
function()
|
|
Snacks.picker.buffers()
|
|
end,
|
|
desc = "Buffers",
|
|
},
|
|
{
|
|
"<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 Git Files",
|
|
},
|
|
{
|
|
"<leader>fp",
|
|
function()
|
|
Snacks.picker.projects()
|
|
end,
|
|
desc = "Projects",
|
|
},
|
|
{
|
|
"<leader>fr",
|
|
function()
|
|
Snacks.picker.recent()
|
|
end,
|
|
desc = "Recent",
|
|
},
|
|
-- git
|
|
{
|
|
"<leader>gcb",
|
|
function()
|
|
local cwd = vim.fn.getcwd()
|
|
|
|
-- Helper to run git commands and capture both stdout and stderr
|
|
local function git_cmd(cmd)
|
|
local full_cmd = "cd " .. vim.fn.shellescape(cwd) .. " && " .. cmd .. " 2>&1"
|
|
local handle = io.popen(full_cmd)
|
|
local result = handle and handle:read("*a") or ""
|
|
if handle then
|
|
handle:close()
|
|
end
|
|
return result:gsub("%s+$", "")
|
|
end
|
|
|
|
-- Check if in a git repo
|
|
local git_dir = git_cmd("git rev-parse --git-dir")
|
|
if git_dir == "" or git_dir:match("^fatal") then
|
|
vim.notify("Not in a git repository", vim.log.levels.WARN)
|
|
return
|
|
end
|
|
|
|
-- Get the default branch
|
|
local function branch_exists(branch)
|
|
local result = git_cmd("git rev-parse --verify refs/remotes/origin/" .. branch)
|
|
-- If branch exists, rev-parse returns a hash; if not, it returns fatal error
|
|
return not result:match("^fatal")
|
|
end
|
|
|
|
local default_branch = nil
|
|
if branch_exists("main") then
|
|
default_branch = "main"
|
|
elseif branch_exists("master") then
|
|
default_branch = "master"
|
|
end
|
|
|
|
if not default_branch then
|
|
vim.notify("No origin/main or origin/master found", vim.log.levels.WARN)
|
|
return
|
|
end
|
|
|
|
-- Get current branch
|
|
local current_branch = git_cmd("git branch --show-current")
|
|
if current_branch == "" then
|
|
current_branch = "HEAD"
|
|
end
|
|
|
|
local compare_target = "origin/" .. default_branch
|
|
|
|
-- Get files that differ from origin/main (includes committed + uncommitted changes)
|
|
local result = git_cmd("git diff --name-only " .. compare_target)
|
|
|
|
-- Also get untracked files
|
|
local untracked = git_cmd("git ls-files --others --exclude-standard")
|
|
|
|
-- Combine results
|
|
local all_files = {}
|
|
local seen = {}
|
|
|
|
for line in result:gmatch("[^\r\n]+") do
|
|
if line ~= "" and not seen[line] then
|
|
seen[line] = true
|
|
table.insert(all_files, { text = line, file = line })
|
|
end
|
|
end
|
|
|
|
for line in untracked:gmatch("[^\r\n]+") do
|
|
if line ~= "" and not seen[line] then
|
|
seen[line] = true
|
|
table.insert(all_files, { text = line .. " [untracked]", file = line })
|
|
end
|
|
end
|
|
|
|
if #all_files == 0 then
|
|
vim.notify("No modified files (vs " .. compare_target .. ")", vim.log.levels.INFO)
|
|
return
|
|
end
|
|
|
|
Snacks.picker({
|
|
title = "Modified Files (vs " .. compare_target .. ")",
|
|
items = all_files,
|
|
layout = { preset = "default" },
|
|
confirm = function(picker, item)
|
|
picker:close()
|
|
if item and item.text then
|
|
-- Strip [untracked] suffix if present
|
|
local file = item.text:gsub(" %[untracked%]$", "")
|
|
vim.cmd("edit " .. vim.fn.fnameescape(file))
|
|
end
|
|
end,
|
|
})
|
|
end,
|
|
desc = "Git Modified Files (vs origin/main)",
|
|
},
|
|
{
|
|
"<leader>gb",
|
|
function()
|
|
Snacks.picker.git_branches()
|
|
end,
|
|
desc = "Git Branches",
|
|
},
|
|
{
|
|
"<leader>gl",
|
|
function()
|
|
Snacks.picker.git_log()
|
|
end,
|
|
desc = "Git Log",
|
|
},
|
|
{
|
|
"<leader>gL",
|
|
function()
|
|
Snacks.picker.git_log_line()
|
|
end,
|
|
desc = "Git Log Line",
|
|
},
|
|
{
|
|
"<leader>gs",
|
|
function()
|
|
Snacks.picker.git_status()
|
|
end,
|
|
desc = "Git Status",
|
|
},
|
|
{
|
|
"<leader>gS",
|
|
function()
|
|
Snacks.picker.git_stash()
|
|
end,
|
|
desc = "Git Stash",
|
|
},
|
|
{
|
|
"<leader>gd",
|
|
function()
|
|
Snacks.picker.git_diff()
|
|
end,
|
|
desc = "Git Diff (Hunks)",
|
|
},
|
|
{
|
|
"<leader>gf",
|
|
function()
|
|
Snacks.picker.git_log_file()
|
|
end,
|
|
desc = "Git Log File",
|
|
},
|
|
-- gh
|
|
{
|
|
"<leader>gi",
|
|
function()
|
|
Snacks.picker.gh_issue()
|
|
end,
|
|
desc = "GitHub Issues (open)",
|
|
},
|
|
{
|
|
"<leader>gI",
|
|
function()
|
|
Snacks.picker.gh_issue({ state = "all" })
|
|
end,
|
|
desc = "GitHub Issues (all)",
|
|
},
|
|
{
|
|
"<leader>gp",
|
|
function()
|
|
Snacks.picker.gh_pr()
|
|
end,
|
|
desc = "GitHub Pull Requests (open)",
|
|
},
|
|
{
|
|
"<leader>gP",
|
|
function()
|
|
Snacks.picker.gh_pr({ state = "all" })
|
|
end,
|
|
desc = "GitHub Pull Requests (all)",
|
|
},
|
|
-- 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>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>s/",
|
|
function()
|
|
Snacks.picker.search_history()
|
|
end,
|
|
desc = "Search History",
|
|
},
|
|
{
|
|
"<leader>sa",
|
|
function()
|
|
Snacks.picker.autocmds()
|
|
end,
|
|
desc = "Autocmds",
|
|
},
|
|
{
|
|
"<leader>sb",
|
|
function()
|
|
Snacks.picker.lines()
|
|
end,
|
|
desc = "Buffer Lines",
|
|
},
|
|
{
|
|
"<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>sD",
|
|
function()
|
|
Snacks.picker.diagnostics_buffer()
|
|
end,
|
|
desc = "Buffer 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.marks()
|
|
end,
|
|
desc = "Marks",
|
|
},
|
|
{
|
|
"<leader>sM",
|
|
function()
|
|
Snacks.picker.man()
|
|
end,
|
|
desc = "Man Pages",
|
|
},
|
|
{
|
|
"<leader>sp",
|
|
function()
|
|
Snacks.picker.lazy()
|
|
end,
|
|
desc = "Search for Plugin Spec",
|
|
},
|
|
{
|
|
"<leader>sq",
|
|
function()
|
|
Snacks.picker.qflist()
|
|
end,
|
|
desc = "Quickfix List",
|
|
},
|
|
{
|
|
"<leader>sr",
|
|
function()
|
|
Snacks.picker.resume()
|
|
end,
|
|
desc = "Resume",
|
|
},
|
|
{
|
|
"<leader>su",
|
|
function()
|
|
Snacks.picker.undo()
|
|
end,
|
|
desc = "Undo History",
|
|
},
|
|
{
|
|
"<leader>uC",
|
|
function()
|
|
Snacks.picker.colorschemes()
|
|
end,
|
|
desc = "Colorschemes",
|
|
},
|
|
-- LSP
|
|
{
|
|
"gd",
|
|
function()
|
|
Snacks.picker.lsp_definitions()
|
|
end,
|
|
desc = "Goto Definition",
|
|
},
|
|
{
|
|
"gD",
|
|
function()
|
|
Snacks.picker.lsp_declarations()
|
|
end,
|
|
desc = "Goto Declaration",
|
|
},
|
|
{
|
|
"gref",
|
|
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",
|
|
},
|
|
{
|
|
"gai",
|
|
function()
|
|
Snacks.picker.lsp_incoming_calls()
|
|
end,
|
|
desc = "C[a]lls Incoming",
|
|
},
|
|
{
|
|
"gao",
|
|
function()
|
|
Snacks.picker.lsp_outgoing_calls()
|
|
end,
|
|
desc = "C[a]lls Outgoing",
|
|
},
|
|
{
|
|
"<leader>ss",
|
|
function()
|
|
Snacks.picker.lsp_symbols()
|
|
end,
|
|
desc = "LSP Symbols",
|
|
},
|
|
{
|
|
"<leader>sS",
|
|
function()
|
|
Snacks.picker.lsp_workspace_symbols()
|
|
end,
|
|
desc = "LSP Workspace Symbols",
|
|
},
|
|
},
|
|
}
|