Command completion

Richard Suchenwirth 2002-07-29 - The behavior of some shells (even including cmd.exe!) to complete commands or filenames on <Tab> is occasionally asked from Tcl too. Here is a quick shot of a mini-console with an entry, that does command completion, a label where multiple alternatives are shown, and a text widget where the command and its result (or error message) are displayed when <Return> was hit:


 proc complete {varName infoName} {
     upvar 1 $varName var
     upvar 1 $infoName info
     if {[llength $var]==1} {
         set cmds [info commands $var*]
         if {[llength $cmds]==1} {
             set var "$cmds " ;# added complementary blank
         } elseif {[llength $cmds]>1} {
             set info [lsort $cmds] ;# make choices available for display
             set var [longestCommonPrefix $cmds] ;# partial completion (1)
         } else bell
     }
 }
 # (1): longestCommonPrefix is available on [Additional string functions]
 entry .e -textvar entry
 bind .e <Tab> {complete entry info; %W icursor end; break}
 bind .e <Return> {catch $entry res; .t insert end "%% $entry\n$res\n"}
 label .info -textvar info -anchor w -width 60
 text .t
 pack .e .info  -fill x
 pack .t        -fill both -expand 1 

Further extensions that one could add:

  • try subcommands for well-known commands like string, package, info, ...
  • if a word starts with $, check [info vars] of the rest of string
  • try glob on other than first word

Use tclreadline to enable TAB command, variable and arguments complition in your interpreter. For tclsh put to your ~/.tclshrc (you MUST replace ^A, ^B and ^[ with corresponding Control-character, use C-q C-a, etc in Emacs editor):

  if {$tcl_interactive} {
      catch {
          package require tclreadline
          namespace eval tclreadline {
              if ([regexp "^(xterm|eterm-color)" "$::env(TERM)"]) {
                  proc prompt1 {} { return "^A^[\[0;31m^[\[1m^Btcl>^A^[\[0m^B " }
                  proc prompt2 {} { return "^A^[\[0;31m^B...> ^A^[\[0m^B" }
              } {
                  proc prompt1 {} { return "tcl> " }
                  proc prompt2 {} { return "...> " }
              }
          }
          ::tclreadline::Loop
      }
  }

Read tclreadline(3tcl) man page and "Readline Init File" section in info readline for more info. Some funny ~/.inputrc settings:

  # Invoke an editor on the current command line, and execute the result as
  # shell commands. Bash attempts to invoke $FCEDIT, $EDITOR, and emacs as the
  # editor, in that order.
  "\C-x\C-e": edit-and-execute-command

  # Define my favorite Emacs key bindings.
  "\C-@": set-mark
  "\C-w": kill-region
  "\M-w": copy-region-as-kill

  # Ctrl+Left/Right to move by whole words.
  "\e[1;5C": forward-word
  "\e[1;5D": backward-word
  # Same with Shift pressed.
  "\e[1;6C": forward-word
  "\e[1;6D": backward-word

  # Ctrl+Backspace/Delete to delete whole words.
  "\e[3;5~": kill-word
  "\C-_": backward-kill-word

  # UP/DOWN filter history by typed string as prefix.
  "\e[A": history-search-backward
  "\C-p": history-search-backward
  "\eOA": history-search-backward
  "\e[B": history-search-forward
  "\C-n": history-search-forward
  "\eOB": history-search-forward

  # Use 'Control+TAB' for cycling possible completion in bash.
  "\e[1;5I": menu-complete

tkcon has routines for expanding pathnames, command names and variable names (::tkcon::Expand* in the code). These have also been carried over into the updated console of the Tcl core.


a variant with instant completion Command completion in the iFile console