223 lines
6.2 KiB
Lua
223 lines
6.2 KiB
Lua
local state_option = ya.sync(function(state, attr)
|
|
return state[attr]
|
|
end)
|
|
|
|
local function shell_choice(shell_val)
|
|
-- input is in lowercase always
|
|
local alt_name_map = {
|
|
kornshell = "ksh",
|
|
powershell = "pwsh",
|
|
nushell = "nu",
|
|
}
|
|
|
|
local shell_map = {
|
|
bash = { shell_val = "bash", supporter = "-ic", wait_cmd = "read", separator = ";" },
|
|
zsh = { shell_val = "zsh", supporter = "-ic", wait_cmd = "read", separator = ";" },
|
|
fish = { shell_val = "fish", supporter = "-c", wait_cmd = "read", separator = ";" },
|
|
pwsh = { shell_val = "pwsh", supporter = "-Command", wait_cmd = "Read-Host", separator = ";" },
|
|
sh = { shell_val = "sh", supporter = "-c", wait_cmd = "read", separator = ";" },
|
|
ksh = { shell_val = "ksh", supporter = "-c", wait_cmd = "read", separator = ";" },
|
|
csh = { shell_val = "csh", supporter = "-c", wait_cmd = "$<", separator = ";" },
|
|
tcsh = { shell_val = "tcsh", supporter = "-c", wait_cmd = "$<", separator = ";" },
|
|
dash = { shell_val = "dash", supporter = "-c", wait_cmd = "read", separator = ";" },
|
|
nu = { shell_val = "nu", supporter = "-l -i -c", wait_cmd = "input", separator = "| print;" },
|
|
}
|
|
|
|
shell_val = alt_name_map[shell_val] or shell_val
|
|
local shell_info = shell_map[shell_val]
|
|
|
|
if shell_info then
|
|
return shell_info.shell_val, shell_info.supporter, shell_info.wait_cmd, shell_info.separator
|
|
else
|
|
return nil, "-c", "read"
|
|
end
|
|
end
|
|
|
|
local function manage_extra_args(job)
|
|
-- function for dealing with --option, --option=boolean, nil
|
|
local function tobool(arg, default)
|
|
if type(arg) == "boolean" then
|
|
return arg
|
|
elseif type(arg) == "string" then
|
|
return arg:lower() == "true"
|
|
end
|
|
-- Fallback in case of nil
|
|
return default
|
|
end
|
|
|
|
local block = tobool(job.args.block, true)
|
|
local orphan = tobool(job.args.orphan, false)
|
|
local wait = tobool(job.args.wait, false)
|
|
local interactive = tobool(job.args.confirm, false)
|
|
|
|
return block, orphan, wait, interactive
|
|
end
|
|
|
|
local function manage_additional_title_text(block, wait)
|
|
local txt = ""
|
|
if block or wait then
|
|
txt = "(" .. (block and wait and "block and wait" or block and "block" or "") .. ")"
|
|
end
|
|
return txt
|
|
end
|
|
|
|
local function history_add(history_path, cmd_run)
|
|
local history_file = history_path
|
|
local history = {}
|
|
|
|
-- Ensure the history file exists
|
|
local file = io.open(history_file, "a+")
|
|
if file then
|
|
file:close()
|
|
end
|
|
|
|
-- Read existing history
|
|
for line in io.lines(history_file) do
|
|
-- add line if it is not empty
|
|
if line:match("%S") then
|
|
table.insert(history, line)
|
|
end
|
|
end
|
|
|
|
if cmd_run == nil then
|
|
return history
|
|
end
|
|
|
|
-- Append the new command to the history if it doesn't already exist
|
|
local command_exists = false
|
|
for _, cmd in ipairs(history) do
|
|
if cmd == cmd_run then
|
|
command_exists = true
|
|
break
|
|
end
|
|
end
|
|
|
|
if not command_exists then
|
|
file = io.open(history_file, "a")
|
|
if file then
|
|
file:write(cmd_run .. "\n")
|
|
file:close()
|
|
end
|
|
end
|
|
|
|
return history
|
|
end
|
|
|
|
local function history_prev(history_path)
|
|
-- get the history commands
|
|
local history_cmds = history_add(history_path)
|
|
if #history_cmds < 1 then
|
|
ya.notify({ title = "Custom-Shell", content = "History is Empty.", timeout = 3 })
|
|
return
|
|
end
|
|
-- preview the commands list in fzf and return selected cmd
|
|
for i, cmd in ipairs(history_cmds) do
|
|
history_cmds[i] = cmd:gsub("'", "'\\''") -- Escape single quotes
|
|
end
|
|
local permit = ya.hide()
|
|
|
|
local cmd = string.format('%s < "%s"', "fzf", history_path)
|
|
local handle = io.popen(cmd, "r")
|
|
|
|
local his_cmd = ""
|
|
if handle then
|
|
-- strip
|
|
his_cmd = string.gsub(handle:read("*all") or "", "^%s*(.-)%s*$", "%1")
|
|
handle:close()
|
|
end
|
|
|
|
permit:drop()
|
|
return his_cmd
|
|
end
|
|
|
|
local function entry(_, job)
|
|
local shell_env = os.getenv("SHELL"):match(".*/(.*)")
|
|
local shell_value, cmd, custom_shell_cmd = "", "", ""
|
|
|
|
local history_path, save_history = state_option("history_path"), state_option("save_history")
|
|
|
|
if job.args[1] == "auto" or job.args[1] == "history" then
|
|
shell_value = shell_env:lower()
|
|
elseif job.args[1] == "custom" then
|
|
shell_value = job.args[2]
|
|
cmd = job.args[3]
|
|
-- when the first param is a shell name
|
|
elseif job.args[1] ~= "history" then
|
|
shell_value = job.args[1]:lower()
|
|
end
|
|
|
|
local shell_val, supp, wait_cmd, separator = shell_choice(shell_value:lower())
|
|
|
|
if job.args[1] == "history" then
|
|
local his_cmd = history_prev(history_path)
|
|
if his_cmd == nil then
|
|
return
|
|
end
|
|
local value, event = ya.input({
|
|
title = "Custom-Shell History",
|
|
position = { "top-center", y = 3, w = 40 },
|
|
value = his_cmd,
|
|
})
|
|
if event == 1 then
|
|
-- this may lead to nested zsh -c "zsh -c 'zsh -c ...'"
|
|
-- But that's not a problem
|
|
cmd = value
|
|
end
|
|
end
|
|
if shell_val == nil then
|
|
ya.notify("Unsupported shell: " .. shell_value .. "Choosing Default Shell: " .. shell_env)
|
|
shell_val, supp = shell_choice(shell_env)
|
|
end
|
|
|
|
local block, orphan, wait, interactive = manage_extra_args(job) -- , confirm
|
|
local additional_title_text = manage_additional_title_text(block, wait)
|
|
local input_title = shell_value .. " Shell " .. additional_title_text .. ": "
|
|
local event = 1
|
|
|
|
if job.args[1] ~= "custom" and job.args[1] ~= "history" then
|
|
cmd, event = ya.input({
|
|
title = input_title,
|
|
position = { "top-center", y = 3, w = 40 },
|
|
})
|
|
end
|
|
|
|
if event == 1 then
|
|
local after_cmd = separator .. (wait and wait_cmd or "exit")
|
|
-- for history also, this will be added.
|
|
custom_shell_cmd = shell_val .. " " .. supp .. " " .. ya.quote(cmd .. after_cmd, true)
|
|
|
|
ya.manager_emit("shell", {
|
|
custom_shell_cmd,
|
|
block = block,
|
|
interactive = interactive,
|
|
orphan = orphan,
|
|
})
|
|
|
|
if save_history then
|
|
if job.args[1] == "history" then
|
|
-- to avoid nested "zsh -c 'zsh -c ...'"
|
|
history_add(history_path, cmd)
|
|
else
|
|
history_add(history_path, custom_shell_cmd)
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
--- @since 25.2.7
|
|
|
|
return {
|
|
setup = function(state, options)
|
|
local default_history_path = (
|
|
ya.target_family() == "windows"
|
|
and os.getenv("APPDATA") .. "\\yazi\\config\\plugins\\custom-shell.yazi\\yazi_cmd_history"
|
|
) or (os.getenv("HOME") .. "/.config/yazi/plugins/custom-shell.yazi/yazi_cmd_history")
|
|
|
|
state.history_path = options.history_path or default_history_path
|
|
if state.history_path:lower() == "default" then
|
|
state.history_path = default_history_path
|
|
end
|
|
state.save_history = options.save_history and true
|
|
end,
|
|
entry = entry,
|
|
}
|