Sarnold This is a GUI tool for launching system commands. You can type command arguments in a text field like you would in a shell.

Documentation
You can use it as a GUI front-end for tools like bc, and pressing Escape cause the last result to be recalled as command argument. It stores a table of command prefixes in its configuration. You can use a few command modifiers to perform special tasks:
@dir Title -> prompts for a directory choice and replace them by this choice @temp .... -> stores remaining arguments in a temporary file and replace them by its path (currently under /tmp) @end -> ignores further arguments @bg -> runs command in background (appends '&' to the command line) @wdir /path/to/dir -> runs command with /path/to/dir as work directory, only for the current command
News
2010-Apr 4: Sarnold releases v0.3.
Discussion
The source is there:
proc DefaultConfig {args} {
global HANDLER HELP ASK
set HANDLER ""
set HELP ""
foreach {key val usage} {
{Calculator} {bc @temp} {Enter a math expression\nlike 3+2*4 (requires the program 'bc')}
{Tfu} {tfu @dir Source @dir Destination @end} {The tfu script which keeps two directories in sync.}
} {
dict set HANDLER $key $val
dict set HELP $key $usage
}
return "Configuration reset done"
}
# intercepte l'erreur et relance $msg
proc Rethrow {body msg} {
if {[catch {uplevel 1 $body} res]} {error $msg}
set res
}
proc Debug {message {level INFO}} {
set level [dict get {INFO 0 WARNING 1 ERROR 2} $level]
if {$level < 1} return
tk_messageBox -message $message
set message
}
proc CommandList {} {lsort [dict keys $::HANDLER]}
set DIALOG() ""
proc Dialog {name {cmd ""}} {
destroy $name
if {$cmd ne ""} {
eval $cmd
}
array unset ::DIALOG *
}
proc CreateAction {} {
global HANDLER DIALOG HELP
llength $DIALOG(prefix)
set cmd $DIALOG(prefix)
dict set HANDLER $DIALOG(name) $cmd
dict set HELP $DIALOG(name) $DIALOG(usage)
}
proc ModifyAction {} {
NewAction [GetAction $::Current]
}
proc GetAction {name} {
global HANDLER HELP
list name $name prefix [dict get $HANDLER $name] usage [dict get $HELP $name]
}
proc NewAction {{dict ""} {frtitle "Edit action"}} {
toplevel .new
wm title .new $frtitle
global DIALOG
foreach {name key} {{Command name} name {Command line prefix} prefix {Usage (help)} usage} {
set fr [ttk::frame .new.$key]
set DIALOG($key) [Get $dict $key]
ttk::label $fr.label -text $name -width 20
ttk::entry $fr.entry -textvariable ::DIALOG($key) -width 36
pack $fr.label $fr.entry -side left -padx 2 -pady 4 -fill both
pack $fr
}
pack [set fr [ttk::frame .new.confirm]]
pack [ttk::button $fr.ok -text Ok -command {Dialog .new CreateAction}]\
[ttk::button $fr.delete -text Delete -command {Dialog .new DeleteAction}]\
[ttk::button $fr.cancel -text Cancel -command {Dialog .new}] -side left -padx 2 -pady 4 -fill both
}
proc Get {dict key {default ""}} {
if {[dict exists $dict $key]} {return [dict get $dict $key]}
set default
}
proc SaveConfig {} {
catch {
set fd [open ~/.blauncherrc w]
foreach {key val} $::HANDLER {
puts $fd [list $key $val [Get $::HELP $key]]
}
close $fd
}
}
proc LoadConfig {} {
if {![file exists ~/.blauncherrc]} {
DefaultConfig
SaveConfig
return
}
global HANDLER HELP
set HELP ""
catch {
set fd [open ~/.blauncherrc]
while {![eof $fd]} {
lassign [gets $fd] key val usage
if {$key eq ""} continue
dict set HANDLER $key $val
dict set HELP $key $usage
}
close $fd
}
}
proc ResetConfig {} {
Confirm [txt "Sure you want to reset?"] {
DefaultConfig
Show [txt "Reset done"]
}
}
proc Cwd {} {
set dir [Ask [txt "Choose working directory"] on]
if {$dir ne ""} {cd $dir}
}
proc Show {text} {
tk_messageBox -type ok -message $text -title [txt Message]
}
# creates a temporary file
# with an id (unique within a command Exec)
# and a text to fill with
proc MakeTemp {id text} {
set fname /tmp/blaunch[pid].$id
set fd [open $fname w]
puts $fd $text
close $fd
set fname
}
proc txt arg {set arg};#i18n
proc Exec args {
set tmp 0
set background no
set wdir [pwd]
for {set i 0} {$i<[llength $args]} {incr i} {
lassign [lrange $args $i end] descr txt
if {$descr eq "@dir"} {
set f [Ask $txt]
if {$f eq ""} {error "Directory choice aborted by user."}
set args [lreplace $args $i [expr {$i+1}] $f]
}
if {$descr eq "@wdir"} {
cd $txt
set args [lreplace $args $i [expr {$i+1}]]
incr i -1
}
if {$descr eq "@temp"} {
set args [lreplace $args $i end [MakeTemp [incr ::tmp] [lrange $args [incr i] end]]]
break
}
if {$descr eq "@end"} {
#ignores remaining arguments
set args [lrange $args 0 [expr {$i-1}]]
break
}
if {$descr eq "@bg"} {
set args [lreplace $args $i $i]
set background yes
incr i -1
}
}
if {$background} {lappend args &}
exec {*}$args
cd $wdir
}
proc ? {val def} {expr {$val eq ""?$def:$val}}
proc txt? {val def} {? $val [txt $def]}
proc Ask {txt {mustexist no}} {
if {![info exists ::choosedir]} {
tk_chooseDirectory -initialdir [pwd] -title [txt? $txt "Choose directory"] -mustexist $mustexist
} else {
exec $::choosedir $txt
}
}
proc Blaunch {} {
global Current Command HANDLER HISTORY
lappend HISTORY $Current $Command
if {[catch {Exec {*}[dict get $HANDLER $Current] {*}$Command} result]} {
Show "An error occured, see the message below."
PutText .result $result
return
}
lappend HISTORY $result
PutText .result $result
set Command ""
}
proc PutText {path text} {
$path delete 1.0 end
$path insert end $text
}
proc Paste {} {
lappend ::Command {*}[split [lindex $::HISTORY end] \n]
.command.entry icursor end
}
proc Quit {} {SaveConfig; exit}
proc Exit {} {
Confirm [txt "Sure you want to quit?"] Quit
}
proc UpdateCombobox {args} {
.actions.choose configure -values [CommandList]
if {$::Current ni [CommandList]} {set ::Current [lindex $::HANDLER 0]}
}
proc DeleteAction {} {
Confirm [format [txt "Are you sure you want to drop action '%s'?"] $::Current] {dict unset ::HANDLER $::Current}
}
proc Confirm {txt body} {
if {[tk_messageBox -message $txt -type okcancel -title [txt Question]] eq "ok"} {eval $body}
}
proc History {} {Show "Not implemented yet"}
proc Clear {} {set ::Command ""}
proc Help {} {Show "$::VERSION
An enhanced command launcher written in Tcl/Tk.
(c) Stéphane Arnold 2010
New BSD license (like Tcl)
Press Enter to launch, and Escape to paste last result."}
proc Usage {} {
global HELP Current
Show [dict get $HELP $Current]
}
proc Focus {} {focus .command.entry}
set HISTORY ""
set VERSION "Blauncher v0.3"
LoadConfig
set Current [lindex $HANDLER 0]
set Command ""
# option database
option add *button.padx 7
option add *button.pady 7
option add *button.width 12
option add *entry.font {Courier 10}
wm title . $VERSION
pack [ttk::frame .actions]
pack [ttk::combobox .actions.choose -textvariable ::Current -state readonly -values [CommandList] -width 30]\
[ttk::button .actions.new -text "New action" -command NewAction] \
[ttk::button .actions.modify -text [txt Edit/Delete] -command ModifyAction]\
[ttk::button .actions.reset -text Reset -command ResetConfig]\
[ttk::button .actions.history -text "Usage" -command Usage] -side left -fill both -padx 2 -pady 4
pack [ttk::frame .command]
pack [ttk::button .command.clr -text Clear -command Clear]\
[ttk::entry .command.entry -textvariable ::Command -width 40] \
[ttk::button .command.ok -text Blaunch! -command Blaunch] -side left -fill both -padx 2 -pady 4
pack [text .result -width 64 -height 8 -background #fafafa -font {Courier 10}]
pack [ttk::frame .sys]
pack [ttk::button .sys.recall -text "Paste result" -command Paste] \
[ttk::button .sys.cwd -text "Work directory" -command Cwd] \
[ttk::button .sys.exit -text Exit -command Exit] \
[ttk::button .sys.help -text Help -command Help] -side left -padx 2 -pady 4
trace add variable ::HANDLER write UpdateCombobox
bind . <FocusIn> Focus
bind . <Key-Return> Blaunch
bind . <Key-Escape> Paste
# avoids selection in combobox (default Tk behavior)
bind .actions.choose <<ComboboxSelected>> {.actions.choose selection clear}
Focus
# program name for choosing a directory
# comment it for standard tk_chooseDirectory
#set choosedir choosedir
# Save config on exit (when delete main window)
wm protocol . WM_DELETE_WINDOW Exit