logoalt Hacker News

Writing simple tab-completions for Bash and Zsh

255 pointsby lihaoyilast Sunday at 9:50 AM83 commentsview on HN

Comments

homebrewerlast Sunday at 10:34 AM

With fish, if the program you're interested in hasn't betrayed the decades-old tradition of shipping man pages, it's often as simple as running `fish_update_completions`.

It parses all man pages on your system and generates completion files for you. By default, they go into ~/.cache/fish/generated_completions/*

If the man page was written poorly/is missing, you can always write your own completion (and hopefully send it upstream). fish uses such a simple format that I don't think there's any need for tutorials save the official doc:

https://fishshell.com/docs/current/completions.html

For example, here's an excerpt from curl

  complete --command curl --short-option 'L' --long-option 'location' --description 'Follow redirects' 
  complete --command curl --short-option 'O' --long-option 'remote-name' --description 'Write output to file named as remote file'
show 9 replies
derrizlast Sunday at 11:06 AM

I feel that the ergonomics of bash completion took a hit as the configurations got “smarter” and “helpfully” started blocking file or directory name completion if it thinks it wouldn’t be appropriate to have a file name at the current cursor position. Instead of blocking, the default should always be to fall back to filename completion.

Sometimes I’m close to disabling/uninstalling all completion scripts out of irritation as decades of muscle memory are frustrated by this behavior.

It’s like that bad/annoying UX with text fields where the UI is constantly fighting against you in order prevent you from producing “illegal” intermediate input - e.g. let me paste the clipboard here goddammit - I know what I’m doing - I’ll correct it.

show 5 replies
lihaoyilast Sunday at 10:21 AM

I wrote this, hope everyone finds it as interesting reading this as I did figuring this out for the first time!

show 3 replies
paradox460last Sunday at 7:14 PM

I've started using jdx's usage[1] for my clis. It integrates neatly into clap, and can be used stand alone in scripts. It can generate completions, argparse, manpages, and more

I'm still on the fence if replacing the argparse blocks in my fish scripts is worth the hassle, but against things like old school optparse, it's far better

[1]: https://usage.jdx.dev/

show 1 reply
medvlast Sunday at 12:36 PM

JSON fields autocomplete right in bash/zsh: https://fx.wtf/install#autocomplete

show 1 reply
oezilast Sunday at 10:22 AM

Isn't there a standard flag which programs can implement to avoid writing this bash script?

Ideally this could all be part of a library such as argparse for typical cases, right?

show 3 replies
VagabundoPlast Monday at 11:54 AM

zsh standard tab completion drives me batty. But I come from bash where 99% of the time I just want filename completion.

vcdimensionlast Sunday at 10:31 AM

Here's another tutorial for creating zsh completers using the built-in functions: https://github.com/vapniks/zsh-completions/blob/master/zsh-c...

sebtronlast Sunday at 1:16 PM

Basic completion in ksh is as easy as defining an array. From https://man.openbsd.org/ksh :

Custom completions may be configured by creating an array named ‘complete_command’, optionally suffixed with an argument number to complete only for a single argument. So defining an array named ‘complete_kill’ provides possible completions for any argument to the kill(1) command, but ‘complete_kill_1’ only completes the first argument. For example, the following command makes ksh offer a selection of signal names for the first argument to kill(1):

    set -A complete_kill_1 -- -9 -HUP -INFO -KILL -TERM
show 1 reply
vismit2000last Monday at 4:37 AM

Since auto text completion is the primary task of an LLM, I have seen GitHub copilot do that very well on both bash and zsh within vscode terminal!

vbezhenarlast Sunday at 11:51 AM

Here's zsh snippet I've came up with for my own simple functions. I'm using it as a base for other completions. In this example, function `set-java-home zulu-21` sets JAVA_HOME to `~/apps/java/zulu-21`. Here's `_set-java-home`:

    #compdef set-java-home
    
    local -a versions=(~/apps/java/*(:t))
    _describe 'version' versions
So basically almost a one-liner (but couldn't do it really one-liner, unfortunately).
bravesoul2last Sunday at 10:26 AM

Do many people do bash on osx or zsh on Linux, and would this make much of a difference?

show 3 replies
harimurtilast Sunday at 1:12 PM

I’m not familiar with `_gnu_generic`, but it sounds like a handy shortcut for basic completions without writing a full script. Does it work with commands that only have `--help` but no man pages?

camdroidwlast Sunday at 10:43 AM

Why doesn't someone (not me) just build a basic DSL and a transpiler that does this?

show 2 replies
gosub100last Sunday at 6:43 PM

I did something similar to this for tab-completing server names for use with ssh. I went a step further and allowed pattern matching based on the server being qa/prod and on locale. so for instance you could type `ssh co prod <tab>` and it would tab-complete / suggest any servers that were production and located in the Denver datacenter (co is the state abbrev for Colorado, for non-US readers).

Unfortunately my work doesn't allow me to share code, but essentially I remapped ssh to a bash script that maintains an environment variable containing the args (you must do this because each <tab> press is an independent invocation of the script. Then you run into persistence problems, so I added a call to compute elapsed seconds so that it flushes the state variable after a 10s timeout).

The bash script then forwards the args to a python script that reads a JSON file and figures out which params (such as 'co' or 'qa') map to which hostnames. It also matches against partial hostnames, so when you see this after tab

qa-server-co1 qa-server-co2 pr-server-co3

you only need to add '3' to the list of args to narrow it down to 1 match, then hit <enter> to ssh to that host.

xenophonflast Sunday at 1:09 PM

I wish tcsh would get more love.

show 2 replies
wiseowiselast Sunday at 10:33 AM

Shell syntax is the exact reason why we've needed LLMs in the first place.

show 2 replies