// History:
// Jan 29 13 tcolar Creation
//
using fwt
**
** Executable command
**
abstract const class ExecCmd : Cmd
{
** How interactive is the command (can user review/edit the command)
abstract ExecCmdInteractive interaction()
** Persist to file or not - Whether to remember across restarts, or just for this session
abstract Bool persist()
** A unique key for the command
abstract Str cmdKey()
** Default command args
abstract CmdArgs defaultCmd()
** The variables for this command (Ex: "env_home" : "/tmp/...")
virtual Str:Str variables() {[:]}
** the folder where the command will be executed
abstract File folder()
abstract |Console|? callback()
abstract |Str -> Item?|? itemFinder()
override Void invoke(Event event)
{
frame.save
key := cmdKey
cmd := frame.process.getCmd(cmdKey)
if(cmd == null)
{
cmd = defaultCmd
if(interaction != ExecCmdInteractive.never)
cmd = confirmCmd(cmd)
}
else
if(interaction == ExecCmdInteractive.always)
cmd = confirmCmd(cmd)
if(cmd == null)
return // cancelled
if(interaction != ExecCmdInteractive.never)
{
frame.process.setCmd(cmdKey, cmd, persist)
}
cmd.execute(frame.console, variables, callback, itemFinder)
}
private CmdArgs? confirmCmd(CmdArgs cmd)
{
f := frame.curFile
runArgsFile := frame.process.file
dir := Text{text = cmd.runDir}
desc := persist ? Label{text = "This will be saved in $runArgsFile.osPath"} : null
Text[] texts := Text[,]
(0 .. 6).each |index|
{
texts.add( Text{it.text = cmd.arg(index) ?: ""} )
}
dialog := Dialog(frame)
{
title = "Exec"
commands = [ok, cancel]
body = EdgePane
{
it.top = GridPane
{
numCols = 2
Label{text="Command"}, texts[0],
Label{text="arg1"}, texts[1],
Label{text="arg2"}, texts[2],
Label{text="arg3"}, texts[3],
Label{text="arg4"}, texts[4],
Label{text="arg5"}, texts[5],
Label{text="arg6"}, texts[6],
Label{text="Run in"}, dir,
}
it.bottom = desc
}
}
if (Dialog.ok != dialog.open) return null
d := dir.text.trim
params := Str[,]
texts.each
{
if( ! it.text.trim.isEmpty)
params.add(it.text.trim)
}
newCmd := CmdArgs.makeManual(params, d)
return newCmd
}
}
**************************************************************************
** ExecCmdInteractive
**************************************************************************
** Whether the user gets to review/edit the command before it's executed
** onetime, will ask once and then be remembered after that
enum class ExecCmdInteractive
{
never, onetime, always
}
**************************************************************************
** CmdArgs
**************************************************************************
@Serializable
const class CmdArgs
{
const Str[] args
const Str runDir
new make(|This| f) {f(this)}
new makeManual(Str[] args, Str runDir)
{
this.args = args
this.runDir = runDir.trim
}
Void execute(Console console, Str:Str variables,
|Console|? callback := null, |Str -> Item?|? itemFinder := null)
{
if(args.isEmpty)
return
params := Str[,]
dir := runDir
variables.each |val, key|
{
dir = dir.replace("{{$key}}", val)
}
args.each
{
param := it
variables.each |val, key|
{
param = param.replace("{{$key}}", val)
}
params.add(param)
}
cmd := ConsoleCmd{it.args = params; it.dir = File.os(dir);
it.onDone = callback; it.itemFinder = itemFinder}
console.exec(cmd)
}
Str? arg(Int index)
{
args.size > index ? args[index] : null
}
}