I’ve been working on a simple library to automatically generate shell completion files from spec for the Arg module.
I’ve been having trouble figuring out how to properly install these completions script in an opam package once they are built.
I can have install completion script somewhere in $OPAM_SWITCH_PREFIX/share/<pkg_name>/... but they wouldn’t be sourced by the user’s shell.
The only package I could find implementing any kind of shell completion is opam itself, and they are doing it by directly sourcing the completion file from opam-init/init.sh. I don’t think I should be modifying any opam file as my package is installed.
The only way I thought that could resolve this problem is by doing an executable similar to opam-user-setup that would modify the user .bashrc or .zshrc and add a line to source a custom script that would in turn source all completion script for the current opam switch. It seems like a complicated way of solving an issue like this, but relying on the user to manually source every single completion file also doesn’t feel quite right.
Would there be any cleaner way to implement this? Does any opam package implement shell completion in a clean way?
I used to leverage the language-specific build tool for many diverse tasks in the past since the build tool is what I used the most, and I don’t really want to learn anything else.
But I tend to realise that doing stuff outside of “resolving language-specific dependencies” and “compiling my package” is probably better be done in some OS package manager (apt, brew, etc.). Otherwise, you’ll end up duplicating all their work in your language build tool
For example, if your tool can output the proper shell completion script to stdout, then installing completion is just a matter of putting smth like below in your .bashrc:
Does your shell source completions installed in $HOME/.local/share? If so, I imagine an appropriate install stanza in the dune file should be able to put it there.
I don’t think this would solve the issue. Installing in $HOME/.local/share would first mean that i would loose the ability to have different completion file depending on the version of the program that is being used by the current opam switch.
My question was mostly about where should I put it if i want the user to be able to use it with the less effort possible, so by knowing if opam has a way of sourcing those completion file automatically.
I don’t know if the completion in stdout in the .bashrc is the better solution for this particular problem but I do agree about everything you said. The only thing is that we do have executables that are only available in opam, and that for those packages some of these edge cases can make sense.
For my particular problem, maybe I should consider proposing the completion files in the opam package but only installing them if installed through an OS package manager.
The closest I could get to a bash-completions FAQ says, in relation to the question “Where should I install my own local completions”:
Put them in the completions subdir of $BASH_COMPLETION_USER_DIR (defaults to $XDG_DATA_HOME/bash-completion or ~/.local/share/bash-completion if $XDG_DATA_HOME is not set) to have them loaded automatically on demand when the respective command is being completed. See also the next question’s answer for considerations for these files’ names, they apply here as well. Alternatively, you can write them directly in ~/.bash_completion which is loaded eagerly by our main script.
Unfortunately, whether BASH_COMPLETION_USER_DIR is set may be distro-specific. Mine does not set it so $HOME/.local/share/bash-completion/completions works. On reflection, maybe $HOME/.bash_completion is a better bet, but that is not in use in my distro.
XDG_DATA_DIRS (or the system directories /usr/local/share:/usr/share if empty). The subdirectory bash-completion/completions of each paths in XDG_DATA_DIRS separated by colons is considered.
Perhaps you could stick a directory on that, as part of opam env setup ?
Slightly off-topic, but still related and possibly of interest: I have a library called arg-complete. But I think the two are somewhat complementary:
Yours generates shell completion scripts for standard Arg specifications.
Mine allows dynamic completions for an extension of Arg specifications, e.g. also completing the values for arguments. But I haven’t automated the shell completion script itself, only manually written one to ask the program to complete its arguments via a special --complete (or whatever) argument.