feat(ui): Add color-coordinated syntax, fix clipping, redesign flag browser
Major UI improvements addressing user feedback:
1. Color-Coordinated Syntax Highlighting
- Command names: Bright cyan + bold
- [OPTIONS]/[OPTION]: Yellow
- UPPERCASE args (FILE, PATH, STRING): Magenta
- Lowercase optional args: Green
- Ellipsis (...): Dim white
- Applied to both interactive menu and explain mode
2. Fixed Clipping Bug in Interactive Menu
- Recalculated width allocations more conservatively
- Changed to percentage-based DESC_WIDTH (40% of terminal)
- Added min/max caps for widths
- Improved spacing calculation (TERM_WIDTH - VISIBLE_WIDTH - 8)
- Added safety bounds (min 3, max 20 spaces)
- Syntax now always visible (truncated with ... if needed)
3. Redesigned Flag Browser for Better UX
- Eliminated wasted dead space above fzf
- Integrated syntax and description INTO fzf header
- Created elegant box header with command info:
- Command name
- Colorized syntax
- Description
- Height increased to 95% for more flags visible
- Preview window reduced to down:3:wrap
- Removed echo spam ("Extracting flags...", "Found X flags...")
- Clean, immediate transition to flag browser
4. Updated Function Signatures
- show_flags() now accepts: cmd_name, syntax, description
- browse_flags_fuzzy() now accepts: cmd_name, syntax, description
- Interactive mode passes all three parameters
- Explain mode uses colorize_syntax() function
5. New Functions
- colorize_syntax(): Parse and colorize syntax by element type
- Applied consistently across all display modes
User Experience Improvements:
- ✅ No more clipping - syntax always visible
- ✅ Instant recognition of parameter types via color
- ✅ No wasted screen space before flag browser
- ✅ Command info integrated cleanly in fzf interface
- ✅ Professional, color-coordinated appearance
Technical Details:
- Width calculation: DESC (40% terminal), SYNTAX (remaining - 25)
- Safety bounds on all width calculations
- Color coordination: cyan/yellow/magenta/green/dim
- Consistent formatting across interactive and explain modes
This commit is contained in:
+111
-86
@@ -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 ""
|
||||
|
||||
Reference in New Issue
Block a user