diff --git a/bash-helper.sh b/bash-helper.sh index 97c6c83..d482f76 100755 --- a/bash-helper.sh +++ b/bash-helper.sh @@ -430,7 +430,8 @@ mode_explain() { # Display colorized syntax if [ -n "$raw_syntax" ]; then - colorize_syntax "$raw_syntax" | sed 's/^/ /' + local colored=$(colorize_syntax "$raw_syntax") + printf " %b\n" "$colored" fi echo "" @@ -593,36 +594,38 @@ get_practical_example() { } # Colorize syntax elements by type for instant recognition +# Returns raw string with ANSI codes (caller should use echo -e or printf %b) colorize_syntax() { local syntax="$1" local colored_syntax="$syntax" # Color scheme for syntax elements: - # - Command name (first word): Bright cyan + # - Command name (first word): Bright cyan + bold # - [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}') + # Extract command name (first word) - escape special chars for sed + local cmd_word=$(echo "$syntax" | awk '{print $1}' | sed 's/[]\/$*.^[]/\\&/g') - # Start with command in bright cyan - colored_syntax=$(echo "$syntax" | sed "s/^$cmd_word/\\${CYAN}\\${BOLD}$cmd_word\\${NC}/") + # Start with command in bright cyan + bold + colored_syntax=$(echo "$syntax" | sed "s/^$cmd_word/\\\\033[0;36m\\\\033[1m$cmd_word\\\\033[0m/") # Color [OPTIONS], [OPTION], [EXPRESSION], etc. in yellow - colored_syntax=$(echo "$colored_syntax" | sed -E "s/\[([A-Z][A-Z_-]*)\]/[\\${YELLOW}\1\\${NC}]/g") + colored_syntax=$(echo "$colored_syntax" | sed -E "s/\[([A-Z][A-Z_-]*)\]/[\\\\033[0;33m\1\\\\033[0m]/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") + colored_syntax=$(echo "$colored_syntax" | sed -E "s/([[:space:]])([A-Z][A-Z0-9_-]*[A-Z])([[:space:][:punct:]$])/\1\\\\033[0;35m\2\\\\033[0m\3/g") # Color lowercase optional arguments in green - colored_syntax=$(echo "$colored_syntax" | sed -E "s/\[([a-z][a-z-]*)\]/[\\${GREEN}\1\\${NC}]/g") + colored_syntax=$(echo "$colored_syntax" | sed -E "s/\[([a-z][a-z-]*)\]/[\\\\033[0;32m\1\\\\033[0m]/g") # Color ellipsis (...) in dim white - colored_syntax=$(echo "$colored_syntax" | sed "s/\.\.\./\\${DIM}...\\${NC}/g") + colored_syntax=$(echo "$colored_syntax" | sed "s/\.\.\./\\\\033[2m...\\\\033[0m/g") - echo -e "$colored_syntax" + # Return raw string (no echo -e, let caller handle interpretation) + printf "%s" "$colored_syntax" } # Extract all flags from man page or help @@ -663,15 +666,17 @@ browse_flags_fuzzy() { local flag_count=$(echo "$all_flags" | wc -l) # Colorize the syntax for the header + # colorize_syntax now returns raw \033 codes that printf %b will interpret local colored_syntax=$(colorize_syntax "$cmd_syntax") - # 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" + # Create multi-line header with command info using printf %b for proper escape code interpretation + # Use actual ANSI codes for command and description, use %b for colored syntax + local header + printf -v header "╔═══════════════════════════════════════════════════════════════════════════════╗\n║ Command: \033[0;36m\033[1m%s\033[0m\n║ Syntax: %b\n║ Desc: \033[0;32m%s\033[0m\n╚═══════════════════════════════════════════════════════════════════════════════╝\n🔍 Fuzzy search %d flags | Multi-select: Ctrl-A/D | Esc: Back to menu" \ + "$cmd_name" \ + "$colored_syntax" \ + "$cmd_desc" \ + "$flag_count" # Show in fzf with integrated command info echo "$all_flags" | fzf \ @@ -993,29 +998,34 @@ if [ "$INTERACTIVE" = true ]; then SYNTAX_PART="$CMD_NAME [options]" fi - # Truncate if too long + # Truncate description if too long if [ ${#DESC_PART} -gt $DESC_WIDTH ]; then DESC_PART="${DESC_PART:0:$((DESC_WIDTH-3))}..." fi + + # Truncate syntax if too long (before colorizing) if [ ${#SYNTAX_PART} -gt $SYNTAX_WIDTH ]; then SYNTAX_PART="${SYNTAX_PART:0:$((SYNTAX_WIDTH-3))}..." fi + # Colorize the syntax (command in cyan, [OPTIONS] in yellow, FILE in magenta, etc.) + # colorize_syntax returns raw string with \033 codes, need to preserve them + COLORIZED_SYNTAX=$(colorize_syntax "$SYNTAX_PART") + # Calculate exact padding needed for right-alignment - # Account for visual width only (not ANSI codes) + # Use UNCOLORIZED lengths for spacing calculation CMD_LEN=${#CMD_NAME} DESC_LEN=${#DESC_PART} - SYNTAX_LEN=${#SYNTAX_PART} + SYNTAX_LEN=${#SYNTAX_PART} # Use original length, not colorized - # Calculate spaces needed: terminal width - all visible characters - separator chars - # Visible: cmd + ": " + desc + syntax = CMD_LEN + 2 + DESC_LEN + SYNTAX_LEN + # Calculate spaces needed for flush right-alignment + # Account for: cmd + ": " + desc + spaces + syntax + # Reduce safety padding from 8 to 2 for tighter right-alignment VISIBLE_WIDTH=$((CMD_LEN + 2 + DESC_LEN + SYNTAX_LEN)) - NEEDED_SPACES=$((TERM_WIDTH - VISIBLE_WIDTH - 8)) # Extra padding for safety + NEEDED_SPACES=$((TERM_WIDTH - VISIBLE_WIDTH - 2)) # Minimal padding for flush right - # Minimum spacing - [ $NEEDED_SPACES -lt 3 ] && NEEDED_SPACES=3 - # Maximum spacing to prevent excessive gaps - [ $NEEDED_SPACES -gt 20 ] && NEEDED_SPACES=20 + # Ensure minimum spacing + [ $NEEDED_SPACES -lt 2 ] && NEEDED_SPACES=2 # Create spacing string SPACES=$(printf '%*s' "$NEEDED_SPACES" '') @@ -1023,8 +1033,8 @@ if [ "$INTERACTIVE" = true ]; then # Format with colors: # - Bright cyan for command name # - White for description - # - 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" + # - Colorized syntax (right-aligned with cyan cmd, yellow [OPTIONS], magenta FILE, etc.) + formatted_line="\033[0;36m${CMD_NAME}\033[0m: ${DESC_PART}${SPACES}${COLORIZED_SYNTAX}" FORMATTED_COMMANDS+=("$formatted_line") done @@ -1033,7 +1043,7 @@ if [ "$INTERACTIVE" = true ]; then SELECTED=$(printf "%b\n" "${FORMATTED_COMMANDS[@]}" | fzf \ --height 60% \ --border \ - --header "Select a command (Esc to exit) | cyan: command | description | dim: syntax" \ + --header "Select a command (Esc to exit) | Colorized: cmd=[cyan] [OPTIONS]=[yellow] FILE=[magenta]" \ --prompt "🔍 Search: " \ --preview-window=hidden \ --ansi)