neogit/lua/neogit.lua

297 lines
6.7 KiB
Lua

local M = {}
local did_setup = false
---Setup neogit
---@param opts NeogitConfig
function M.setup(opts)
if vim.fn.has("nvim-0.10") ~= 1 then
vim.notify("Neogit HEAD requires at least NVIM 0.10 - Pin to tag 'v0.0.1' for NVIM 0.9.x")
return
end
local config = require("neogit.config")
local signs = require("neogit.lib.signs")
local autocmds = require("neogit.autocmds")
local hl = require("neogit.lib.hl")
local state = require("neogit.lib.state")
local logger = require("neogit.logger")
if did_setup then
logger.debug("Already did setup!")
return
end
did_setup = true
M.autocmd_group = vim.api.nvim_create_augroup("Neogit", { clear = false })
M.status = require("neogit.buffers.status")
M.dispatch_reset = function()
local instance = M.status.instance()
if instance then
instance:dispatch_reset()
end
end
M.refresh = function()
local instance = M.status.instance()
if instance then
instance:refresh()
end
end
M.reset = function()
local instance = M.status.instance()
if instance then
instance:reset()
end
end
M.dispatch_refresh = function()
local instance = M.status.instance()
if instance then
instance:dispatch_refresh()
end
end
M.close = function()
local instance = M.status.instance()
if instance then
instance:close()
end
end
-- TODO ?
-- M.refresh_viml_compat = M.status.refresh_viml_compat
-- M.refresh_manually = M.status.refresh_manually
M.lib = require("neogit.lib")
M.cli = M.lib.git.cli
M.popups = require("neogit.popups")
M.config = config
M.notification = require("neogit.lib.notification")
config.setup(opts)
hl.setup()
signs.setup()
state.setup()
autocmds.setup()
end
local function construct_opts(opts)
opts = opts or {}
if opts.cwd and not opts.no_expand then
opts.cwd = vim.fn.expand(opts.cwd)
end
if not opts.cwd then
local git = require("neogit.lib.git")
opts.cwd = git.cli.git_root(".")
if opts.cwd == "" then
opts.cwd = vim.uv.cwd()
end
end
return opts
end
local function open_popup(name)
local has_pop, popup = pcall(require, "neogit.popups." .. name)
if not has_pop then
M.notification.error(("Invalid popup %q"):format(name))
else
popup.create {}
end
end
local function open_status_buffer(opts)
local status = require("neogit.buffers.status")
local config = require("neogit.config")
-- We need to construct the repo instance manually here since the actual CWD may not be the directory neogit is
-- going to open into. We will use vim.fn.lcd() in the status buffer constructor, so this will eventually be
-- correct.
local repo = require("neogit.lib.git.repository").instance(opts.cwd)
status.new(repo.state, config.values, repo.git_root):open(opts.kind, opts.cwd):dispatch_refresh()
end
---@alias Popup
---| "bisect"
---| "branch"
---| "branch_config"
---| "cherry_pick"
---| "commit"
---| "diff"
---| "fetch"
---| "help"
---| "ignore"
---| "log"
---| "merge"
---| "pull"
---| "push"
---| "rebase"
---| "remote"
---| "remote_config"
---| "reset"
---| "revert"
---| "stash"
---| "tag"
---| "worktree"
---@class OpenOpts
---@field cwd string|nil
---@field [1] Popup|nil
---@field kind string|nil
---@field no_expand boolean|nil
---@param opts OpenOpts|nil
function M.open(opts)
local notification = require("neogit.lib.notification")
if not did_setup then
notification.error("Neogit has not been setup!")
return
end
opts = construct_opts(opts)
local git = require("neogit.lib.git")
if not git.cli.is_inside_worktree(opts.cwd) then
local input = require("neogit.lib.input")
if input.get_permission(("Initialize repository in %s?"):format(opts.cwd)) then
git.init.create(opts.cwd)
else
notification.error("The current working directory is not a git repository")
return
end
end
if opts[1] ~= nil then
local a = require("plenary.async")
local cb = function()
open_popup(opts[1])
end
a.void(function()
git.repo:dispatch_refresh { source = "popup", callback = cb }
end)()
else
open_status_buffer(opts)
end
end
-- This can be used to create bindable functions for custom keybindings:
-- local neogit = require("neogit")
-- vim.keymap.set('n', '<leader>gcc', neogit.action('commit', 'commit', { '--verbose', '--all' }))
--
---@param popup string Name of popup, as found in `lua/neogit/popups/*`
---@param action string Name of action for popup, found in `lua/neogit/popups/*/actions.lua`
---@param args table? CLI arguments to pass to git command
---@return function
function M.action(popup, action, args)
local util = require("neogit.lib.util")
local a = require("plenary.async")
args = args or {}
local internal_args = {
graph = util.remove_item_from_table(args, "--graph"),
color = util.remove_item_from_table(args, "--color"),
decorate = util.remove_item_from_table(args, "--decorate"),
}
return function()
a.void(function()
local ok, actions = pcall(require, "neogit.popups." .. popup .. ".actions")
if ok then
local fn = actions[action]
if fn then
fn {
state = { env = {} },
get_arguments = function()
return args
end,
get_internal_arguments = function()
return internal_args
end,
}
else
M.notification.error(
string.format(
"Invalid action %s for %s popup\nValid actions are: %s",
action,
popup,
table.concat(vim.tbl_keys(actions), ", ")
)
)
end
else
M.notification.error("Invalid popup: " .. popup)
end
end)()
end
end
function M.complete(arglead)
if arglead:find("^kind=") then
return {
"kind=replace",
"kind=tab",
"kind=split",
"kind=split_above",
"kind=split_above_all",
"kind=split_below",
"kind=split_below_all",
"kind=vsplit",
"kind=floating",
"kind=auto",
}
end
if arglead:find("^cwd=") then
return {
"cwd=" .. vim.uv.cwd(),
}
end
return vim.tbl_filter(function(arg)
return arg:match("^" .. arglead)
end, {
"kind=",
"cwd=",
"bisect",
"branch",
"branch_config",
"cherry_pick",
"commit",
"diff",
"fetch",
"help",
"ignore",
"log",
"merge",
"pull",
"push",
"rebase",
"remote",
"remote_config",
"reset",
"revert",
"stash",
"tag",
"worktree",
})
end
function M.get_log_file_path()
return vim.fn.stdpath("cache") .. "/neogit.log"
end
function M.get_config()
return M.config.values
end
return M