if vim.g.loaded_git then return end vim.g.loaded_git = 1 local DEFAULT_HIGHLIGHTS = { GitIgnored = "Comment", GitSha = "Identifier", GitStaged = "Constant", GitUnmerged = "Todo", GitUnpulled = "Removed", GitUnpushed = "Added", GitUnstaged = "Changed", GitUntracked = "Added", GitStagedAdded = "GitStaged", GitStagedCopied = "GitStaged", GitStagedDeleted = "GitStaged", GitStagedModified = "GitStaged", GitStagedRenamed = "GitStaged", GitStagedTypeChanged = "GitStaged", GitUnstagedAdded = "GitUnstaged", GitUnstagedCopied = "GitUnstaged", GitUnstagedDeleted = "Removed", GitUnstagedModified = "GitUnstaged", GitUnstagedRenamed = "GitStaged", GitUnstagedTypeChanged = "GitUnstaged", GitUnmergedAddedByThem = "GitUnmerged", GitUnmergedAddedByUs = "GitUnmerged", GitUnmergedBothAdded = "GitUnmerged", GitUnmergedBothDeleted = "GitUnmerged", GitUnmergedBothModified = "GitUnmerged", GitUnmergedDeletedByThem = "GitUnmerged", GitUnmergedDeletedByUs = "GitUnmerged", GitHunkAdded = "Added", GitHunkChanged = "Changed", GitHunkRemoved = "Removed", GitHunkAddLine = "DiffAdd", GitHunkDeleteLine = "DiffDelete", } for name, link in pairs(DEFAULT_HIGHLIGHTS) do vim.api.nvim_set_hl(0, name, { link = link, default = true }) end local group = vim.api.nvim_create_augroup("ow.git", { clear = true }) vim.api.nvim_create_autocmd({ "BufReadPost", "BufNewFile" }, { group = group, callback = function(args) require("git.core.repo").track(args.buf) require("git.hunks").attach(args.buf) end, }) vim.api.nvim_create_autocmd({ "BufWritePost", "FileChangedShellPost" }, { group = group, callback = function(args) require("git.core.repo").refresh(args.buf) end, }) vim.api.nvim_create_autocmd({ "ShellCmdPost", "TermLeave", "FocusGained" }, { group = group, callback = function() for _, r in pairs(require("git.core.repo").all()) do r:refresh({ invalidate = true }) end end, }) vim.api.nvim_create_autocmd({ "BufDelete", "BufWipeout" }, { group = group, callback = function(args) require("git.hunks").detach(args.buf) require("git.core.repo").unbind(args.buf) end, }) vim.api.nvim_create_autocmd("VimLeavePre", { group = group, callback = function() require("git.core.repo").stop_all() end, }) vim.api.nvim_create_autocmd({ "VimEnter", "DirChanged", "TabEnter" }, { group = group, callback = function() require("git.core.repo").update_cwd_repo() end, }) vim.api.nvim_create_autocmd("TabClosed", { group = group, callback = function(args) local tab = tonumber(args.file) --[[@as integer?]] if tab then require("git.core.repo").release_tab(tab) end end, }) vim.api.nvim_create_autocmd("BufReadCmd", { pattern = "git://*", group = group, callback = function(args) require("git.object").read_uri(args.buf) end, }) vim.api.nvim_create_user_command("G", function(opts) local cmd = require("git.cmd") cmd.run(cmd.parse_args(opts.args), { bang = opts.bang }) end, { nargs = "*", bang = true, complete = function(...) return require("git.cmd").complete(...) end, }) vim.api.nvim_create_user_command("Grefresh", function() require("git.core.repo").refresh_all() end, { desc = "Refresh git status for all repos" }) vim.api.nvim_create_user_command("Glog", function(opts) require("git.log_view").run_glog(opts) end, { nargs = "*", complete = function(...) return require("git.log_view").complete_glog(...) end, desc = "Show git log", }) local function complete_rev(...) return require("git.cmd").complete_rev(...) end local DIFF_DIRECTIONS = { "vertical", "horizontal" } vim.api.nvim_create_user_command("Gdiffsplit", function(opts) local fargs = opts.fargs local mods = nil local rev_idx = 1 if fargs[1] == "vertical" then mods = { vertical = true } rev_idx = 2 elseif fargs[1] == "horizontal" then mods = { vertical = false } rev_idx = 2 end require("git.diffsplit").open({ target = fargs[rev_idx], mods = mods }) end, { nargs = "*", complete = function(arg_lead, cmd_line, _) local rest = cmd_line:gsub("^%s*%S+%s*", "", 1) local trailing_space = rest == "" or rest:sub(-1):match("%s") ~= nil local tokens = vim.split(vim.trim(rest), "%s+", { trimempty = true }) local prior = trailing_space and tokens or vim.list_slice(tokens, 1, #tokens - 1) local results = {} if #prior == 0 then for _, d in ipairs(DIFF_DIRECTIONS) do if vim.startswith(d, arg_lead) then table.insert(results, d) end end end local first_is_direction = prior[1] == "vertical" or prior[1] == "horizontal" if #prior == 0 or (#prior == 1 and first_is_direction) then vim.list_extend(results, complete_rev(arg_lead)) end return results end, desc = "Open a diff split", }) vim.api.nvim_create_user_command("Gedit", function(opts) vim.cmd.edit({ args = { require("git.object").URI_PREFIX .. opts.args }, magic = { file = false }, }) end, { nargs = 1, complete = complete_rev, desc = "Edit a git object ()", }) vim.api.nvim_create_user_command("Gstatus", function(opts) require("git.status_view").open({ placement = opts.fargs[1] --[[@as ow.Git.StatusView.Placement]] or "split", }) end, { nargs = "?", complete = function() return require("git.status_view").PLACEMENTS end, desc = "Open git status view", }) vim.keymap.set("n", "(git-edit)", function() local rev = vim.fn.input("Edit git object: ") if rev == "" then return end vim.cmd.edit({ args = { require("git.object").URI_PREFIX .. rev }, magic = { file = false }, }) end, { silent = true, desc = "Edit a git object" }) vim.keymap.set("n", "(git-diffsplit-vertical)", function() require("git.diffsplit").open({ mods = { vertical = true } }) end, { silent = true, desc = "Open a diff split against index (vertical)" }) vim.keymap.set("n", "(git-diffsplit-horizontal)", function() require("git.diffsplit").open({ mods = { vertical = false } }) end, { silent = true, desc = "Open a diff split against index (horizontal)" }) vim.keymap.set("n", "(git-diffsplit-vertical-head)", function() require("git.diffsplit").open({ target = "HEAD", mods = { vertical = true }, }) end, { silent = true, desc = "Open a diff split against HEAD (vertical)" }) vim.keymap.set("n", "(git-diffsplit-horizontal-head)", function() require("git.diffsplit").open({ target = "HEAD", mods = { vertical = false }, }) end, { silent = true, desc = "Open a diff split against HEAD (horizontal)" }) vim.keymap.set("n", "(git-status-open)", function() require("git.status_view").open() end, { silent = true, desc = "Open git status sidebar" }) vim.keymap.set("n", "(git-status-toggle)", function() require("git.status_view").toggle() end, { silent = true, desc = "Toggle git status sidebar" }) vim.keymap.set("n", "(git-log)", function() require("git.log_view").open({ max_count = 1000 }) end, { silent = true, desc = "Open git log" }) vim.keymap.set("n", "(git-commit)", function() require("git.commit").commit() end, { silent = true, desc = "Start a git commit" }) vim.keymap.set("n", "(git-commit-amend)", function() require("git.commit").commit({ args = { "--amend" } }) end, { silent = true, desc = "Amend the last git commit" }) if vim.g.git_statusline ~= false then vim.api.nvim_create_autocmd("BufWinEnter", { group = group, once = true, callback = function() require("git.statusline") end, }) end vim.keymap.set({ "n", "x" }, "(git-hunk-next)", function() require("git.hunks").nav("next") end, { silent = true, desc = "Jump to next git hunk" }) vim.keymap.set({ "n", "x" }, "(git-hunk-prev)", function() require("git.hunks").nav("prev") end, { silent = true, desc = "Jump to previous git hunk" }) vim.keymap.set("n", "(git-hunk-stage)", function() require("git.hunks").stage_hunk() end, { silent = true, desc = "Stage hunk under cursor" }) vim.keymap.set("n", "(git-hunk-reset)", function() require("git.hunks").reset_hunk() end, { silent = true, desc = "Reset hunk under cursor" }) vim.keymap.set("n", "(git-hunk-preview)", function() require("git.hunks").preview_hunk() end, { silent = true, desc = "Preview hunk under cursor" }) vim.keymap.set("n", "(git-hunk-select)", function() require("git.hunks").select_hunk() end, { silent = true, desc = "Select hunk under cursor" }) vim.keymap.set("n", "(git-overlay-toggle)", function() require("git.hunks").toggle_overlay() end, { silent = true, desc = "Toggle the git diff overlay" }) vim.api.nvim_create_user_command("GitDiffOverlay", function() require("git.hunks").toggle_overlay() end, { desc = "Toggle the git diff overlay in the current buffer" })