mirror of
https://github.com/SpaceVim/SpaceVim.git
synced 2025-02-04 05:50:06 +08:00
214 lines
7.1 KiB
Lua
214 lines
7.1 KiB
Lua
local parser = require("neo-tree.command.parser")
|
|
local log = require("neo-tree.log")
|
|
local manager = require("neo-tree.sources.manager")
|
|
local utils = require("neo-tree.utils")
|
|
local renderer = require("neo-tree.ui.renderer")
|
|
local inputs = require("neo-tree.ui.inputs")
|
|
local completion = require("neo-tree.command.completion")
|
|
local do_show_or_focus, handle_reveal
|
|
|
|
local M = {
|
|
complete_args = completion.complete_args,
|
|
}
|
|
|
|
---Executes a Neo-tree action from outside of a Neo-tree window,
|
|
---such as show, hide, navigate, etc.
|
|
---@param args table The action to execute. The table can have the following keys:
|
|
--- action = string The action to execute, can be one of:
|
|
--- "close",
|
|
--- "focus", <-- default value
|
|
--- "show",
|
|
--- source = string The source to use for this action. This will default
|
|
--- to the default_source specified in the user's config.
|
|
--- Can be one of:
|
|
--- "filesystem",
|
|
--- "buffers",
|
|
--- "git_status",
|
|
-- "migrations"
|
|
--- position = string The position this action will affect. This will default
|
|
--- to the the last used position or the position specified
|
|
--- in the user's config for the given source. Can be one of:
|
|
--- "left",
|
|
--- "right",
|
|
--- "float",
|
|
--- "current"
|
|
--- toggle = boolean Whether to toggle the visibility of the Neo-tree window.
|
|
--- reveal = boolean Whether to reveal the current file in the Neo-tree window.
|
|
--- reveal_file = string The specific file to reveal.
|
|
--- dir = string The root directory to set.
|
|
--- git_base = string The git base used for diff
|
|
M.execute = function(args)
|
|
local nt = require("neo-tree")
|
|
nt.ensure_config()
|
|
|
|
if args.source == "migrations" then
|
|
require("neo-tree.setup.deprecations").show_migrations()
|
|
return
|
|
end
|
|
|
|
args.action = args.action or "focus"
|
|
|
|
-- handle close action, which can specify a source and/or position
|
|
if args.action == "close" then
|
|
if args.source then
|
|
manager.close(args.source, args.position)
|
|
else
|
|
manager.close_all(args.position)
|
|
end
|
|
return
|
|
end
|
|
|
|
-- The rest of the actions require a source
|
|
args.source = args.source or nt.config.default_source
|
|
|
|
-- If position=current was requested, but we are currently in a neo-tree window,
|
|
-- then we need to override that.
|
|
if args.position == "current" and vim.bo.filetype == "neo-tree" then
|
|
local position = vim.api.nvim_buf_get_var(0, "neo_tree_position")
|
|
if position then
|
|
args.position = position
|
|
end
|
|
end
|
|
|
|
-- Now get the correct state
|
|
local state
|
|
local requested_position = args.position or nt.config[args.source].window.position
|
|
if requested_position == "current" then
|
|
local winid = vim.api.nvim_get_current_win()
|
|
state = manager.get_state(args.source, nil, winid)
|
|
else
|
|
state = manager.get_state(args.source, nil, nil)
|
|
end
|
|
|
|
-- Next handle toggle, the rest is irrelevant if there is a window to toggle
|
|
if args.toggle then
|
|
if renderer.close(state) then
|
|
-- It was open, and now it's not.
|
|
return
|
|
end
|
|
end
|
|
|
|
-- Handle position override
|
|
local default_position = nt.config[args.source].window.position
|
|
local current_position = state.current_position or default_position
|
|
local position_changed = false
|
|
if args.position then
|
|
state.current_position = args.position
|
|
position_changed = args.position ~= current_position
|
|
end
|
|
|
|
-- Handle setting directory if requested
|
|
local path_changed = false
|
|
if utils.truthy(args.dir) then
|
|
if #args.dir > 1 and args.dir:sub(-1) == utils.path_separator then
|
|
args.dir = args.dir:sub(1, -2)
|
|
end
|
|
path_changed = state.path ~= args.dir
|
|
else
|
|
args.dir = state.path
|
|
end
|
|
|
|
-- Handle setting git ref
|
|
local git_base_changed = state.git_base ~= args.git_base
|
|
if utils.truthy(args.git_base) then
|
|
state.git_base = args.git_base
|
|
end
|
|
|
|
-- Handle reveal logic
|
|
args.reveal = args.reveal or args.reveal_force_cwd
|
|
local do_reveal = utils.truthy(args.reveal_file)
|
|
if args.reveal and not do_reveal then
|
|
args.reveal_file = manager.get_path_to_reveal()
|
|
do_reveal = utils.truthy(args.reveal_file)
|
|
end
|
|
|
|
-- All set, now show or focus the window
|
|
local force_navigate = path_changed or do_reveal or git_base_changed or state.dirty
|
|
if position_changed and args.position ~= "current" and current_position ~= "current" then
|
|
manager.close(args.source)
|
|
end
|
|
if do_reveal then
|
|
handle_reveal(args, state)
|
|
else
|
|
do_show_or_focus(args, state, force_navigate)
|
|
end
|
|
end
|
|
|
|
---Parses and executes the command line. Use execute(args) instead.
|
|
---@param ... string Argument as strings.
|
|
M._command = function(...)
|
|
local args = parser.parse({ ... }, true)
|
|
M.execute(args)
|
|
end
|
|
|
|
do_show_or_focus = function(args, state, force_navigate)
|
|
local window_exists = renderer.window_exists(state)
|
|
local function close_other_sources()
|
|
if not window_exists then
|
|
-- Clear the space in case another source is already open
|
|
local target_position = args.position or state.current_position or state.window.position
|
|
if target_position ~= "current" then
|
|
manager.close_all(target_position)
|
|
end
|
|
end
|
|
end
|
|
|
|
if args.action == "show" then
|
|
-- "show" means show the window without focusing it
|
|
if window_exists and not force_navigate then
|
|
-- There's nothing to do here, we are already at the target state
|
|
return
|
|
end
|
|
close_other_sources()
|
|
local current_win = vim.api.nvim_get_current_win()
|
|
manager.navigate(state, args.dir, args.reveal_file, function()
|
|
-- navigate changes the window to neo-tree, so just quickly hop back to the original window
|
|
vim.api.nvim_set_current_win(current_win)
|
|
end, false)
|
|
elseif args.action == "focus" then
|
|
-- "focus" mean open and jump to the window if closed, and just focus it if already opened
|
|
if window_exists then
|
|
vim.api.nvim_set_current_win(state.winid)
|
|
end
|
|
if force_navigate or not window_exists then
|
|
close_other_sources()
|
|
manager.navigate(state, args.dir, args.reveal_file, nil, false)
|
|
end
|
|
end
|
|
end
|
|
|
|
handle_reveal = function(args, state)
|
|
-- Deal with cwd if we need to
|
|
local cwd = state.path
|
|
local path = args.reveal_file
|
|
if cwd == nil then
|
|
cwd = manager.get_cwd(state)
|
|
end
|
|
if args.reveal_force_cwd and not utils.is_subpath(cwd, path) then
|
|
args.dir, _ = utils.split_path(path)
|
|
do_show_or_focus(args, state, true)
|
|
return
|
|
elseif not utils.is_subpath(cwd, path) then
|
|
-- force was not specified, so we need to ask the user
|
|
cwd, _ = utils.split_path(path)
|
|
local nt = require("neo-tree")
|
|
if nt.config.force_change_cwd then
|
|
args.dir = cwd
|
|
do_show_or_focus(args, state, true)
|
|
else
|
|
inputs.confirm("File not in cwd. Change cwd to " .. cwd .. "?", function(response)
|
|
if response == true then
|
|
args.dir = cwd
|
|
else
|
|
args.reveal_file = nil
|
|
end
|
|
do_show_or_focus(args, state, true)
|
|
end)
|
|
end
|
|
return
|
|
else
|
|
do_show_or_focus(args, state, true)
|
|
end
|
|
end
|
|
return M
|