From 73de59c92b74f026306b7b81a581f82d79a84b95 Mon Sep 17 00:00:00 2001 From: priestlypython Date: Tue, 28 Oct 2025 01:51:56 -0700 Subject: [PATCH] feat(interactive): Add intuitive loop to go back to command search MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Added seamless loop functionality for interactive mode: Features: 1. Main Interactive Loop: - Wrapped entire interactive mode in while true loop - After viewing flags, prompts to search another command - Press Enter to return to command menu - Clear screen for clean UX 2. Multiple Exit Options: - Esc in command menu: Clean exit with goodbye message - Ctrl+C at prompt: Immediate exit - Clear, intuitive navigation 3. User Flow: Step 1: Select command from fuzzy search Step 2: View command details and syntax Step 3: Browse flags with fuzzy search Step 4: Press Enter → Back to Step 1 OR Ctrl+C → Exit 4. Visual Feedback: - Clear prompt: 'Press Enter to search another command' - Separator lines for clarity - Screen clear between iterations - Goodbye message on exit Benefits: - No need to restart script for each command - Intuitive navigation (Enter = continue, Esc/Ctrl+C = exit) - Seamless command exploration workflow - Better for learning/comparing multiple commands - Professional UX with clear feedback Example Session: 1. User selects 'ls' → views flags 2. Press Enter 3. Back to command menu, selects 'grep' → views flags 4. Press Enter 5. Back to command menu, selects 'tar' → views flags 6. Ctrl+C to exit User Request: 'we also want a means to easily go back intuitively from after pulling up the fuzzy search for flags for a command back to the command fuzzy search' --- bash-helper.sh | 157 +++++++++++++++++++++++++++---------------------- 1 file changed, 86 insertions(+), 71 deletions(-) diff --git a/bash-helper.sh b/bash-helper.sh index 432c26f..b39d53a 100755 --- a/bash-helper.sh +++ b/bash-helper.sh @@ -918,7 +918,7 @@ if [ -n "$MODE" ]; then esac fi -# Interactive mode with fzf +# Interactive mode with fzf (loopable) if [ "$INTERACTIVE" = true ]; then # Check if fzf is available if ! command -v fzf &> /dev/null; then @@ -929,78 +929,86 @@ if [ "$INTERACTIVE" = true ]; then exit 1 fi - # Format commands for display: description on left, syntax on right - # Get terminal width for proper alignment - TERM_WIDTH=$(tput cols 2>/dev/null || echo 120) + # Main interactive loop + while true; do + # Format commands for display: description on left, syntax on right + # Get terminal width for proper alignment + TERM_WIDTH=$(tput cols 2>/dev/null || echo 120) - # Calculate widths (leave room for colors and spacing) - MAX_CMD_WIDTH=15 - SYNTAX_WIDTH=45 - DESC_WIDTH=$((TERM_WIDTH - MAX_CMD_WIDTH - SYNTAX_WIDTH - 10)) + # Calculate widths (leave room for colors and spacing) + MAX_CMD_WIDTH=15 + SYNTAX_WIDTH=45 + DESC_WIDTH=$((TERM_WIDTH - MAX_CMD_WIDTH - SYNTAX_WIDTH - 10)) - # Ensure minimum widths - if [ $DESC_WIDTH -lt 30 ]; then - DESC_WIDTH=30 - SYNTAX_WIDTH=$((TERM_WIDTH - MAX_CMD_WIDTH - DESC_WIDTH - 10)) - fi - - # Format each command with colors and right-aligned syntax - FORMATTED_COMMANDS=() - for cmd in "${COMMANDS[@]}"; do - CMD_NAME=${cmd%%:*} - REST=${cmd#*:} - - # Extract description and syntax - if [[ "$REST" =~ (.+)\ \|\ (.+) ]]; then - DESC_PART="${BASH_REMATCH[1]}" - SYNTAX_PART="${BASH_REMATCH[2]}" - else - DESC_PART="$REST" - SYNTAX_PART="$CMD_NAME [options]" + # Ensure minimum widths + if [ $DESC_WIDTH -lt 30 ]; then + DESC_WIDTH=30 + SYNTAX_WIDTH=$((TERM_WIDTH - MAX_CMD_WIDTH - DESC_WIDTH - 10)) fi - # Truncate if too long (accounting for actual content, not color codes) - if [ ${#DESC_PART} -gt $DESC_WIDTH ]; then - DESC_PART="${DESC_PART:0:$((DESC_WIDTH-3))}..." - fi - if [ ${#SYNTAX_PART} -gt $SYNTAX_WIDTH ]; then - SYNTAX_PART="${SYNTAX_PART:0:$((SYNTAX_WIDTH-3))}..." + # Format each command with colors and right-aligned syntax + FORMATTED_COMMANDS=() + for cmd in "${COMMANDS[@]}"; do + CMD_NAME=${cmd%%:*} + REST=${cmd#*:} + + # Extract description and syntax + if [[ "$REST" =~ (.+)\ \|\ (.+) ]]; then + DESC_PART="${BASH_REMATCH[1]}" + SYNTAX_PART="${BASH_REMATCH[2]}" + else + DESC_PART="$REST" + SYNTAX_PART="$CMD_NAME [options]" + fi + + # Truncate if too long (accounting for actual content, not color codes) + if [ ${#DESC_PART} -gt $DESC_WIDTH ]; then + DESC_PART="${DESC_PART:0:$((DESC_WIDTH-3))}..." + fi + if [ ${#SYNTAX_PART} -gt $SYNTAX_WIDTH ]; then + SYNTAX_PART="${SYNTAX_PART:0:$((SYNTAX_WIDTH-3))}..." + fi + + # Calculate padding for right-alignment of syntax + # Total visible length = cmd_name + ": " + desc + spaces + syntax + CMD_LEN=${#CMD_NAME} + DESC_LEN=${#DESC_PART} + SYNTAX_LEN=${#SYNTAX_PART} + NEEDED_SPACES=$((TERM_WIDTH - CMD_LEN - 2 - DESC_LEN - SYNTAX_LEN - 5)) + + # Ensure at least 2 spaces + if [ $NEEDED_SPACES -lt 2 ]; then + NEEDED_SPACES=2 + fi + + # Create spacing string + SPACES=$(printf '%*s' "$NEEDED_SPACES" '') + + # Format with colors: + # - Cyan for command name + # - White for description + # - Dim cyan for syntax + formatted_line="\033[0;36m${CMD_NAME}\033[0m: ${DESC_PART}${SPACES}\033[2;36m${SYNTAX_PART}\033[0m" + + FORMATTED_COMMANDS+=("$formatted_line") + done + + # Show in fzf with formatted display + SELECTED=$(printf "%b\n" "${FORMATTED_COMMANDS[@]}" | fzf \ + --height 60% \ + --border \ + --header "Select a command (Esc to exit) | cyan: command | description | dim: syntax" \ + --prompt "🔍 Search: " \ + --preview-window=hidden \ + --ansi) + + if [ -z "$SELECTED" ]; then + # User pressed Esc or cancelled + echo "" + echo -e "${YELLOW}Exiting Bash Buddy. Happy coding! 👋${NC}" + exit 0 fi - # Calculate padding for right-alignment of syntax - # Total visible length = cmd_name + ": " + desc + spaces + syntax - CMD_LEN=${#CMD_NAME} - DESC_LEN=${#DESC_PART} - SYNTAX_LEN=${#SYNTAX_PART} - NEEDED_SPACES=$((TERM_WIDTH - CMD_LEN - 2 - DESC_LEN - SYNTAX_LEN - 5)) - - # Ensure at least 2 spaces - if [ $NEEDED_SPACES -lt 2 ]; then - NEEDED_SPACES=2 - fi - - # Create spacing string - SPACES=$(printf '%*s' "$NEEDED_SPACES" '') - - # Format with colors: - # - Cyan for command name - # - White for description - # - Dim cyan for syntax - formatted_line="\033[0;36m${CMD_NAME}\033[0m: ${DESC_PART}${SPACES}\033[2;36m${SYNTAX_PART}\033[0m" - - FORMATTED_COMMANDS+=("$formatted_line") - done - - # Show in fzf with formatted display - SELECTED=$(printf "%b\n" "${FORMATTED_COMMANDS[@]}" | fzf \ - --height 60% \ - --border \ - --header "Select a command (cyan: command | description | dim: syntax)" \ - --prompt "🔍 Search: " \ - --preview-window=hidden \ - --ansi) - - if [ -n "$SELECTED" ]; then # Extract command name from selection (strip color codes) CMD=$(echo "$SELECTED" | sed 's/\x1b\[[0-9;]*m//g' | awk -F: '{print $1}' | sed 's/^[[:space:]]*//' | sed 's/[[:space:]]*$//') @@ -1036,10 +1044,17 @@ if [ "$INTERACTIVE" = true ]; then # Directly show fuzzy flag browser (no filter prompt) show_flags "$CMD" - else - echo "No command selected" - exit 0 - fi + + # After viewing flags, ask if user wants to search another command + echo "" + echo -e "${YELLOW}───────────────────────────────────────────────────────────${NC}" + echo -e "${CYAN}Press Enter to search another command, or Ctrl+C to exit${NC}" + echo -e "${YELLOW}───────────────────────────────────────────────────────────${NC}" + read -r + + # Clear screen for better UX + clear + done # Direct mode elif [ -n "$COMMAND" ]; then # Validate command exists in our list