How do I get multi-word autocompletion with rlwrap for tclsh?Example: I type file <space> then pressing <tab> <tab> I only want to see the sub-commands to file, such as exists isdirectory or isfile.I tried adding file\ isfile (i.e. escaping the space) to the completion file, but this did not help. It just caused isfile to appear as another autocomplete command.I guess I could accomplish multi-word autocompletion with an rlwrap filter, but there were no obvious examples in /usr/share/rlwarp/filters/ for me to hook on.
rlwrap: tclsh multi-word autocompletion
command line;autocomplete;readline;line editor;tcl
With the help from the excellent answer from thrig I cooked the following tclsh multi-word completion filter for tclsh. The script below should be stored in tclsh_filter and executed with rlwrap -z tclsh_filter tclsh. Remember to chmod +x tclsh_filter.#!/usr/bin/env perluse strict;use warnings;use lib $ENV{RLWRAP_FILTERDIR};use RlwrapFilter;my @tcl_cmds = qw/encoding if pid tcl_endOfWord eof incr pkg::create tcl_findLibrary after error info pkg_mkIndex tcl_startOfNextWord append eval interp proc tcl_startOfPreviousWord array exec join puts tcl_wordBreakAfter auto_execok exit lappend pwd tcl_wordBreakBefore auto_import expr lindex re_syntax tcltest auto_load fblocked linsert read tclvars auto_mkindex fconfigure list regexp tell auto_mkindex_old fcopy llength registry time auto_qualify file load regsub trace auto_reset fileevent lrange rename unknown bgerror filename lreplace return unset binary flush lsearch scan update break for lset seek uplevel catch foreach lsort set upvar cd format memory socket variable clock gets msgcat source vwait close glob namespace split while concat global open string continue history package subst dde http parray switch/;# Below is copy paste from tcl.tk web pages.my $tcl_txt = <<END;file atime name ?time?file attributes namefile attributes name ?option?file attributes name ?option value option value...?file channels ?pattern?file copy ?-force? ?--? source targetfile copy ?-force? ?--? source ?source ...? targetDirfile delete ?-force? ?--? pathname ?pathname ... ?file dirname namefile executable namefile exists namefile extension namefile isdirectory namefile isfile namefile join name ?name ...?file link ?-linktype? linkName ?target?file lstat name varNamefile mkdir dir ?dir ...?file mtime name ?time?file nativename namefile normalize namefile owned namefile pathtype namefile readable namefile readlink namefile rename ?-force? ?--? source targetfile rename ?-force? ?--? source ?source ...? targetDirfile rootname namefile separator ?name?file size namefile split namefile stat name varNamefile system namefile tail namefile type namefile volumesfile writable namestring compare ?-nocase? ?-length int? string1 string2string equal ?-nocase? ?-length int? string1 string2string first needleString haystackString ?startIndex?string index string charIndexstring is alnum  ?-strict? ?-failindex varname? stringstring is alphastring is asciistring is booleanstring is controlstring is digitstring is doublestring is falsestring is graphstring is integerstring is lowerstring is printstring is punctstring is spacestring is truestring is upperstring is wordcharstring is xdigitstring last needleString haystackString ?lastIndex?string length stringstring map ?-nocase? mapping stringstring match ?-nocase? pattern stringstring range string first laststring repeat string countstring replace string first last ?newstring?string tolower string ?first? ?last?string totitle string ?first? ?last?string toupper string ?first? ?last?string trim string ?chars?string trimleft string ?chars?string trimright string ?chars?lsort -asciilsort -dictionarylsort -integerlsort -reallsort -command commandlsort -increasinglsort -decreasinglsort -index indexlsort -uniqueregexp -aboutregexp -expandedregexp -indicesregexp -lineregexp -linestopregexp -lineanchorregexp -nocaseregexp -allregexp -inlineregexp -start indexregexp --ENDmy @multi;foreach my $line (split /\n/, $tcl_txt) {  $line =~ s/\?//g;  $line =~ s/ - -/ --/g;  $line =~ s/ \.\.\.//g;  $line =~ s/\s{2,}/ /g;  $line =~ s/\s+$//;  push @multi, $line;  if ($line =~ /^(.*\s)(-\w+)\s(-\w+)(.*)$/) {    push @multi, $1$3 $2$4;  }}my $filter = RlwrapFilter->new;$filter->completion_handler(\&completion);$filter->run;sub completion {  my ($input, $prefix, @completions) = @_;  $input =~ s/\s+/ /g;  # Support completion on composite expressions. Hacky, limited syntax support.  $input =~ s/^[^[]+\[//;  $input =~ s/^.*;\s*//;  # If last complete words were options, remove these so we can restart option   # matching.  $input =~ s/(?:\s-\w+)+\s((?:-\w+)?)$/ $1/;  my $word_cnt = () = $input =~ m/\b\s+/g;  if ($word_cnt == 0) {    @completions = grep /^\Q$input\E/, @tcl_cmds;  } else {    my @mmatch = grep /^\Q$input\E/, @multi;    @completions = map {my @F = split /\s/, $_;                        $F[$word_cnt]} @mmatch;    # rlwrap seem to have a 'feature' where words beginning with '-' are     # prepended with '-', forcing us to remove the dash. Downside is that     #  will list the options without '-'.    @completions = map {s/^-//; $_} @completions;  }  return @completions;}