# Installing shell completion file in an opam package

**URL:** <https://discuss.ocaml.org/t/installing-shell-completion-file-in-an-opam-package/13540>\
**Category:** Learning\
**Tags:** opam, dune\
**Created:** [November 30, 2023, 9:14pm UTC](https://discuss.ocaml.org/t/installing-shell-completion-file-in-an-opam-package/13540 "2023-11-30T21:14:23Z")\
**Posts on this page:** 11\
**Page:** 1

<div class="post-metadata">

**Author:** ![Gurvan](https://sea2.discourse-cdn.com/flex020/user_avatar/discuss.ocaml.org/gurvan/32/4756_2.png) [@Gurvan](https://discuss.ocaml.org/u/Gurvan)\
**Post date:** [November 30, 2023, 9:14pm UTC](https://discuss.ocaml.org/t/installing-shell-completion-file-in-an-opam-package/13540/1 "2023-11-30T21:14:23Z")

</div>

I’ve been working on a [simple library](https://codeberg.org/gurvan/argsh) 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?

---

<div class="post-metadata">

**Author:** ![chshersh](https://sea2.discourse-cdn.com/flex020/user_avatar/discuss.ocaml.org/chshersh/32/4964_2.png) [@chshersh](https://discuss.ocaml.org/u/chshersh)\
**Post date:** [December 1, 2023, 12:05pm UTC](https://discuss.ocaml.org/t/installing-shell-completion-file-in-an-opam-package/13540/2 "2023-12-01T12:05:36Z")

</div>

(Sorry, not an answer to your question)

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`:

```bash
eval "$(my_tool --bash-completion-script)"

```

---

<div class="post-metadata">

**Author:** ![cvine](https://avatars.discourse-cdn.com/v4/letter/c/90db22/32.png) [@cvine](https://discuss.ocaml.org/u/cvine)\
**Post date:** [December 1, 2023, 12:07pm UTC](https://discuss.ocaml.org/t/installing-shell-completion-file-in-an-opam-package/13540/3 "2023-12-01T12:07:40Z")

</div>

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.

---

<div class="post-metadata">

**Author:** ![Gurvan](https://sea2.discourse-cdn.com/flex020/user_avatar/discuss.ocaml.org/gurvan/32/4756_2.png) [@Gurvan](https://discuss.ocaml.org/u/Gurvan)\
**Post date:** [December 1, 2023, 4:38pm UTC](https://discuss.ocaml.org/t/installing-shell-completion-file-in-an-opam-package/13540/4 "2023-12-01T16:38:29Z")

</div>

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.

---

<div class="post-metadata">

**Author:** ![Gurvan](https://sea2.discourse-cdn.com/flex020/user_avatar/discuss.ocaml.org/gurvan/32/4756_2.png) [@Gurvan](https://discuss.ocaml.org/u/Gurvan)\
**Post date:** [December 1, 2023, 4:46pm UTC](https://discuss.ocaml.org/t/installing-shell-completion-file-in-an-opam-package/13540/5 "2023-12-01T16:46:44Z")

</div>

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.

---

<div class="post-metadata">

**Author:** ![Chet\_Murthy](https://sea2.discourse-cdn.com/flex020/user_avatar/discuss.ocaml.org/chet_murthy/32/1501_2.png) [@Chet\_Murthy](https://discuss.ocaml.org/u/Chet_Murthy)\
**Post date:** [December 1, 2023, 5:54pm UTC](https://discuss.ocaml.org/t/installing-shell-completion-file-in-an-opam-package/13540/6 "2023-12-01T17:54:28Z")

</div>

Can you point to where one might learn about this? I didn’t realize that bash could pick up completions from that directory.

---

<div class="post-metadata">

**Author:** ![cvine](https://avatars.discourse-cdn.com/v4/letter/c/90db22/32.png) [@cvine](https://discuss.ocaml.org/u/cvine)\
**Post date:** [December 1, 2023, 6:42pm UTC](https://discuss.ocaml.org/t/installing-shell-completion-file-in-an-opam-package/13540/7 "2023-12-01T18:42:42Z")

</div>

The closest I could get to a bash-completions [FAQ](https://github.com/scop/bash-completion#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.

---

<div class="post-metadata">

**Author:** ![Chet\_Murthy](https://sea2.discourse-cdn.com/flex020/user_avatar/discuss.ocaml.org/chet_murthy/32/1501_2.png) [@Chet\_Murthy](https://discuss.ocaml.org/u/Chet_Murthy)\
**Post date:** [December 1, 2023, 6:59pm UTC](https://discuss.ocaml.org/t/installing-shell-completion-file-in-an-opam-package/13540/8 "2023-12-01T18:59:49Z")

</div>

Hmmm … I see

> 1. `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 ?

---

<div class="post-metadata">

**Author:** ![sim642](https://sea2.discourse-cdn.com/flex020/user_avatar/discuss.ocaml.org/sim642/32/3597_2.png) [@sim642](https://discuss.ocaml.org/u/sim642)\
**Post date:** [December 2, 2023, 10:17am UTC](https://discuss.ocaml.org/t/installing-shell-completion-file-in-an-opam-package/13540/9 "2023-12-02T10:17:35Z")

</div>

Slightly off-topic, but still related and possibly of interest: I have a library called [arg-complete](https://github.com/sim642/ocaml-arg-complete). But I think the two are somewhat complementary:

1. Yours generates shell completion scripts for standard `Arg` specifications.
2. 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.

---

<div class="post-metadata">

**Author:** ![dbuenzli](https://sea2.discourse-cdn.com/flex020/user_avatar/discuss.ocaml.org/dbuenzli/32/18_2.png) [@dbuenzli](https://discuss.ocaml.org/u/dbuenzli)\
**Post date:** [March 18, 2025, 8:53pm UTC](https://discuss.ocaml.org/t/installing-shell-completion-file-in-an-opam-package/13540/10 "2025-03-18T20:53:26Z")

</div>

This looks like an unsolved problem at the moment.

> [@chshersh](#):
>
> 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`:
> 
> ```auto
> eval "$(my_tool --bash-completion-script)"
> 
> ```

That’s a bit annoying though. It’s one more operation to perform after an `opam install` and cruft that will remain even if you uninstall the tool.

> [@Gurvan](#):
>
> Would there be any cleaner way to implement this? Does any opam package implement shell completion in a clean way?

Following on the idea that `opam` is just a package manager that handles a unix prefix. I think opam packages should simply install shell completions scripts where shell expect them – this will also make it easier for system packagers to transform your opam package into a system one.

Taking a cue from how [brew](https://docs.brew.sh/Shell-Completion)/debian handle this, this seems to be something like

- For zsh, `$OPAM_SWITCH_PREFIX/share/zsh/site-functions/`
- For bash, `$OPAM_SWITCH_PREFIX/share/bash-completions/completions/`
- For fish, `$OPAM_SWITCH_PREFIX/share/fish/completions/`

Now since opam is already in charge of doing shell-dependent business shouldn’t perhaps the `.opam/opam-init/*` scripts make sure the shell looks up for completion in these directories (e.g. for `zsh` this involves adding the directory to the `fpath` environment variable) ?

---

<div class="post-metadata">

**Author:** ![dbuenzli](https://sea2.discourse-cdn.com/flex020/user_avatar/discuss.ocaml.org/dbuenzli/32/18_2.png) [@dbuenzli](https://discuss.ocaml.org/u/dbuenzli)\
**Post date:** [March 20, 2025, 10:34pm UTC](https://discuss.ocaml.org/t/installing-shell-completion-file-in-an-opam-package/13540/11 "2025-03-20T22:34:13Z")

</div>

I [opened](https://github.com/ocaml/opam/issues/6427) an issue upstream to see what `opam` devs think about that.
