Skip to content

Conversation

@ubunatic
Copy link

@ubunatic ubunatic commented Nov 1, 2025

User description

Changes

  • rewrote Makefile scraping to extract targets and vars, incl. descriptions
  • added support for include files
  • tracking tab presses to display target description on multiple key presses

Usage

  • Press Tab once to complete targets
  • Press Tab twice to see target descriptions

Example

Makefile Structure:

  Makefile
  ├── scripts
  │   ├── ai.mk
  │   └── ...

Makefile content:

include scripts/usage.mk
include scripts/ai.mk
include scripts/go.mk

Included content:

## AI-related tasks
.PHONY: ⚙️  # make all non-file targets phony

ai-init: ⚙️  ## Initialize AI environment
   @echo "Setting up AI environment..."

ai-files: ⚙️  ## Ensure AI agent files match provider-recommended structure
   @echo "Checking AI agent files..."

# ... other targets ...

Example Output:
1st <tab> press on query "ai"

17:52:16 user@machine myrepo ±|main ✗|→ make ai

ai_chat=        ai-files        ai-init         ai-review       ai-tech-only    ai-update-docs  
17:52:16 user@machine myrepo ±|main ✗|→ make ai

2nd <tab> press on query "ai"

17:52:16 user@machine myrepo ±|main ✗|→ make ai░
--Makefile--
--scripts/usage.mk--
--scripts/ai.mk--
   ai-init                Initialize AI environment
   ai-files               Ensure AI agent files match provider-recommended structure
   ai-review              Use AI to review recent changes in the repository
   ai-tech-only           Use AI to identify and remove of non-technical content
   ai-update-docs         Use AI to update documentation based on code changes
   ai_chat=code chat
--scripts/go.mk--

ai_chat=        ai-files        ai-init         ai-review       ai-tech-only    ai-update-docs  
17:52:17 user@machine myrepo ±|main ✗|→ make ai

Approach

  • scrape *makefile
    • find include files
  • scrape all discovered files
    • find targets + descs
    • find variables + descs
    • filter for completion query
  • provide simple completions on first <tab>
  • provide targets usage info on consecutive <tab>
  • reset <tab> tracking after 10s

Technologies

  • use awk where possible
  • use _omb_term_* colors
  • use grep, echo, sort, uniq
  • do not use make, since this can have side effects

Tests

Tested on two multi-file Makefile projects with include files. \

OS: Ubuntu LTS 2024
Arch: AMD64
Bash: GNU bash, version 5.2.21(1)-release (x86_64-pc-linux-gnu)

Tests:

  • make <tab> -> shows short list
  • make <tab> <tab> -> shows extracted, colored usage info
  • make unknown <tab> -> does not show anything and does not break the prompt
  • make partial <tab> -> shows short list for partial*
  • make partial <tab> <tab> -> shows usage for partial*
  • make var_ <tab> -> shows vars and targets VAR_* or var_*
  • make var_ <tab> <tab> -> shows vars and targets and usage
  • make var_ab <tab> (1 match) -> completes and does not break prompt
  • make - <tab> shows common make flags
  • make - <tab> <tab> shows common make flags and usage info (incl. --help to indicate further help)
  • make --<flag> <tab> shows long and short flag
  • make --<flag> <tab> <tab> shows long and short flag and usage

PR Type

Enhancement


Description

  • Rewrote makefile completion to extract targets, variables, and descriptions

  • Added support for included .mk files with recursive discovery

  • Implemented tab press tracking to show descriptions on repeated Tab presses

  • Added colorized output using terminal color variables for better readability

  • Replaced simple regex with comprehensive AWK-based parsing for robust extraction


Diagram Walkthrough

flowchart LR
  A["Makefile Query"] --> B["Find Includes"]
  B --> C["Parse Targets & Vars"]
  C --> D["Filter by Query"]
  D --> E["Tab Press 1"]
  E --> F["Show Completions"]
  D --> G["Tab Press 2+"]
  G --> H["Show Descriptions"]
  H --> I["Colorized Output"]
Loading

File Walkthrough

Relevant files
Enhancement
makefile.completion.sh
Complete rewrite of makefile completion with descriptions

completions/makefile.completion.sh

  • Replaced single-line complete command with comprehensive 370-line
    completion module
  • Added helper functions to discover included makefiles and parse
    targets/variables
  • Implemented tab press counter to toggle between simple completions and
    detailed descriptions
  • Added colorized output formatting using _omb_term_* color variables
  • Included extensive documentation with usage examples and bash style
    guidelines
  • Added support for make flags (-h, -B, -n, -C, -f, -E) with
    descriptions
+369/-3 

@qodo-free-for-open-source-projects
Copy link

qodo-free-for-open-source-projects bot commented Nov 1, 2025

PR Compliance Guide 🔍

Below is a summary of compliance checks for this PR:

Security Compliance
🟢
No security concerns identified No security vulnerabilities detected by AI analysis. Human verification advised for critical code.
Ticket Compliance
🎫 No ticket provided
  • Create ticket/issue
Codebase Duplication Compliance
Codebase context is not defined

Follow the guide to enable codebase context checks.

Custom Compliance
🟢
Generic: Secure Error Handling

Objective: To prevent the leakage of sensitive system information through error messages while
providing sufficient detail for internal debugging.

Status: Passed

Generic: Secure Logging Practices

Objective: To ensure logs are useful for debugging and auditing without exposing sensitive
information like PII, PHI, or cardholder data.

Status: Passed

Generic: Comprehensive Audit Trails

Objective: To create a detailed and reliable record of critical system actions for security analysis
and compliance.

Status:
No audit logs: The new completion logic performs various parsing and output actions without any audit
trail, but as a shell completion helper it may not require security-grade audit logging;
confirm scope.

Referred Code
# Main completion function for 'make' command.
# See top of file: completions/makefile.completion.sh for usage and description.
_omb_completion_makefile() {
     # Include a compact usage info for make flags
     local flags_and_descs="

---- Make Options ----
-h --help               \tShow extended usage info and exit.
-B --always-make        \tUnconditionally make all targets.
-n --dry-run            \tDon't actually run any recipe; just print them.
-C DIR --directory=DIR  \tChange to DIR before doing anything.
-f FILE --file=FILE     \tRead FILE as a makefile.
-E STRING --eval=STRING \tEvaluate STRING as a makefile statement.
"

     # Get all make flags as a flat list for completion
     local flags="$(
        echo "$flags_and_descs" |
        command grep -v '^----' |
        command grep -ioE '\-[a-z]|--[a-z][a-z_=-]*' |
        command sort -u


 ... (clipped 114 lines)
Generic: Meaningful Naming and Self-Documenting Code

Objective: Ensure all identifiers clearly express their purpose and intent, making code
self-documenting

Status:
Ambiguous names: Some names like 'usage', 'targets' are generic and locally scoped but
could be clearer in a large script; however, overall naming is mostly descriptive and may
be acceptable.

Referred Code
usage=$(echo -e "$targets_and_descs" "$flags_and_descs" | _omb_completion_makefile_awk -F '\t' '
$0 ~ exp_header                 {print usage_header($0); next;}            # file header line
$1 ~ query  && $0 ~ exp_assign  {print usage_variable($1, $2, $3); next; } # var + value
$1 ~ flag   && $0 ~ exp_flag    {print usage_flag($1, $2); next; }         # make flags
$1 ~ target                     {print usage_target($1, $2); next;}        # trg + desc
                                {next;}                                    # skip anything else
')

local ticks=("" "" "" "")  # 4 frames
local tick="${ticks[$((presses % 4))]}"
# The repeat rotator indicates repeated tab presses without changed input.
# It will appear behind the previous line:
Generic: Robust Error Handling and Edge Case Management

Objective: Ensure comprehensive error handling that provides meaningful context and graceful
degradation

Status:
Missing error checks: External command failures (awk/grep/date/column) and missing files are not explicitly
handled beyond redirecting stderr, which could cause silent failures in edge cases.

Referred Code
     # Include a compact usage info for make flags
     local flags_and_descs="

---- Make Options ----
-h --help               \tShow extended usage info and exit.
-B --always-make        \tUnconditionally make all targets.
-n --dry-run            \tDon't actually run any recipe; just print them.
-C DIR --directory=DIR  \tChange to DIR before doing anything.
-f FILE --file=FILE     \tRead FILE as a makefile.
-E STRING --eval=STRING \tEvaluate STRING as a makefile statement.
"

     # Get all make flags as a flat list for completion
     local flags="$(
        echo "$flags_and_descs" |
        command grep -v '^----' |
        command grep -ioE '\-[a-z]|--[a-z][a-z_=-]*' |
        command sort -u
     )"

     # Get all Makefile targets with descriptions


 ... (clipped 111 lines)
Generic: Security-First Input Validation and Data Handling

Objective: Ensure all data inputs are validated, sanitized, and handled securely to prevent
vulnerabilities

Status:
Unvalidated input: User-typed query is interpolated into regex for grep/awk without escaping which could lead
to unexpected behavior; as a local completion script this may be acceptable but should be
reviewed.

Referred Code
local debug="$_omb_completion_makefile_debug"
local query="${COMP_WORDS[COMP_CWORD]}"
local t_last="${_omb_completion_makefile_last_queried_at:-0}"
local presses=$_omb_completion_makefile_tab_presses
local prev_reply="$_omb_completion_makefile_last_reply"

# clear old values if too much time has passed
local now=$(command date +%s)
local dt_last=$(( $now - $t_last ))
if test "$dt_last" -gt 10
then # reset tab presses after 10s of inactivity
     prev_reply=""
     presses=1
fi

# build new completion reply
# cannot use 'compgen' with case-insensitive matching, so use grep
COMPREPLY=($(echo "$targets" "$flags" | command grep -iE "^$query" ))
local reply="${COMPREPLY[*]}"
local num_matches=${#COMPREPLY[@]}
  • Update
Compliance status legend 🟢 - Fully Compliant
🟡 - Partial Compliant
🔴 - Not Compliant
⚪ - Requires Further Human Verification
🏷️ - Compliance label

@qodo-free-for-open-source-projects
Copy link

qodo-free-for-open-source-projects bot commented Nov 1, 2025

PR Code Suggestions ✨

Explore these optional code suggestions:

CategorySuggestion                                                                                                                                    Impact
Possible issue
Correctly reset global completion state

Correct the timeout logic to reset the global state variables
_omb_completion_makefile_tab_presses and _omb_completion_makefile_last_reply.
This fixes a bug causing inconsistent completion behavior after a period of
inactivity.

completions/makefile.completion.sh [276-283]

 # clear old values if too much time has passed
  local now=$(command date +%s)
  local dt_last=$(( $now - $t_last ))
  if test "$dt_last" -gt 10
  then # reset tab presses after 10s of inactivity
+      _omb_completion_makefile_last_reply=""
+      _omb_completion_makefile_tab_presses=1
       prev_reply=""
       presses=1
  fi
  • Apply / Chat
Suggestion importance[1-10]: 9

__

Why: The suggestion correctly identifies a logic bug where the global state for tab presses is not reset after a timeout, leading to incorrect completion behavior. The fix is critical for the intended functionality of cycling through completion details.

High
Implement recursive makefile include discovery

Modify the _omb_completion_makefile_find_includes function to be recursive,
enabling it to discover targets from nested makefile includes. Add protection
against circular dependencies.

completions/makefile.completion.sh [132-141]

-# Find included Makefile paths (.mk) from given Makefiles.
+# Find included Makefile paths (.mk) from given Makefiles, recursively.
 _omb_completion_makefile_find_includes() {
      shopt -u nullglob
      shopt -s nocaseglob
-     local makefiles="$*"
-     if test -z "$makefiles"
-     then makefiles="*makefile"
+     local makefiles=("$@")
+     if test "${#makefiles[@]}" -eq 0
+     then makefiles=(*makefile)
      fi
-     command awk -F '[[:space:]]+' '/^include[[:space:]]/ {print $2;}' $makefiles 2>/dev/null
+
+     local seen=()
+     _omb_completion_makefile_find_includes_recursive() {
+          local file
+          for file in "$@"; do
+               # Avoid circular dependencies
+               if [[ " ${seen[*]} " == *" $file "* ]]; then continue; fi
+               seen+=("$file")
+
+               local includes
+               # Find includes in the current file
+               includes=($(command awk -F '[[:space:]]+' '/^include[[:space:]]/ {print $2;}' "$file" 2>/dev/null))
+               if test "${#includes[@]}" -gt 0; then
+                    # Print found includes and recurse
+                    printf "%s\n" "${includes[@]}"
+                    _omb_completion_makefile_find_includes_recursive "${includes[@]}"
+               fi
+          done
+     }
+     _omb_completion_makefile_find_includes_recursive "${makefiles[@]}"
 }
  • Apply / Chat
Suggestion importance[1-10]: 8

__

Why: The suggestion correctly identifies that the _omb_completion_makefile_find_includes function is not recursive, which would lead to incomplete completions for projects with nested makefiles. The proposed recursive solution is a significant functional improvement.

Medium
Fix handling of filenames with spaces

Refactor _omb_completion_makefile_comp_details to use bash arrays and proper
quoting. This will ensure correct handling of filenames containing spaces or
other special characters.

completions/makefile.completion.sh [214-229]

 _omb_completion_makefile_comp_details() {
      shopt -u nullglob
      shopt -s nocaseglob
 
-     local makefiles="*makefile"
-     makefiles="*makefile $(_omb_completion_makefile_find_includes $makefiles)"
+     local makefiles=(*makefile)
+     # Use process substitution and mapfile to read includes into an array
+     local includes=()
+     mapfile -t includes < <(_omb_completion_makefile_find_includes "${makefiles[@]}")
+     makefiles+=("${includes[@]}")
 
-     for mf in $makefiles
+     local mf
+     for mf in "${makefiles[@]}"
      do
+          # Skip non-existent files that might result from glob patterns
+          if ! test -f "$mf"; then continue; fi
           echo "---- $mf ----"
           _omb_completion_makefile_targets "$mf"
           echo ""
           _omb_completion_makefile_vars "$mf"
           echo ""
      done
 }
  • Apply / Chat
Suggestion importance[1-10]: 7

__

Why: The suggestion correctly identifies a robustness issue where filenames with spaces would break the script due to word splitting. The proposed fix using arrays and proper quoting makes the completion script more reliable.

Medium
  • Update

@ubunatic ubunatic force-pushed the completions-makefile-usage-assist branch from 84d53f9 to fa9f5f2 Compare November 2, 2025 12:58
Parse Makefiles to extracts targets and vars, incl. descriptions.
Show targets on first tab press and usage info on multiple tab presses.
@ubunatic ubunatic force-pushed the completions-makefile-usage-assist branch from fa9f5f2 to e59426a Compare November 2, 2025 17:49
Detect dir and file from -C and -f. Respect dir in include search.
Add file completion fallback. Add more std. make flags.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant