Tclsh-Wrapper is a tiny wrapper for tclsh ( Shell/interpretor application for Tcl programming language )
Most shell applications (Bash, Python, etc) have command history navigation feature (mostly invoked by pressing UP key). However, tclsh
offers no such basic functionality. It doesn't even understand UP/DOWN key press!!!
That is not a big problem since Tcl/Tk package ships with an alternative shell application tkcon. It's a GUI shell, and much better.
But still, if tclsh
can offer command history navigation, I'll prefer it to tkcon
since it's much more productive and convenient to terminal geeks anyway.
After a bit of research, I found this code which offers what I needed. I changed some code in it and added a few new convenient features and that is Tclsh-Wrapper.
tclsh
only in Unix like systems, that 3rd party package was a complete overkill.Assume you copy the package to ~/lib/tcl
. (Of course, you can copy it anywhere you like)
git clone https://github.com/suewonjp/tclsh-wrapper.git ~/lib/tcl/tclsh-wrapper
Create a launcher script like so:
touch tcl; chmod a+x tcl; echo "
#!/bin/sh
exec tclsh ~/lib/tcl/tclsh-wrapper/TclReadLine/TclReadLine.tcl
" > tcl
tcl
script somewhere in the system path.tcl
instead of tclsh
tcl
script above is intended for interactive uses only and not a complete replacement for tclsh
.tclsh
for executing Tcl scripts.Alternatively, create a ~/.tclshrc
file and append the code as follows:
lappend auto_path "~/lib/tcl/tclsh-wrapper"
if {$::tcl_interactive} {
package require TclReadLine
TclReadLine::interact
}
In this case, you can run tclsh
directly, then it will read ~/.tclshrc
at startup and eventually load Tclsh-Wrapper.
Once Tclsh-Wrapper invoked, Type
help
to print out all key bindings and additional help messages.
exit
command.Depending on terminals you're using, Tclsh-Wrapper may not recognize ALT key press. Read the topic of ALT key limitation below for more detail
?
at the start of the line.You can navigate the command history one by one by typing UP/CONTROL+p/ALT+k
(retrieving older command lines) or DOWN/CONTROL+n/ALT+j
(retrieving newer command lines).
But sometimes this may be so tedious. When you know some word contained in your target command line, you can quickly retrieve it by using that word.
For example, type ?foo
(question mark + [your search word]) and press ENTER
. Tclsh-Wrapper will quickly retrieve the most recent command line containing foo
. Also this will let you in a special mode called History Search Mode. Remember, in History Search Mode, UP/CONTROL+p/ALT+k
and DOWN/CONTROL+n/ALT+j
behave a little bit differently. When you press UP
in the previous example, Tclsh-Wrapper will retrieve one step older command line containing foo
if any.
In History Search Mode, navigation will be restricted to only command lines containing the search word.
The History Search Mode will end as soon as you execute some command. To manually end the History Search Mode without executing any command, type CONTROL+g
and ENTER
. ( Alternatively, type ALT+/
and ENTER
)
Most of these features were already there at the base code and quite useful.
Tclsh-Wrapper reads a configuration file if it discovers one at startup and executes arbitrary Tcl commands in that file.
The path to the file is ~/.tcllinerc
by default, but you can change the path by assigning a new path to TCLLINERC environment variable.
If you find yourself typing same command lines over and over, then aliases may help you.
> TclReadLine::alias p puts
> p {hello}
hello
Aliases defined inside an interactive session will be valid only in that session. You can write aliases in your configuration file (~/.tclshrc
) and make them persistent.
Also there is a TclReadLine::unalias
command so you can remove them.
You should use command aliases at the start of command line. Aliases in anywhere else won't be recognized
Also when the aliased command has whitespaces in them, you should quote it with braces (See examples below)
Useful Aliases:
### Print a long horizontal line in magenta color
TclReadLine::alias l {puts "\\033\\[35m===========================================\\033\\[0m"}
### I'm kind of lazy so I'd like to type `p` instead of `puts`
TclReadLine::alias p puts
### Alias on the fly (e.g., %a iii {info globals})
TclReadLine::alias %a {TclReadLine::alias}
### Unalias on the fly (e.g., %u iii)
TclReadLine::alias %u {TclReadLine::unalias}
Simple keyword completion is provided. For example, fore<TAB>
will expand to foreach
.
By default, you can expand patterns if that matches either of the following:
Understand that you may not match every Tcl/Tk command. ( It seems like a limitation of Tcl interpretor rather than Tclsh-Wrapper ).
You can match Ensemble commands such as string
, array
, etc. (Since version 1.4)
Also, you can extend the list of match candidates using TclReadLine::keyword
API. For example, inserting the line TclReadLine::keyword {TclReadLine::}
in the configuration file will let you type just TclR<TAB>
for TclReadLine::
.
For another example, inserting the following lines into the configuration file will let you just type s*tol<TAB>
for string tolower
.
TclReadLine::keyword {string tolower}
TclReadLine::keyword {string totitle}
TclReadLine::keyword {string toupper}
TclReadLine::keyword {string trim}
TclReadLine::keyword {string trimleft}
TclReadLine::keyword {string trimright}
However, s*trim<TAB>
will print out 3 candidates (string trim
, string trimleft
, string trimright
). If your target were string trimleft
, then what you do is just appending l
and type <TAB>
. What if your target were string trim
? Then, type s*trim$<TAB>
. $
notation at the end will match words ending with the character before that $
.
See the sample .tcllinerc file
Tclsh-Wrapper persists the command history records to a file. (~/tclline_history
by default)
You can change the path by assigning a new path to TCLLINE_HISTORY environment variable.
This may be useful when you want to maintain separate command history for tclsh
and wish
. In my opinion, sharing the same command history for both shells is not a good idea since tclsh
doesn't understand Tk commands by default and when using tclsh
after using wish
, the command history would be polluted with a bunch of commands that tclsh
can't even execute.
For example, you can change the launcher script (named tcl
) introduced earlier like so:
#!/bin/sh
if [ "$1" = "w" ]; then
TCLLINE_HISTORY=~/.tclline_history_w exec wish ~/test/trysomething/tclsh-wrapper/TclReadLine/TclReadLine.tcl
else
TCLLINE_HISTORY=~/.tclline_history exec tclsh ~/test/trysomething/tclsh-wrapper/TclReadLine/TclReadLine.tcl
fi
You can invoke tclsh
as before by running tcl
, and invoke wish
by running tcl w
. Notice that ~/.tclline_history
will be used for tclsh
sessions, and ~/.tclline_history_w
will be used for wish
sessions.
tclsh.exe
, the Windows executable, not tclsh
on Cygwincat -v
and type ALT+a
(Press ALT
and a
together)^[a
, then you're OK. ~/Google\ Drive
.Copyright (c) 2018 Suewon Bahng, suewonjp@gmail.com
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
Suewon Bahng
Updated by Suewon Bahng ( Jan 2018 )