TCSH tab auto complete with the part of current typed command

I am trying to write my own complete for a command.
The completion needs to use a portion of the typed command to for a path search.

I am trying to get the following behavior

When I write my_commad -ws my_ws -t[TAB] a list of folders under my_ws/tests appears as a list of completion
I couldn’t figure out how to break it

I tried the following, but failed because of quotes problem, I guess

complete my_command 'n@-t@`echo $COMMAND_LINE | perl -ne '/-ws (w+)/; print $1'`@'
Asked By: Dan Messer

||

Quoting problem

The problem with your command, as you mentioned, is that you have single quotes inside your single quotes that you need to escape. There are couple of way to do that.

If your backslash_quote shell variable is set, you can escape the internal single quotes by a backslash.

complete my_command 'n@-t@`echo $COMMAND_LINE | perl -ne '/-ws (w+)/; print $1'`@'
  • You can check if it is by running echo $?backslash_quote and see that the value is 1.
  • If it’s not set, you can set it by running set backslash_quote

Alternatively, if your backslash_quote is not set and you don’t want to change it, you can replace your internal single quotes with '"'"'.

complete my_command 'n@-t@`echo $COMMAND_LINE | perl -ne '"'"'/-ws (w+)/; print $1'"'"'`@'

Both solutions would solve your quotes issue, and the result would be that the argument after -t would be complete by your argument for -ws.

$ my_command -ws my_ws -t TABmy_ws

Anyway, that’s not what you’re trying to achieve. You want it to be completed by the "list of folders under my_ws/tests".

Answering your actual requirements

For more complicated completions, you might consider to create a wrapper script that would parse your $COMMAND_LINE variable and perform additional actions.

For instance, if you want the argument after -t to be completed by the subdirectories under $WS/tests, you can write a script in your home directory similar to the following:

$ cat $HOME/findtest.sh
#!/bin/sh
ws=$(perl -ne '/-ws (S+)/; print $1' <<< $@)
find $ws/tests -mindepth 1 -maxdepth 1 -type d 2>/dev/null

And then in your complete command, you will call the findtest.sh script with your $COMMAND_LINE variable as the arguments:

complete my_command 'n@-t@`$HOME/findtest.sh $COMMAND_LINE`@'

Results:

Assuming that under my_ws/tests you have the following folders:

ls -1 my_ws/tests
test1
test2
test3

Then trying to complete the parameter for -t would result in:

$ my_command -ws my_ws -t TAB
my_ws/tests/test1 my_ws/tests/test2 my_ws/tests/test3 
$ my_command -ws my_ws -t my_ws/tests/test

If you don’t want to show the full path, but just the directories under my_ws/tests without the leading path, you can change your find command in the script to:

find $ws/tests -mindepth 1 -maxdepth 1 -type d -printf "%fn" 2>/dev/null

Result:

$ my_command -ws my_ws -t TAB
test1 test2 test3 
$ my_command -ws my_ws -t test

Additional recommendations

You can add additional features for your completion. For instance:

complete my_command 'n@-t@`$HOME/findtest.sh $COMMAND_LINE`@' 'N/-ws/(-t)/' 'n/-ws/d/' 'p/*/(-ws)/'

Or more readable:

complete my_command 
  'n@-t@`$HOME/findtest.sh $COMMAND_LINE`@' 
  'N/-ws/(-t)/' 
  'n/-ws/d/' 
  'p/*/(-ws)/'

Explanation:

  • 'p/*/(-ws)/' – at any place after your my_command it will try to complete to -ws.
  • 'n/-ws/d/' – after -ws it will try to complete only to directories.
  • 'N/-ws/(-t)/' – If two words before your current position in your line the word was -ws, the next argument it expects is -t.

Notice that the order here is important, as tcsh will try to complete according to the order the words appear in the complete command. For instance, if you move the 'p/*/(-ws)/' to the beginning, it will always try to complete to -ws and will not try the rest of the line.

Result:

$ my_command TAB                # will complete to -ws
$ my_command -ws 
$ my_command -ws mTAB           # will complete list of directories that start with m
$ my_command -ws my_ws/ 
$ my_command -ws my_ws/ TAB     # Will complete to -t
$ my_command -ws my_ws/ -t
$ my_command -ws my_ws/ -t TAB  # Will complete to list of folders under my_ws/tests
test1 test2 test3 
$ my_command -ws my_ws/ -t test
Answered By: aviro
Categories: Answers Tags: ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.