--> lib: Builder pattern class to spawn child processes local process = require("@lune/process") local stdio = require("@lune/stdio") local CommandBuilder = {} export type CommandBuilder = typeof(setmetatable({} :: CommandBuilderFields, { __index = CommandBuilder })) type CommandBuilderFields = { program: string, args: { string }, stdioStrategy: IoStrategyMapping?, } export type StdioStrategy = "pipe" | "forward" | "none" export type IoStrategyMapping = { stdout: StdioStrategy?, stderr: StdioStrategy?, } local DEFAULT_STDIO_STRATEGY: IoStrategyMapping = { stdout = "pipe", stderr = "pipe", } function CommandBuilder.new(program: string) return setmetatable( { program = program, args = {}, stdioStrategy = nil, } :: CommandBuilderFields, { __index = CommandBuilder, } ) end function CommandBuilder.withArg(self: CommandBuilder, arg: string): CommandBuilder table.insert(self.args, arg) return self end function CommandBuilder.withArgs(self: CommandBuilder, args: { string }): CommandBuilder for _, arg in args do self:withArg(arg) end return self end function CommandBuilder.withStdioStrategy( self: CommandBuilder, strategy: StdioStrategy | IoStrategyMapping ): CommandBuilder self.stdioStrategy = if typeof(strategy) == "string" then { stdout = strategy, stderr = strategy, } else strategy return self end local function intoSpawnOptionsStdioKind(strategy: StdioStrategy): process.SpawnOptionsStdioKind if strategy == "pipe" then return "default" end if strategy == "forward" then return "forward" end if strategy == "none" then return "none" end error(`Non-strategy provided: {strategy}`) end function CommandBuilder.exec(self: CommandBuilder): process.SpawnResult print("$", stdio.style("dim") .. self.program, table.concat(self.args, " ") .. stdio.style("reset")) local function translateIoStrategyMappings(mappings: IoStrategyMapping) local translatedMappings: process.SpawnOptionsStdio = {} for field, value in mappings do translatedMappings[field] = intoSpawnOptionsStdioKind(value) end return translatedMappings end local child = process.spawn(self.program, self.args, { shell = true, stdio = translateIoStrategyMappings(self.stdioStrategy or DEFAULT_STDIO_STRATEGY), }) if not child.ok then print(`\n{stdio.color("red")}[luau-lsp]{stdio.color("reset")} Exited with code`, child.code) end return child end return CommandBuilder