Config Files for Interactive Tcl

by Sam A. Hill

If you don't use the language Tcl/Tk then this probably won't be of any use to you. Tcl/Tk is an awesome programming language for throwing together GUI applications on the desktop, and I've used it for many years. It's not well-known, however, and sometimes its interface can feel a little lacking. For instance, for a long time I thought there were only two ways to run tcl from the command line: either you could type tcl and enter interactive mode, or you could type tcl filename.tcl to run filename.tcl in non-interactive mode. There wasn't really a hybrid option to open an interactive session after running some code, the way python -i does. Or at least, so I thought.

The RC Files

Today I discovered that if you create .tclshrc in your home directory, then tclsh will always run that code and then open an interactive session. Or if you run wish (the version of tclsh which includes the Tk graphical extension), it will always run .wishrc from your home directory.

Note that it always runs the same file, the one in your home directory. This might be useful if there are certain packages or default settings you always like to use, but what if you want to be able to use different init files in different circumstances?

Well, one thing you can do is to place this code into ~/.tclshrc or ~/.wishrc:

catch {source .tclinit}  

Then when you run the command in a folder that contains the file .tclinit, it will treat that file as an init file instead. If the .tclinit file doesn't exist, then it continues on into interactive mode as usual. You can use any name you want in place of .tclinit, although I don't recommend using .tclshrc or .wishrc themselves or else you could end up in an infinite loop if you run tclsh in the home directory.

Or maybe you want to be able to choose your init file straight from the command-line, like python -i file.py? In that case, put into ~/.tclshrc the code

catch {source {*}[lrange $argv 1 end]}  

Then you can type tclsh -i initfile.tcl and it will run initfile.tcl before dropping into interactive mode.

(You may be wondering where the -i comes from since it doesn't show up in the code. Well, the command-line definition of tclsh is

tclsh ?-encoding name? ?fileName arg arg ...?

What this means is that tclsh takes the first argument it is given and tries to open it as a file, which would be great except it does so non-interactively. But for some reason, if that first argument starts with a - and it's not a recognized flag, then Tcl knows that there isn't a filename coming, and it puts all of its arguments into the argv list. You could in fact use any flag in place of -i so long as it wasn't known by the interpreter. (For tclsh, that just means you need to avoid encoding; wish has the flags colormap, display, geometry, name, sync, use, and visual as well.)

We could do even more sophisticated things with this method. For instance, we could combine the two options, running .tclinit only if another init file isn't provided:

if {$argc>1} {
    catch {source {*}[lrange $argv 1 end]}
} elseif {catch {source .tclinit}} {
    puts "No init file found."
}

You could even define your own command-line flags for tclsh or wish by parsing argv for elements that start with -. Have a favorite package like tablelist that you want to be able to use interactively in a quick way?

if {[lsearch $argv "-table"]>=0} {
    package require tablelist
}
#then continue with the rest of your init code