diff --git a/bash-helper.sh b/bash-helper.sh index b39d53a..97c6c83 100755 --- a/bash-helper.sh +++ b/bash-helper.sh @@ -407,29 +407,31 @@ mode_explain() { if command -v "$base_cmd" &> /dev/null || type "$base_cmd" 2>/dev/null | grep -q "shell builtin"; then echo -e "${CYAN}${BOLD}SYNTAX:${NC}" + local raw_syntax="" if type "$base_cmd" 2>/dev/null | grep -q "shell builtin"; then # For builtins, get the first line of help - local syntax=$(help "$base_cmd" 2>/dev/null | head -1 | sed 's/^[[:space:]]*//') - if [ -n "$syntax" ]; then - echo -e " ${GREEN}$syntax${NC}" - else - echo -e " ${GREEN}$base_cmd [options]${NC}" - fi + raw_syntax=$(help "$base_cmd" 2>/dev/null | head -1 | sed 's/^[[:space:]]*//') + [ -z "$raw_syntax" ] && raw_syntax="$base_cmd [options]" else # For regular commands, extract SYNOPSIS section from man page - local synopsis=$(man "$base_cmd" 2>/dev/null | col -b | sed -n '/^SYNOPSIS/,/^DESCRIPTION/p' | head -15 | tail -n +2 | head -n -1 | sed 's/^[[:space:]]*/ /') + local synopsis=$(man "$base_cmd" 2>/dev/null | col -b | sed -n '/^SYNOPSIS/,/^DESCRIPTION/p' | head -15 | tail -n +2 | head -n -1 | tr '\n' ' ' | sed 's/^[[:space:]]*//' | sed 's/[[:space:]]*$//') if [ -n "$synopsis" ]; then - echo -e "${GREEN}$synopsis${NC}" + raw_syntax="$synopsis" else # Fallback: try to get usage from command itself - local usage=$("$base_cmd" --help 2>&1 | grep -i "usage" | head -1 | sed 's/^[Uu]sage: / /') + local usage=$("$base_cmd" --help 2>&1 | grep -i "usage" | head -1 | sed 's/^[Uu]sage: //') if [ -n "$usage" ]; then - echo -e " ${GREEN}$usage${NC}" + raw_syntax="$usage" else - echo -e " ${GREEN}$base_cmd [options]${NC}" + raw_syntax="$base_cmd [options]" fi fi fi + + # Display colorized syntax + if [ -n "$raw_syntax" ]; then + colorize_syntax "$raw_syntax" | sed 's/^/ /' + fi echo "" # Add practical example @@ -590,6 +592,39 @@ get_practical_example() { echo "$example" } +# Colorize syntax elements by type for instant recognition +colorize_syntax() { + local syntax="$1" + local colored_syntax="$syntax" + + # Color scheme for syntax elements: + # - Command name (first word): Bright cyan + # - [OPTIONS], [OPTION], etc.: Yellow + # - UPPERCASE args (FILE, STRING, SET1, etc.): Magenta + # - Lowercase/optional args: Green + # - ... (ellipsis): Dim white + + # Extract command name (first word) + local cmd_word=$(echo "$syntax" | awk '{print $1}') + + # Start with command in bright cyan + colored_syntax=$(echo "$syntax" | sed "s/^$cmd_word/\\${CYAN}\\${BOLD}$cmd_word\\${NC}/") + + # Color [OPTIONS], [OPTION], [EXPRESSION], etc. in yellow + colored_syntax=$(echo "$colored_syntax" | sed -E "s/\[([A-Z][A-Z_-]*)\]/[\\${YELLOW}\1\\${NC}]/g") + + # Color UPPERCASE arguments in magenta (FILE, STRING, PATH, SET1, etc.) + colored_syntax=$(echo "$colored_syntax" | sed -E "s/([[:space:]])([A-Z][A-Z0-9_-]*[A-Z])([[:space:][:punct:]$])/\1\\${MAGENTA}\2\\${NC}\3/g") + + # Color lowercase optional arguments in green + colored_syntax=$(echo "$colored_syntax" | sed -E "s/\[([a-z][a-z-]*)\]/[\\${GREEN}\1\\${NC}]/g") + + # Color ellipsis (...) in dim white + colored_syntax=$(echo "$colored_syntax" | sed "s/\.\.\./\\${DIM}...\\${NC}/g") + + echo -e "$colored_syntax" +} + # Extract all flags from man page or help extract_all_flags() { local cmd_name="$1" @@ -608,90 +643,86 @@ extract_all_flags() { } # Interactive flag browser with fuzzy search +# Now includes syntax and description in the fzf interface itself browse_flags_fuzzy() { local cmd_name="$1" + local cmd_syntax="$2" + local cmd_desc="$3" - echo "" - echo -e "${CYAN}Extracting flags from man page...${NC}" - - # Extract all flags + # Extract all flags silently local all_flags=$(extract_all_flags "$cmd_name") if [ -z "$all_flags" ]; then + echo "" 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 + # Colorize the syntax for the header + local colored_syntax=$(colorize_syntax "$cmd_syntax") - # Show in fzf for fuzzy searching + # Create multi-line header with command info + local header="╔═══════════════════════════════════════════════════════════════════════════════╗ +║ Command: ${CYAN}${BOLD}$cmd_name${NC} +║ Syntax: $colored_syntax +║ Desc: ${GREEN}$cmd_desc${NC} +╚═══════════════════════════════════════════════════════════════════════════════╝ +🔍 Fuzzy search $flag_count flags | Multi-select: Ctrl-A/D | Esc: Back to menu" + + # Show in fzf with integrated command info echo "$all_flags" | fzf \ - --height 80% \ - --border \ - --header "🔍 Fuzzy search through $cmd_name flags (Esc to exit)" \ + --height 95% \ + --border=none \ + --header "$header" \ --preview 'echo {}' \ - --preview-window=up:40%:wrap \ - --prompt "Search flags: " \ + --preview-window=down:3:wrap \ + --prompt "⚡ Search: " \ --multi \ --bind 'ctrl-a:select-all' \ - --bind 'ctrl-d:deselect-all' + --bind 'ctrl-d:deselect-all' \ + --ansi \ + --color=header:bold:cyan return 0 } show_flags() { CMD_NAME=$1 - FILTER=$2 - - echo -e "${BLUE}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}" - echo -e "${YELLOW}Command Details: ${GREEN}$CMD_NAME${NC}" - echo -e "${BLUE}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}" - echo "" - - # Display SYNTAX section - if command -v "$CMD_NAME" &> /dev/null || type "$CMD_NAME" 2>/dev/null | grep -q "shell builtin"; then - echo -e "${CYAN}${BOLD}SYNTAX:${NC}" + CMD_SYNTAX=$2 + CMD_DESC=$3 + # Extract syntax if not provided + if [ -z "$CMD_SYNTAX" ]; then if type "$CMD_NAME" 2>/dev/null | grep -q "shell builtin"; then # For builtins, get the first line of help - local syntax=$(help "$CMD_NAME" 2>/dev/null | head -1 | sed 's/^[[:space:]]*//') - if [ -n "$syntax" ]; then - echo -e " ${GREEN}$syntax${NC}" - else - echo -e " ${GREEN}$CMD_NAME [options]${NC}" - fi + CMD_SYNTAX=$(help "$CMD_NAME" 2>/dev/null | head -1 | sed 's/^[[:space:]]*//') + [ -z "$CMD_SYNTAX" ] && CMD_SYNTAX="$CMD_NAME [options]" else # For regular commands, extract SYNOPSIS section from man page - local synopsis=$(man "$CMD_NAME" 2>/dev/null | col -b | sed -n '/^SYNOPSIS/,/^DESCRIPTION/p' | head -15 | tail -n +2 | head -n -1 | sed 's/^[[:space:]]*/ /') + local synopsis=$(man "$CMD_NAME" 2>/dev/null | col -b | sed -n '/^SYNOPSIS/,/^DESCRIPTION/p' | head -15 | tail -n +2 | head -n -1 | tr '\n' ' ' | sed 's/^[[:space:]]*//' | sed 's/[[:space:]]*$//') if [ -n "$synopsis" ]; then - echo -e "${GREEN}$synopsis${NC}" + CMD_SYNTAX="$synopsis" else # Fallback: try to get usage from command itself - local usage=$("$CMD_NAME" --help 2>&1 | grep -i "usage" | head -1 | sed 's/^[Uu]sage: / /') + local usage=$("$CMD_NAME" --help 2>&1 | grep -i "usage" | head -1 | sed 's/^[Uu]sage: //') if [ -n "$usage" ]; then - echo -e " ${GREEN}$usage${NC}" + CMD_SYNTAX="$usage" else - echo -e " ${GREEN}$CMD_NAME [options]${NC}" + CMD_SYNTAX="$CMD_NAME [options]" fi fi fi - echo "" fi - # Display FLAGS/OPTIONS section with fuzzy search - echo -e "${YELLOW}${BOLD}FLAGS/OPTIONS:${NC}" - echo -e "${DIM}Opening interactive flag browser...${NC}" - echo "" + # Default description if not provided + [ -z "$CMD_DESC" ] && CMD_DESC="No description available" - # Use fuzzy flag browser instead of static display - browse_flags_fuzzy "$CMD_NAME" + # Directly open fuzzy flag browser with integrated command info (no wasted space) + browse_flags_fuzzy "$CMD_NAME" "$CMD_SYNTAX" "$CMD_DESC" echo "" echo -e "${BLUE}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}" @@ -935,16 +966,17 @@ if [ "$INTERACTIVE" = true ]; then # Get terminal width for proper alignment TERM_WIDTH=$(tput cols 2>/dev/null || echo 120) - # Calculate widths (leave room for colors and spacing) + # Calculate widths more conservatively to prevent clipping + # Reserve space for: command (15) + ": " (2) + description (40%) + spaces (5) + syntax (remaining) MAX_CMD_WIDTH=15 - SYNTAX_WIDTH=45 - DESC_WIDTH=$((TERM_WIDTH - MAX_CMD_WIDTH - SYNTAX_WIDTH - 10)) + DESC_WIDTH=$((TERM_WIDTH * 40 / 100)) + SYNTAX_WIDTH=$((TERM_WIDTH - MAX_CMD_WIDTH - DESC_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 + # Ensure minimum widths and cap maximums + [ $DESC_WIDTH -lt 20 ] && DESC_WIDTH=20 + [ $SYNTAX_WIDTH -lt 30 ] && SYNTAX_WIDTH=30 + [ $DESC_WIDTH -gt 50 ] && DESC_WIDTH=50 + [ $SYNTAX_WIDTH -gt 60 ] && SYNTAX_WIDTH=60 # Format each command with colors and right-aligned syntax FORMATTED_COMMANDS=() @@ -961,7 +993,7 @@ if [ "$INTERACTIVE" = true ]; then SYNTAX_PART="$CMD_NAME [options]" fi - # Truncate if too long (accounting for actual content, not color codes) + # Truncate if too long if [ ${#DESC_PART} -gt $DESC_WIDTH ]; then DESC_PART="${DESC_PART:0:$((DESC_WIDTH-3))}..." fi @@ -969,25 +1001,29 @@ if [ "$INTERACTIVE" = true ]; 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 + # Calculate exact padding needed for right-alignment + # Account for visual width only (not ANSI codes) 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 + # Calculate spaces needed: terminal width - all visible characters - separator chars + # Visible: cmd + ": " + desc + syntax = CMD_LEN + 2 + DESC_LEN + SYNTAX_LEN + VISIBLE_WIDTH=$((CMD_LEN + 2 + DESC_LEN + SYNTAX_LEN)) + NEEDED_SPACES=$((TERM_WIDTH - VISIBLE_WIDTH - 8)) # Extra padding for safety + + # Minimum spacing + [ $NEEDED_SPACES -lt 3 ] && NEEDED_SPACES=3 + # Maximum spacing to prevent excessive gaps + [ $NEEDED_SPACES -gt 20 ] && NEEDED_SPACES=20 # Create spacing string SPACES=$(printf '%*s' "$NEEDED_SPACES" '') # Format with colors: - # - Cyan for command name + # - Bright cyan for command name # - White for description - # - Dim cyan for syntax + # - Dim cyan for syntax (right-aligned) formatted_line="\033[0;36m${CMD_NAME}\033[0m: ${DESC_PART}${SPACES}\033[2;36m${SYNTAX_PART}\033[0m" FORMATTED_COMMANDS+=("$formatted_line") @@ -1030,20 +1066,9 @@ if [ "$INTERACTIVE" = true ]; then fi done - echo "" - echo -e "${BLUE}═══════════════════════════════════════════════════════════${NC}" - echo -e "${YELLOW}Command:${NC} ${MAGENTA}$CMD${NC}" - echo -e "${BLUE}═══════════════════════════════════════════════════════════${NC}" - echo "" - echo -e "${CYAN}${BOLD}SYNTAX:${NC}" - echo -e " ${GREEN}$SYNTAX${NC}" - echo "" - echo -e "${GREEN}Description:${NC} $DESC" - echo "" - echo -e "${BLUE}═══════════════════════════════════════════════════════════${NC}" - - # Directly show fuzzy flag browser (no filter prompt) - show_flags "$CMD" + # Directly show fuzzy flag browser with integrated command info (no wasted space) + clear + show_flags "$CMD" "$SYNTAX" "$DESC" # After viewing flags, ask if user wants to search another command echo ""