aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSteve Bennett <steveb@workware.net.au>2014-05-19 20:36:00 +1000
committerSteve Bennett <steveb@workware.net.au>2016-09-29 15:13:13 +1000
commit31130bb056088ed80f0ab76daf4d4ac8bda5489d (patch)
tree10e099900cf3dc849b45ab0013f2361ce8e0d152
parent94357f11bcab186bbdbb291cdda0f7acf61165e9 (diff)
downloadjimtcl-31130bb056088ed80f0ab76daf4d4ac8bda5489d.zip
jimtcl-31130bb056088ed80f0ab76daf4d4ac8bda5489d.tar.gz
jimtcl-31130bb056088ed80f0ab76daf4d4ac8bda5489d.tar.bz2
jimsh: Scriptable command-line completion support
via tcl::autocomplete Signed-off-by: Steve Bennett <steveb@workware.net.au>
-rw-r--r--auto.def1
-rw-r--r--initjimsh.tcl21
-rw-r--r--jim-interactive.c42
-rw-r--r--jim_tcl.txt25
-rw-r--r--tclcompat.tcl14
5 files changed, 90 insertions, 13 deletions
diff --git a/auto.def b/auto.def
index c7d9e57..e1a70a0 100644
--- a/auto.def
+++ b/auto.def
@@ -233,7 +233,6 @@ if {[opt-bool-or-full lineedit]} {
if {([cc-check-includes termios.h] && [have-feature isatty]) || [have-feature winconsole]} {
msg-result "Enabling line editing"
define USE_LINENOISE
- define-append CCOPTS -DNO_COMPLETION
define-append PARSE_UNIDATA_FLAGS -width
lappend extra_objs linenoise.o
}
diff --git a/initjimsh.tcl b/initjimsh.tcl
index f929a27..f5420ab 100644
--- a/initjimsh.tcl
+++ b/initjimsh.tcl
@@ -43,4 +43,25 @@ if {$tcl_platform(platform) eq "windows"} {
set jim::argv0 [string map {\\ /} $jim::argv0]
}
+# Simple interactive command line completion callback
+# Explicitly knows about some commands that support "-commands"
+proc tcl::autocomplete {prefix} {
+ if {[string match "* " $prefix]} {
+ set cmd [string range $prefix 0 end-1]
+ if {$cmd in {info tcl::prefix socket namespace array clock file package string dict signal history} || [info channel $cmd] ne ""} {
+ # Add any results from -commands
+ return [lmap p [$cmd -commands] {
+ function "$cmd $p"
+ }]
+ }
+ }
+ # Find matching commands, omitting results containing spaces
+ return [lmap p [lsort [info commands $prefix*]] {
+ if {[string match "* *" $p]} {
+ continue
+ }
+ function $p
+ }]
+}
+
_jimsh_init
diff --git a/jim-interactive.c b/jim-interactive.c
index 1d16ce0..932e8e1 100644
--- a/jim-interactive.c
+++ b/jim-interactive.c
@@ -78,12 +78,41 @@ void Jim_HistoryShow(void)
#endif
}
+#ifdef USE_LINENOISE
+struct JimCompletionInfo {
+ Jim_Interp *interp;
+ Jim_Obj *command;
+};
+
+void JimCompletionCallback(const char *prefix, linenoiseCompletions *comp, void *userdata)
+{
+ struct JimCompletionInfo *info = (struct JimCompletionInfo *)userdata;
+ Jim_Obj *objv[2];
+
+ objv[0] = info->command;
+ objv[1] = Jim_NewStringObj(info->interp, prefix, -1);
+
+ int ret = Jim_EvalObjVector(info->interp, 2, objv);
+
+ /* XXX: Consider how best to handle errors here. bgerror? */
+ if (ret == JIM_OK) {
+ int i;
+ Jim_Obj *listObj = Jim_GetResult(info->interp);
+ int len = Jim_ListLength(info->interp, listObj);
+ for (i = 0; i < len; i++) {
+ linenoiseAddCompletion(comp, Jim_String(Jim_ListGetIndex(info->interp, listObj, i)));
+ }
+ }
+}
+#endif
+
int Jim_InteractivePrompt(Jim_Interp *interp)
{
int retcode = JIM_OK;
char *history_file = NULL;
#ifdef USE_LINENOISE
const char *home;
+ struct JimCompletionInfo compinfo;
home = getenv("HOME");
if (home && isatty(STDIN_FILENO)) {
@@ -92,6 +121,13 @@ int Jim_InteractivePrompt(Jim_Interp *interp)
snprintf(history_file, history_len, "%s/.jim_history", home);
Jim_HistoryLoad(history_file);
}
+
+ compinfo.interp = interp;
+ compinfo.command = Jim_NewStringObj(interp, "tcl::autocomplete", -1);
+ Jim_IncrRefCount(compinfo.command);
+
+ /* Register a callback function for tab-completion. */
+ linenoiseSetCompletionCallback(JimCompletionCallback, &compinfo);
#endif
printf("Welcome to Jim version %d.%d\n",
@@ -173,5 +209,11 @@ int Jim_InteractivePrompt(Jim_Interp *interp)
}
out:
Jim_Free(history_file);
+
+#ifdef USE_LINENOISE
+ Jim_DecrRefCount(interp, compinfo.command);
+ linenoiseSetCompletionCallback(NULL, NULL);
+#endif
+
return retcode;
}
diff --git a/jim_tcl.txt b/jim_tcl.txt
index 88855d0..af95d66 100644
--- a/jim_tcl.txt
+++ b/jim_tcl.txt
@@ -12,9 +12,10 @@ SYNOPSIS
or
- jimsh [<scriptfile>]
+ jimsh [<scriptfile>|-]
jimsh -e '<immediate-script>'
jimsh --version
+ jimsh --help
.Quick Index
@@ -54,6 +55,9 @@ RECENT CHANGES
Changes between 0.77 and 0.78
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1. Add serial/tty support with `aio tty`
+2. Add support for 'jimsh -'
+3. Add hidden '-commands' option to many commands
+4. Add scriptable autocompletion support in interactive mode with `tcl::autocomplete`
Changes between 0.76 and 0.77
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -200,6 +204,10 @@ or to process the Tcl script in a file with:
jimsh filename
+or to process the Tcl script from standard input:
+
+ jimsh -
+
It may also be invoked to execute an immediate script with:
jimsh -e "script"
@@ -4948,7 +4956,7 @@ and zero or more child nodes (ordered), as well as zero or more attribute/value
tcl::prefix
~~~~~~~~~~~
-The optional tclprefix extension provides the Tcl8.6-compatible 'tcl::prefix' command
+The optional tclprefix extension provides the Tcl8.6-compatible `tcl::prefix` command
(http://www.tcl.tk/man/tcl8.6/TclCmd/prefix.htm) for matching strings against a table
of possible values (typically commands or options).
@@ -4971,6 +4979,19 @@ of possible values (typically commands or options).
generating the error message. The default corresponds to
setting +-level 0+.
+tcl::autocomplete
+~~~~~~~~~~~~~~~~~
+Scriptable command line completion is supported in the interactive shell, 'jimsh', through
+the `tcl::autocomplete` callback. A simple implementation is provided, however this may
+be replaced with a custom command instead if desired.
+
+In the interactive shell, press <TAB> to activate command line completion.
+
++*tcl::autocomplete* 'commandline'+::
+ This command is called with the current command line when the user presses <TAB>.
+ The command should return a list of all possible command lines that match the current command line.
+ For example if +*pr*+ is the current command line, the list +*{prefix proc}*+ may be returned.
+
history
~~~~~~~
The optional history extension provides script access to the command line editing
diff --git a/tclcompat.tcl b/tclcompat.tcl
index d1516b3..e2ae56e 100644
--- a/tclcompat.tcl
+++ b/tclcompat.tcl
@@ -63,9 +63,8 @@ proc fileevent {args} {
tailcall {*}$args
}
-# Second, option argument is a glob pattern
+# Second, optional argument is a glob pattern
# Third, optional argument is a "putter" function
-#
proc parray {arrayname {pattern *} {puts puts}} {
upvar $arrayname a
@@ -172,14 +171,9 @@ local proc pid {{channelId {}}} {
# Usage: try ?catchopts? script ?onclause ...? ?finallyclause?
#
# Where:
-# onclause is: on codes {?resultvar? ?optsvar?} script
-#
-# codes is: a list of return codes (ok, error, etc. or integers), or * for any
-#
-# finallyclause is: finally script
-#
-#
-# Where onclause is: on codes {?resultvar? ?optsvar?}
+# onclause is: on codes {?resultvar? ?optsvar?} script
+# codes is: a list of return codes (ok, error, etc. or integers), or * for any
+# finallyclause is: finally script
proc try {args} {
set catchopts {}
while {[string match -* [lindex $args 0]]} {