Add script command to allow calling external helper scripts
This commit is contained in:
4
HELP.md
4
HELP.md
@@ -129,6 +129,10 @@ Restore a `str` session from a saved state file (default `~/.str.json`).
|
||||
#### `runfile <path>`
|
||||
Execute the contents of the given file as a series of `str` commands.
|
||||
|
||||
#### `script <path> [...<args>]`
|
||||
Execute an external script and replace the current subject with the returned output.
|
||||
The current subject is passed as the first argument, followed by the optional additional `args`.
|
||||
|
||||
|
||||
### Basic String Operations
|
||||
|
||||
|
||||
@@ -50,6 +50,7 @@ import {Zip} from "./zip.js";
|
||||
import {Concat} from "./concat.js";
|
||||
import {Call} from "./call.js";
|
||||
import {Chunk} from "./chunk.js";
|
||||
import {Script} from "./script.js";
|
||||
|
||||
export type Commands = Command<CommandData>[]
|
||||
export const commands: Commands = [
|
||||
@@ -90,6 +91,7 @@ export const commands: Commands = [
|
||||
new RSub,
|
||||
new RunFile,
|
||||
new Save,
|
||||
new Script,
|
||||
new Set,
|
||||
new Show,
|
||||
new Sort,
|
||||
|
||||
45
src/vm/commands/script.ts
Normal file
45
src/vm/commands/script.ts
Normal file
@@ -0,0 +1,45 @@
|
||||
import {Command, ParseContext, processPath, StrTerm, unwrapString, wrapString} from "./command.js";
|
||||
import {LexInput} from "../lexer.js";
|
||||
import {promisify} from "node:util";
|
||||
import {execFile} from "node:child_process";
|
||||
import {StrVM} from "../vm.js";
|
||||
|
||||
type ScriptData = {
|
||||
path: StrTerm,
|
||||
args: StrTerm[],
|
||||
}
|
||||
|
||||
export class Script extends Command<ScriptData> {
|
||||
async attemptParse(context: ParseContext): Promise<ScriptData> {
|
||||
const data: ScriptData = {
|
||||
path: await context.popTerm(),
|
||||
args: [],
|
||||
}
|
||||
|
||||
while ( await context.peekTerm() ) {
|
||||
data.args.push(await context.popTerm())
|
||||
}
|
||||
|
||||
return data
|
||||
}
|
||||
|
||||
getDisplayName(): string {
|
||||
return 'script'
|
||||
}
|
||||
|
||||
isParseCandidate(token: LexInput): boolean {
|
||||
return this.isKeyword(token, 'script')
|
||||
}
|
||||
|
||||
async execute(vm: StrVM, data: ScriptData): Promise<StrVM> {
|
||||
return vm.replaceContextMatchingTerm(ctx => ({
|
||||
override: async sub => {
|
||||
const path = processPath(ctx.resolveString(data.path))
|
||||
const args = data.args.map(arg => ctx.resolveString(arg))
|
||||
|
||||
const { stdout, stderr } = await promisify(execFile)(path, [unwrapString(sub), ...args])
|
||||
return wrapString(stdout)
|
||||
},
|
||||
}))
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user