More csh completions

wblock@

Developer
Looking to add to my csh(1) completions. For me, they are almost as good as a man page. Arguably better, especially when they substitute only valid values.

Does anyone have completions for pfctl(8), zfs(8), or zpool(8)?

The full set of completions I've collected are here: http://www.wonkity.com/~wblock/csh/completions

Many of those came from examples, some from online sources including these forums, and a few are my own. Many have been customized from generic versions to work better with FreeBSD. Some common examples have been left out as not very useful, and more could be removed from there.

There are two styles. The normal style actually substitutes parameters. The other style shows valid choices, like the gpart(8) completion there (that one was one of the few I've written). Either type is good, although the actual-value substitution is probably better when possible.
 
I'm not sure this will help. It's also online for zsh. It may be something to easy to convert. I'll post the link and the code as it looks like it's from a cache and the site is down:

http://www.zsh.org/mla/workers/2009/msg00815.html
cache:
https://webcache.googleusercontent..../2009/msg00815.html+&cd=1&hl=en&ct=clnk&gl=us

Code:
#compdef pfctl

local pfctl_flush_modifiers pfctl_optimizer_level pfctl_show_modifiers pfctl_tables_command pfctl_debug_level

pfctl_flush_modifiers=(
    'all:Flush all'
    'info:Flush the filter information'
    'nat:Flush the NAT rules'
    'osfp:Flush the passive operating system fingerprints'
    'queue:Flush the queue rules'
    'rules:Flush the filter rules'
    'state:Flush the stable table'
    'Sources:Flush the source tracking table'
    'Tables:Flush the tables'
)

pfctl_show_modifiers=(
    'nat:Show the currently loaded NAT rules'
    'queue:Show the currently loaded queue rules'
    'rules:Show the currently loaded filter rules'
    'Anchors:Show the currently loaded anchors directly attached to the main ruleset'
    'state:Show the contents of the state table'
    'Sources:Show the contents of the source tracking table'
    'info:Show filter information'
    'labels:Show per-rule statistics of filter rules with labels'
    'timeouts:Show the current global timeouts'
    'memory:Show the current pool memory hard limits'
    'Tables:Show the list of tables'
    'osfp:Show the list of operating system fingerprints'
    'Interfaces:Show the list of interfaces and interface drivers available to PF'
    'all:Show all except for the lists of interfaces and operating system fingerprints'
)

pfctl_optimizer_level=(
    'none:Disable the ruleset optimizer'
    'basic:Enable basic ruleset optimizations'
    'profile:Enable basic ruleset optimizations with profiling'
)
pfctl_tables_command=(
    'kill:Kill a table'
    'flush:Flush all addresses of a table'
    'add:Add one or more addresses in a table'
    'delete:Delete one or more addresses from a table'
    'expire:Delete addresses which had their statistics cleared more than number seconds ago'
    'replace:Replace the addresses of the table'
    'show:Show the content (addresses) of a table'
    'test:Test if the given addresses match a table'
    'zero:Clear all the statistics of a table'
    'load:Load only the table definitions from pf.conf(5)'
)
pfctl_debug_level=(
    "none:Don\'t generate debug messages" 
    'urgent:Generate debug messages only for serious errors' 
    'misc:Generate debug messages for various errors' 
    'loud:Generate debug messages for common conditions'
)
_iface() {
    local pfctl_iface
    pfctl_iface=($(pfctl -s Interfaces))
    compadd $pfctl_iface
}
_tables() {
    local pfctl_tables
    pfctl_tables=($(pfctl -s Tables))
     compadd $pfctl_tables
}
# TODO:
# Missing -a
#
_arguments -s \
    '-F[Flush the filter parameters specified by modifier]:modifier:(($pfctl_flush_modifiers))' \
    '-A[Load only the queue rules present in the rule file]' \
    '-D[Define macro to be set to value]:macro:' \
    '-d[Disable the packet filter]' \
    '-e[Enable the packet filter]' \
    '-f[Load the rules contained in a file]:configuration file:_files' \
    '-g[Include output helpful for debugging]' \
    '-h[Help]' \
    '-i[Restrict the operation to the given interface]:interface:_iface' \
    '-K[Kill all of the source tracking entries originating from the specified host or network]:host or network:_hosts' \
    '-k[Kill all of the state entries originating from the specified host or network]:host or network:_hosts' \
    '-m[Merge in explicitly given options]' \
    '-N[Load only the NAT rules present in the rule file]' \
    '-n[Do not actually load rules, just parse them]' \
    '-O[Load only the options present in the rule file]' \
    '-o[Control the ruleset optimizer]:level:(($pfctl_optimizer_level))' \
    '-p[Use the device file device instead of the default /dev/pf]:device:_files' \
    '-q[Only print errors and warnings]' \
    '-R[Load only the filter rules present in the rule file]' \
    '-r[Perform reverse DNS lookups on states when displaying them]' \
    '-s[Show the filter parameters specified by modifier]:modifier:(($pfctl_show_modifiers ))' \
    '-T[Specify the command to apply to the table]:command:(($pfctl_tables_command))' \
    '-t[Specify the name of the table]:table:_tables' \
    '-v[Produce more verbose output]' \
    '-x[Set the debug level]:debug level:(($pfctl_debug_level))' \
    '-z[Clear per-rule statistics]'
 
wblock@ said:
Does anyone have completions for pfctl(8), zfs(8), or zpool(8)?

There are a whole bunch of examples in /usr/share/examples/tcsh/complete.tcsh.

As for ZFS, I've found these, can't remember where though.

Code:
        set zpool_cmd = (create destroy add remove list iostat status\
                online offline clear attach detach replace scrub\
                import export upgrade history get set)

        set zfs_cmd =   (create destroy snapshot rollback clone promote\
                rename list set get inherit mount unmount\
                share unshare send receive)

        complete zpool \
                'p/1/$zpool_cmd/'\
                'n/destroy/`zpool list -H -o name`/'\
                'n/add/`zpool list -H -o name`/'\
                'n/remove/`zpool list -H -o name`/'\
                'n/list/`zpool list -H -o name`/'\
                'n/iostat/`zpool list -H -o name`/'\
                'n/status/`zpool list -H -o name`/'\
                'n/online/`zpool list -H -o name`/'\
                'n/offline/`zpool list -H -o name`/'\
                'n/clear/`zpool list -H -o name`/'\
                'n/attach/`zpool list -H -o name`/'\
                'n/detach/`zpool list -H -o name`/'\
                'n/replace/`zpool list -H -o name`/'\
                'n/scrub/`zpool list -H -o name`/'\
                'n/import/`zpool list -H -o name`/'\
                'n/export/`zpool list -H -o name`/'\
                'n/upgrade/`zpool list -H -o name`/'\
                'n/history/`zpool list -H -o name`/'\
                'N/get/`zpool list -H -o name`/'\
                'N/set/`zpool list -H -o name`/'

        complete zfs \
                'p/1/$zfs_cmd/'\
                'n/create/`zfs list -H -o name`/'\
                'n/destroy/`zfs list -H -o name`/'\
                'n/snapshot/`zfs list -H -o name`/'\
                'n/rollback/`zfs list -H -t snapshot -o name`/'\
                'n/clone/`zfs list -H -t snapshot -o name`/'\
                'n/promote/`zfs list -H -o name`/'\
                'n/rename/`zfs list -H -o name`/'\
                'n/list/`zfs list -H -o name`/'\
                'N/set/`zfs list -H -o name`/'\
                'N/get/`zfs list -H -o name`/'\
                'n/inherit/`zfs list -H -o name`/'\
                'n/mount/`zfs list -H -o name`/'\
                'n/unmount/`zfs list -H -o name`/'\
                'n/share/`zfs list -H -o name`/'\
                'n/unshare/`zfs list -H -o name`/'\
                'n/send/`zfs list -H -t snapshot -o name`/'\
                'n/receive/`zfs list -H -o name`/'

They work quite reasonably but can't seem to deal with options. That breaks the completion :(
 
Many of mine came from /usr/share/examples. But some of those were generic and not quite right for FreeBSD, so I updated them. Can't recall specifics, though.

The options problem is why I went with the x: version for gpart(8). Showing what is allowed can be considered a context-sensitive help feature:

Code:
% gpart [I][color="Red"]tab[/color][/I]
add      bootcode create   destroy  recover  restore  show     unset
backup   commit   delete   modify   resize   set      undo     
% gpart create [I][color="Red"]tab[/color][/I]
-s scheme [-n entries] [-f flags] provider
 
Here are some other completions, but some of them are incomplete..

Code:
complete pkg 'c/-/(d j c v)/'	\
		'n/add/f:*.{txz,tbz,tgz}/'	\
		'n/remove/`pkg_info |cut  -d" " -f1`/' \
		'n/delete/`pkg_info |cut  -d" " -f1`/' \
		'n/info/`pkg_info |cut  -d" " -f1`/' \
		'n/update/`pkg_info |cut  -d" " -f1`/' \
		'n/which/f/'	\
		'p/*/( add audit autoremove backup check clean create delete fetch help info install query register \
remove repo rquery search set shell shlib stats updating upgrade version which )/'
		
complete portsnap	'c/-/(d f I k l p s)/' \
			'n/-d/d/'	\
			'n/-f/f/'	\
			'n/-p/d/'	\
			'p/*/(fetch extract update)/'
			
complete apachectl	'p/1/(start stop restart fullstatus status graceful graceful-stop configtest)/'

complete postfix	'c/-c/f/'	\
			'p/*/(check start stop abort flush reload status)/'
			
complete sudo	'p/*/c/'

complete squid 'c/-/(d f h i k n r s l u v z C D F I N O R X Y)/'\
		'n/-k/(reconfigure rotate shutdown interrupt kill debug check parse)/'	\
		'n/-f/f/'

complete Xorg	'c/-/(config configdir configure gamma logfile logverbose showconfig)/'

complete wget	'c/--/(input-file no-clobber continue timestamping spider limit-rate wait no-proxy user password header recursive \
convert-links mirror page-requisites domains include-directories exclude-directories no-parent html-extension)/'

complete gpg	'c/--/(sign clearsign encrypt decrypt verify verify-files encrypt-files decrypt-files list-keys \
list-public-keys list-secret-keys delete-key fingerprint check-sigs delete-secret-key export send-keys recv-keys \
search-keys fetch-keys gen-key edit-key sign-key keyserver armor)/'
 
I did some disk recovery with parted magic this afternoon, and I noticed I can complete dd, this works as expected:
$ dd if=/dev/s<Tab>

That would be nice to have ... My last experience with tcsh completions left me traumatized for a week, so I'm not going to try, but if anyone is feeling brave ...
 
That's a good idea, it bugs me every time when it can't complete after if=. For a start:

Code:
complete dd 'c/if=/f/' 'c/of=/f/'
 
wblock@ said:
it bugs me every time when it can't complete after if=.
My sentiments, exactly. Between this and the inability to separately redirect stdout and stderr (at least not easily), it's pretty much all that I don't like about tcsh(1).
 
That completion problem is due to dd(1)'s oddball option specs. Bash and sh aren't particularly smart about it, seem to just offer to complete with a filename if unknown. I prefer csh(1)'s catlike indifference to sh(1)'s doglike desire to please with the wrong thing. :)
 
completion for dd(1)():
Code:
complete dd	'c/if=/f/' 'c/of=/f/'	\
		'c/conv=*,/(ascii block ebcdic lcase pareven noerror notrunc osync sparse swab sync unblock)/,' \
		'c/conv=/(ascii block ebcdic lcase pareven noerror notrunc osync sparse swab sync unblock)/,' \
		'p/*/(bs cbs count files fillcahr ibs if iseek obs of oseek seek skip conv)/='

EDIT:

Oh, I found an useful link: complete.tcsh
 
I've updated some of my completions, some borrows posts in this thread, I've modified/improved some for clarity or personal taste.

In general, all completions should be cross-platform (ie. also works on Linux), and FreeBSD-specific stuff *only* works on FreeBSD (this is especially useful with commands that also exist on Linux, for example the service and kill completions in the OP give errors on Linux).

I did remove many of the single-character arguments as completions, it doesn't seem to matter if I press the `x' or `tab' key. I guess they're there as a mnemonic (?)

Another useful option is `fignore', this allows you to ignore certain file extensions when completing (for example .o or .pyc), note that this *only* works if there is just one completion possible (at first I thought it was broken).

https://bitbucket.org/Carpetsmoker/...285dfd8d40a8b/etc/csh.cshrc?at=default#cl-304
 
I did remove many of the single-character arguments as completions, it doesn't seem to matter if I press the `x' or `tab' key. I guess they're there as a mnemonic (?)

How about this kind of completion?

Code:
complete mergemaster    'c/-p/x:-p :  Pre-buildworld mode./' \
                        'c/-h/x:-h :  Display usage and help information./' \
                        'c/-v/x:-v :  Be more verbose about the process./'  \
                        'c/-a/x:-a :  Run automatically./' \
                        'c/-U/x:-U :  auto upgrade files that have not been user modified./' \
                        'c/-i/x:-i :  install any files that do not exist in the destination./' \
                        'c/-F/x:-F :  install the new file if the files differ only by VCS Id./' \
                        'c/-c/x:-c :  Use context diffs instead of unified diffs./'

For example:

Code:
[CMD]# mergemaster -v[/CMD][color="Red"][tab][/color]
-v :  Be more verbose about the process.
[CMD]# mergemaster -i[/CMD][color="Red"][tab][/color]
-i :  install any files that do not exist in the destination.
[CMD]# mergemaster -U[/CMD][color="Red"][tab][/color]
-U :  auto upgrade files that have not been user modified.
 
Those mergemaster(8) completions are quite neat, however mergemaster is often run only in single user mode where the shell is plain sh(1). Nothing prevents one from applying the same method to other tools, let's say portmaster(8).

Code:
complete portmaster 'c/-L/x:-L :  List all installed ports by category, and search for updates/'
 
The tcsh mailing list pointed me at the Git completion that can be found in search. I'd never really understood it before, but finally sat down and looked at it for a while. It uses xargs(1) and echo(1) to build a list of completions including options with dashes and subcommand names to use with n, and then it uses N to complete just subcommand names. Based on that, this is what I have for pkg(8) so far:

Code:
  # shortcut to retrieve list of all installed packages
  alias __pkgs 'pkg info -E'

  set pkgcmds=(help add annotate audit autoremove backup check clean convert create delete fetch info install lock plugins \
                        query register repo rquery search set shell shlib stats unlock update updating upgrade version which)
  
  # aliases that show lists of possible completions including both package names and options
  alias __pkg-check-opts        '__pkgs | xargs echo -B -d -s -r -y -v -n -a -i g x'
  alias __pkg-del-opts  '__pkgs | xargs echo -a -D -f -g -i -n -q -R -x -y'
  alias __pkg-info-opts '__pkgs | xargs echo -a -A -f -R -e -D -g -i -x -d -r -k -l -b -B -s -q -O -E -o -p -F'
  alias __pkg-which-opts        '__pkgs | xargs echo -q -o -g'
                        
  complete pkg          'p/1/$pkgcmds/' \
                        'n/check/`__pkg-check-opts`/' \
                        'N/check/`__pkgs`/' \
                        'n/delete/`__pkg-del-opts`/' \
                        'N/delete/`__pkgs`/' \
                        'n/help/$pkgcmds/' \
                        'n/info/`__pkg-info-opts`/' \
                        'N/info/`__pkgs`/' \
                        'n/which/`__pkg-which-opts`/' \
                        'N/which/`__pkgs`/'

This type of definition could be used for other commands with subcommands, like zfs(8) or zpool(8). I have not found a way to include x help-style completions natively. However, a post to the tcsh mailing list revealed something that has been there all along: http://mx.gw.com/pipermail/tcsh/2014-January/004734.html

The value of the entire command line can be passed to external commands, and that means that completions can be written in any arbitrary language, working any way that seems appropriate.
 
It appears that pkg info -E is deprecated and not available any more from pkgng. Maybe the following is more convenient: alias __pkgs 'pkg query -a "%n"'.
 
Right. This works, too:
Code:
alias __pkgs 'pkg info -q'

make(1) changed also, so now the target completions no longer work. That was surprisingly useful. I worked on it a while back without success. Has anyone else tried?
 
The -p flag disappeared, apparently. I thought BSD wasn't into randomly removing flags from programs...?

We can use -dg1, which has a different output, and outputs to stderr, which is always fun in tcsh.

Here's my attempt:
Code:
complete make 'n@*@`sh -c "make -dg1 -n 2>&1 | grep ,\ flags\ \[0-9\]\*,\ type\ \[0-9\]\* | cut -wf2 | tr -d , | sed /^\[^a-z\]/d | sort -u"`@'

Completions seem to be pretty much the same as on my 9.2 system. And this will work on GNU make too, so we win that!

It *only* works for FreeBSD 10, though. In FReeBSD <=9, you need to use the old completion; -dg1 works, but has a different format...

To make it work for both:
Code:
if ($uname == FreeBSD && `uname -r | cut -d. -f1` < 10) then
        complete make 'n@*@`make -pn | sed -n -E "/^[#_.\/[:blank:]]+/d; /=/d; s/[[:blank:]]*:.*//gp;"`@'
else
        complete make 'n@*@`sh -c "make -dg1 -n 2>&1 | grep ,\ flags\ \[0-9\]\*,\ type\ \[0-9\]\* | cut -wf2 | tr -d , | sed /^\[^a-z\]/d | sort -u"`@'
endif


Now fetch me a beer. You owe me one.
 
Excellent! If you are at BSDCan, I'll buy you a beer. Otherwise, it will have to be virtual: :beer

While trying to decipher that, I saw this in the make(1) output:
Code:
.ALLTARGETS      =  ...

It appears to be an easy way to find all possible targets:
make -V .ALLTARGETS

Using that for a completion:
Code:
complete make 'n/*/`make -V .ALLTARGETS`/'
 
I also add my profiles from ~/.ssh/config to the hosts:

Code:
set hosts
if ( -r "$HOME/.hosts" ) then
        set hosts=($hosts `grep -Ev '(^#|^$)' $HOME/.hosts`)
endif

if ( -r "$HOME/.ssh/config" ) then
        set hosts=($hosts `grep ^Host ~/.ssh/config | cut -d' ' -f2`)
endif

if ( -r "$HOME/.ssh/known_hosts" ) then
        set hosts=($hosts `cut -d' ' -f 1 ~/.ssh/known_hosts | cut -d, -f1`)
endif

set hosts = `echo "$hosts" | sort -u`

ie:

Code:
Host vagrant
  HostName localhost
  Port 2222
  User vagrant
 
That's a good idea! That also reminds me, cut(1) now supports -w for whitespace delimiters. No idea how long that's been around. So
Code:
if ( -r "$HOME/.ssh/known_hosts" ) then
        set hosts=($hosts `cut -w -f1 ~/.ssh/known_hosts | cut -d, -f1`)
endif

Hmm. Might want to filter out square brackets, sort, and remove duplicates as a final step:
Code:
set hosts=(`echo $hosts | tr -d '[]' | sort | uniq`)
 
Back
Top