fix(ui): Fix color rendering and flush-right alignment

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
This commit is contained in:
2025-10-28 02:11:22 -07:00
parent c0af8c15ca
commit 3af2b2a6ff
+41 -31
View File
@@ -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)