diff options
author | Steve Bennett <steveb@workware.net.au> | 2014-05-19 20:36:00 +1000 |
---|---|---|
committer | Steve Bennett <steveb@workware.net.au> | 2016-09-29 15:13:13 +1000 |
commit | 31130bb056088ed80f0ab76daf4d4ac8bda5489d (patch) | |
tree | 10e099900cf3dc849b45ab0013f2361ce8e0d152 | |
parent | 94357f11bcab186bbdbb291cdda0f7acf61165e9 (diff) | |
download | jimtcl-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.def | 1 | ||||
-rw-r--r-- | initjimsh.tcl | 21 | ||||
-rw-r--r-- | jim-interactive.c | 42 | ||||
-rw-r--r-- | jim_tcl.txt | 25 | ||||
-rw-r--r-- | tclcompat.tcl | 14 |
5 files changed, 90 insertions, 13 deletions
@@ -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]]} { |