#!/bin/sh # execute in wish from path \ exec wish "$0" ${1+"$@"} # Alias.tcl - Takes an "alias" from an input box and runs the alias' # corresponding command # # Author: Luciano Espirito Santo # # More on the purpose of this program: # The very first time I used Linux, I really liked the concept of aliases: the # ability to create short or easier to remember alternative names to commands # or even sequences of commands. # In Windows, I found a very convenient way to do this with PowerPro # ( http://ppro.org ). It provides an input box and a scripting back end. So I # implemented this application with it and got terribly used to it. # A few years later, using Linux a lot more often, I missed my aliases and # decided to reimplement the whole thing, this time with Tcl. # Of course, Linux/Unix already provides its own alias capability. The # advantages of my application over Bash's aliases, for example, are few and # small. Basically, it's just another approach to it. # In Windows, the advantages are obvious: there is no alias capability in # Windows that I ever heard of, unless Bash (again) under Cygwin and a couple # of other applications that are very similar to this one, but do not run on # Linux and therefore are totally inadequate to people who dual-boot often and # otherwise would be forced to keep two isolated alias lists. Keep this # application and the alias list in a partition accessible to both (or all) # your operating systems and you should find no trouble in keeping the alias # list always updated, regardless of which OS you're running at the time. # # History # # Version 1.0 2005-03-02 Luciano Espirito Santo # First beta. # # Version 1.1 2005-03-02 Luciano Espirito Santo # - Added some voodoo magic to cope with kfmclient because it won't do # the right thing with full paths or single program names that # otherwise could be found easily in $PATH. # # KNOWN ISSUES: # - For the time being, it requires KDE. We can get by without it, but # the commands become longer, more awkward and prone to errors. # - Many commands are likely not to work due to all very well-known # issues related with Tcl's exec command. # # This program offers no guarantees! Use it at your own risk! # # TO DO: # - Lots of improvements planned. Stay tuned! # # LICENSE: BSD # # How to use it: # # - Save this file in any directory with read and write permission. # - Create another file called Alias_list.txt in that same directory. Copy # the sample provided right after the script. That is where you will # maintain your alias list. # - The following rules apply to the alias list: # Each alias-separator-command group must be in its own single line. # Format: # alias = command [optional arguments] # In other words: # + the alias (any character except the "equals" sign), followed by: # + any number of "blanks" (space or tabs), followed by: # + an "equals" sign (=), followed by: # + any number of "blanks" (space or tabs), followed by: # + any command, with options and/or arguments. # Some commands may cause an error. Please see the "KNOWN ISSUES" above. # The first "equals" sign works as a delimiter, so that symbol cannot be # used in any alias. It can be part of any command, though. # - You may comment out any line you want. Lines starting with the "hash" # symbol (#), with or without "blanks" (space or tabs), before or after # the "hash" symbol, are ignored. # - If you use Linux/Unix and KDE, open KDE's Control Center and, in the # HotKeys section, assign a shortcut key to this command: # '/path/to/tcl/wish /path/to/Alias.tcl # - If you use Windows, create a new shortcut to this application (in your # Start menu or any other place), right-click it, select "Properties" and # assign a keyboard shortcut to it. # - When (and if) the input box appears, type in an alias and press the # Enter/Return key. If you want to cancel the action and close the box # without running anything, press the Esc key. # - Whenever you want to edit the alias list, launch the program and press # the F5 key. # - If you know Tcl, you may want to change the value of a few variables # in the section, "SET VARS". # ================================================ # SET VARS # myAliasFile: Alias list file location # myAliasBg: input box's (entry widget) background color # myAliasFg: input box's (entry widget) foreground font color # myAliasFont: input box's (entry widget) font face # myAliasWidth: input box's (entry widget) width (measured in characters) # myAliasAlign: input box's (entry widget) text alignment # mySoundEnabled: Boolean: whether to play a sound in case of error # myErrorSound: sound file to play in case of error # myHasTitle: set to "yes" if you want the box to have a title/caption # myWindowTitle: the title/caption of the box # ================================================ if { $::tcl_platform(platform) == "windows" } { set myAliasFile "[ file normalize [pwd]/Alias_list.txt ]" set myAliasBg "#ffffff" ;# or "white" set myAliasFg "#000000" ;# or "black" set myAliasFont "Arial 12" ;# or "{Times New Roman} 12" set myAliasWidth 40 set myAliasAlign center set mySoundEnabled "yes" set myErrorSound "D:/System/Sound/uh-oh.wav" } if { $::tcl_platform(platform) == "unix" } { set myAliasFile "/am/d/home/xxxx/Alias_list.txt" set myAliasBg "#ffffff" ;# or "white" set myAliasFg "#000000" ;# or "black" set myAliasFont "Helvetica 18" ;# or "{Times New Roman} 12" set myAliasWidth 40 set myAliasAlign center set mySoundEnabled "no" set myErrorSound "/am/d/System/Sound/uh-oh.wav" } set myHasTitle "yes" set myWindowTitle "A rose, by any other name..." # this is an ugly hack, will fix it someday. DO NOT CHANGE IT. set myNotFound 0 # ================================================ # PROCS # packages: sound (optional) # p.1.playwav: plays a sound file # p.2.error: plays error sound and clears input box # p.3.center_window: place a window at the center of the screen # p.4.check_alias_file: checks existence of alias list file # p.5.get_alias: reads input box, parses alias list and returns final command # p.6.which: searches a program in $PATH # p.7.voodoo: voodoo magic to workaround kfmclient's idiosyncrasy # p.8.run_alias: the final command that runs the alias's corresponding command # p.9.edit_alias: open alias list file in text editor so it can be edited # ================================================ # ---------------------------------------------------------------- # proc 1 of 9 # plays a sound file proc p.1.playwav { argWavFile } { if { $::mySoundEnabled != "yes" } { return } package require sound snack::sound s -file $argWavFile; s play -block 1 } # ---------------------------------------------------------------- # proc 2 of 9 # plays error sound and clears input box proc p.2.error {} { p.1.playwav $::myErrorSound $::w.frame0.aliasbox delete 0 end } # ---------------------------------------------------------------- # proc 3 of 9 # place a window at the center of the screen # argW = window to be placed at the center of the screen proc p.3.center_window { argW } { wm withdraw $argW update idletasks set x [ expr [ winfo screenwidth $argW ] /2 - [ winfo reqwidth $argW ] /2 - [ winfo vrootx [ winfo parent $argW ] ] ] set y [ expr [ winfo screenheight $argW ] /2 - [ winfo reqheight $argW ] /2 - [ winfo vrooty [ winfo parent $argW ] ] ] wm geom $argW +$x+$y wm deiconify $argW } # ---------------------------------------------------------------- # proc 4 of 9 # checks existence of alias list file # complains loudly if file is not found proc p.4.check_alias_file {} { if { ! [ file exists $::myAliasFile ] } { p.2.error $::w.frame0.aliasbox insert end "ALIAS LIST FILE NOT FOUND" $::w.frame0.aliasbox selection range 0 end set ::myNotFound 1 return "0" } else { return "1" } } # ---------------------------------------------------------------- # proc 5 of 9 # reads input box, parses alias list and returns final command proc p.5.get_alias {} { # first check the existence of the alias list file if { ! [ p.4.check_alias_file ] } { return } array set ::myAliasHash {} set myRegex {([^=]+)\s*=\s*(.*)} # Parse $::myAliasFile and build the array myAliasHash set myFP [ open $::myAliasFile r ] while { ! [ eof $myFP ] } { set myLine [ string trim [ gets $myFP ] ] # this excludes commented out lines in the alias file if { [ regexp {^\s*#.*$} $myLine ] } { continue } regexp $myRegex $myLine => myKey myValue set myKey [ string trim $myKey ] set myValue [ string trim $myValue ] set myAliasHash($myKey) $myValue } close $myFP # if alias is found in hash, return command # if alias is not found in hash, produce error set myRun [ array get myAliasHash $::myAlias ] if { $myRun == "" } { p.2.error return "!!ERROR!!" } if { $myRun != "" } { set myRun $myAliasHash($::myAlias) return $myRun } } # ---------------------------------------------------------------- # proc 6 of 9 # searches a program in PATH # myFilename = name of file to search in PATH; an executable proc p.6.which { myFilename } { switch $::tcl_platform(platform) { windows { set myPathList [ split $::env(PATH) \; ] } default { set myPathList [ split $::env(PATH) : ] } } foreach dir $myPathList { foreach ext { "" .bin .exe .dll .com .bat } { set myCTL [ file join $dir "$myFilename$ext" ] if { [ file exists $myCTL ] \ && [ file readable $myCTL ] \ && [ file executable $myCTL ] } { return $myCTL } } } return "" } # ---------------------------------------------------------------- # proc 7 of 9 # applies some voodoo on the command string so as to workaround kfmclient's # and maybe even exec's quirks in the future proc p.7.voodoo { argRun } { # if it is an Internet address, do nothing. if { [ regexp -nocase {^(ht|f)tp.*} $argRun ] } { return $argRun } # we need to go to / due to kfmclient's idiosyncrasy: it always # assumes the HOME directory. Full paths are useless to it. if { $::tcl_platform(platform) == "unix" } { cd / } # "command" may have arguments (multiple words). Isolate the program: set myProgram [ lindex $argRun 0 ] # check if full path to program was provided and if exists. # If yes, nothing else to do. set myProgram [ file normalize "[ pwd ]/$myProgram" ] if { [ file exists $myProgram ] } { return $argRun } # if full path to program was NOT provided, find out where it is. # find it with 'which' then replace Program with Full Path set myProgram [ string map { / "" } $myProgram ] set myFullPath [ p.6.which $myProgram ] regsub $myProgram $argRun $myFullPath myRun return $myRun } # ---------------------------------------------------------------- # proc 8 of 9 # the final command that runs the alias's corresponding command proc p.8.run_alias {} { set myRun [ p.5.get_alias ] set myRun [ p.7.voodoo $myRun ] if { $myRun == "!!ERROR!!" } { return } else { # set myRun [ file normalize $myRun ] if { $::tcl_platform(platform) == "windows" } { eval exec start $myRun & } else { #set myRun [ exec which $myRun ] eval exec kfmclient exec $myRun & } # and here is the ugly hack again if { $::myNotFound != 1 } { exit } } } # ---------------------------------------------------------------- # proc 9 of 9 # open alias list file in text editor so it can be edited proc p.9.edit_alias {} { if { $::tcl_platform(platform) == "windows" } { eval exec start $::myAliasFile & } if { $::tcl_platform(platform) == "unix" } { eval exec kfmclient exec $::myAliasFile & } exit } # ================================================ # DRAW WINDOW # widgets: # toplevel .popbox # frame $::w.frame0 # entry $::w.frame0.aliasbox # ================================================ catch { destroy .popbox } set w [ toplevel .popbox ] wm withdraw . wm geometry $::w +50+200 wm title $::w $myWindowTitle wm overrideredirect $::w [ expr { $myHasTitle=="yes" ? "0" : "1" } ] #wm overrideredirect $::w [ if { $myHasTitle=="yes" } { list 0 } { list 1 } ] # -------------------------------- frame $::w.frame0 $::w.frame0 configure -relief sunken $::w.frame0 configure -bd 0 pack $::w.frame0 -fill both -expand 1 entry $::w.frame0.aliasbox $::w.frame0.aliasbox configure -takefocus 1 $::w.frame0.aliasbox configure -relief sunken $::w.frame0.aliasbox configure -bd 0 $::w.frame0.aliasbox configure -width $myAliasWidth $::w.frame0.aliasbox configure -background $myAliasBg $::w.frame0.aliasbox configure -foreground $myAliasFg $::w.frame0.aliasbox configure -font $myAliasFont $::w.frame0.aliasbox configure -justify $myAliasAlign $::w.frame0.aliasbox configure -textvariable myAlias pack $::w.frame0.aliasbox -expand 1 # ================================================ # BINDINGS # ================================================ bind $::w.frame0.aliasbox { p.8.run_alias } bind $::w { exit } bind $::w { p.9.edit_alias } wm protocol $::w WM_DELETE_WINDOW { exit } # ================================================ # RUN # ================================================ focus $::w.frame0.aliasbox p.3.center_window $::w ---- [LES]: Here is the alias list sample: # ================================================ # ALIAS LIST # ================================================ 2d = ~/Desktop/todo.txt 4 = http://mini.net/tcl/4 chat = D:/TclTk/chat/tkchat.kit clt = http://groups.google.com/groups?ie=UTF-8&group=comp.lang.tcl ff = /usr/local/bin/firefox ffex = http://texturizer.net/firefox/extensions/ ggf = http://www.googlefight.com pkg = ftp://ftp.netbsd.org/pub/NetBSD/packages/pkgsrc/README-all.html rot = http://www.rottentomatoes.com sp 1 = /usr/local/bin/adsl on sp 0 = /usr/local/bin/adsl off tz = http://www.timeanddate.com/worldclock/ ws = http://www.wordspy.com/ xc = http://www.x-rates.com/calculator.html ---- [Category Application] [Category Desktop]