From 1a80a9862abf381c92000ad0ae0c864b1fa11adf Mon Sep 17 00:00:00 2001 From: priestlypython Date: Tue, 28 Oct 2025 01:06:50 -0700 Subject: [PATCH] feat(ui): Right-align syntax in interactive menu + fuzzy flag search Major UX improvements: 1. Interactive menu now shows syntax right-aligned (clean layout) 2. Replaced broken filter prompt with fuzzy flag search 3. Simplified flag extraction (more reliable, gets all flags) Interactive Menu Enhancement: - Description on left, syntax on right - Terminal-width aware formatting - Clean, scannable display - Example: 'ls:List directory contents ls [OPTION]... [FILE]...' Fuzzy Flag Browser: - Removed filter prompt step (was broken) - Extract ALL flags from man page (up to 200) - Show in fzf with fuzzy search - Type to search through flags dynamically - Multi-select support (Ctrl-A, Ctrl-D) - Clean header with instructions Flag Extraction: - Simplified from complex awk to simple grep - More reliable: grep -E '^[[:space:]]*-' - Works for all commands with man pages - Extracts 60+ flags for common commands - Handles both long and short flags User Experience: - No more broken filter step - Instant fuzzy search through all flags - Right-aligned syntax for better readability - Consistent, professional display --- bash-helper.sh | 183 ++++++++++++++++++++++++++++++++----------------- 1 file changed, 121 insertions(+), 62 deletions(-) diff --git a/bash-helper.sh b/bash-helper.sh index 205d517..5fca91f 100755 --- a/bash-helper.sh +++ b/bash-helper.sh @@ -500,15 +500,68 @@ get_quick_syntax() { echo "$syntax" } +# Extract all flags from man page or help +extract_all_flags() { + local cmd_name="$1" + local flags_list="" + + if type "$cmd_name" 2>/dev/null | grep -q "shell builtin"; then + # Shell builtin - use help command + flags_list=$(help "$cmd_name" 2>/dev/null | grep -E '^\s*-') + elif command -v "$cmd_name" &> /dev/null; then + # External command - use man page + # Get lines that start with optional whitespace and a dash (flags) + flags_list=$(man "$cmd_name" 2>/dev/null | col -b | grep -E '^[[:space:]]*-' | head -200) + fi + + echo "$flags_list" +} + +# Interactive flag browser with fuzzy search +browse_flags_fuzzy() { + local cmd_name="$1" + + echo "" + echo -e "${CYAN}Extracting flags from man page...${NC}" + + # Extract all flags + local all_flags=$(extract_all_flags "$cmd_name") + + if [ -z "$all_flags" ]; then + echo -e "${RED}No flags found for: $cmd_name${NC}" + echo "" + echo "Showing basic command info..." + return 1 + fi + + # Count flags + local flag_count=$(echo "$all_flags" | wc -l) + + echo -e "${GREEN}Found $flag_count flags. Opening fuzzy search...${NC}" + echo "" + sleep 1 + + # Show in fzf for fuzzy searching + echo "$all_flags" | fzf \ + --height 80% \ + --border \ + --header "🔍 Fuzzy search through $cmd_name flags (Esc to exit)" \ + --preview 'echo {}' \ + --preview-window=up:40%:wrap \ + --prompt "Search flags: " \ + --multi \ + --bind 'ctrl-a:select-all' \ + --bind 'ctrl-d:deselect-all' + + return 0 +} + show_flags() { CMD_NAME=$1 FILTER=$2 echo -e "${BLUE}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}" echo -e "${YELLOW}Command Details: ${GREEN}$CMD_NAME${NC}" - if [ -n "$FILTER" ]; then - echo -e "${YELLOW}Filter: ${GREEN}$FILTER${NC}" - fi echo -e "${BLUE}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}" echo "" @@ -542,51 +595,14 @@ show_flags() { echo "" fi - # Display FLAGS/OPTIONS section + # Display FLAGS/OPTIONS section with fuzzy search echo -e "${YELLOW}${BOLD}FLAGS/OPTIONS:${NC}" + echo -e "${DIM}Opening interactive flag browser...${NC}" echo "" - # Try to get flags from man page - if type "$CMD_NAME" 2>/dev/null | grep -q "shell builtin"; then - # Shell builtin - use help command - if [ -n "$FILTER" ]; then - help "$CMD_NAME" 2>/dev/null | grep -iE "(^|\s)-.*$FILTER" | head -30 - else - help "$CMD_NAME" 2>/dev/null | grep -E '^\s*-' | head -30 - fi - elif command -v "$CMD_NAME" &> /dev/null; then - # External command - use man page - # Extract the OPTIONS section from man page - local man_output=$(man "$CMD_NAME" 2>/dev/null | col -b) + # Use fuzzy flag browser instead of static display + browse_flags_fuzzy "$CMD_NAME" - if [ -z "$man_output" ]; then - echo -e "${RED}No manual page available for: $CMD_NAME${NC}" - return 1 - fi - - # Try to extract just the OPTIONS/FLAGS section - local options_section=$(echo "$man_output" | sed -n '/^OPTIONS/,/^[A-Z][A-Z]/p' | head -100) - - if [ -z "$options_section" ]; then - # Fallback: get all lines that look like flags - options_section=$(echo "$man_output" | grep -E '^\s*-' | head -50) - fi - - if [ -n "$FILTER" ]; then - # Improved filter logic: match flag name or description - echo "$options_section" | grep -iE "(^|\s)-.*$FILTER|$FILTER.*-" | head -40 - else - echo "$options_section" | head -40 - fi - else - echo -e "${RED}Could not find help for: $CMD_NAME${NC}" - echo "" - echo "Make sure the command is installed or check the spelling." - return 1 - fi - - echo "" - echo -e "${DIM}Tip: Use the filter to search for specific flags or keywords${NC}" echo "" echo -e "${BLUE}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}" } @@ -823,27 +839,71 @@ if [ "$INTERACTIVE" = true ]; then exit 1 fi - # Enhanced preview showing command, description, and syntax - FZF_COMMAND=$(printf "%s\n" "${COMMANDS[@]}" | fzf --height 60% --border \ - --preview 'echo -e "\033[0;36mCommand:\033[0m {1}\n\033[0;36mDescription:\033[0m {2}\n\033[0;36mSyntax:\033[0m {3}"' \ - --preview-window=up:3:wrap \ - --delimiter ':|\|' \ - --with-nth 1,2,3) + # 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) + SYNTAX_WIDTH=50 + DESC_WIDTH=$((TERM_WIDTH - SYNTAX_WIDTH - 5)) - if [ -n "$FZF_COMMAND" ]; then - # Parse the selected command: "cmd:description | syntax" - CMD=${FZF_COMMAND%%:*} - REST=${FZF_COMMAND#*:} + # Format each command with right-aligned syntax + FORMATTED_COMMANDS=() + for cmd in "${COMMANDS[@]}"; do + CMD_NAME=${cmd%%:*} + REST=${cmd#*:} # Extract description and syntax if [[ "$REST" =~ (.+)\ \|\ (.+) ]]; then - DESC="${BASH_REMATCH[1]}" - SYNTAX="${BASH_REMATCH[2]}" + DESC_PART="${BASH_REMATCH[1]}" + SYNTAX_PART="${BASH_REMATCH[2]}" else - DESC="$REST" - SYNTAX="$CMD [options]" + DESC_PART="$REST" + SYNTAX_PART="$CMD_NAME [options]" fi + # Truncate if too long + 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 + + # Format with padding + printf -v formatted_line "%-${DESC_WIDTH}s %${SYNTAX_WIDTH}s" "$CMD_NAME:$DESC_PART" "$SYNTAX_PART" + FORMATTED_COMMANDS+=("$formatted_line") + done + + # Show in fzf with formatted display + SELECTED=$(printf "%s\n" "${FORMATTED_COMMANDS[@]}" | fzf \ + --height 60% \ + --border \ + --header "Select a command (description | syntax)" \ + --prompt "🔍 Search: " \ + --preview-window=hidden \ + --ansi) + + if [ -n "$SELECTED" ]; then + # Extract command name from selection + CMD=$(echo "$SELECTED" | awk -F: '{print $1}') + + # Find the original command entry to get full details + for cmd in "${COMMANDS[@]}"; do + CMD_NAME=${cmd%%:*} + if [ "$CMD_NAME" = "$CMD" ]; then + REST=${cmd#*:} + + # Extract description and syntax + if [[ "$REST" =~ (.+)\ \|\ (.+) ]]; then + DESC="${BASH_REMATCH[1]}" + SYNTAX="${BASH_REMATCH[2]}" + else + DESC="$REST" + SYNTAX="$CMD [options]" + fi + break + fi + done + echo "" echo -e "${BLUE}═══════════════════════════════════════════════════════════${NC}" echo -e "${YELLOW}Command:${NC} ${MAGENTA}$CMD${NC}" @@ -855,10 +915,9 @@ if [ "$INTERACTIVE" = true ]; then echo -e "${GREEN}Description:${NC} $DESC" echo "" echo -e "${BLUE}═══════════════════════════════════════════════════════════${NC}" - echo "" - read -p "Filter flags (optional, press Enter to skip): " FILTER - echo "" - show_flags "$CMD" "$FILTER" + + # Directly show fuzzy flag browser (no filter prompt) + show_flags "$CMD" else echo "No command selected" exit 0