CLI: enable Fish completion

Michael Muré created

Change summary

.gitignore                   |   2 
git-bug.go                   |   1 
misc/fish_completion/git-bug | 137 ++++++++++++++++++++++++++++++++++++++
misc/gen_fish_completion.go  |  24 ++++++
4 files changed, 164 insertions(+)

Detailed changes

.gitignore 🔗

@@ -1,5 +1,7 @@
 git-bug
 !/misc/bash_completion/git-bug
+!/misc/fish_completion/git-bug
+!/misc/powershell_completion/git-bug
 !/misc/zsh_completion/git-bug
 .gitkeep
 dist

git-bug.go 🔗

@@ -1,6 +1,7 @@
 //go:generate go run doc/gen_markdown.go
 //go:generate go run doc/gen_manpage.go
 //go:generate go run misc/gen_bash_completion.go
+//go:generate go run misc/gen_fish_completion.go
 //go:generate go run misc/gen_powershell_completion.go
 //go:generate go run misc/gen_zsh_completion.go
 

misc/fish_completion/git-bug 🔗

@@ -0,0 +1,137 @@
+# fish completion for git-bug                              -*- shell-script -*-
+
+function __git-bug_debug
+    set file "$BASH_COMP_DEBUG_FILE"
+    if test -n "$file"
+        echo "$argv" >> $file
+    end
+end
+
+function __git-bug_perform_completion
+    __git-bug_debug "Starting __git-bug_perform_completion with: $argv"
+
+    set args (string split -- " " "$argv")
+    set lastArg "$args[-1]"
+
+    __git-bug_debug "args: $args"
+    __git-bug_debug "last arg: $lastArg"
+
+    set emptyArg ""
+    if test -z "$lastArg"
+        __git-bug_debug "Setting emptyArg"
+        set emptyArg \"\"
+    end
+    __git-bug_debug "emptyArg: $emptyArg"
+
+    set requestComp "$args[1] __complete $args[2..-1] $emptyArg"
+    __git-bug_debug "Calling $requestComp"
+
+    set results (eval $requestComp 2> /dev/null)
+    set comps $results[1..-2]
+    set directiveLine $results[-1]
+
+    # For Fish, when completing a flag with an = (e.g., <program> -n=<TAB>)
+    # completions must be prefixed with the flag
+    set flagPrefix (string match -r -- '-.*=' "$lastArg")
+
+    __git-bug_debug "Comps: $comps"
+    __git-bug_debug "DirectiveLine: $directiveLine"
+    __git-bug_debug "flagPrefix: $flagPrefix"
+
+    for comp in $comps
+        printf "%s%s\n" "$flagPrefix" "$comp"
+    end
+
+    printf "%s\n" "$directiveLine"
+end
+
+# This function does three things:
+# 1- Obtain the completions and store them in the global __git-bug_comp_results
+# 2- Set the __git-bug_comp_do_file_comp flag if file completion should be performed
+#    and unset it otherwise
+# 3- Return true if the completion results are not empty
+function __git-bug_prepare_completions
+    # Start fresh
+    set --erase __git-bug_comp_do_file_comp
+    set --erase __git-bug_comp_results
+
+    # Check if the command-line is already provided.  This is useful for testing.
+    if not set --query __git-bug_comp_commandLine
+        set __git-bug_comp_commandLine (commandline)
+    end
+    __git-bug_debug "commandLine is: $__git-bug_comp_commandLine"
+
+    set results (__git-bug_perform_completion "$__git-bug_comp_commandLine")
+    set --erase __git-bug_comp_commandLine
+    __git-bug_debug "Completion results: $results"
+
+    if test -z "$results"
+        __git-bug_debug "No completion, probably due to a failure"
+        # Might as well do file completion, in case it helps
+        set --global __git-bug_comp_do_file_comp 1
+        return 0
+    end
+
+    set directive (string sub --start 2 $results[-1])
+    set --global __git-bug_comp_results $results[1..-2]
+
+    __git-bug_debug "Completions are: $__git-bug_comp_results"
+    __git-bug_debug "Directive is: $directive"
+
+    if test -z "$directive"
+        set directive 0
+    end
+
+    set compErr (math (math --scale 0 $directive / 1) % 2)
+    if test $compErr -eq 1
+        __git-bug_debug "Received error directive: aborting."
+        # Might as well do file completion, in case it helps
+        set --global __git-bug_comp_do_file_comp 1
+        return 0
+    end
+
+    set nospace (math (math --scale 0 $directive / 2) % 2)
+    set nofiles (math (math --scale 0 $directive / 4) % 2)
+
+    __git-bug_debug "nospace: $nospace, nofiles: $nofiles"
+
+    # Important not to quote the variable for count to work
+    set numComps (count $__git-bug_comp_results)
+    __git-bug_debug "numComps: $numComps"
+
+    if test $numComps -eq 1; and test $nospace -ne 0
+        # To support the "nospace" directive we trick the shell
+        # by outputting an extra, longer completion.
+        __git-bug_debug "Adding second completion to perform nospace directive"
+        set --append __git-bug_comp_results $__git-bug_comp_results[1].
+    end
+
+    if test $numComps -eq 0; and test $nofiles -eq 0
+        __git-bug_debug "Requesting file completion"
+        set --global __git-bug_comp_do_file_comp 1
+    end
+
+    # If we don't want file completion, we must return true even if there
+    # are no completions found.  This is because fish will perform the last
+    # completion command, even if its condition is false, if no other
+    # completion command was triggered
+    return (not set --query __git-bug_comp_do_file_comp)
+end
+
+# Remove any pre-existing completions for the program since we will be handling all of them
+# TODO this cleanup is not sufficient.  Fish completions are only loaded once the user triggers
+# them, so the below deletion will not work as it is run too early.  What else can we do?
+complete -c git-bug -e
+
+# The order in which the below two lines are defined is very important so that __git-bug_prepare_completions
+# is called first.  It is __git-bug_prepare_completions that sets up the __git-bug_comp_do_file_comp variable.
+#
+# This completion will be run second as complete commands are added FILO.
+# It triggers file completion choices when __git-bug_comp_do_file_comp is set.
+complete -c git-bug -n 'set --query __git-bug_comp_do_file_comp'
+
+# This completion will be run first as complete commands are added FILO.
+# The call to __git-bug_prepare_completions will setup both __git-bug_comp_results abd __git-bug_comp_do_file_comp.
+# It provides the program's completion choices.
+complete -c git-bug -n '__git-bug_prepare_completions' -f -a '$__git-bug_comp_results'
+

misc/gen_fish_completion.go 🔗

@@ -0,0 +1,24 @@
+// +build ignore
+
+package main
+
+import (
+	"fmt"
+	"log"
+	"os"
+	"path"
+
+	"github.com/MichaelMure/git-bug/commands"
+)
+
+func main() {
+	cwd, _ := os.Getwd()
+	dir := path.Join(cwd, "misc", "fish_completion", "git-bug")
+
+	fmt.Println("Generating Fish completion file ...")
+
+	err := commands.RootCmd.GenFishCompletionFile(dir, true)
+	if err != nil {
+		log.Fatal(err)
+	}
+}