From b202954d6c6598084bb4bec4062869f1cf5af26d Mon Sep 17 00:00:00 2001
From: Hyunho Cho <mug896@gmail.com>
Date: Sat, 13 Aug 2022 23:37:18 +0900
Subject: [PATCH 1/2] misc: Improve bash-completion.sh behavior

Resolved issues with the current bash-completion.sh script:
1. Options are now properly listed, starting with "-" or "--".
2. Files from the current directory and subcommands are no longer
   incorrectly included in the completion listing.

Fixed: #873

Signed-off-by: Hyunho Cho <mug896@gmail.com>
Signed-off-by: Kang Minchul <tegongkang@gmail.com>
---
 misc/bash-completion.sh | 87 ++++++++++++++++++++++++++---------------
 1 file changed, 55 insertions(+), 32 deletions(-)

diff --git a/misc/bash-completion.sh b/misc/bash-completion.sh
index 236d44669..2d1fb134b 100644
--- a/misc/bash-completion.sh
+++ b/misc/bash-completion.sh
@@ -1,35 +1,58 @@
-_uftrace () {
-    local cur prev subcmds options uftrace_comp
+_uftrace()
+{
+    local CMD=${COMP_WORDS[0]}
+    local CUR=${COMP_WORDS[COMP_CWORD]}
+    local PREV=${COMP_WORDS[COMP_CWORD - 1]}
+    [[ $PREV = "=" ]] && PREV=${COMP_WORDS[COMP_CWORD-2]}
+    local IFS=$' \t\n' WORDS OPTS=() OPT1=() OPT2=() TMP i
+    local COMP_LINE2=${COMP_LINE:0:$COMP_POINT}
+    [[ ${COMP_LINE2: -1} = " " && -n $CUR ]] && CUR=""
 
-    cur=${COMP_WORDS[COMP_CWORD]}
-    prev=${COMP_WORDS[COMP_CWORD - 1]}
+    IFS=$'\n'
+    for TMP in $( $CMD --help | sed -En '/^\s+-/{ s/^\s{,10}((-\w),?\s)?(--[[:alnum:]-]+=?)?.*/ \2 \3/p }')
+    do
+        if [[ $TMP =~ "=" ]]; then
+            TMP=${TMP/=/} OPT1+=( ${TMP// /$'\n'} )
+        else
+            OPT2+=( ${TMP// /$'\n'} )
+        fi
+    done
+    unset IFS
 
-    COMPREPLY=()
-
-    subcmds='record replay report live dump graph info recv script tui'
-    options=$(uftrace -h | awk '$1 ~ /--[a-z]/ { split($1, r, "="); print r[1] } \
-                                $2 ~ /--[a-z]/ { split($2, r, "="); print r[1] }')
-    demangle='full simple no'
-    sort_key='total self call avg min max'
-
-    uftrace_comp="${subcmds} ${options}"
-
-    case $prev in
-	-d|--data|--diff|-L|--libmcount-path)
-	    # complete directory name
-	    COMPREPLY=($(compgen -d -- "${cur}"))
-	    ;;
-	--demangle)
-	    COMPREPLY=($(compgen -W "${demangle}" -- "${cur}"))
-	    ;;
-	-s|--sort)
-	    COMPREPLY=($(compgen -W "${sort_key}" -- "${cur}"))
-	    ;;
-	*)
-	    # complete subcommand, long option or (executable) filename
-	    COMPREPLY=($(compgen -f -W "${uftrace_comp}" -- "${cur}"))
-	    ;;
-    esac
-    return 0
+    OPTS=( "${OPT1[@]}" "${OPT2[@]}" )
+    if [[ $CUR =~ ^-- ]]; then
+        WORDS=${OPTS[@]/#-[^-]*/}
+    elif [[ $CUR =~ ^- ]]; then
+        WORDS=${OPTS[@]/#--*/}" -?"
+    else
+        if [[ $PREV = @(-d|--data|--diff|-L|--libmcount-path) ]]; then
+	        COMPREPLY=( $(compgen -d -- "$CUR") )
+            return
+        elif [[ $PREV = --color ]]; then
+            WORDS="yes no auto"
+        elif [[ $PREV = --demangle ]]; then
+            WORDS="full simple no"
+        elif [[ $PREV = --match ]]; then
+            WORDS="regex glob"
+        elif [[ $PREV = @(-s|--sort) ]]; then
+            WORDS="total self call avg min max"
+        else
+            WORDS="record replay live report info dump recv graph script tui"
+            if printf '%s\n' "${OPT1[@]}" | grep -xq -- "$PREV" ||
+                [[ $PREV = @(,|@) ]] || [[ $CUR = @(,|@) ]]; then
+                WORDS=""
+            else
+                for (( i = 1; i < ${#COMP_WORDS[@]}; i++ )); do
+                    for TMP in $WORDS; do
+                        [[ ${COMP_WORDS[i]} = $TMP ]] && WORDS=""
+                    done
+                done
+            fi
+        fi
+    fi
+    [[ $CUR = "=" ]] && CUR=""
+    COMPREPLY=( $(compgen -W "$WORDS" -- "$CUR") )
+    [ "${COMPREPLY: -1}" = "=" ] && compopt -o nospace
 }
-complete -o filenames -F _uftrace uftrace
+
+complete -o default -o bashdefault -F _uftrace uftrace

From 7a26665fb217be836f477e7eeb58eeff6353beff Mon Sep 17 00:00:00 2001
From: Kang Minchul <tegongkang@gmail.com>
Date: Mon, 23 Sep 2024 13:35:11 +0900
Subject: [PATCH 2/2] build: Amend path handling for bash completion

Adjusted the `configure` script for improved quoting and proper handling of
bash completion directory based on `pkg-config` detection.

The recommended directory is completionsdir,
which can be obtained like below [1]:

  $ pkg-config --variable=completionsdir bash-completion

[1] https://github.com/scop/bash-completion#faq

Signed-off-by: Kang Minchul <tegongkang@gmail.com>
---
 Makefile  |  2 +-
 configure | 12 ++++++++++++
 2 files changed, 13 insertions(+), 1 deletion(-)

diff --git a/Makefile b/Makefile
index c78e7201e..8889d77dd 100644
--- a/Makefile
+++ b/Makefile
@@ -31,7 +31,7 @@ libdir = $(prefix)/lib/uftrace
 etcdir = $(prefix)/etc
 mandir = $(prefix)/share/man
 docdir = $(srcdir)/doc
-completiondir = $(etcdir)/bash_completion.d
+completiondir = $(compldir)
 
 ifeq ($(DOCLANG), ko)
   docdir = $(srcdir)/doc/ko
diff --git a/configure b/configure
index fe48e6305..86561386f 100755
--- a/configure
+++ b/configure
@@ -146,6 +146,17 @@ libdir=${libdir:-${prefix}/lib/uftrace}
 etcdir=${etcdir:-${prefix}/etc}
 mandir=${mandir:-${prefix}/share/man}
 
+if [ -z "$compldir" ]; then
+    if command -v pkg-config >/dev/null 2>&1 && pkg-config --exists bash-completion; then
+        compldir=$(pkg-config --variable=completionsdir bash-completion)
+        if [[ "$compldir" == /usr/share/* ]] && [ "$prefix" != "/usr" ]; then
+            compldir="${prefix}/share/bash-completion/completions"
+        fi
+    else
+        compldir=${prefix}/share/bash-completion/completions
+    fi
+fi
+
 if [ "$etcdir" = /usr/etc ]; then
     etcdir=/etc
 fi
@@ -280,6 +291,7 @@ override bindir := $bindir
 override libdir := $libdir
 override mandir := $mandir
 override etcdir := $etcdir
+override compldir := $compldir
 EOF
 
 if [ ! -z $with_elfutils ]; then