Introduce config module for managing user options, defaults, and watchexec binary discovery. Add window module for creating and managing the output window (float or split) with append, clear, resize, and keymap support.
162 lines
3.6 KiB
Lua
162 lines
3.6 KiB
Lua
---@class watchexec.FloatOpts
|
|
---@field relative? string
|
|
---@field width? number
|
|
---@field height? number
|
|
---@field row? number
|
|
---@field col? number
|
|
|
|
---@class watchexec.WindowOpts
|
|
---@field type? "float"|"split"
|
|
---@field split? "below"|"above"|"left"|"right"
|
|
---@field size? integer
|
|
---@field float? watchexec.FloatOpts
|
|
---@field border? string|string[]
|
|
|
|
---@class watchexec.WatchexecOpts
|
|
---@field bin? string
|
|
---@field args? string[]
|
|
|
|
---@class watchexec.IndicatorPatterns
|
|
---@field success? string
|
|
---@field running? string
|
|
|
|
---@class watchexec.IndicatorOpts
|
|
---@field enabled? boolean
|
|
---@field position? "bottom-left"|"bottom-right"|"top-left"|"top-right"
|
|
---@field success_hl? string
|
|
---@field failure_hl? string
|
|
---@field width? integer
|
|
---@field height? integer
|
|
---@field patterns? watchexec.IndicatorPatterns
|
|
|
|
---@class watchexec.Config
|
|
---@field watchexec? watchexec.WatchexecOpts
|
|
---@field window? watchexec.WindowOpts
|
|
---@field indicator? watchexec.IndicatorOpts
|
|
---@field auto_scroll? boolean
|
|
---@field max_lines? integer
|
|
|
|
local M = {}
|
|
|
|
---@type watchexec.Config
|
|
local defaults = {
|
|
watchexec = {
|
|
bin = "watchexec",
|
|
args = {},
|
|
},
|
|
window = {
|
|
type = "float",
|
|
split = "below",
|
|
size = 12,
|
|
float = {
|
|
relative = "editor",
|
|
width = 0.8,
|
|
height = 0.6,
|
|
row = 0.5,
|
|
col = 0.5,
|
|
},
|
|
border = "single",
|
|
},
|
|
indicator = {
|
|
enabled = true,
|
|
position = "bottom-right",
|
|
success_hl = "WatchexecSuccess",
|
|
failure_hl = "WatchexecFailure",
|
|
width = 2,
|
|
height = 1,
|
|
patterns = {
|
|
success = "%[Command was successful%]",
|
|
running = "%[Running",
|
|
},
|
|
},
|
|
auto_scroll = true,
|
|
max_lines = 5000,
|
|
}
|
|
|
|
---@type watchexec.Config
|
|
local config = vim.deepcopy(defaults)
|
|
|
|
---Search for the watchexec binary in PATH and candidate locations.
|
|
---@return string|nil
|
|
local function find_binary()
|
|
local bin = config.watchexec.bin
|
|
|
|
if bin and vim.fn.executable(bin) == 1 then
|
|
return bin
|
|
end
|
|
|
|
local home = vim.fn.expand("~")
|
|
|
|
if vim.fn.has("win32") == 1 or vim.fn.has("win64") == 1 then
|
|
local candidates = {
|
|
home .. "\\cargo\\bin\\watchexec.exe",
|
|
vim.fn.expand("$USERPROFILE") .. "\\.cargo\\bin\\watchexec.exe",
|
|
"C:\\tools\\watchexec\\watchexec.exe",
|
|
}
|
|
|
|
for _, p in ipairs(candidates) do
|
|
if vim.fn.executable(p) == 1 then
|
|
return p
|
|
end
|
|
end
|
|
else
|
|
local candidates = {
|
|
home .. "/.cargo/bin/watchexec",
|
|
home .. "/.local/bin/watchexec",
|
|
"/opt/homebrew/bin/watchexec",
|
|
"/usr/local/bin/watchexec",
|
|
}
|
|
|
|
for _, p in ipairs(candidates) do
|
|
if vim.fn.executable(p) == 1 then
|
|
return p
|
|
end
|
|
end
|
|
|
|
if vim.fn.executable("wsl.exe") == 1 then
|
|
local result = vim.fn.system({ "wsl.exe", "which", "watchexec" })
|
|
|
|
if vim.v.shell_error == 0 then
|
|
result = vim.trim(result)
|
|
if #result > 0 then
|
|
return "wsl.exe --exec " .. result
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
return nil
|
|
end
|
|
|
|
---Merge user options into the current config and resolve the binary path.
|
|
---@param opts? watchexec.Config
|
|
function M.setup(opts)
|
|
if not opts then
|
|
return
|
|
end
|
|
|
|
config = vim.tbl_deep_extend("force", config, opts)
|
|
|
|
config.watchexec.bin = find_binary()
|
|
|
|
if not config.watchexec.bin then
|
|
vim.notify(
|
|
"watchexec.nvim: could not find watchexec binary. Set opts.watchexec.bin in your config.",
|
|
vim.log.levels.WARN
|
|
)
|
|
end
|
|
end
|
|
|
|
---Return the current configuration table.
|
|
---@return watchexec.Config
|
|
function M.get()
|
|
return config
|
|
end
|
|
|
|
---Reset configuration back to defaults.
|
|
function M.reset()
|
|
config = vim.deepcopy(defaults)
|
|
end
|
|
|
|
return M
|