Error processing request

Parameters

CONTENT_LENGTH0
REQUEST_METHODGET
REQUEST_URI/revision/Pure-tcl+readline2?V=64
QUERY_STRINGV=64
CONTENT_TYPE
DOCUMENT_URI/revision/Pure-tcl+readline2
DOCUMENT_ROOT/var/www/nikit/nikit/nginx/../docroot
SCGI1
SERVER_PROTOCOLHTTP/1.1
HTTPSon
REMOTE_ADDR172.70.126.64
REMOTE_PORT48878
SERVER_PORT4443
SERVER_NAMEwiki.tcl-lang.org
HTTP_HOSTwiki.tcl-lang.org
HTTP_CONNECTIONKeep-Alive
HTTP_ACCEPT_ENCODINGgzip, br
HTTP_X_FORWARDED_FOR3.138.35.229
HTTP_CF_RAY88374b7039ce2943-ORD
HTTP_X_FORWARDED_PROTOhttps
HTTP_CF_VISITOR{"scheme":"https"}
HTTP_ACCEPT*/*
HTTP_USER_AGENTMozilla/5.0 AppleWebKit/537.36 (KHTML, like Gecko; compatible; ClaudeBot/1.0; [email protected])
HTTP_REFERERhttps://wiki.tcl.tk/revision/Pure%2Dtcl+readline2?V=64
HTTP_CF_CONNECTING_IP3.138.35.229
HTTP_CDN_LOOPcloudflare
HTTP_CF_IPCOUNTRYUS

Body


Error

Unknow state transition: LINE -> END

-code

1

-level

0

-errorstack

INNER {returnImm {Unknow state transition: LINE -> END} {}} CALL {my render_wikit {Pure-tcl readline2} ======\n#\n#\ tclline:\ An\ attempt\ at\ a\ pure\ tcl\ readline.\n#\n#\ This\ base\ code\ taken\ from\ http://wiki.tcl.tk/20215\ and\n#\ http://wiki.tcl.tk/16139\n#\n#\ Author:\ HCG\n#\ Licence:\ \"as\ freely\ available\ as\ possible\"\ http://wiki.tcl.tk/4381\n#\n#\ Modified\ by\ rjmcmahon:\ fixes\ history\ and\ multiple\ key\ sequences\ per\ input\ char\ (may\ not\ assume\ atomic)\n#\ Also\ added\ ability\ to\ extend\ the\ completion\ handlers\n#\n#\ Note:\ The\ wiki.tcl.tk\ is\ broken\ with\ respect\ to\ creating\ a\ new\ page\ and\ reverting\ back\ to\ an\ old\ page\n#\ Some\ comments\ from\ the\ previous\ wiki\ page\ no\ longer\ shown\ as\ the\ file\ upload\ seem\ to\ overwrite\ the\ entire\ wiki\ page.\n#\n#\ \[LV\]\ Actually,\ it\ isn't\ broken\ -\ but\ there\ might\ be\ a\ misunderstanding\ in\ terms\ of\ the\ functionality\ of\ file\ upload.\n#\ The\ comments\ on\ each\ page\ are\ literally\ part\ of\ the\ page\ itself.\ The\ file\ upload\ replaces\ the\ complete\ contents\ of\ the\ page\ with\ new\ contents\n#\ Thus,\ if\ the\ comments\ would\ be\ useful\ to\ keep,\ you\ should\ download\ the\ current\ wiki\ text\ page,\ replace\ the\ portion\ of\ the\ page\ containing\n#\ code\ or\ whatever\ with\ the\ new\ contents,\ then\ upload\ the\ entire\ page.\ By\ just\ uploading\ tclline,\ you\ are\ effectively\ saying\ \"the\ only\ thing\n#\ I\ want\ on\ this\ page\ is\ the\ contents\ of\ this\ file\".\n#\npackage\ provide\ TclReadLine\ 1.1\n\n#\ Use\ Tclx\ if\ available:\ncatch\ \{\n\ \ \ \ \ \ package\ require\ Tclx\n\n\ \ \ \ \ \ #\ Prevent\ sigint\ from\ killing\ our\ shell:\n\ \ \ \ \ \ signal\ ignore\ SIGINT\n\}\n\nnamespace\ eval\ TclReadLine\ \{\n\n\ \ \ \ namespace\ export\ interact\n\n\ \ \ \ #\ Initialise\ our\ own\ env\ variables:\n\ \ \ \ variable\ PROMPT\ \">\"\n\ \ \ \ variable\ COMPLETION_MATCH\ \"\"\n\ \ \ \ \n\ \ \ \ #\ Support\ extensions\ to\ the\ completion\ handling\n\ \ \ \ #\ which\ will\ be\ called\ in\ list\ order.\n\ \ \ \ #\ Initialize\ with\ the\ \"open\ sourced\"\ TCL\ base\ handler\n\ \ \ \ #\ taken\ from\ the\ wiki\ page\n\ \ \ \ variable\ COMPLETION_HANDLERS\ \[list\ TclReadLine::handleCompletionBase\]\n\n\ \ \ \ #\n\ \ \ \ #\ \ This\ value\ was\ determined\ by\ measuring\ \n\ \ \ \ #\ \ a\ cygwin\ over\ ssh.\ \n\ \ \ \ #\n\ \ \ \ variable\ READLINE_LATENCY\ 10\ \;#\ in\ ms\n\ \ \ \ \n\ \ \ \ variable\ CMDLINE\ \"\"\n\ \ \ \ variable\ CMDLINE_CURSOR\ 0\n\ \ \ \ variable\ CMDLINE_LINES\ 0\n\ \ \ \ variable\ CMDLINE_PARTIAL\n\ \ \ \ \n\ \ \ \ variable\ ALIASES\n\ \ \ \ array\ set\ ALIASES\ \{\}\n\ \ \ \ \n\ \ \ \ variable\ forever\ 0\n\ \ \ \ \n\ \ \ \ #\ Resource\ and\ history\ files:\n\ \ \ \ variable\ HISTORY_SIZE\ 100\n\ \ \ \ variable\ HISTORY_LEVEL\ 0\n\ \ \ \ variable\ HISTFILE\ \$::env(HOME)/.tclline_history\n\ \ \ \ variable\ \ RCFILE\ \$::env(HOME)/.tcllinerc\n\}\n\nproc\ TclReadLine::ESC\ \{\}\ \{\n\ \ \ \ return\ \"\\033\"\n\}\n\nproc\ TclReadLine::shift\ \{ls\}\ \{\n\ \ \ \ upvar\ 1\ \$ls\ LIST\n\ \ \ \ set\ ret\ \[lindex\ \$LIST\ 0\]\n\ \ \ \ set\ LIST\ \[lrange\ \$LIST\ 1\ end\]\n\ \ \ \ return\ \$ret\n\}\n\nproc\ TclReadLine::readbuf\ \{txt\}\ \{\n\ \ \ \ upvar\ 1\ \$txt\ STRING\n\ \ \ \ \n\ \ \ \ set\ ret\ \[string\ index\ \$STRING\ 0\]\n\ \ \ \ set\ STRING\ \[string\ range\ \$STRING\ 1\ end\]\n\ \ \ \ return\ \$ret\n\}\n\nproc\ TclReadLine::goto\ \{row\ \{col\ 1\}\}\ \{\n\ \ \ \ switch\ --\ \$row\ \{\n\ \ \ \ \ \ \ \ \"home\"\ \{set\ row\ 1\}\n\ \ \ \ \}\n\ \ \ \ print\ \"\[ESC\]\\\[\$\{row\}\;\$\{col\}H\"\ nowait\n\}\n\nproc\ TclReadLine::gotocol\ \{col\}\ \{\n\ \ \ \ print\ \"\\r\"\ nowait\n\ \ \ \ if\ \{\$col\ >\ 0\}\ \{\n\ \ \ \ \ \ \ \ print\ \"\[ESC\]\\\[\$\{col\}C\"\ nowait\n\ \ \ \ \}\n\}\n\nproc\ TclReadLine::clear\ \{\}\ \{\n\ \ \ \ print\ \"\[ESC\]\\\[2J\"\ nowait\n\ \ \ \ goto\ home\n\}\n\nproc\ TclReadLine::clearline\ \{\}\ \{\n\ \ \ \ print\ \"\[ESC\]\\\[2K\\r\"\ nowait\n\}\n\nproc\ TclReadLine::getColumns\ \{\}\ \{\n\ \ \ \ set\ cols\ 0\n\ \ \ \ if\ \{!\[catch\ \{exec\ stty\ -a\}\ err\]\}\ \{\n\ \ \ \ \ \ \ \ #\ check\ for\ Linux\ stlye\ stty\ output\n\ \ \ \ \ \ \ \ if\ \{\[regexp\ \{rows\ (=\ )?(\\d+)\;\ columns\ (=\ )?(\\d+)\}\ \$err\ -\ i1\ rows\ i2\ cols\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ return\ \$cols\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ #\ check\ for\ BSD\ style\ stty\ output\n\ \ \ \ \ \ \ \ if\ \{\[regexp\ \{\ (\\d+)\ rows\;\ (\\d+)\ columns\;\}\ \$err\ -\ rows\ cols\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ return\ \$cols\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\ \ \ \ return\ \$cols\n\}\n\nproc\ TclReadLine::localInfo\ \{args\}\ \{\n\ \ \ \ set\ v\ \[uplevel\ _info\ \$args\]\n\ \ \ \ if\ \{\ \[string\ equal\ \"script\"\ \[lindex\ \$args\ 0\]\]\ \}\ \{\n\ \ \ \ \ \ \ \ if\ \{\ \[string\ equal\ \$v\ \$TclReadLine::ThisScript\]\ \}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ return\ \"\"\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\ \ \ \ return\ \$v\n\}\n\nproc\ TclReadLine::localPuts\ \{args\}\ \{\n\ \ \ \ \n\ \ \ \ set\ l\ \[llength\ \$args\]\n\ \ \ \ if\ \{\ 3\ <\ \$l\ \}\ \{\n\ \ \ \ \ \ \ \ return\ -code\ error\ \"Error:\ wrong\ \\#\ args\"\n\ \ \ \ \}\n\ \ \ \ \n\ \ \ \ if\ \{\ 1\ <\ \$l\ \}\ \{\n\ \ \ \ \ \ \ \ if\ \{\ \[string\ equal\ \"-nonewline\"\ \[lindex\ \$args\ 0\]\]\ \}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\ 2\ <\ \$l\ \}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ we\ don't\ send\ to\ channel...\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ eval\ _origPuts\ \$args\n\ \ \ \ \ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ str\ \[lindex\ \$args\ 1\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ append\ TclReadLine::putsString\ \$str\ \;#\ no\ newline...\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ #\ must\ be\ a\ channel\n\ \ \ \ \ \ \ \ \ \ \ \ eval\ _origPuts\ \$args\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ append\ TclReadLine::putsString\ \[lindex\ \$args\ 0\]\ \"\\n\"\n\ \ \ \ \}\n\}\n\nproc\ TclReadLine::prompt\ \{\{txt\ \"\"\}\}\ \{\n\ \ \ \ \n\ \ \ \ if\ \{\ \"\"\ !=\ \[info\ var\ ::tcl_prompt1\]\ \}\ \{\n\ \ \ \ \ \ \ \ rename\ ::puts\ ::_origPuts\n\ \ \ \ \ \ \ \ rename\ TclReadLine::localPuts\ ::puts\n\ \ \ \ \ \ \ \ variable\ putsString\n\ \ \ \ \ \ \ \ set\ putsString\ \"\"\n\ \ \ \ \ \ \ \ eval\ \[set\ ::tcl_prompt1\]\n\ \ \ \ \ \ \ \ set\ prompt\ \$putsString\n\ \ \ \ \ \ \ \ rename\ ::puts\ TclReadLine::localPuts\n\ \ \ \ \ \ \ \ rename\ ::_origPuts\ ::puts\n\ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ variable\ PROMPT\n\ \ \ \ \ \ \ \ set\ prompt\ \[subst\ \$PROMPT\]\n\ \ \ \ \}\n\ \ \ \ set\ txt\ \"\$prompt\$txt\"\n\ \ \ \ variable\ CMDLINE_LINES\n\ \ \ \ variable\ CMDLINE_CURSOR\n\ \ \ \ variable\ COLUMNS\n\ \ \ \ foreach\ \{end\ mid\}\ \$CMDLINE_LINES\ break\n\ \ \ \ \n\ \ \ \ #\ Calculate\ how\ many\ extra\ lines\ we\ need\ to\ display.\n\ \ \ \ #\ Also\ calculate\ cursor\ position:\n\ \ \ \ set\ n\ -1\n\ \ \ \ set\ totalLen\ 0\n\ \ \ \ set\ cursorLen\ \[expr\ \{\$CMDLINE_CURSOR+\[string\ length\ \$prompt\]\}\]\n\ \ \ \ set\ row\ 0\n\ \ \ \ set\ col\ 0\n\ \ \ \ \n\ \ \ \ #\ Render\ output\ line-by-line\ to\ \$out\ then\ copy\ back\ to\ \$txt:\n\ \ \ \ set\ found\ 0\n\ \ \ \ set\ out\ \[list\]\n\ \ \ \ foreach\ line\ \[split\ \$txt\ \"\\n\"\]\ \{\n\ \ \ \ \ \ \ \ set\ len\ \[expr\ \{\[string\ length\ \$line\]+1\}\]\n\ \ \ \ \ \ \ \ incr\ totalLen\ \$len\n\ \ \ \ \ \ \ \ if\ \{\$found\ ==\ 0\ &&\ \$totalLen\ >=\ \$cursorLen\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ cursorLen\ \[expr\ \{\$cursorLen\ -\ (\$totalLen\ -\ \$len)\}\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ col\ \[expr\ \{\$cursorLen\ %\ \$COLUMNS\}\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ row\ \[expr\ \{\$n\ +\ (\$cursorLen\ /\ \$COLUMNS)\ +\ 1\}\]\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$cursorLen\ >=\ \$len\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ col\ 0\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ incr\ row\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ set\ found\ 1\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ incr\ n\ \[expr\ \{int(ceil(double(\$len)/\$COLUMNS))\}\]\n\ \ \ \ \ \ \ \ while\ \{\$len\ >\ 0\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lappend\ out\ \[string\ range\ \$line\ 0\ \[expr\ \{\$COLUMNS-1\}\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ line\ \[string\ range\ \$line\ \$COLUMNS\ end\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ len\ \[expr\ \{\$len-\$COLUMNS\}\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\ \ \ \ set\ txt\ \[join\ \$out\ \"\\n\"\]\n\ \ \ \ set\ row\ \[expr\ \{\$n-\$row\}\]\n\ \ \ \ \n\ \ \ \ #\ Reserve\ spaces\ for\ display:\n\ \ \ \ if\ \{\$end\}\ \{\n\ \ \ \ \ \ \ \ if\ \{\$mid\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ print\ \"\[ESC\]\\\[\$\{mid\}B\"\ nowait\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ for\ \{set\ x\ 0\}\ \{\$x\ <\ \$end\}\ \{incr\ x\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ clearline\n\ \ \ \ \ \ \ \ \ \ \ \ print\ \"\[ESC\]\\\[1A\"\ nowait\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\ \ \ \ clearline\n\ \ \ \ set\ CMDLINE_LINES\ \$n\n\ \ \ \ \n\ \ \ \ #\ Output\ line(s):\n\ \ \ \ print\ \"\\r\$txt\"\n\ \ \ \ \n\ \ \ \ if\ \{\$row\}\ \{\n\ \ \ \ \ \ \ \ print\ \"\[ESC\]\\\[\$\{row\}A\"\ nowait\n\ \ \ \ \}\n\ \ \ \ gotocol\ \$col\n\ \ \ \ lappend\ CMDLINE_LINES\ \$row\n\}\n\nproc\ TclReadLine::print\ \{txt\ \{wait\ wait\}\}\ \{\n\ \ \ \ #\ Sends\ output\ to\ stdout\ chunks\ at\ a\ time.\n\ \ \ \ #\ This\ is\ to\ prevent\ the\ terminal\ from\n\ \ \ \ #\ hanging\ if\ we\ output\ too\ much:\n\ \ \ \ while\ \{\[string\ length\ \$txt\]\}\ \{\n\ \ \ \ \ \ \ \ puts\ -nonewline\ \[string\ range\ \$txt\ 0\ 2047\]\n\ \ \ \ \ \ \ \ set\ txt\ \[string\ range\ \$txt\ 2048\ end\]\n\ \ \ \ \ \ \ \ if\ \{\$wait\ ==\ \"wait\"\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ after\ 1\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\}\n\nproc\ TclReadLine::unknown\ \{args\}\ \{\n\ \ \ \ \n\ \ \ \ set\ name\ \[lindex\ \$args\ 0\]\n\ \ \ \ set\ cmdline\ \$TclReadLine::CMDLINE\n\ \ \ \ set\ cmd\ \[string\ trim\ \[regexp\ -inline\ \{^\\s*\[^\\s\]+\}\ \$cmdline\]\]\n\ \ \ \ if\ \{\[info\ exists\ TclReadLine::ALIASES(\$cmd)\]\}\ \{\n\ \ \ \ \ \ \ \ set\ cmd\ \[regexp\ -inline\ \{^\\s*\[^\\s\]+\}\ \$TclReadLine::ALIASES(\$cmd)\]\n\ \ \ \ \}\n\ \ \ \ \n\ \ \ \ set\ new\ \[auto_execok\ \$name\]\n\ \ \ \ if\ \{\$new\ !=\ \"\"\}\ \{\n\ \ \ \ \ \ \ \ set\ redir\ \"\"\n\ \ \ \ \ \ \ \ if\ \{\$name\ ==\ \$cmd\ &&\ \[info\ command\ \$cmd\]\ ==\ \"\"\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ redir\ \">&@\ stdout\ <@\ stdin\"\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ if\ \{\[catch\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ uplevel\ 1\ exec\ \$redir\ \$new\ \[lrange\ \$args\ 1\ end\]\}\ ret\]\n\ \ \ \ \ \ \ \ \}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ return\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ return\ \$ret\n\ \ \ \ \}\n\ \ \ \ \n\ \ \ \ uplevel\ _unknown\ \$args\n\}\n\nproc\ TclReadLine::alias\ \{word\ command\}\ \{\n\ \ \ \ variable\ ALIASES\n\ \ \ \ set\ ALIASES(\$word)\ \$command\n\}\n\nproc\ TclReadLine::unalias\ \{word\}\ \{\n\ \ \ \ variable\ ALIASES\n\ \ \ \ array\ unset\ ALIASES\ \$word\n\}\n\n################################\n#\ Key\ bindings\n################################\nproc\ TclReadLine::handleEscapes\ \{\}\ \{\n\ \ \ \ \n\ \ \ \ variable\ CMDLINE\n\ \ \ \ variable\ CMDLINE_CURSOR\n\ \ \ \ \n\ \ \ \ upvar\ 1\ keybuffer\ keybuffer\n\ \ \ \ set\ seq\ \"\"\n\ \ \ \ set\ found\ 0\n\ \ \ \ while\ \{\[set\ ch\ \[readbuf\ keybuffer\]\]\ !=\ \"\"\}\ \{\n\ \ \ \ \ \ \ \ append\ seq\ \$ch\n\n\ \ \ \ \ \ \ \ switch\ -exact\ --\ \$seq\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \"\\\[A\"\ \{\ \;#\ Cursor\ Up\ (cuu1,up)\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ handleHistory\ 1\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ found\ 1\;\ break\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \"\\\[B\"\ \{\ \;#\ Cursor\ Down\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ handleHistory\ -1\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ found\ 1\;\ break\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \"\\\[C\"\ \{\ \;#\ Cursor\ Right\ (cuf1,nd)\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$CMDLINE_CURSOR\ <\ \[string\ length\ \$CMDLINE\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ incr\ CMDLINE_CURSOR\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ found\ 1\;\ break\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \"\\\[D\"\ \{\ \;#\ Cursor\ Left\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$CMDLINE_CURSOR\ >\ 0\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ incr\ CMDLINE_CURSOR\ -1\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ found\ 1\;\ break\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \"\\\[H\"\ -\n\ \ \ \ \ \ \ \ \ \ \ \ \"\\\[7~\"\ -\n\ \ \ \ \ \ \ \ \ \ \ \ \"\\\[1~\"\ \{\ \;#\ home\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ CMDLINE_CURSOR\ 0\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ found\ 1\;\ break\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \"\\\[3~\"\ \{\ \;#\ delete\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$CMDLINE_CURSOR\ <\ \[string\ length\ \$CMDLINE\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ CMDLINE\ \[string\ replace\ \$CMDLINE\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$CMDLINE_CURSOR\ \$CMDLINE_CURSOR\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ found\ 1\;\ break\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \"\\\[F\"\ -\n\ \ \ \ \ \ \ \ \ \ \ \ \"\\\[K\"\ -\n\ \ \ \ \ \ \ \ \ \ \ \ \"\\\[8~\"\ -\n\ \ \ \ \ \ \ \ \ \ \ \ \"\\\[4~\"\ \{\ \;#\ end\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ CMDLINE_CURSOR\ \[string\ length\ \$CMDLINE\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ found\ 1\;\ break\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \"\\\[5~\"\ \{\ \;#\ Page\ Up\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \"\\\[6~\"\ \{\ \;#\ Page\ Down\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\ \ \ \ return\ \$found\n\}\n\nproc\ TclReadLine::handleControls\ \{\}\ \{\n\ \ \ \ \n\ \ \ \ variable\ CMDLINE\n\ \ \ \ variable\ CMDLINE_CURSOR\n\ \ \ \ \n\ \ \ \ upvar\ 1\ char\ char\n\ \ \ \ upvar\ 1\ keybuffer\ keybuffer\n\ \ \ \ \n\ \ \ \ #\ Control\ chars\ start\ at\ a\ ==\ \\u0001\ and\ count\ up.\n\ \ \ \ switch\ -exact\ --\ \$char\ \{\n\ \ \ \ \ \ \ \ \\u0001\ \{\ \;#\ ^a\n\ \ \ \ \ \ \ \ \ \ \ \ set\ CMDLINE_CURSOR\ 0\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \\u0002\ \{\ \;#\ ^b\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\ \$CMDLINE_CURSOR\ >\ 0\ \}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ incr\ CMDLINE_CURSOR\ -1\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \\u0004\ \{\ \;#\ ^d\n\ \ \ \ \ \ \ \ \ \ \ \ #\ should\ exit\ -\ if\ this\ is\ the\ EOF\ char,\ and\ the\n\ \ \ \ \ \ \ \ \ \ \ \ #\ \ \ cursor\ is\ at\ the\ end-of-input\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\ 0\ ==\ \[string\ length\ \$CMDLINE\]\ \}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ doExit\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ set\ CMDLINE\ \[string\ replace\ \$CMDLINE\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$CMDLINE_CURSOR\ \$CMDLINE_CURSOR\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \\u0005\ \{\ \;#\ ^e\n\ \ \ \ \ \ \ \ \ \ \ \ set\ CMDLINE_CURSOR\ \[string\ length\ \$CMDLINE\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \\u0006\ \{\ \;#\ ^f\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$CMDLINE_CURSOR\ <\ \[string\ length\ \$CMDLINE\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ incr\ CMDLINE_CURSOR\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \\u0007\ \{\ \;#\ ^g\n\ \ \ \ \ \ \ \ \ \ \ \ set\ CMDLINE\ \"\"\n\ \ \ \ \ \ \ \ \ \ \ \ set\ CMDLINE_CURSOR\ 0\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \\u000b\ \{\ \;#\ ^k\n\ \ \ \ \ \ \ \ \ \ \ \ variable\ YANK\n\ \ \ \ \ \ \ \ \ \ \ \ set\ YANK\ \ \[string\ range\ \$CMDLINE\ \[expr\ \{\$CMDLINE_CURSOR\ \ \}\ \]\ end\ \]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ CMDLINE\ \[string\ range\ \$CMDLINE\ 0\ \[expr\ \{\$CMDLINE_CURSOR\ -\ 1\ \}\ \]\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \\u0019\ \{\ \;#\ ^y\n\ \ \ \ \ \ \ \ \ \ \ \ variable\ YANK\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\ \[\ info\ exists\ YANK\ \]\ \}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ CMDLINE\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \"\[string\ range\ \$CMDLINE\ 0\ \[expr\ \{\$CMDLINE_CURSOR\ -\ 1\ \}\]\]\$YANK\[string\ range\ \$CMDLINE\ \$CMDLINE_CURSOR\ end\]\"\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \\u000e\ \{\ \;#\ ^n\n\ \ \ \ \ \ \ \ \ \ \ \ handleHistory\ -1\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \\u0010\ \{\ \;#\ ^p\n\ \ \ \ \ \ \ \ \ \ \ \ handleHistory\ 1\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \\u0003\ \{\ \;#\ ^c\n\ \ \ \ \ \ \ \ \ \ \ \ #\ clear\ line\n\ \ \ \ \ \ \ \ \ \ \ \ set\ CMDLINE\ \"\"\n\ \ \ \ \ \ \ \ \ \ \ \ set\ CMDLINE_CURSOR\ 0\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \\u0008\ -\n\ \ \ \ \ \ \ \ \\u007f\ \{\ \;#\ ^h\ &&\ backspace\ ?\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$CMDLINE_CURSOR\ >\ 0\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ incr\ CMDLINE_CURSOR\ -1\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ CMDLINE\ \[string\ replace\ \$CMDLINE\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$CMDLINE_CURSOR\ \$CMDLINE_CURSOR\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \\u001b\ \{\ \;#\ ESC\ -\ handle\ escape\ sequences\n\ \ \ \ \ \ \ \ \ \ \ \ handleEscapes\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\ \ \ \ #\ Rate\ limiter:\n\ \ \ \ set\ keybuffer\ \"\"\n\}\n\nproc\ TclReadLine::shortMatch\ \{maybe\}\ \{\n\ \ \ \ #\ Find\ the\ shortest\ matching\ substring:\n\ \ \ \ set\ maybe\ \[lsort\ \$maybe\]\n\ \ \ \ set\ shortest\ \[lindex\ \$maybe\ 0\]\n\ \ \ \ foreach\ x\ \$maybe\ \{\n\ \ \ \ \ \ \ \ while\ \{!\[string\ match\ \$shortest*\ \$x\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ shortest\ \[string\ range\ \$shortest\ 0\ end-1\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\ \ \ \ return\ \$shortest\n\}\n\nproc\ TclReadLine::addCompletionHandler\ \{completion_extension\}\ \{\n\ \ \ \ variable\ COMPLETION_HANDLERS\n\ \ \ \ set\ COMPLETION_HANDLERS\ \[concat\ \$completion_extension\ \$COMPLETION_HANDLERS\]\n\}\n\nproc\ TclReadLine::delCompletionHandler\ \{completion_extension\}\ \{\n\ \ \ \ variable\ COMPLETION_HANDLERS\n\ \ \ \ set\ COMPLETION_HANDLERS\ \[lsearch\ -all\ -not\ -inline\ \$COMPLETION_HANDLERS\ \$completion_extension\]\ \n\}\n\nproc\ TclReadLine::getCompletionHandler\ \{\}\ \{\n\ \ \ \ variable\ COMPLETION_HANDLERS\n\ \ \ \ return\ \"\$COMPLETION_HANDLERS\"\n\}\n\nproc\ TclReadLine::handleCompletion\ \{\}\ \{\n\ \ \ \ variable\ COMPLETION_HANDLERS\n\ \ \ \ foreach\ handler\ \$COMPLETION_HANDLERS\ \{\n\ \ \ \ \ \ \ \ if\ \{\[eval\ \$handler\]\ ==\ 1\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ break\n\ \ \ \ \ \ \ \ \}\ \n\ \ \ \ \}\n\ \ \ \ return\ \n\}\n\nproc\ TclReadLine::handleCompletionBase\ \{\}\ \{\n\ \ \ \ variable\ CMDLINE\n\ \ \ \ variable\ CMDLINE_CURSOR\n\ \ \ \ \n\ \ \ \ set\ vars\ \"\"\n\ \ \ \ set\ cmds\ \"\"\n\ \ \ \ set\ execs\ \"\"\n\ \ \ \ set\ files\ \"\"\n\ \ \ \ \n\ \ \ \ #\ First\ find\ out\ what\ kind\ of\ word\ we\ need\ to\ complete:\n\ \ \ \ set\ wordstart\ \[string\ last\ \"\ \"\ \$CMDLINE\ \[expr\ \{\$CMDLINE_CURSOR-1\}\]\]\n\ \ \ \ incr\ wordstart\n\ \ \ \ set\ wordend\ \[string\ first\ \"\ \"\ \$CMDLINE\ \$wordstart\]\n\ \ \ \ if\ \{\$wordend\ ==\ -1\}\ \{\n\ \ \ \ \ \ \ \ set\ wordend\ end\n\ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ incr\ wordend\ -1\n\ \ \ \ \}\n\ \ \ \ set\ word\ \[string\ range\ \$CMDLINE\ \$wordstart\ \$wordend\]\n\ \ \ \ \n\ \ \ \ if\ \{\[string\ trim\ \$word\]\ ==\ \"\"\}\ return\n\ \ \ \ \n\ \ \ \ set\ firstchar\ \[string\ index\ \$word\ 0\]\n\ \ \ \ \n\ \ \ \ #\ Check\ if\ word\ is\ a\ variable:\n\ \ \ \ if\ \{\$firstchar\ ==\ \"\\\$\"\}\ \{\n\ \ \ \ \ \ \ \ set\ word\ \[string\ range\ \$word\ 1\ end\]\n\ \ \ \ \ \ \ \ incr\ wordstart\n\ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ #\ Check\ if\ it\ is\ an\ array\ key:proc\n\ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ set\ x\ \[string\ first\ \"(\"\ \$word\]\n\ \ \ \ \ \ \ \ if\ \{\$x\ !=\ -1\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ v\ \[string\ range\ \$word\ 0\ \[expr\ \{\$x-1\}\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ incr\ x\n\ \ \ \ \ \ \ \ \ \ \ \ set\ word\ \[string\ range\ \$word\ \$x\ end\]\n\ \ \ \ \ \ \ \ \ \ \ \ incr\ wordstart\ \$x\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[uplevel\ \\#0\ \"array\ exists\ \$v\"\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ vars\ \[uplevel\ \\#0\ \"array\ names\ \$v\ \$word*\"\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ foreach\ x\ \[uplevel\ \\#0\ \{info\ vars\}\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[string\ match\ \$word*\ \$x\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lappend\ vars\ \$x\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ #\ Check\ if\ word\ is\ possibly\ a\ path:\n\ \ \ \ \ \ \ \ if\ \{\$firstchar\ ==\ \"/\"\ ||\ \$firstchar\ ==\ \".\"\ ||\ \$wordstart\ !=\ 0\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ files\ \[glob\ -nocomplain\ --\ \$word*\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ if\ \{\$files\ ==\ \"\"\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ #\ Not\ a\ path\ then\ get\ all\ possibilities:\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$firstchar\ ==\ \"\\\[\"\ ||\ \$wordstart\ ==\ 0\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$firstchar\ ==\ \"\\\[\"\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ word\ \[string\ range\ \$word\ 1\ end\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ incr\ wordstart\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ Check\ executables:\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ foreach\ dir\ \[split\ \$::env(PATH)\ :\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ foreach\ f\ \[glob\ -nocomplain\ -directory\ \$dir\ --\ \$word*\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ exe\ \[string\ trimleft\ \[string\ range\ \$f\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[string\ length\ \$dir\]\ end\]\ \"/\"\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[lsearch\ -exact\ \$execs\ \$exe\]\ ==\ -1\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lappend\ execs\ \$exe\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ Check\ commands:\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ foreach\ x\ \[info\ commands\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[string\ match\ \$word*\ \$x\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lappend\ cmds\ \$x\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ Check\ commands\ anyway:\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ foreach\ x\ \[info\ commands\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[string\ match\ \$word*\ \$x\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lappend\ cmds\ \$x\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ if\ \{\$wordstart\ !=\ 0\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ #\ Check\ variables\ anyway:\n\ \ \ \ \ \ \ \ \ \ \ \ set\ x\ \[string\ first\ \"(\"\ \$word\]\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$x\ !=\ -1\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ v\ \[string\ range\ \$word\ 0\ \[expr\ \{\$x-1\}\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ incr\ x\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ word\ \[string\ range\ \$word\ \$x\ end\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ incr\ wordstart\ \$x\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[uplevel\ \\#0\ \"array\ exists\ \$v\"\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ vars\ \[uplevel\ \\#0\ \"array\ names\ \$v\ \$word*\"\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ foreach\ x\ \[uplevel\ \\#0\ \{info\ vars\}\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[string\ match\ \$word*\ \$x\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lappend\ vars\ \$x\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\ \ \ \ \n\ \ \ \ variable\ COMPLETION_MATCH\n\ \ \ \ set\ maybe\ \[concat\ \$vars\ \$cmds\ \$execs\ \$files\]\n\ \ \ \ set\ shortest\ \[shortMatch\ \$maybe\]\n\ \ \ \ if\ \{\"\$word\"\ ==\ \"\$shortest\"\}\ \{\n\ \ \ \ \ \ \ \ if\ \{\[llength\ \$maybe\]\ >\ 1\ &&\ \$COMPLETION_MATCH\ !=\ \$maybe\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ COMPLETION_MATCH\ \$maybe\n\ \ \ \ \ \ \ \ \ \ \ \ clearline\n\ \ \ \ \ \ \ \ \ \ \ \ set\ temp\ \"\"\n\ \ \ \ \ \ \ \ \ \ \ \ foreach\ \{match\ format\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ vars\ \ \"35\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ cmds\ \ \"1\;32\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ execs\ \"32\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ files\ \"0\"\n\ \ \ \ \ \ \ \ \ \ \ \ \}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[llength\ \[set\ \$match\]\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ append\ temp\ \"\[ESC\]\\\[\$\{format\}m\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ foreach\ x\ \[set\ \$match\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ append\ temp\ \"\[file\ tail\ \$x\]\ \"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ append\ temp\ \"\[ESC\]\\\[0m\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ print\ \"\\n\$temp\\n\"\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ if\ \{\[file\ isdirectory\ \$shortest\]\ &&\n\ \ \ \ \ \ \ \ \ \ \ \ \[string\ index\ \$shortest\ end\]\ !=\ \"/\"\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ append\ shortest\ \"/\"\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ if\ \{\$shortest\ !=\ \"\"\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ CMDLINE\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[string\ replace\ \$CMDLINE\ \$wordstart\ \$wordend\ \$shortest\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ CMDLINE_CURSOR\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[expr\ \{\$wordstart+\[string\ length\ \$shortest\]\}\]\n\ \ \ \ \ \ \ \ \}\ elseif\ \{\ \$COMPLETION_MATCH\ !=\ \"\ not\ found\ \"\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ COMPLETION_MATCH\ \"\ not\ found\ \"\n\ \ \ \ \ \ \ \ \ \ \ \ print\ \"\\nNo\ match\ found.\\n\"\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\}\n\nproc\ TclReadLine::handleHistory\ \{x\}\ \{\n\ \ \ \ variable\ HISTORY_LEVEL\n\ \ \ \ variable\ HISTORY_SIZE\n\ \ \ \ variable\ CMDLINE\n\ \ \ \ variable\ CMDLINE_CURSOR\n\ \ \ \ variable\ CMDLINE_PARTIAL\n\ \ \ \ \n\ \ \ \ set\ maxid\ \[expr\ \[history\ nextid\]\ -\ 1\]\n\ \ \ \ if\ \{\$maxid\ >\ 0\}\ \{\n\ \ \ \ \ \ \ \ #\n\ \ \ \ \ \ \ \ #\ \ Check\ for\ a\ top\ level\ command\ line\ and\ history\ event\n\ \ \ \ \ \ \ \ #\ \ Store\ this\ command\ line\ locally\ (i.e.\ don't\ use\ the\ history\ stack)\n\ \ \ \ \ \ \ \ #\n\ \ \ \ \ \ \ \ if\ \{\$HISTORY_LEVEL\ ==\ 0\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ CMDLINE_PARTIAL\ \$CMDLINE\n\ \ \ \ \ \ \ \ \}\ \n\ \ \ \ \ \ \ \ incr\ HISTORY_LEVEL\ \$x\n\ \ \ \ \ \ \ \ #\n\ \ \ \ \ \ \ \ #\ \ Note:\ \ HISTORY_LEVEL\ is\ used\ to\ offset\ into\n\ \ \ \ \ \ \ \ #\ \ the\ history\ events.\ \ It\ will\ be\ reset\ to\ zero\ \n\ \ \ \ \ \ \ \ #\ \ when\ a\ command\ is\ executed\ by\ tclline.\n\ \ \ \ \ \ \ \ #\ \ \n\ \ \ \ \ \ \ \ #\ \ Check\ the\ three\ bounds\ of\n\ \ \ \ \ \ \ \ #\ \ 1)\ HISTORY_LEVEL\ <=\ 0\ -\ Restore\ the\ top\ level\ cmd\ line\ (not\ in\ history\ stack)\n\ \ \ \ \ \ \ \ #\ \ 2)\ HISTORY_LEVEL\ >\ HISTORY_SIZE\n\ \ \ \ \ \ \ \ #\ \ 3)\ HISTORY_LEVEL\ >\ maxid\n\ \ \ \ \ \ \ \ #\n\ \ \ \ \ \ \ \ if\ \{\$HISTORY_LEVEL\ <=\ 0\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ HISTORY_LEVEL\ 0\ \n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ exists\ CMDLINE_PARTIAL\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ CMDLINE\ \$CMDLINE_PARTIAL\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ CMDLINE_CURSOR\ \[string\ length\ \$CMDLINE\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ return\n\ \ \ \ \ \ \ \ \}\ elseif\ \{\$HISTORY_LEVEL\ >\ \$maxid\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ HISTORY_LEVEL\ \$maxid\n\ \ \ \ \ \ \ \ \}\ elseif\ \{\$HISTORY_LEVEL\ >\ \$HISTORY_SIZE\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ HISTORY_LEVEL\ \$HISTORY_SIZE\n\ \ \ \ \ \ \ \ \}\ \n\ \ \ \ \ \ \ \ set\ id\ \[expr\ (\$maxid\ +\ 1)\ -\ \$HISTORY_LEVEL\]\n\ \ \ \ \ \ \ \ set\ cmd\ \[history\ event\ \$id\]\n\ \ \ \ \ \ \ \ set\ CMDLINE\ \$cmd\n\ \ \ \ \ \ \ \ set\ CMDLINE_CURSOR\ \[string\ length\ \$cmd\]\n\ \ \ \ \}\n\}\n\n################################\n#\ History\ handling\ functions\n################################\n\nproc\ TclReadLine::getHistory\ \{\}\ \{\n\ \ \ \ variable\ HISTORY_SIZE\n\ \ \ \ \n\ \ \ \ set\ l\ \[list\]\n\ \ \ \ set\ e\ \[history\ nextid\]\n\ \ \ \ set\ i\ \[expr\ \$e\ -\ \$HISTORY_SIZE\]\n\ \ \ \ if\ \{\$i\ <=\ 0\}\ \{\n\ \ \ \ \ \ \ \ set\ i\ 1\n\ \ \ \ \}\n\ \ \ \ for\ \{\ set\ i\ \}\ \{\$i\ <\ \$e\}\ \{incr\ i\}\ \{\n\ \ \ \ \ \ \ \ lappend\ l\ \[history\ event\ \$i\]\n\ \ \ \ \}\n\ \ \ \ return\ \$l\n\}\n\nproc\ TclReadLine::setHistory\ \{hlist\}\ \{\n\ \ \ \ foreach\ event\ \$hlist\ \{\n\ \ \ \ \ \ \ \ history\ add\ \$event\n\ \ \ \ \}\n\}\n\n################################\n#\ main()\n################################\n\nproc\ TclReadLine::rawInput\ \{\}\ \{\n\ \ \ \ fconfigure\ stdin\ -buffering\ none\ -blocking\ 0\n\ \ \ \ fconfigure\ stdout\ -buffering\ none\ -translation\ crlf\n\ \ \ \ exec\ stty\ raw\ -echo\n\}\n\nproc\ TclReadLine::lineInput\ \{\}\ \{\n\ \ \ \ fconfigure\ stdin\ -buffering\ line\ -blocking\ 1\n\ \ \ \ fconfigure\ stdout\ -buffering\ line\n\ \ \ \ exec\ stty\ -raw\ echo\n\}\n\nproc\ TclReadLine::doExit\ \{\{code\ 0\}\}\ \{\n\ \ \ \ variable\ HISTFILE\n\ \ \ \ variable\ HISTORY_SIZE\ \n\n\ \ \ \ #\ Reset\ terminal:\n\ \ \ \ #print\ \"\[ESC\]c\[ESC\]\\\[2J\"\ nowait\n\ \ \ \ \n\ \ \ \ restore\ \;#\ restore\ \"info'\ command\ -\n\ \ \ \ lineInput\n\ \ \ \ \n\ \ \ \ set\ hlist\ \[getHistory\]\n\ \ \ \ #\n\ \ \ \ #\ Get\ rid\ of\ the\ TclReadLine::doExit,\ shouldn't\ be\ more\ than\ one\n\ \ \ \ #\n\ \ \ \ set\ hlist\ \[lsearch\ -all\ -not\ -inline\ \$hlist\ \"TclReadLine::doExit\"\]\n\ \ \ \ set\ hlistlen\ \[llength\ \$hlist\]\n\ \ \ \ if\ \{\$hlistlen\ >\ 0\}\ \{\n\ \ \ \ \ \ \ \ set\ f\ \[open\ \$HISTFILE\ w\]\n\ \ \ \ \ \ \ \ if\ \{\$hlistlen\ >\ \$HISTORY_SIZE\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ hlist\ \[lrange\ \$hlist\ \[expr\ (\$hlistlen\ -\ \$HISTORY_SIZE\ -\ 1)\]\ end\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ foreach\ x\ \$hlist\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ #\ Escape\ newlines:\n\ \ \ \ \ \ \ \ \ \ \ \ puts\ \$f\ \[string\ map\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \\n\ \"\\\\n\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \"\\\\\"\ \"\\\\b\"\n\ \ \ \ \ \ \ \ \ \ \ \ \}\ \$x\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ close\ \$f\n\ \ \ \ \}\n\ \ \ \ \n\ \ \ \ exit\ \$code\n\}\n\nproc\ TclReadLine::restore\ \{\}\ \{\n\ \ \ \ lineInput\n\ \ \ \ rename\ ::unknown\ TclReadLine::unknown\n\ \ \ \ rename\ ::_unknown\ ::unknown\n\}\n\nproc\ TclReadLine::interact\ \{\}\ \{\n\n\ \ \ \ rename\ ::unknown\ ::_unknown\n\ \ \ \ rename\ TclReadLine::unknown\ ::unknown\n\ \ \ \ \n\ \ \ \ variable\ RCFILE\n\ \ \ \ if\ \{\[file\ exists\ \$RCFILE\]\}\ \{\n\ \ \ \ \ \ \ \ source\ \$RCFILE\n\ \ \ \ \}\n\n\ \ \ \ #\ Load\ history\ if\ available:\n\ \ \ \ #\ variable\ HISTORY\n\ \ \ \ variable\ HISTFILE\n\ \ \ \ variable\ HISTORY_SIZE\n\ \ \ \ history\ keep\ \$HISTORY_SIZE\n\ \ \ \ \n\ \ \ \ if\ \{\[file\ exists\ \$HISTFILE\]\}\ \{\n\ \ \ \ \ \ \ \ set\ f\ \[open\ \$HISTFILE\ r\]\n\ \ \ \ \ \ \ \ set\ hlist\ \[list\]\n\ \ \ \ \ \ \ \ foreach\ x\ \[split\ \[read\ \$f\]\ \"\\n\"\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$x\ !=\ \"\"\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ Undo\ newline\ escapes:\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lappend\ hlist\ \[string\ map\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \"\\\\n\"\ \\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \"\\\\\\\\\"\ \"\\\\\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \"\\\\b\"\ \"\\\\\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\ \$x\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ setHistory\ \$hlist\n\ \ \ \ \ \ \ \ unset\ hlist\n\ \ \ \ \ \ \ \ close\ \$f\n\ \ \ \ \}\n\ \ \ \ \n\ \ \ \ rawInput\n\ \ \ \ \n\ \ \ \ #\ This\ is\ to\ restore\ the\ environment\ on\ exit:\n\ \ \ \ #\ Do\ not\ unalias\ this!\n\ \ \ \ alias\ exit\ TclReadLine::doExit\n\ \ \ \ \n\ \ \ \ variable\ ThisScript\ \[info\ script\]\n\ \ \ \ \n\ \ \ \ tclline\ \;#\ emit\ the\ first\ prompt\n\ \ \ \ \n\ \ \ \ fileevent\ stdin\ readable\ TclReadLine::tclline\n\ \ \ \ variable\ forever\n\ \ \ \ vwait\ TclReadLine::forever\n\ \ \ \ \n\ \ \ \ restore\n\}\n\n\nproc\ TclReadLine::check_partial_keyseq\ \{buffer\}\ \{\n\ \ \ \ variable\ READLINE_LATENCY\n\ \ \ \ upvar\ \$buffer\ keybuffer\n\n\ \ \ \ #\n\ \ \ \ #\ check\ for\ a\ partial\ esc\ sequence\ as\ tclline\ expects\ the\ whole\ sequence\n\ \ \ \ #\n\ \ \ \ if\ \{\[string\ index\ \$keybuffer\ 0\]\ ==\ \[ESC\]\}\ \{\n\ \ \ \ \ \ \ \ #\n\ \ \ \ \ \ \ \ #\ Give\ extra\ time\ to\ read\ partial\ key\ sequences\n\ \ \ \ \ \ \ \ #\ \n\ \ \ \ \ \ \ \ set\ timer\ \ \[expr\ \[clock\ clicks\ -milliseconds\]\ +\ \$READLINE_LATENCY\]\n\ \ \ \ \ \ \ \ while\ \{\[clock\ clicks\ -milliseconds\]\ <\ \$timer\ \}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ append\ keybuffer\ \[read\ stdin\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\}\n\nproc\ TclReadLine::tclline\ \{\}\ \{\n\ \ \ \ variable\ COLUMNS\n\ \ \ \ variable\ CMDLINE_CURSOR\n\ \ \ \ variable\ CMDLINE\n\ \ \ \ \n\ \ \ \ set\ char\ \"\"\n\ \ \ \ set\ keybuffer\ \[read\ stdin\]\n\ \ \ \ set\ COLUMNS\ \[getColumns\]\n\ \ \ \ \n\ \ \ \ check_partial_keyseq\ keybuffer\n\ \ \ \ \n\ \ \ \ while\ \{\$keybuffer\ !=\ \"\"\}\ \{\n\ \ \ \ \ \ \ \ if\ \{\[eof\ stdin\]\}\ return\n\ \ \ \ \ \ \ \ set\ char\ \[readbuf\ keybuffer\]\n\ \ \ \ \ \ \ \ if\ \{\$char\ ==\ \"\"\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ #\ Sleep\ for\ a\ bit\ to\ reduce\ CPU\ overhead:\n\ \ \ \ \ \ \ \ \ \ \ \ after\ 40\n\ \ \ \ \ \ \ \ \ \ \ \ continue\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ if\ \{\[string\ is\ print\ \$char\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ x\ \$CMDLINE_CURSOR\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$x\ <\ 1\ &&\ \[string\ trim\ \$char\]\ ==\ \"\"\}\ continue\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ trailing\ \[string\ range\ \$CMDLINE\ \$x\ end\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ CMDLINE\ \[string\ replace\ \$CMDLINE\ \$x\ end\]\n\ \ \ \ \ \ \ \ \ \ \ \ append\ CMDLINE\ \$char\n\ \ \ \ \ \ \ \ \ \ \ \ append\ CMDLINE\ \$trailing\n\ \ \ \ \ \ \ \ \ \ \ \ incr\ CMDLINE_CURSOR\n\ \ \ \ \ \ \ \ \}\ elseif\ \{\$char\ ==\ \"\\t\"\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ handleCompletion\n\ \ \ \ \ \ \ \ \}\ elseif\ \{\$char\ ==\ \"\\n\"\ ||\ \$char\ ==\ \"\\r\"\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ complete\ \$CMDLINE\]\ &&\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[string\ index\ \$CMDLINE\ end\]\ !=\ \"\\\\\"\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lineInput\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ print\ \"\\n\"\ nowait\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ uplevel\ \\#0\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ Handle\ aliases:\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ cmdline\ \$TclReadLine::CMDLINE\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ Add\ the\ cmd\ line\ to\ history\ before\ doing\ any\ substitutions\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ history\ add\ \$cmdline\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ cmd\ \[string\ trim\ \[regexp\ -inline\ \{^\\s*\[^\\s\]+\}\ \$cmdline\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ exists\ TclReadLine::ALIASES(\$cmd)\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ regsub\ --\ \"(?q)\$cmd\"\ \$cmdline\ \$TclReadLine::ALIASES(\$cmd)\ cmdline\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ Perform\ glob\ substitutions:\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ cmdline\ \[string\ map\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \"\\\\*\"\ \\0\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \"\\\\~\"\ \\1\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\ \$cmdline\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ Prevent\ glob\ substitution\ of\ *,~\ for\ tcl\ commands\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ commands\ \$cmd\]\ !=\ \"\"\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ cmdline\ \[string\ map\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \"\\*\"\ \\0\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \"\\~\"\ \\1\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\ \$cmdline\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ while\ \{\[regexp\ -indices\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{(\[\\w/\\.\]*(?:~|\\*)\[\\w/\\.\]*)+\}\ \$cmdline\ x\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ foreach\ \{i\ n\}\ \$x\ break\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ s\ \[string\ range\ \$cmdline\ \$i\ \$n\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ x\ \[glob\ -nocomplain\ --\ \$s\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ If\ glob\ can't\ find\ anything\ then\ don't\ do\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ glob\ substitution,\ pass\ *\ or\ ~\ as\ literals:\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$x\ ==\ \"\"\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ x\ \[string\ map\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \"*\"\ \\0\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \"~\"\ \\1\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\ \$s\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ cmdline\ \[string\ replace\ \$cmdline\ \$i\ \$n\ \$x\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ cmdline\ \[string\ map\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \\0\ \"*\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \\1\ \"~\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\ \$cmdline\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ rename\ ::info\ ::_info\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ rename\ TclReadLine::localInfo\ ::info\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ Reset\ HISTORY_LEVEL\ before\ next\ command\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ TclReadLine::HISTORY_LEVEL\ 0\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ exists\ TclReadLine::CMDLINE_PARTIAL\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ unset\ TclReadLine::CMDLINE_PARTIAL\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ Run\ the\ command:\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ code\ \[catch\ \$cmdline\ res\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ rename\ ::info\ TclReadLine::localInfo\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ rename\ ::_info\ ::info\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$code\ ==\ 1\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ TclReadLine::print\ \"\$::errorInfo\\n\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ TclReadLine::print\ \"\$res\\n\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ TclReadLine::CMDLINE\ \"\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ TclReadLine::CMDLINE_CURSOR\ 0\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ TclReadLine::CMDLINE_LINES\ \{0\ 0\}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\ \;#\ end\ uplevel\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ rawInput\n\ \ \ \ \ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ x\ \$CMDLINE_CURSOR\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$x\ <\ 1\ &&\ \[string\ trim\ \$char\]\ ==\ \"\"\}\ continue\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ trailing\ \[string\ range\ \$CMDLINE\ \$x\ end\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ CMDLINE\ \[string\ replace\ \$CMDLINE\ \$x\ end\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ append\ CMDLINE\ \$char\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ append\ CMDLINE\ \$trailing\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ incr\ CMDLINE_CURSOR\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ handleControls\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\ \ \ \ prompt\ \$CMDLINE\n\}\n\n#\n#\ Use\ the\ following\ to\ invoke\ readline\ \ \n#\n#\ TclReadLine::interact\n#\n======\n\n\nIt\ might\ be\ faster\ to\ use\ \[scan\]\ vs.\ firing\ up\ the\ regex\ engine,\ especially\ as\ this\ is\ called\ for\ every\ character\ input.\ \ Alternatively,\ if\ Tclx\ is\ available\ it\ makes\ more\ sense\ to\ trap\ SIGWINCH\ and\ update\ COLUMNS\ in\ the\ handler.\n----\n<<discussion>>\n\[wdb\]\ works\ fine.\ \nHow\ to\ manage\ that\ it\ is\ executed\ automatically\ on\ invoking\ tclsh?\n\n\[LV\]\ See\ \[tclshrc\]\ for\ a\ suggestion.\n\n\[RLH\]\ Does\ this\ mean\ readline\ can\ now\ work\ in\ tclsh?\n\n\[LV\]\ I\ think\ it\ means\ that\ the\ code\ on\ this\ page\ works\ in\ tclsh.\ As\ long\ as\ that\ is\ what\ you\ mean\ by\ readline,\ then\ sure.\n\n----\n\[tb\]\ -\ 2009-12-16\ -\ I\ just\ sourced\ this\ code\ into\ a\ tclkit-8.5.1\ and\ noticed\ I\ had\ to\ escape\ the\ star\ in:\n\n\ info\ proc\ ::TclReadLine::\\*\n\n\[AM\}\ Yes,\ I\ can\ confirm\ that.\ Though:\ \n\n\ info\ proc\ ::TclReadLine::g*\n\nor\n\ \n\ info\ proc\ ::TclReadline::*g*\n\ndoes\ work,\ so\ it\ seems\ to\ be\ a\ problem\ with\ a\ bare\ asterisk\ only.\ (The\ command\ that\ is\ stored\ contains\ the\ list\ of\ files\ that\ are\ present\ ...)\n\n\n----\n'''\[LVwikignome\]\ -\ 2009-12-16\ 08:33:33'''\n\nIf\ this\ code\ appears\ to\ be\ working\ well,\ perhaps\ it\ would\ be\ worthwhile\ considering\ adding\ it\ to\ \[tcllib\]\ or\ some\ similar\ commonly\ distributed\ package\ so\ that\ it\ is\ available\ readily.\n\n----\n'''\[arjen\]\ -\ 2009-12-18\ 05:48:42'''\n\nI\ copied\ the\ code\ verbatim\ and\ had\ no\ problem\ whatsoever.\n\nNice\ work!\ (It\ really\ acts\ as\ an\ interactive\ shell,\ so\ that\ you\ can\ run\ external\ commands\ like\ ls\ and\ vi)\n\n----\n'''\[mjs\]\ -\ 2010-02-16\ 00:58:43'''\n\nAs\ with\ the\ previous\ version,\ the\ stty\ regexp\ doesn't\ work\ for\ BSD\ stty\ (e.g.\ Mac\ OS\ X).\ \ This\ works\ for\ me:\n\n======\n\ \ \ \ set\ cols\ 0\n\ \ \ \ if\ \{!\[catch\ \{exec\ stty\ -a\}\ err\]\}\ \{\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ #\ match\ for\ BSD\ stty\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ regexp\ \{(\\d+)\ rows\;\ (\\d+)\ columns\;\}\ \$err\ junk\ rows\ cols\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ if\ \{\$cols\ ==\ 0\}\ \{\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ #\ match\ for\ Linux\ stty\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ regexp\ \{rows\ (=\ )?(\\d+)\;\ columns\ (=\ )?(\\d+)\}\ \$err\ junk\ i1\ rows\ i2\ cols\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \}\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \}\n======\n\n\n\n----\n'''\[rjmcmahon\]\ -\ 2010-03-03\ 13:22:11'''\nMade\ a\ fix\ to\ handle\ preserving\ the\ command\ line\ under\ edit\ during\ history\ events.\ \ See\ the\ code\ around\ CMDLINE_PARTIAL.\ \ Note:\ Still\ need\ to\ look\ into\ adding\ mjs'\ BSD\ fix.\ \ (Trying\ to\ find\ a\ MAC\ to\ verify.)\n\n----\n'''\[rjmcmahon\]\ -\ 2010-03-04\ 14:40:10'''\n\nMade\ the\ fix\ (per\ mjs'\ commnet)\ to\ TclReadLine::getColumns\ enabling\ support\ for\ BSD\ style\ stty\ output.\ \ Tested\ it\ on\ a\ MAC.\n\n----\n'''\[rjmcmahon\]\ -\ 2010-03-05\ 14:18:43'''\n\nFound\ and\ fixed\ a\ bug\ when\ history\ was\ larger\ than\ history\ size\ and\ doExit\ is\ called.\n\n----\n'''\[rjmcmahon\]\ -\ 2010-03-12\ 19:19:59'''\n\nFix\ for\ glob\ substitutions\ of\ *\ and\ ~\ so\ handled\ properly\ per\ shell,\ tcl\ command\ and\ history\ add.\n\n----\n'''\[mocallins\]\ -\ 2010-05-20\ 14:08:38'''\n\nProblem\ with\ down\ arrow\ and\ last\ command\ on\ the\ stack.\nLocks\ up\ tclsh\ and\ you\ have\ to\ go\ to\ another\ session\ and\ kill\ the\ process\ id\ :((\n\n----\n'''\[SRIV\]\ -\ 2010-05-26\ 08:33:38'''\nAny\ error\ in\ this\ code\ will\ make\ the\ tclsh\ non-responsive\ because\ you\ loose\ control\ over\ the\ raw\ tty.\ I\ noted\ the\ same\ problem\ and\ after\ looking\ through\ the\ stack\ trace,\ I\ came\ up\ with\ a\ fix.\ I\ didn't\ go\ through\ all\ the\ code\ to\ try\ to\ understand\ how\ it\ was\ supposed\ to\ work,\ but\ I\ understand\ the\ fail\ condition.\nModify\ the\ last\ few\ lines\ of\ TclReadLine::handleHistory\ as\ follows.\n======\nset\ id\ \[expr\ (\$maxid\ +\ 1)\ -\ \$HISTORY_LEVEL\]\nif\ \{\$id\ >\ \$maxid\}\ \{\n\ \ set\ cmd\ \"\"\n\}\ else\ \{\n\ \ set\ cmd\ \[history\ event\ \$id\]\n\}\nset\ CMDLINE\ \$cmd\nset\ CMDLINE_CURSOR\ \[string\ length\ \$cmd\]\n======\n\nUnrelated\ to\ the\ bug\ above,\ when\ I\ place\ this\ code\ into\ ~/.tclshrc,\ I\ add\ the\ following\ line\ to\ the\ end:\n======\nif\ \{\$::tcl_interactive\}\ \{TclReadLine::interact\}\n======\nso\ that\ it\ only\ is\ enabled\ from\ interactive\ shells,\ not\ running\ apps.\n----\n\[rjmcmahon\]-\ 2010-07-13\ \n\nFix\ down\ arrow,\ last\ command,\ bug\ per\ mocallins\ note.\ \ Should\ work\ now.\n\nPS.\ \ I\ don't\ check\ this\ site\ very\ often.\ \ Next\ time\ if\ you\ see\ a\ bug\ and\ need\ a\ fix\ please\ feel\ free\ to\ email\ me\ at\ rjmcmahon\ at\ rjmcmahon\ dot\ com\ with\ TCL\ twiki\ bug\ in\ the\ subject.\ \ Thanks\ -Bob\n----\n\[makr\]\ 2011-01-07:\ For\ those\ that\ -\ like\ me\ -\ do\ not\ have\ \[Tclx\]\ available,\ but\ \[Expect\],\ you\ could\ do\n======\npackage\ require\ Expect\n\n#\ Prevent\ sigint\ from\ killing\ our\ shell:\nexp_trap\ SIG_IGN\ SIGINT\n======\n\nYou\ may\ want\ to\ change\ '''exec\ stty'''\ into\ '''exp_stty'''\ further\ down\ in\ the\ script.\ Expect\ might\ still\ call\ the\ system's\ '''stty'''\ tool,\ however.\n\nI\ also\ extended\ '''getColumns'''\ to\ avoid\ the\ ''\[regexp\]''\ calls\ if\ possible\ (works\ for\ \[AIX\],\ \[HP-UX\],\ and\ \[Linux\],\ but\ needs\ the\ original\ code\ as\ fallback\ on\ \[Solaris\],\ though):\n======\nproc\ TclReadLine::getColumns\ \{\}\ \{\n\ \ \ \ set\ cols\ 0\n\ \ \ \ if\ \{!\[catch\ \{exp_stty\ size\}\ size\]\}\ \{\n\ \ \ \ \ \ \ \ lassign\ \$size\ rows\ cols\n\ \ \ \ \}\ elseif\ \{!\[catch\ \{exp_stty\ -a\}\ rs\]\}\ \{\n\ \ \ \ \ \ \ \ if\ \{\[regexp\ \{rows\ (=\ )?(\\d+)\;\ columns\ (=\ )?(\\d+)\}\ \$rs\ -\ i1\ rows\ i2\ cols\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ #\ Linux\ style\ stty\ output\n\ \ \ \ \ \ \ \ \}\ elseif\ \{\[regexp\ \{\ (\\d+)\ rows\;\ (\\d+)\ columns\;\}\ \$rs\ -\ rows\ cols\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ #\ BSD\ style\ stty\ output\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\ \ \ \ return\ \$cols\n\}\n======\n\ngavino\ 26june2011\n\nWorks\ like\ a\ charm.\ \ I\ uncommented\ the\ last\ line.\ \ I\ then\ saved\ it\ to\ /opt/tclreadline2.\ \ In\ /usr/local/bin/tcl\ I\ put\ /opt/tcl86/bin/tclsh8.6\ /opt/tclreadline2.\ \ Typing\ tcl\ then\ gave\ >\ prompt.\ \ Typing\ info\ patchlevel\ returned\ 8.6b1.\ \ I\ up\ arrowed\ and\ command\ came\ back.\ \ Nice.\ \ I\ did\ no\ tclx.\ \ I\ used\ compiled\ tcl\ 8.6\ -wth\ --disable-shared\ option\ and\ gcc\ 4.6\ on\ archlinux.\n\n======\n<<categories>>Category\ Dev.\ Tools regexp2} CALL {my render {Pure-tcl readline2} ======\n#\n#\ tclline:\ An\ attempt\ at\ a\ pure\ tcl\ readline.\n#\n#\ This\ base\ code\ taken\ from\ http://wiki.tcl.tk/20215\ and\n#\ http://wiki.tcl.tk/16139\n#\n#\ Author:\ HCG\n#\ Licence:\ \"as\ freely\ available\ as\ possible\"\ http://wiki.tcl.tk/4381\n#\n#\ Modified\ by\ rjmcmahon:\ fixes\ history\ and\ multiple\ key\ sequences\ per\ input\ char\ (may\ not\ assume\ atomic)\n#\ Also\ added\ ability\ to\ extend\ the\ completion\ handlers\n#\n#\ Note:\ The\ wiki.tcl.tk\ is\ broken\ with\ respect\ to\ creating\ a\ new\ page\ and\ reverting\ back\ to\ an\ old\ page\n#\ Some\ comments\ from\ the\ previous\ wiki\ page\ no\ longer\ shown\ as\ the\ file\ upload\ seem\ to\ overwrite\ the\ entire\ wiki\ page.\n#\n#\ \[LV\]\ Actually,\ it\ isn't\ broken\ -\ but\ there\ might\ be\ a\ misunderstanding\ in\ terms\ of\ the\ functionality\ of\ file\ upload.\n#\ The\ comments\ on\ each\ page\ are\ literally\ part\ of\ the\ page\ itself.\ The\ file\ upload\ replaces\ the\ complete\ contents\ of\ the\ page\ with\ new\ contents\n#\ Thus,\ if\ the\ comments\ would\ be\ useful\ to\ keep,\ you\ should\ download\ the\ current\ wiki\ text\ page,\ replace\ the\ portion\ of\ the\ page\ containing\n#\ code\ or\ whatever\ with\ the\ new\ contents,\ then\ upload\ the\ entire\ page.\ By\ just\ uploading\ tclline,\ you\ are\ effectively\ saying\ \"the\ only\ thing\n#\ I\ want\ on\ this\ page\ is\ the\ contents\ of\ this\ file\".\n#\npackage\ provide\ TclReadLine\ 1.1\n\n#\ Use\ Tclx\ if\ available:\ncatch\ \{\n\ \ \ \ \ \ package\ require\ Tclx\n\n\ \ \ \ \ \ #\ Prevent\ sigint\ from\ killing\ our\ shell:\n\ \ \ \ \ \ signal\ ignore\ SIGINT\n\}\n\nnamespace\ eval\ TclReadLine\ \{\n\n\ \ \ \ namespace\ export\ interact\n\n\ \ \ \ #\ Initialise\ our\ own\ env\ variables:\n\ \ \ \ variable\ PROMPT\ \">\"\n\ \ \ \ variable\ COMPLETION_MATCH\ \"\"\n\ \ \ \ \n\ \ \ \ #\ Support\ extensions\ to\ the\ completion\ handling\n\ \ \ \ #\ which\ will\ be\ called\ in\ list\ order.\n\ \ \ \ #\ Initialize\ with\ the\ \"open\ sourced\"\ TCL\ base\ handler\n\ \ \ \ #\ taken\ from\ the\ wiki\ page\n\ \ \ \ variable\ COMPLETION_HANDLERS\ \[list\ TclReadLine::handleCompletionBase\]\n\n\ \ \ \ #\n\ \ \ \ #\ \ This\ value\ was\ determined\ by\ measuring\ \n\ \ \ \ #\ \ a\ cygwin\ over\ ssh.\ \n\ \ \ \ #\n\ \ \ \ variable\ READLINE_LATENCY\ 10\ \;#\ in\ ms\n\ \ \ \ \n\ \ \ \ variable\ CMDLINE\ \"\"\n\ \ \ \ variable\ CMDLINE_CURSOR\ 0\n\ \ \ \ variable\ CMDLINE_LINES\ 0\n\ \ \ \ variable\ CMDLINE_PARTIAL\n\ \ \ \ \n\ \ \ \ variable\ ALIASES\n\ \ \ \ array\ set\ ALIASES\ \{\}\n\ \ \ \ \n\ \ \ \ variable\ forever\ 0\n\ \ \ \ \n\ \ \ \ #\ Resource\ and\ history\ files:\n\ \ \ \ variable\ HISTORY_SIZE\ 100\n\ \ \ \ variable\ HISTORY_LEVEL\ 0\n\ \ \ \ variable\ HISTFILE\ \$::env(HOME)/.tclline_history\n\ \ \ \ variable\ \ RCFILE\ \$::env(HOME)/.tcllinerc\n\}\n\nproc\ TclReadLine::ESC\ \{\}\ \{\n\ \ \ \ return\ \"\\033\"\n\}\n\nproc\ TclReadLine::shift\ \{ls\}\ \{\n\ \ \ \ upvar\ 1\ \$ls\ LIST\n\ \ \ \ set\ ret\ \[lindex\ \$LIST\ 0\]\n\ \ \ \ set\ LIST\ \[lrange\ \$LIST\ 1\ end\]\n\ \ \ \ return\ \$ret\n\}\n\nproc\ TclReadLine::readbuf\ \{txt\}\ \{\n\ \ \ \ upvar\ 1\ \$txt\ STRING\n\ \ \ \ \n\ \ \ \ set\ ret\ \[string\ index\ \$STRING\ 0\]\n\ \ \ \ set\ STRING\ \[string\ range\ \$STRING\ 1\ end\]\n\ \ \ \ return\ \$ret\n\}\n\nproc\ TclReadLine::goto\ \{row\ \{col\ 1\}\}\ \{\n\ \ \ \ switch\ --\ \$row\ \{\n\ \ \ \ \ \ \ \ \"home\"\ \{set\ row\ 1\}\n\ \ \ \ \}\n\ \ \ \ print\ \"\[ESC\]\\\[\$\{row\}\;\$\{col\}H\"\ nowait\n\}\n\nproc\ TclReadLine::gotocol\ \{col\}\ \{\n\ \ \ \ print\ \"\\r\"\ nowait\n\ \ \ \ if\ \{\$col\ >\ 0\}\ \{\n\ \ \ \ \ \ \ \ print\ \"\[ESC\]\\\[\$\{col\}C\"\ nowait\n\ \ \ \ \}\n\}\n\nproc\ TclReadLine::clear\ \{\}\ \{\n\ \ \ \ print\ \"\[ESC\]\\\[2J\"\ nowait\n\ \ \ \ goto\ home\n\}\n\nproc\ TclReadLine::clearline\ \{\}\ \{\n\ \ \ \ print\ \"\[ESC\]\\\[2K\\r\"\ nowait\n\}\n\nproc\ TclReadLine::getColumns\ \{\}\ \{\n\ \ \ \ set\ cols\ 0\n\ \ \ \ if\ \{!\[catch\ \{exec\ stty\ -a\}\ err\]\}\ \{\n\ \ \ \ \ \ \ \ #\ check\ for\ Linux\ stlye\ stty\ output\n\ \ \ \ \ \ \ \ if\ \{\[regexp\ \{rows\ (=\ )?(\\d+)\;\ columns\ (=\ )?(\\d+)\}\ \$err\ -\ i1\ rows\ i2\ cols\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ return\ \$cols\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ #\ check\ for\ BSD\ style\ stty\ output\n\ \ \ \ \ \ \ \ if\ \{\[regexp\ \{\ (\\d+)\ rows\;\ (\\d+)\ columns\;\}\ \$err\ -\ rows\ cols\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ return\ \$cols\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\ \ \ \ return\ \$cols\n\}\n\nproc\ TclReadLine::localInfo\ \{args\}\ \{\n\ \ \ \ set\ v\ \[uplevel\ _info\ \$args\]\n\ \ \ \ if\ \{\ \[string\ equal\ \"script\"\ \[lindex\ \$args\ 0\]\]\ \}\ \{\n\ \ \ \ \ \ \ \ if\ \{\ \[string\ equal\ \$v\ \$TclReadLine::ThisScript\]\ \}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ return\ \"\"\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\ \ \ \ return\ \$v\n\}\n\nproc\ TclReadLine::localPuts\ \{args\}\ \{\n\ \ \ \ \n\ \ \ \ set\ l\ \[llength\ \$args\]\n\ \ \ \ if\ \{\ 3\ <\ \$l\ \}\ \{\n\ \ \ \ \ \ \ \ return\ -code\ error\ \"Error:\ wrong\ \\#\ args\"\n\ \ \ \ \}\n\ \ \ \ \n\ \ \ \ if\ \{\ 1\ <\ \$l\ \}\ \{\n\ \ \ \ \ \ \ \ if\ \{\ \[string\ equal\ \"-nonewline\"\ \[lindex\ \$args\ 0\]\]\ \}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\ 2\ <\ \$l\ \}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ we\ don't\ send\ to\ channel...\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ eval\ _origPuts\ \$args\n\ \ \ \ \ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ str\ \[lindex\ \$args\ 1\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ append\ TclReadLine::putsString\ \$str\ \;#\ no\ newline...\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ #\ must\ be\ a\ channel\n\ \ \ \ \ \ \ \ \ \ \ \ eval\ _origPuts\ \$args\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ append\ TclReadLine::putsString\ \[lindex\ \$args\ 0\]\ \"\\n\"\n\ \ \ \ \}\n\}\n\nproc\ TclReadLine::prompt\ \{\{txt\ \"\"\}\}\ \{\n\ \ \ \ \n\ \ \ \ if\ \{\ \"\"\ !=\ \[info\ var\ ::tcl_prompt1\]\ \}\ \{\n\ \ \ \ \ \ \ \ rename\ ::puts\ ::_origPuts\n\ \ \ \ \ \ \ \ rename\ TclReadLine::localPuts\ ::puts\n\ \ \ \ \ \ \ \ variable\ putsString\n\ \ \ \ \ \ \ \ set\ putsString\ \"\"\n\ \ \ \ \ \ \ \ eval\ \[set\ ::tcl_prompt1\]\n\ \ \ \ \ \ \ \ set\ prompt\ \$putsString\n\ \ \ \ \ \ \ \ rename\ ::puts\ TclReadLine::localPuts\n\ \ \ \ \ \ \ \ rename\ ::_origPuts\ ::puts\n\ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ variable\ PROMPT\n\ \ \ \ \ \ \ \ set\ prompt\ \[subst\ \$PROMPT\]\n\ \ \ \ \}\n\ \ \ \ set\ txt\ \"\$prompt\$txt\"\n\ \ \ \ variable\ CMDLINE_LINES\n\ \ \ \ variable\ CMDLINE_CURSOR\n\ \ \ \ variable\ COLUMNS\n\ \ \ \ foreach\ \{end\ mid\}\ \$CMDLINE_LINES\ break\n\ \ \ \ \n\ \ \ \ #\ Calculate\ how\ many\ extra\ lines\ we\ need\ to\ display.\n\ \ \ \ #\ Also\ calculate\ cursor\ position:\n\ \ \ \ set\ n\ -1\n\ \ \ \ set\ totalLen\ 0\n\ \ \ \ set\ cursorLen\ \[expr\ \{\$CMDLINE_CURSOR+\[string\ length\ \$prompt\]\}\]\n\ \ \ \ set\ row\ 0\n\ \ \ \ set\ col\ 0\n\ \ \ \ \n\ \ \ \ #\ Render\ output\ line-by-line\ to\ \$out\ then\ copy\ back\ to\ \$txt:\n\ \ \ \ set\ found\ 0\n\ \ \ \ set\ out\ \[list\]\n\ \ \ \ foreach\ line\ \[split\ \$txt\ \"\\n\"\]\ \{\n\ \ \ \ \ \ \ \ set\ len\ \[expr\ \{\[string\ length\ \$line\]+1\}\]\n\ \ \ \ \ \ \ \ incr\ totalLen\ \$len\n\ \ \ \ \ \ \ \ if\ \{\$found\ ==\ 0\ &&\ \$totalLen\ >=\ \$cursorLen\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ cursorLen\ \[expr\ \{\$cursorLen\ -\ (\$totalLen\ -\ \$len)\}\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ col\ \[expr\ \{\$cursorLen\ %\ \$COLUMNS\}\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ row\ \[expr\ \{\$n\ +\ (\$cursorLen\ /\ \$COLUMNS)\ +\ 1\}\]\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$cursorLen\ >=\ \$len\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ col\ 0\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ incr\ row\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ set\ found\ 1\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ incr\ n\ \[expr\ \{int(ceil(double(\$len)/\$COLUMNS))\}\]\n\ \ \ \ \ \ \ \ while\ \{\$len\ >\ 0\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lappend\ out\ \[string\ range\ \$line\ 0\ \[expr\ \{\$COLUMNS-1\}\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ line\ \[string\ range\ \$line\ \$COLUMNS\ end\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ len\ \[expr\ \{\$len-\$COLUMNS\}\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\ \ \ \ set\ txt\ \[join\ \$out\ \"\\n\"\]\n\ \ \ \ set\ row\ \[expr\ \{\$n-\$row\}\]\n\ \ \ \ \n\ \ \ \ #\ Reserve\ spaces\ for\ display:\n\ \ \ \ if\ \{\$end\}\ \{\n\ \ \ \ \ \ \ \ if\ \{\$mid\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ print\ \"\[ESC\]\\\[\$\{mid\}B\"\ nowait\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ for\ \{set\ x\ 0\}\ \{\$x\ <\ \$end\}\ \{incr\ x\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ clearline\n\ \ \ \ \ \ \ \ \ \ \ \ print\ \"\[ESC\]\\\[1A\"\ nowait\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\ \ \ \ clearline\n\ \ \ \ set\ CMDLINE_LINES\ \$n\n\ \ \ \ \n\ \ \ \ #\ Output\ line(s):\n\ \ \ \ print\ \"\\r\$txt\"\n\ \ \ \ \n\ \ \ \ if\ \{\$row\}\ \{\n\ \ \ \ \ \ \ \ print\ \"\[ESC\]\\\[\$\{row\}A\"\ nowait\n\ \ \ \ \}\n\ \ \ \ gotocol\ \$col\n\ \ \ \ lappend\ CMDLINE_LINES\ \$row\n\}\n\nproc\ TclReadLine::print\ \{txt\ \{wait\ wait\}\}\ \{\n\ \ \ \ #\ Sends\ output\ to\ stdout\ chunks\ at\ a\ time.\n\ \ \ \ #\ This\ is\ to\ prevent\ the\ terminal\ from\n\ \ \ \ #\ hanging\ if\ we\ output\ too\ much:\n\ \ \ \ while\ \{\[string\ length\ \$txt\]\}\ \{\n\ \ \ \ \ \ \ \ puts\ -nonewline\ \[string\ range\ \$txt\ 0\ 2047\]\n\ \ \ \ \ \ \ \ set\ txt\ \[string\ range\ \$txt\ 2048\ end\]\n\ \ \ \ \ \ \ \ if\ \{\$wait\ ==\ \"wait\"\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ after\ 1\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\}\n\nproc\ TclReadLine::unknown\ \{args\}\ \{\n\ \ \ \ \n\ \ \ \ set\ name\ \[lindex\ \$args\ 0\]\n\ \ \ \ set\ cmdline\ \$TclReadLine::CMDLINE\n\ \ \ \ set\ cmd\ \[string\ trim\ \[regexp\ -inline\ \{^\\s*\[^\\s\]+\}\ \$cmdline\]\]\n\ \ \ \ if\ \{\[info\ exists\ TclReadLine::ALIASES(\$cmd)\]\}\ \{\n\ \ \ \ \ \ \ \ set\ cmd\ \[regexp\ -inline\ \{^\\s*\[^\\s\]+\}\ \$TclReadLine::ALIASES(\$cmd)\]\n\ \ \ \ \}\n\ \ \ \ \n\ \ \ \ set\ new\ \[auto_execok\ \$name\]\n\ \ \ \ if\ \{\$new\ !=\ \"\"\}\ \{\n\ \ \ \ \ \ \ \ set\ redir\ \"\"\n\ \ \ \ \ \ \ \ if\ \{\$name\ ==\ \$cmd\ &&\ \[info\ command\ \$cmd\]\ ==\ \"\"\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ redir\ \">&@\ stdout\ <@\ stdin\"\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ if\ \{\[catch\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ uplevel\ 1\ exec\ \$redir\ \$new\ \[lrange\ \$args\ 1\ end\]\}\ ret\]\n\ \ \ \ \ \ \ \ \}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ return\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ return\ \$ret\n\ \ \ \ \}\n\ \ \ \ \n\ \ \ \ uplevel\ _unknown\ \$args\n\}\n\nproc\ TclReadLine::alias\ \{word\ command\}\ \{\n\ \ \ \ variable\ ALIASES\n\ \ \ \ set\ ALIASES(\$word)\ \$command\n\}\n\nproc\ TclReadLine::unalias\ \{word\}\ \{\n\ \ \ \ variable\ ALIASES\n\ \ \ \ array\ unset\ ALIASES\ \$word\n\}\n\n################################\n#\ Key\ bindings\n################################\nproc\ TclReadLine::handleEscapes\ \{\}\ \{\n\ \ \ \ \n\ \ \ \ variable\ CMDLINE\n\ \ \ \ variable\ CMDLINE_CURSOR\n\ \ \ \ \n\ \ \ \ upvar\ 1\ keybuffer\ keybuffer\n\ \ \ \ set\ seq\ \"\"\n\ \ \ \ set\ found\ 0\n\ \ \ \ while\ \{\[set\ ch\ \[readbuf\ keybuffer\]\]\ !=\ \"\"\}\ \{\n\ \ \ \ \ \ \ \ append\ seq\ \$ch\n\n\ \ \ \ \ \ \ \ switch\ -exact\ --\ \$seq\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \"\\\[A\"\ \{\ \;#\ Cursor\ Up\ (cuu1,up)\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ handleHistory\ 1\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ found\ 1\;\ break\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \"\\\[B\"\ \{\ \;#\ Cursor\ Down\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ handleHistory\ -1\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ found\ 1\;\ break\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \"\\\[C\"\ \{\ \;#\ Cursor\ Right\ (cuf1,nd)\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$CMDLINE_CURSOR\ <\ \[string\ length\ \$CMDLINE\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ incr\ CMDLINE_CURSOR\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ found\ 1\;\ break\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \"\\\[D\"\ \{\ \;#\ Cursor\ Left\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$CMDLINE_CURSOR\ >\ 0\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ incr\ CMDLINE_CURSOR\ -1\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ found\ 1\;\ break\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \"\\\[H\"\ -\n\ \ \ \ \ \ \ \ \ \ \ \ \"\\\[7~\"\ -\n\ \ \ \ \ \ \ \ \ \ \ \ \"\\\[1~\"\ \{\ \;#\ home\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ CMDLINE_CURSOR\ 0\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ found\ 1\;\ break\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \"\\\[3~\"\ \{\ \;#\ delete\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$CMDLINE_CURSOR\ <\ \[string\ length\ \$CMDLINE\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ CMDLINE\ \[string\ replace\ \$CMDLINE\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$CMDLINE_CURSOR\ \$CMDLINE_CURSOR\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ found\ 1\;\ break\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \"\\\[F\"\ -\n\ \ \ \ \ \ \ \ \ \ \ \ \"\\\[K\"\ -\n\ \ \ \ \ \ \ \ \ \ \ \ \"\\\[8~\"\ -\n\ \ \ \ \ \ \ \ \ \ \ \ \"\\\[4~\"\ \{\ \;#\ end\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ CMDLINE_CURSOR\ \[string\ length\ \$CMDLINE\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ found\ 1\;\ break\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \"\\\[5~\"\ \{\ \;#\ Page\ Up\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \"\\\[6~\"\ \{\ \;#\ Page\ Down\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\ \ \ \ return\ \$found\n\}\n\nproc\ TclReadLine::handleControls\ \{\}\ \{\n\ \ \ \ \n\ \ \ \ variable\ CMDLINE\n\ \ \ \ variable\ CMDLINE_CURSOR\n\ \ \ \ \n\ \ \ \ upvar\ 1\ char\ char\n\ \ \ \ upvar\ 1\ keybuffer\ keybuffer\n\ \ \ \ \n\ \ \ \ #\ Control\ chars\ start\ at\ a\ ==\ \\u0001\ and\ count\ up.\n\ \ \ \ switch\ -exact\ --\ \$char\ \{\n\ \ \ \ \ \ \ \ \\u0001\ \{\ \;#\ ^a\n\ \ \ \ \ \ \ \ \ \ \ \ set\ CMDLINE_CURSOR\ 0\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \\u0002\ \{\ \;#\ ^b\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\ \$CMDLINE_CURSOR\ >\ 0\ \}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ incr\ CMDLINE_CURSOR\ -1\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \\u0004\ \{\ \;#\ ^d\n\ \ \ \ \ \ \ \ \ \ \ \ #\ should\ exit\ -\ if\ this\ is\ the\ EOF\ char,\ and\ the\n\ \ \ \ \ \ \ \ \ \ \ \ #\ \ \ cursor\ is\ at\ the\ end-of-input\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\ 0\ ==\ \[string\ length\ \$CMDLINE\]\ \}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ doExit\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ set\ CMDLINE\ \[string\ replace\ \$CMDLINE\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$CMDLINE_CURSOR\ \$CMDLINE_CURSOR\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \\u0005\ \{\ \;#\ ^e\n\ \ \ \ \ \ \ \ \ \ \ \ set\ CMDLINE_CURSOR\ \[string\ length\ \$CMDLINE\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \\u0006\ \{\ \;#\ ^f\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$CMDLINE_CURSOR\ <\ \[string\ length\ \$CMDLINE\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ incr\ CMDLINE_CURSOR\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \\u0007\ \{\ \;#\ ^g\n\ \ \ \ \ \ \ \ \ \ \ \ set\ CMDLINE\ \"\"\n\ \ \ \ \ \ \ \ \ \ \ \ set\ CMDLINE_CURSOR\ 0\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \\u000b\ \{\ \;#\ ^k\n\ \ \ \ \ \ \ \ \ \ \ \ variable\ YANK\n\ \ \ \ \ \ \ \ \ \ \ \ set\ YANK\ \ \[string\ range\ \$CMDLINE\ \[expr\ \{\$CMDLINE_CURSOR\ \ \}\ \]\ end\ \]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ CMDLINE\ \[string\ range\ \$CMDLINE\ 0\ \[expr\ \{\$CMDLINE_CURSOR\ -\ 1\ \}\ \]\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \\u0019\ \{\ \;#\ ^y\n\ \ \ \ \ \ \ \ \ \ \ \ variable\ YANK\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\ \[\ info\ exists\ YANK\ \]\ \}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ CMDLINE\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \"\[string\ range\ \$CMDLINE\ 0\ \[expr\ \{\$CMDLINE_CURSOR\ -\ 1\ \}\]\]\$YANK\[string\ range\ \$CMDLINE\ \$CMDLINE_CURSOR\ end\]\"\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \\u000e\ \{\ \;#\ ^n\n\ \ \ \ \ \ \ \ \ \ \ \ handleHistory\ -1\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \\u0010\ \{\ \;#\ ^p\n\ \ \ \ \ \ \ \ \ \ \ \ handleHistory\ 1\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \\u0003\ \{\ \;#\ ^c\n\ \ \ \ \ \ \ \ \ \ \ \ #\ clear\ line\n\ \ \ \ \ \ \ \ \ \ \ \ set\ CMDLINE\ \"\"\n\ \ \ \ \ \ \ \ \ \ \ \ set\ CMDLINE_CURSOR\ 0\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \\u0008\ -\n\ \ \ \ \ \ \ \ \\u007f\ \{\ \;#\ ^h\ &&\ backspace\ ?\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$CMDLINE_CURSOR\ >\ 0\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ incr\ CMDLINE_CURSOR\ -1\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ CMDLINE\ \[string\ replace\ \$CMDLINE\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \$CMDLINE_CURSOR\ \$CMDLINE_CURSOR\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \\u001b\ \{\ \;#\ ESC\ -\ handle\ escape\ sequences\n\ \ \ \ \ \ \ \ \ \ \ \ handleEscapes\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\ \ \ \ #\ Rate\ limiter:\n\ \ \ \ set\ keybuffer\ \"\"\n\}\n\nproc\ TclReadLine::shortMatch\ \{maybe\}\ \{\n\ \ \ \ #\ Find\ the\ shortest\ matching\ substring:\n\ \ \ \ set\ maybe\ \[lsort\ \$maybe\]\n\ \ \ \ set\ shortest\ \[lindex\ \$maybe\ 0\]\n\ \ \ \ foreach\ x\ \$maybe\ \{\n\ \ \ \ \ \ \ \ while\ \{!\[string\ match\ \$shortest*\ \$x\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ shortest\ \[string\ range\ \$shortest\ 0\ end-1\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\ \ \ \ return\ \$shortest\n\}\n\nproc\ TclReadLine::addCompletionHandler\ \{completion_extension\}\ \{\n\ \ \ \ variable\ COMPLETION_HANDLERS\n\ \ \ \ set\ COMPLETION_HANDLERS\ \[concat\ \$completion_extension\ \$COMPLETION_HANDLERS\]\n\}\n\nproc\ TclReadLine::delCompletionHandler\ \{completion_extension\}\ \{\n\ \ \ \ variable\ COMPLETION_HANDLERS\n\ \ \ \ set\ COMPLETION_HANDLERS\ \[lsearch\ -all\ -not\ -inline\ \$COMPLETION_HANDLERS\ \$completion_extension\]\ \n\}\n\nproc\ TclReadLine::getCompletionHandler\ \{\}\ \{\n\ \ \ \ variable\ COMPLETION_HANDLERS\n\ \ \ \ return\ \"\$COMPLETION_HANDLERS\"\n\}\n\nproc\ TclReadLine::handleCompletion\ \{\}\ \{\n\ \ \ \ variable\ COMPLETION_HANDLERS\n\ \ \ \ foreach\ handler\ \$COMPLETION_HANDLERS\ \{\n\ \ \ \ \ \ \ \ if\ \{\[eval\ \$handler\]\ ==\ 1\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ break\n\ \ \ \ \ \ \ \ \}\ \n\ \ \ \ \}\n\ \ \ \ return\ \n\}\n\nproc\ TclReadLine::handleCompletionBase\ \{\}\ \{\n\ \ \ \ variable\ CMDLINE\n\ \ \ \ variable\ CMDLINE_CURSOR\n\ \ \ \ \n\ \ \ \ set\ vars\ \"\"\n\ \ \ \ set\ cmds\ \"\"\n\ \ \ \ set\ execs\ \"\"\n\ \ \ \ set\ files\ \"\"\n\ \ \ \ \n\ \ \ \ #\ First\ find\ out\ what\ kind\ of\ word\ we\ need\ to\ complete:\n\ \ \ \ set\ wordstart\ \[string\ last\ \"\ \"\ \$CMDLINE\ \[expr\ \{\$CMDLINE_CURSOR-1\}\]\]\n\ \ \ \ incr\ wordstart\n\ \ \ \ set\ wordend\ \[string\ first\ \"\ \"\ \$CMDLINE\ \$wordstart\]\n\ \ \ \ if\ \{\$wordend\ ==\ -1\}\ \{\n\ \ \ \ \ \ \ \ set\ wordend\ end\n\ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ incr\ wordend\ -1\n\ \ \ \ \}\n\ \ \ \ set\ word\ \[string\ range\ \$CMDLINE\ \$wordstart\ \$wordend\]\n\ \ \ \ \n\ \ \ \ if\ \{\[string\ trim\ \$word\]\ ==\ \"\"\}\ return\n\ \ \ \ \n\ \ \ \ set\ firstchar\ \[string\ index\ \$word\ 0\]\n\ \ \ \ \n\ \ \ \ #\ Check\ if\ word\ is\ a\ variable:\n\ \ \ \ if\ \{\$firstchar\ ==\ \"\\\$\"\}\ \{\n\ \ \ \ \ \ \ \ set\ word\ \[string\ range\ \$word\ 1\ end\]\n\ \ \ \ \ \ \ \ incr\ wordstart\n\ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ #\ Check\ if\ it\ is\ an\ array\ key:proc\n\ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ set\ x\ \[string\ first\ \"(\"\ \$word\]\n\ \ \ \ \ \ \ \ if\ \{\$x\ !=\ -1\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ v\ \[string\ range\ \$word\ 0\ \[expr\ \{\$x-1\}\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ incr\ x\n\ \ \ \ \ \ \ \ \ \ \ \ set\ word\ \[string\ range\ \$word\ \$x\ end\]\n\ \ \ \ \ \ \ \ \ \ \ \ incr\ wordstart\ \$x\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[uplevel\ \\#0\ \"array\ exists\ \$v\"\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ vars\ \[uplevel\ \\#0\ \"array\ names\ \$v\ \$word*\"\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ foreach\ x\ \[uplevel\ \\#0\ \{info\ vars\}\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[string\ match\ \$word*\ \$x\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lappend\ vars\ \$x\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ #\ Check\ if\ word\ is\ possibly\ a\ path:\n\ \ \ \ \ \ \ \ if\ \{\$firstchar\ ==\ \"/\"\ ||\ \$firstchar\ ==\ \".\"\ ||\ \$wordstart\ !=\ 0\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ files\ \[glob\ -nocomplain\ --\ \$word*\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ if\ \{\$files\ ==\ \"\"\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ #\ Not\ a\ path\ then\ get\ all\ possibilities:\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$firstchar\ ==\ \"\\\[\"\ ||\ \$wordstart\ ==\ 0\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$firstchar\ ==\ \"\\\[\"\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ word\ \[string\ range\ \$word\ 1\ end\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ incr\ wordstart\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ Check\ executables:\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ foreach\ dir\ \[split\ \$::env(PATH)\ :\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ foreach\ f\ \[glob\ -nocomplain\ -directory\ \$dir\ --\ \$word*\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ exe\ \[string\ trimleft\ \[string\ range\ \$f\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[string\ length\ \$dir\]\ end\]\ \"/\"\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[lsearch\ -exact\ \$execs\ \$exe\]\ ==\ -1\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lappend\ execs\ \$exe\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ Check\ commands:\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ foreach\ x\ \[info\ commands\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[string\ match\ \$word*\ \$x\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lappend\ cmds\ \$x\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ Check\ commands\ anyway:\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ foreach\ x\ \[info\ commands\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[string\ match\ \$word*\ \$x\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lappend\ cmds\ \$x\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ if\ \{\$wordstart\ !=\ 0\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ #\ Check\ variables\ anyway:\n\ \ \ \ \ \ \ \ \ \ \ \ set\ x\ \[string\ first\ \"(\"\ \$word\]\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$x\ !=\ -1\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ v\ \[string\ range\ \$word\ 0\ \[expr\ \{\$x-1\}\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ incr\ x\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ word\ \[string\ range\ \$word\ \$x\ end\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ incr\ wordstart\ \$x\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[uplevel\ \\#0\ \"array\ exists\ \$v\"\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ vars\ \[uplevel\ \\#0\ \"array\ names\ \$v\ \$word*\"\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ foreach\ x\ \[uplevel\ \\#0\ \{info\ vars\}\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[string\ match\ \$word*\ \$x\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lappend\ vars\ \$x\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\ \ \ \ \n\ \ \ \ variable\ COMPLETION_MATCH\n\ \ \ \ set\ maybe\ \[concat\ \$vars\ \$cmds\ \$execs\ \$files\]\n\ \ \ \ set\ shortest\ \[shortMatch\ \$maybe\]\n\ \ \ \ if\ \{\"\$word\"\ ==\ \"\$shortest\"\}\ \{\n\ \ \ \ \ \ \ \ if\ \{\[llength\ \$maybe\]\ >\ 1\ &&\ \$COMPLETION_MATCH\ !=\ \$maybe\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ COMPLETION_MATCH\ \$maybe\n\ \ \ \ \ \ \ \ \ \ \ \ clearline\n\ \ \ \ \ \ \ \ \ \ \ \ set\ temp\ \"\"\n\ \ \ \ \ \ \ \ \ \ \ \ foreach\ \{match\ format\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ vars\ \ \"35\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ cmds\ \ \"1\;32\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ execs\ \"32\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ files\ \"0\"\n\ \ \ \ \ \ \ \ \ \ \ \ \}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[llength\ \[set\ \$match\]\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ append\ temp\ \"\[ESC\]\\\[\$\{format\}m\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ foreach\ x\ \[set\ \$match\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ append\ temp\ \"\[file\ tail\ \$x\]\ \"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ append\ temp\ \"\[ESC\]\\\[0m\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ print\ \"\\n\$temp\\n\"\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ if\ \{\[file\ isdirectory\ \$shortest\]\ &&\n\ \ \ \ \ \ \ \ \ \ \ \ \[string\ index\ \$shortest\ end\]\ !=\ \"/\"\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ append\ shortest\ \"/\"\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ if\ \{\$shortest\ !=\ \"\"\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ CMDLINE\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[string\ replace\ \$CMDLINE\ \$wordstart\ \$wordend\ \$shortest\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ CMDLINE_CURSOR\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[expr\ \{\$wordstart+\[string\ length\ \$shortest\]\}\]\n\ \ \ \ \ \ \ \ \}\ elseif\ \{\ \$COMPLETION_MATCH\ !=\ \"\ not\ found\ \"\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ COMPLETION_MATCH\ \"\ not\ found\ \"\n\ \ \ \ \ \ \ \ \ \ \ \ print\ \"\\nNo\ match\ found.\\n\"\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\}\n\nproc\ TclReadLine::handleHistory\ \{x\}\ \{\n\ \ \ \ variable\ HISTORY_LEVEL\n\ \ \ \ variable\ HISTORY_SIZE\n\ \ \ \ variable\ CMDLINE\n\ \ \ \ variable\ CMDLINE_CURSOR\n\ \ \ \ variable\ CMDLINE_PARTIAL\n\ \ \ \ \n\ \ \ \ set\ maxid\ \[expr\ \[history\ nextid\]\ -\ 1\]\n\ \ \ \ if\ \{\$maxid\ >\ 0\}\ \{\n\ \ \ \ \ \ \ \ #\n\ \ \ \ \ \ \ \ #\ \ Check\ for\ a\ top\ level\ command\ line\ and\ history\ event\n\ \ \ \ \ \ \ \ #\ \ Store\ this\ command\ line\ locally\ (i.e.\ don't\ use\ the\ history\ stack)\n\ \ \ \ \ \ \ \ #\n\ \ \ \ \ \ \ \ if\ \{\$HISTORY_LEVEL\ ==\ 0\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ CMDLINE_PARTIAL\ \$CMDLINE\n\ \ \ \ \ \ \ \ \}\ \n\ \ \ \ \ \ \ \ incr\ HISTORY_LEVEL\ \$x\n\ \ \ \ \ \ \ \ #\n\ \ \ \ \ \ \ \ #\ \ Note:\ \ HISTORY_LEVEL\ is\ used\ to\ offset\ into\n\ \ \ \ \ \ \ \ #\ \ the\ history\ events.\ \ It\ will\ be\ reset\ to\ zero\ \n\ \ \ \ \ \ \ \ #\ \ when\ a\ command\ is\ executed\ by\ tclline.\n\ \ \ \ \ \ \ \ #\ \ \n\ \ \ \ \ \ \ \ #\ \ Check\ the\ three\ bounds\ of\n\ \ \ \ \ \ \ \ #\ \ 1)\ HISTORY_LEVEL\ <=\ 0\ -\ Restore\ the\ top\ level\ cmd\ line\ (not\ in\ history\ stack)\n\ \ \ \ \ \ \ \ #\ \ 2)\ HISTORY_LEVEL\ >\ HISTORY_SIZE\n\ \ \ \ \ \ \ \ #\ \ 3)\ HISTORY_LEVEL\ >\ maxid\n\ \ \ \ \ \ \ \ #\n\ \ \ \ \ \ \ \ if\ \{\$HISTORY_LEVEL\ <=\ 0\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ HISTORY_LEVEL\ 0\ \n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ exists\ CMDLINE_PARTIAL\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ CMDLINE\ \$CMDLINE_PARTIAL\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ CMDLINE_CURSOR\ \[string\ length\ \$CMDLINE\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ return\n\ \ \ \ \ \ \ \ \}\ elseif\ \{\$HISTORY_LEVEL\ >\ \$maxid\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ HISTORY_LEVEL\ \$maxid\n\ \ \ \ \ \ \ \ \}\ elseif\ \{\$HISTORY_LEVEL\ >\ \$HISTORY_SIZE\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ HISTORY_LEVEL\ \$HISTORY_SIZE\n\ \ \ \ \ \ \ \ \}\ \n\ \ \ \ \ \ \ \ set\ id\ \[expr\ (\$maxid\ +\ 1)\ -\ \$HISTORY_LEVEL\]\n\ \ \ \ \ \ \ \ set\ cmd\ \[history\ event\ \$id\]\n\ \ \ \ \ \ \ \ set\ CMDLINE\ \$cmd\n\ \ \ \ \ \ \ \ set\ CMDLINE_CURSOR\ \[string\ length\ \$cmd\]\n\ \ \ \ \}\n\}\n\n################################\n#\ History\ handling\ functions\n################################\n\nproc\ TclReadLine::getHistory\ \{\}\ \{\n\ \ \ \ variable\ HISTORY_SIZE\n\ \ \ \ \n\ \ \ \ set\ l\ \[list\]\n\ \ \ \ set\ e\ \[history\ nextid\]\n\ \ \ \ set\ i\ \[expr\ \$e\ -\ \$HISTORY_SIZE\]\n\ \ \ \ if\ \{\$i\ <=\ 0\}\ \{\n\ \ \ \ \ \ \ \ set\ i\ 1\n\ \ \ \ \}\n\ \ \ \ for\ \{\ set\ i\ \}\ \{\$i\ <\ \$e\}\ \{incr\ i\}\ \{\n\ \ \ \ \ \ \ \ lappend\ l\ \[history\ event\ \$i\]\n\ \ \ \ \}\n\ \ \ \ return\ \$l\n\}\n\nproc\ TclReadLine::setHistory\ \{hlist\}\ \{\n\ \ \ \ foreach\ event\ \$hlist\ \{\n\ \ \ \ \ \ \ \ history\ add\ \$event\n\ \ \ \ \}\n\}\n\n################################\n#\ main()\n################################\n\nproc\ TclReadLine::rawInput\ \{\}\ \{\n\ \ \ \ fconfigure\ stdin\ -buffering\ none\ -blocking\ 0\n\ \ \ \ fconfigure\ stdout\ -buffering\ none\ -translation\ crlf\n\ \ \ \ exec\ stty\ raw\ -echo\n\}\n\nproc\ TclReadLine::lineInput\ \{\}\ \{\n\ \ \ \ fconfigure\ stdin\ -buffering\ line\ -blocking\ 1\n\ \ \ \ fconfigure\ stdout\ -buffering\ line\n\ \ \ \ exec\ stty\ -raw\ echo\n\}\n\nproc\ TclReadLine::doExit\ \{\{code\ 0\}\}\ \{\n\ \ \ \ variable\ HISTFILE\n\ \ \ \ variable\ HISTORY_SIZE\ \n\n\ \ \ \ #\ Reset\ terminal:\n\ \ \ \ #print\ \"\[ESC\]c\[ESC\]\\\[2J\"\ nowait\n\ \ \ \ \n\ \ \ \ restore\ \;#\ restore\ \"info'\ command\ -\n\ \ \ \ lineInput\n\ \ \ \ \n\ \ \ \ set\ hlist\ \[getHistory\]\n\ \ \ \ #\n\ \ \ \ #\ Get\ rid\ of\ the\ TclReadLine::doExit,\ shouldn't\ be\ more\ than\ one\n\ \ \ \ #\n\ \ \ \ set\ hlist\ \[lsearch\ -all\ -not\ -inline\ \$hlist\ \"TclReadLine::doExit\"\]\n\ \ \ \ set\ hlistlen\ \[llength\ \$hlist\]\n\ \ \ \ if\ \{\$hlistlen\ >\ 0\}\ \{\n\ \ \ \ \ \ \ \ set\ f\ \[open\ \$HISTFILE\ w\]\n\ \ \ \ \ \ \ \ if\ \{\$hlistlen\ >\ \$HISTORY_SIZE\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ hlist\ \[lrange\ \$hlist\ \[expr\ (\$hlistlen\ -\ \$HISTORY_SIZE\ -\ 1)\]\ end\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ foreach\ x\ \$hlist\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ #\ Escape\ newlines:\n\ \ \ \ \ \ \ \ \ \ \ \ puts\ \$f\ \[string\ map\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \\n\ \"\\\\n\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \"\\\\\"\ \"\\\\b\"\n\ \ \ \ \ \ \ \ \ \ \ \ \}\ \$x\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ close\ \$f\n\ \ \ \ \}\n\ \ \ \ \n\ \ \ \ exit\ \$code\n\}\n\nproc\ TclReadLine::restore\ \{\}\ \{\n\ \ \ \ lineInput\n\ \ \ \ rename\ ::unknown\ TclReadLine::unknown\n\ \ \ \ rename\ ::_unknown\ ::unknown\n\}\n\nproc\ TclReadLine::interact\ \{\}\ \{\n\n\ \ \ \ rename\ ::unknown\ ::_unknown\n\ \ \ \ rename\ TclReadLine::unknown\ ::unknown\n\ \ \ \ \n\ \ \ \ variable\ RCFILE\n\ \ \ \ if\ \{\[file\ exists\ \$RCFILE\]\}\ \{\n\ \ \ \ \ \ \ \ source\ \$RCFILE\n\ \ \ \ \}\n\n\ \ \ \ #\ Load\ history\ if\ available:\n\ \ \ \ #\ variable\ HISTORY\n\ \ \ \ variable\ HISTFILE\n\ \ \ \ variable\ HISTORY_SIZE\n\ \ \ \ history\ keep\ \$HISTORY_SIZE\n\ \ \ \ \n\ \ \ \ if\ \{\[file\ exists\ \$HISTFILE\]\}\ \{\n\ \ \ \ \ \ \ \ set\ f\ \[open\ \$HISTFILE\ r\]\n\ \ \ \ \ \ \ \ set\ hlist\ \[list\]\n\ \ \ \ \ \ \ \ foreach\ x\ \[split\ \[read\ \$f\]\ \"\\n\"\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$x\ !=\ \"\"\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ Undo\ newline\ escapes:\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lappend\ hlist\ \[string\ map\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \"\\\\n\"\ \\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \"\\\\\\\\\"\ \"\\\\\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \"\\\\b\"\ \"\\\\\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\ \$x\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ setHistory\ \$hlist\n\ \ \ \ \ \ \ \ unset\ hlist\n\ \ \ \ \ \ \ \ close\ \$f\n\ \ \ \ \}\n\ \ \ \ \n\ \ \ \ rawInput\n\ \ \ \ \n\ \ \ \ #\ This\ is\ to\ restore\ the\ environment\ on\ exit:\n\ \ \ \ #\ Do\ not\ unalias\ this!\n\ \ \ \ alias\ exit\ TclReadLine::doExit\n\ \ \ \ \n\ \ \ \ variable\ ThisScript\ \[info\ script\]\n\ \ \ \ \n\ \ \ \ tclline\ \;#\ emit\ the\ first\ prompt\n\ \ \ \ \n\ \ \ \ fileevent\ stdin\ readable\ TclReadLine::tclline\n\ \ \ \ variable\ forever\n\ \ \ \ vwait\ TclReadLine::forever\n\ \ \ \ \n\ \ \ \ restore\n\}\n\n\nproc\ TclReadLine::check_partial_keyseq\ \{buffer\}\ \{\n\ \ \ \ variable\ READLINE_LATENCY\n\ \ \ \ upvar\ \$buffer\ keybuffer\n\n\ \ \ \ #\n\ \ \ \ #\ check\ for\ a\ partial\ esc\ sequence\ as\ tclline\ expects\ the\ whole\ sequence\n\ \ \ \ #\n\ \ \ \ if\ \{\[string\ index\ \$keybuffer\ 0\]\ ==\ \[ESC\]\}\ \{\n\ \ \ \ \ \ \ \ #\n\ \ \ \ \ \ \ \ #\ Give\ extra\ time\ to\ read\ partial\ key\ sequences\n\ \ \ \ \ \ \ \ #\ \n\ \ \ \ \ \ \ \ set\ timer\ \ \[expr\ \[clock\ clicks\ -milliseconds\]\ +\ \$READLINE_LATENCY\]\n\ \ \ \ \ \ \ \ while\ \{\[clock\ clicks\ -milliseconds\]\ <\ \$timer\ \}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ append\ keybuffer\ \[read\ stdin\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\}\n\nproc\ TclReadLine::tclline\ \{\}\ \{\n\ \ \ \ variable\ COLUMNS\n\ \ \ \ variable\ CMDLINE_CURSOR\n\ \ \ \ variable\ CMDLINE\n\ \ \ \ \n\ \ \ \ set\ char\ \"\"\n\ \ \ \ set\ keybuffer\ \[read\ stdin\]\n\ \ \ \ set\ COLUMNS\ \[getColumns\]\n\ \ \ \ \n\ \ \ \ check_partial_keyseq\ keybuffer\n\ \ \ \ \n\ \ \ \ while\ \{\$keybuffer\ !=\ \"\"\}\ \{\n\ \ \ \ \ \ \ \ if\ \{\[eof\ stdin\]\}\ return\n\ \ \ \ \ \ \ \ set\ char\ \[readbuf\ keybuffer\]\n\ \ \ \ \ \ \ \ if\ \{\$char\ ==\ \"\"\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ #\ Sleep\ for\ a\ bit\ to\ reduce\ CPU\ overhead:\n\ \ \ \ \ \ \ \ \ \ \ \ after\ 40\n\ \ \ \ \ \ \ \ \ \ \ \ continue\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ if\ \{\[string\ is\ print\ \$char\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ x\ \$CMDLINE_CURSOR\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$x\ <\ 1\ &&\ \[string\ trim\ \$char\]\ ==\ \"\"\}\ continue\n\ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ set\ trailing\ \[string\ range\ \$CMDLINE\ \$x\ end\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ CMDLINE\ \[string\ replace\ \$CMDLINE\ \$x\ end\]\n\ \ \ \ \ \ \ \ \ \ \ \ append\ CMDLINE\ \$char\n\ \ \ \ \ \ \ \ \ \ \ \ append\ CMDLINE\ \$trailing\n\ \ \ \ \ \ \ \ \ \ \ \ incr\ CMDLINE_CURSOR\n\ \ \ \ \ \ \ \ \}\ elseif\ \{\$char\ ==\ \"\\t\"\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ handleCompletion\n\ \ \ \ \ \ \ \ \}\ elseif\ \{\$char\ ==\ \"\\n\"\ ||\ \$char\ ==\ \"\\r\"\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ complete\ \$CMDLINE\]\ &&\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \[string\ index\ \$CMDLINE\ end\]\ !=\ \"\\\\\"\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lineInput\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ print\ \"\\n\"\ nowait\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ uplevel\ \\#0\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ Handle\ aliases:\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ cmdline\ \$TclReadLine::CMDLINE\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ Add\ the\ cmd\ line\ to\ history\ before\ doing\ any\ substitutions\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ history\ add\ \$cmdline\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ cmd\ \[string\ trim\ \[regexp\ -inline\ \{^\\s*\[^\\s\]+\}\ \$cmdline\]\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ exists\ TclReadLine::ALIASES(\$cmd)\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ regsub\ --\ \"(?q)\$cmd\"\ \$cmdline\ \$TclReadLine::ALIASES(\$cmd)\ cmdline\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ Perform\ glob\ substitutions:\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ cmdline\ \[string\ map\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \"\\\\*\"\ \\0\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \"\\\\~\"\ \\1\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\ \$cmdline\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ Prevent\ glob\ substitution\ of\ *,~\ for\ tcl\ commands\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ commands\ \$cmd\]\ !=\ \"\"\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ cmdline\ \[string\ map\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \"\\*\"\ \\0\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \"\\~\"\ \\1\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\ \$cmdline\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ while\ \{\[regexp\ -indices\ \\\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \{(\[\\w/\\.\]*(?:~|\\*)\[\\w/\\.\]*)+\}\ \$cmdline\ x\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ foreach\ \{i\ n\}\ \$x\ break\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ s\ \[string\ range\ \$cmdline\ \$i\ \$n\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ x\ \[glob\ -nocomplain\ --\ \$s\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ If\ glob\ can't\ find\ anything\ then\ don't\ do\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ glob\ substitution,\ pass\ *\ or\ ~\ as\ literals:\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$x\ ==\ \"\"\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ x\ \[string\ map\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \"*\"\ \\0\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \"~\"\ \\1\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\ \$s\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ cmdline\ \[string\ replace\ \$cmdline\ \$i\ \$n\ \$x\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ cmdline\ \[string\ map\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \\0\ \"*\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \\1\ \"~\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\ \$cmdline\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ rename\ ::info\ ::_info\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ rename\ TclReadLine::localInfo\ ::info\n\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ Reset\ HISTORY_LEVEL\ before\ next\ command\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ TclReadLine::HISTORY_LEVEL\ 0\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ exists\ TclReadLine::CMDLINE_PARTIAL\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ unset\ TclReadLine::CMDLINE_PARTIAL\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ #\ Run\ the\ command:\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ code\ \[catch\ \$cmdline\ res\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ rename\ ::info\ TclReadLine::localInfo\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ rename\ ::_info\ ::info\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$code\ ==\ 1\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ TclReadLine::print\ \"\$::errorInfo\\n\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ TclReadLine::print\ \"\$res\\n\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ TclReadLine::CMDLINE\ \"\"\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ TclReadLine::CMDLINE_CURSOR\ 0\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ TclReadLine::CMDLINE_LINES\ \{0\ 0\}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\ \;#\ end\ uplevel\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ rawInput\n\ \ \ \ \ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ x\ \$CMDLINE_CURSOR\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$x\ <\ 1\ &&\ \[string\ trim\ \$char\]\ ==\ \"\"\}\ continue\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ trailing\ \[string\ range\ \$CMDLINE\ \$x\ end\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ CMDLINE\ \[string\ replace\ \$CMDLINE\ \$x\ end\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ append\ CMDLINE\ \$char\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ append\ CMDLINE\ \$trailing\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ incr\ CMDLINE_CURSOR\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ handleControls\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\ \ \ \ prompt\ \$CMDLINE\n\}\n\n#\n#\ Use\ the\ following\ to\ invoke\ readline\ \ \n#\n#\ TclReadLine::interact\n#\n======\n\n\nIt\ might\ be\ faster\ to\ use\ \[scan\]\ vs.\ firing\ up\ the\ regex\ engine,\ especially\ as\ this\ is\ called\ for\ every\ character\ input.\ \ Alternatively,\ if\ Tclx\ is\ available\ it\ makes\ more\ sense\ to\ trap\ SIGWINCH\ and\ update\ COLUMNS\ in\ the\ handler.\n----\n<<discussion>>\n\[wdb\]\ works\ fine.\ \nHow\ to\ manage\ that\ it\ is\ executed\ automatically\ on\ invoking\ tclsh?\n\n\[LV\]\ See\ \[tclshrc\]\ for\ a\ suggestion.\n\n\[RLH\]\ Does\ this\ mean\ readline\ can\ now\ work\ in\ tclsh?\n\n\[LV\]\ I\ think\ it\ means\ that\ the\ code\ on\ this\ page\ works\ in\ tclsh.\ As\ long\ as\ that\ is\ what\ you\ mean\ by\ readline,\ then\ sure.\n\n----\n\[tb\]\ -\ 2009-12-16\ -\ I\ just\ sourced\ this\ code\ into\ a\ tclkit-8.5.1\ and\ noticed\ I\ had\ to\ escape\ the\ star\ in:\n\n\ info\ proc\ ::TclReadLine::\\*\n\n\[AM\}\ Yes,\ I\ can\ confirm\ that.\ Though:\ \n\n\ info\ proc\ ::TclReadLine::g*\n\nor\n\ \n\ info\ proc\ ::TclReadline::*g*\n\ndoes\ work,\ so\ it\ seems\ to\ be\ a\ problem\ with\ a\ bare\ asterisk\ only.\ (The\ command\ that\ is\ stored\ contains\ the\ list\ of\ files\ that\ are\ present\ ...)\n\n\n----\n'''\[LVwikignome\]\ -\ 2009-12-16\ 08:33:33'''\n\nIf\ this\ code\ appears\ to\ be\ working\ well,\ perhaps\ it\ would\ be\ worthwhile\ considering\ adding\ it\ to\ \[tcllib\]\ or\ some\ similar\ commonly\ distributed\ package\ so\ that\ it\ is\ available\ readily.\n\n----\n'''\[arjen\]\ -\ 2009-12-18\ 05:48:42'''\n\nI\ copied\ the\ code\ verbatim\ and\ had\ no\ problem\ whatsoever.\n\nNice\ work!\ (It\ really\ acts\ as\ an\ interactive\ shell,\ so\ that\ you\ can\ run\ external\ commands\ like\ ls\ and\ vi)\n\n----\n'''\[mjs\]\ -\ 2010-02-16\ 00:58:43'''\n\nAs\ with\ the\ previous\ version,\ the\ stty\ regexp\ doesn't\ work\ for\ BSD\ stty\ (e.g.\ Mac\ OS\ X).\ \ This\ works\ for\ me:\n\n======\n\ \ \ \ set\ cols\ 0\n\ \ \ \ if\ \{!\[catch\ \{exec\ stty\ -a\}\ err\]\}\ \{\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ #\ match\ for\ BSD\ stty\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ regexp\ \{(\\d+)\ rows\;\ (\\d+)\ columns\;\}\ \$err\ junk\ rows\ cols\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ if\ \{\$cols\ ==\ 0\}\ \{\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ #\ match\ for\ Linux\ stty\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \ \ \ \ regexp\ \{rows\ (=\ )?(\\d+)\;\ columns\ (=\ )?(\\d+)\}\ \$err\ junk\ i1\ rows\ i2\ cols\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \ \ \ \ \}\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \n\ \ \ \ \}\n======\n\n\n\n----\n'''\[rjmcmahon\]\ -\ 2010-03-03\ 13:22:11'''\nMade\ a\ fix\ to\ handle\ preserving\ the\ command\ line\ under\ edit\ during\ history\ events.\ \ See\ the\ code\ around\ CMDLINE_PARTIAL.\ \ Note:\ Still\ need\ to\ look\ into\ adding\ mjs'\ BSD\ fix.\ \ (Trying\ to\ find\ a\ MAC\ to\ verify.)\n\n----\n'''\[rjmcmahon\]\ -\ 2010-03-04\ 14:40:10'''\n\nMade\ the\ fix\ (per\ mjs'\ commnet)\ to\ TclReadLine::getColumns\ enabling\ support\ for\ BSD\ style\ stty\ output.\ \ Tested\ it\ on\ a\ MAC.\n\n----\n'''\[rjmcmahon\]\ -\ 2010-03-05\ 14:18:43'''\n\nFound\ and\ fixed\ a\ bug\ when\ history\ was\ larger\ than\ history\ size\ and\ doExit\ is\ called.\n\n----\n'''\[rjmcmahon\]\ -\ 2010-03-12\ 19:19:59'''\n\nFix\ for\ glob\ substitutions\ of\ *\ and\ ~\ so\ handled\ properly\ per\ shell,\ tcl\ command\ and\ history\ add.\n\n----\n'''\[mocallins\]\ -\ 2010-05-20\ 14:08:38'''\n\nProblem\ with\ down\ arrow\ and\ last\ command\ on\ the\ stack.\nLocks\ up\ tclsh\ and\ you\ have\ to\ go\ to\ another\ session\ and\ kill\ the\ process\ id\ :((\n\n----\n'''\[SRIV\]\ -\ 2010-05-26\ 08:33:38'''\nAny\ error\ in\ this\ code\ will\ make\ the\ tclsh\ non-responsive\ because\ you\ loose\ control\ over\ the\ raw\ tty.\ I\ noted\ the\ same\ problem\ and\ after\ looking\ through\ the\ stack\ trace,\ I\ came\ up\ with\ a\ fix.\ I\ didn't\ go\ through\ all\ the\ code\ to\ try\ to\ understand\ how\ it\ was\ supposed\ to\ work,\ but\ I\ understand\ the\ fail\ condition.\nModify\ the\ last\ few\ lines\ of\ TclReadLine::handleHistory\ as\ follows.\n======\nset\ id\ \[expr\ (\$maxid\ +\ 1)\ -\ \$HISTORY_LEVEL\]\nif\ \{\$id\ >\ \$maxid\}\ \{\n\ \ set\ cmd\ \"\"\n\}\ else\ \{\n\ \ set\ cmd\ \[history\ event\ \$id\]\n\}\nset\ CMDLINE\ \$cmd\nset\ CMDLINE_CURSOR\ \[string\ length\ \$cmd\]\n======\n\nUnrelated\ to\ the\ bug\ above,\ when\ I\ place\ this\ code\ into\ ~/.tclshrc,\ I\ add\ the\ following\ line\ to\ the\ end:\n======\nif\ \{\$::tcl_interactive\}\ \{TclReadLine::interact\}\n======\nso\ that\ it\ only\ is\ enabled\ from\ interactive\ shells,\ not\ running\ apps.\n----\n\[rjmcmahon\]-\ 2010-07-13\ \n\nFix\ down\ arrow,\ last\ command,\ bug\ per\ mocallins\ note.\ \ Should\ work\ now.\n\nPS.\ \ I\ don't\ check\ this\ site\ very\ often.\ \ Next\ time\ if\ you\ see\ a\ bug\ and\ need\ a\ fix\ please\ feel\ free\ to\ email\ me\ at\ rjmcmahon\ at\ rjmcmahon\ dot\ com\ with\ TCL\ twiki\ bug\ in\ the\ subject.\ \ Thanks\ -Bob\n----\n\[makr\]\ 2011-01-07:\ For\ those\ that\ -\ like\ me\ -\ do\ not\ have\ \[Tclx\]\ available,\ but\ \[Expect\],\ you\ could\ do\n======\npackage\ require\ Expect\n\n#\ Prevent\ sigint\ from\ killing\ our\ shell:\nexp_trap\ SIG_IGN\ SIGINT\n======\n\nYou\ may\ want\ to\ change\ '''exec\ stty'''\ into\ '''exp_stty'''\ further\ down\ in\ the\ script.\ Expect\ might\ still\ call\ the\ system's\ '''stty'''\ tool,\ however.\n\nI\ also\ extended\ '''getColumns'''\ to\ avoid\ the\ ''\[regexp\]''\ calls\ if\ possible\ (works\ for\ \[AIX\],\ \[HP-UX\],\ and\ \[Linux\],\ but\ needs\ the\ original\ code\ as\ fallback\ on\ \[Solaris\],\ though):\n======\nproc\ TclReadLine::getColumns\ \{\}\ \{\n\ \ \ \ set\ cols\ 0\n\ \ \ \ if\ \{!\[catch\ \{exp_stty\ size\}\ size\]\}\ \{\n\ \ \ \ \ \ \ \ lassign\ \$size\ rows\ cols\n\ \ \ \ \}\ elseif\ \{!\[catch\ \{exp_stty\ -a\}\ rs\]\}\ \{\n\ \ \ \ \ \ \ \ if\ \{\[regexp\ \{rows\ (=\ )?(\\d+)\;\ columns\ (=\ )?(\\d+)\}\ \$rs\ -\ i1\ rows\ i2\ cols\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ #\ Linux\ style\ stty\ output\n\ \ \ \ \ \ \ \ \}\ elseif\ \{\[regexp\ \{\ (\\d+)\ rows\;\ (\\d+)\ columns\;\}\ \$rs\ -\ rows\ cols\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ #\ BSD\ style\ stty\ output\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\ \ \ \ return\ \$cols\n\}\n======\n\ngavino\ 26june2011\n\nWorks\ like\ a\ charm.\ \ I\ uncommented\ the\ last\ line.\ \ I\ then\ saved\ it\ to\ /opt/tclreadline2.\ \ In\ /usr/local/bin/tcl\ I\ put\ /opt/tcl86/bin/tclsh8.6\ /opt/tclreadline2.\ \ Typing\ tcl\ then\ gave\ >\ prompt.\ \ Typing\ info\ patchlevel\ returned\ 8.6b1.\ \ I\ up\ arrowed\ and\ command\ came\ back.\ \ Nice.\ \ I\ did\ no\ tclx.\ \ I\ used\ compiled\ tcl\ 8.6\ -wth\ --disable-shared\ option\ and\ gcc\ 4.6\ on\ archlinux.\n\n======\n<<categories>>Category\ Dev.\ Tools} CALL {my revision {Pure-tcl readline2}} CALL {::oo::Obj552159 process revision/Pure-tcl+readline2} CALL {::oo::Obj552157 process}

-errorcode

NONE

-errorinfo

Unknow state transition: LINE -> END
    while executing
"error $msg"
    (class "::Wiki" method "render_wikit" line 6)
    invoked from within
"my render_$default_markup $N $C $mkup_rendering_engine"
    (class "::Wiki" method "render" line 8)
    invoked from within
"my render $name $C"
    (class "::Wiki" method "revision" line 31)
    invoked from within
"my revision $page"
    (class "::Wiki" method "process" line 56)
    invoked from within
"$server process [string trim $uri /]"

-errorline

4