--[[ Runner engine: run the current buffer's file with a per-filetype command. Features register a shell command per filetype; the engine runs the current buffer's file with the registered command and reports the result. Commands are registered in plugin/50-runner.lua. API: register(filetype, cmd) — `cmd` is a command list; `%` in any argument expands to the current file path. Call once per filetype. run() — run the current buffer with its filetype's command. ]] local M = {} -- Registered run commands, keyed by filetype. M.runners = {} -- Expand `%` in each argument of `cmd` to `file`, returning a new command list. local function _expand(cmd, file) local out = {} for i, arg in ipairs(cmd) do out[i] = arg:gsub("%%", file) end return out end --- Register the run command `cmd` for `filetype`. ---@param filetype string ---@param cmd string[] function M.register(filetype, cmd) assert(type(filetype) == "string", "runner.register: filetype must be a string") assert(type(cmd) == "table", "runner.register: cmd must be a command list") M.runners[filetype] = cmd end --- Run the current buffer's file, notifying on a missing command or a non-zero exit. ---@return nil function M.run() local ft = vim.bo.filetype local cmd = M.runners[ft] if cmd == nil then vim.notify("No runner registered for " .. ft, vim.log.levels.ERROR) return end local file = vim.api.nvim_buf_get_name(0) -- Spawn the command and wait for it. See . local r = vim.system(_expand(cmd, file), { text = true }):wait() if r.code ~= 0 then vim.notify(r.stderr, vim.log.levels.WARN) return end vim.notify(r.stdout) end return M