4

I have two separate scripts with the same filename, in different paths, for different projects: /home/me/projects/alpha/bin/hithere and /home/me/projects/beta/bin/hithere.

Correspondingly, I have two separate bash completion scripts, because the proper completions differ for each of the scripts. In the completion scripts, the "complete" command is run for each completion specifying the full name of the script in question, i.e.

complete -F _alpha_hithere_completion /home/me/projects/alpha/bin/hithere

However, only the most-recently-run script seems to have an effect, regardless of which actual version of hithere is invoked: it seems that bash completion only cares about the filename of the command and disregards path information.

Is there any way to change this behavior so that I can have these two independent scripts with the same name, each with different completion functions?

Please note that I'm not interested in a solution which requires alpha to know about beta, or which would require a third component to know about either of them--that would defeat the purpose in my case.

Jeremy
  • 1,049
  • 1
  • 15
  • 28
  • Off the wall nonsense, but perhaps you could have a callback-style meta-completion function that you could register individual commands with, and then route to the appropriate completion function dynamically? – dimo414 Jun 01 '17 at 05:57
  • Unfortunately this wouldn't suit the constraints in practice; the two need to be independent and to not rely on a third component. – Jeremy Jun 01 '17 at 10:04
  • 1
    Can the "third component" simply be bundled in with each of the `complete` scripts, so it's not really separate? You could [inspect](https://superuser.com/q/947065/16275) the current completion function and either add to the callback or install it depending on whether it exists or not. That would allow the scripts to install independently while still hooking into each other's completions when possible. – dimo414 Jun 01 '17 at 16:19
  • I appreciate you're looking for a built-in solution that doesn't involve something like this, but assuming that doesn't exist (no idea) that's the direction I'd go. Everyone loves callbacks ;) – dimo414 Jun 01 '17 at 16:20
  • I haven't been able to replicate your experience that `complete -F _alpha_hithere_completion /home/me/projects/alpha/bin/hithere` is also used for `hithere` - what do you see if you run `complete -p hithere` and `complete -p | grep hithere`? – dimo414 Jun 01 '17 at 21:25
  • I see the exact two ```complete``` invocations originally provided. And yeah, having a dynamically-patchable third component would be a cool solution except for the hard/painful parts, including keeping the patching mechanism synced over time and figuring out enough bash to write it in the first place! – Jeremy Jun 02 '17 at 00:03
  • I don't actually think a callback mechanism would be *all* that complicated ;) basically just call `mycallback _alpha_foo /path/to/alpha/foo` and have `mycallback invoke `complete` with a function that delegates to `_alpha_foo` when appropriate. The details might be a little messy, but honestly shouldn't be that bad. – dimo414 Jun 02 '17 at 00:42
  • I'm sure it's doable but would definitely exceed my time budget at this point. (And I might spend that time looking at the bash source to try to build a patch instead ;)) – Jeremy Jun 02 '17 at 22:02

2 Answers2

3

The Bash manual describes the lookup process for completions:

If the command word is a full pathname, a compspec for the full pathname is searched for first. If no compspec is found for the full pathname, an attempt is made to find a compspec for the portion following the final slash. If those searches do not result in a compspec, any compspec defined with the -D option to complete is used as the default.

So the full path is used by complete, but only if you invoke the command via its full path. As for getting completions to work using just the short name, I think your only option (judging from the spec) is going to be some sort of dynamic hook that determines which completion function to invoke based on the $PWD - I don't see any evidence that Bash supports overloading a completion name like you're envisioning.

dimo414
  • 47,227
  • 18
  • 148
  • 244
  • Based on this I think there is a bug in my version of bash, because invoking with the full pathname still shows completions from only one of the two projects, no matter which one is actually being invoked. – Jeremy Jun 02 '17 at 00:04
  • What's your `bash -version`? I'm running `4.3.11` at the moment. – dimo414 Jun 02 '17 at 00:39
  • I get ```GNU bash, version 4.4.7(1)-release (x86_64-pc-linux-gnu)``` – Jeremy Jun 02 '17 at 22:00
0

Yes, this is possible. But it's a bit tricky. I am using this for a future scripting concept I am developing: All scripts have the same name as they are build scripts, but still bash completion can do its job.

For this I use a two step process: First of all I place a main script in ~/.config/bash_completion.d. This script is designed to cover all scripts of the particular shared script name. I configured ~/.bashrc in order to load that bash completion file for these scripts.

The script will obtain the full file path of the particular script file I want to have bash completion for. From this path I generate an identifier. For this identifier there exists a file that provides actual bash completion data. So if bash completion is performed the bash completion function from the main bash completion script will check for that file and load it's content. Then it will continue with regular bash completion operation.

If you have two scripts with the same name you will have two different identifiers as those scripts share the same name but have different paths. Therefore two different configurations for bash completion can be used.

This concept works like a charm.


NOTE: I will update this answer soon providing some source code.

Regis May
  • 3,070
  • 2
  • 30
  • 51