From 3af2b2a6ffd8f0a19cec2abb1d9672d78afc8137 Mon Sep 17 00:00:00 2001 From: priestlypython Date: Tue, 28 Oct 2025 02:11:22 -0700 Subject: [PATCH] fix(ui): Fix color rendering and flush-right alignment MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Addressed three critical UI issues identified by user: 1. Fixed Color Codes Showing Literally in Flag Browser - Changed colorize_syntax() to return raw string with \033 codes - Updated to use printf instead of echo -e for proper escaping - Changed printf format from %s to %b for syntax interpretation - Escape codes now render as colors, not literal text 2. Improved Right-Alignment to Be Flush to Edge - Reduced safety padding from 8 to 2 characters - Syntax now sits tighter to right edge - Looks cleaner and more professional - Calculates: NEEDED_SPACES = TERM_WIDTH - VISIBLE_WIDTH - 2 3. Added Colorized Syntax to Interactive Menu - Applied colorize_syntax() to menu display (was dim cyan) - [OPTIONS] now shows in yellow - FILE, PATTERN etc. now show in magenta - Command names in cyan + bold - Consistent with explain mode and flag browser - Updated fzf header to reflect color scheme Technical Changes: - colorize_syntax(): Returns raw \033 codes via printf %s - Callers use printf %b to interpret escape sequences - browse_flags_fuzzy(): Uses %b format for syntax line - mode_explain(): Uses printf %b for colored output - Interactive menu: Applies colorize_syntax() to SYNTAX_PART Testing: - ✓ Explain mode: Colors render correctly - ✓ Interactive menu: Flush right, colorized syntax - ✓ No literal \033 codes appear - ✓ All three issues resolved Before: - Escape codes showing as literal text - Too much gap before syntax - Syntax all one color (dim cyan) After: - Colors render properly - Minimal 2-char gap (flush right) - [OPTIONS]=yellow, FILE=magenta, cmd=cyan --- bash-helper.sh | 72 ++++++++++++++++++++++++++++---------------------- 1 file changed, 41 insertions(+), 31 deletions(-) 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)