diff --git a/bash-helper.sh b/bash-helper.sh index af32d11..f0cd6c0 100755 --- a/bash-helper.sh +++ b/bash-helper.sh @@ -1071,6 +1071,81 @@ if [ -n "$MODE" ]; then esac fi +# Format commands for display - called once and cached for performance +format_commands_for_display() { + # Get terminal width for proper alignment + local term_width=$(tput cols 2>/dev/null || echo 120) + + # Conservative approach to prevent ANY clipping + # Account for fzf border, padding, and any other overhead + local safe_width=$((term_width - 6)) # 2 for border + 4 buffer for safety + + # Fixed 2-column layout: description on left, syntax on right + # Prioritize syntax visibility - give it 50% of space + local syntax_col_width=$((safe_width * 50 / 100)) + [ $syntax_col_width -lt 30 ] && syntax_col_width=30 + + # Description gets the rest (with separator space) + local desc_col_width=$((safe_width - syntax_col_width - 8)) + [ $desc_col_width -lt 25 ] && desc_col_width=25 + + # Format all commands with fixed column widths + FORMATTED_COMMANDS=() + for cmd in "${COMMANDS[@]}"; do + local cmd_name=${cmd%%:*} + local rest=${cmd#*:} + + # Extract description and syntax + local desc_part syntax_part + if [[ "$rest" =~ (.+)\ \|\ (.+) ]]; then + desc_part="${BASH_REMATCH[1]}" + syntax_part="${BASH_REMATCH[2]}" + else + desc_part="$rest" + syntax_part="$cmd_name [options]" + fi + + # Truncate description to fit column (cmd: + desc) + local cmd_desc_str="${cmd_name}: ${desc_part}" + local max_cmd_desc_len=$desc_col_width + + if [ ${#cmd_desc_str} -gt $max_cmd_desc_len ]; then + # Truncate description, keeping command name intact + local desc_available=$((max_cmd_desc_len - ${#cmd_name} - 5)) # 2 for ": ", 3 for "..." + if [ $desc_available -gt 10 ]; then + desc_part="${desc_part:0:$desc_available}..." + else + desc_part="..." + fi + cmd_desc_str="${cmd_name}: ${desc_part}" + fi + + # Truncate syntax to fit its column + local plain_syntax="$syntax_part" + if [ ${#syntax_part} -gt $syntax_col_width ]; then + plain_syntax="${syntax_part:0:$((syntax_col_width-3))}..." + fi + + # Colorize syntax after truncation + local colorized_syntax=$(colorize_syntax "$plain_syntax") + + # Calculate padding to place syntax in its column + local left_len=${#cmd_desc_str} + local syntax_len=${#plain_syntax} + + # Place syntax at fixed position (right-aligned within safe width) + local padding=$((safe_width - left_len - syntax_len - 2)) + [ $padding -lt 3 ] && padding=3 + + local spaces=$(printf '%*s' "$padding" '') + + # Format line with colors + local formatted_line="\033[0;36m${cmd_name}\033[0m: ${desc_part}${spaces}${colorized_syntax}" + + FORMATTED_COMMANDS+=("$formatted_line") + done +} + # Interactive mode with fzf (loopable) if [ "$INTERACTIVE" = true ]; then # Check if fzf is available @@ -1082,82 +1157,20 @@ if [ "$INTERACTIVE" = true ]; then exit 1 fi + # Format commands once before entering loop (performance optimization) + format_commands_for_display + + # Set up window resize detection to trigger reformatting + NEEDS_REFORMAT=false + trap 'NEEDS_REFORMAT=true' WINCH + # Main interactive loop while true; do - # Format commands for display: description on left, syntax on right - # Get terminal width for proper alignment - TERM_WIDTH=$(tput cols 2>/dev/null || echo 120) - - # Conservative approach to prevent ANY clipping - # Account for fzf border, padding, and any other overhead - # Subtract buffer to ensure syntax never clips - SAFE_WIDTH=$((TERM_WIDTH - 6)) # 2 for border + 4 buffer for safety - - # Fixed 2-column layout: description on left, syntax on right - # Prioritize syntax visibility - give it 50% of space - # Description gets remaining space - SYNTAX_COL_WIDTH=$((SAFE_WIDTH * 50 / 100)) - [ $SYNTAX_COL_WIDTH -lt 30 ] && SYNTAX_COL_WIDTH=30 - - # Description gets the rest (with separator space) - DESC_COL_WIDTH=$((SAFE_WIDTH - SYNTAX_COL_WIDTH - 8)) - [ $DESC_COL_WIDTH -lt 25 ] && DESC_COL_WIDTH=25 - - # Format all commands with fixed column widths - FORMATTED_COMMANDS=() - for cmd in "${COMMANDS[@]}"; do - CMD_NAME=${cmd%%:*} - REST=${cmd#*:} - - # Extract description and syntax - if [[ "$REST" =~ (.+)\ \|\ (.+) ]]; then - DESC_PART="${BASH_REMATCH[1]}" - SYNTAX_PART="${BASH_REMATCH[2]}" - else - DESC_PART="$REST" - SYNTAX_PART="$CMD_NAME [options]" - fi - - # Truncate description to fit column (cmd: + desc) - CMD_DESC_STR="${CMD_NAME}: ${DESC_PART}" - MAX_CMD_DESC_LEN=$((DESC_COL_WIDTH)) - - if [ ${#CMD_DESC_STR} -gt $MAX_CMD_DESC_LEN ]; then - # Truncate description, keeping command name intact - DESC_AVAILABLE=$((MAX_CMD_DESC_LEN - ${#CMD_NAME} - 5)) # 2 for ": ", 3 for "..." - if [ $DESC_AVAILABLE -gt 10 ]; then - DESC_PART="${DESC_PART:0:$DESC_AVAILABLE}..." - else - DESC_PART="..." - fi - CMD_DESC_STR="${CMD_NAME}: ${DESC_PART}" - fi - - # Truncate syntax to fit its column - PLAIN_SYNTAX="$SYNTAX_PART" - if [ ${#SYNTAX_PART} -gt $SYNTAX_COL_WIDTH ]; then - PLAIN_SYNTAX="${SYNTAX_PART:0:$((SYNTAX_COL_WIDTH-3))}..." - fi - - # Colorize syntax after truncation - COLORIZED_SYNTAX=$(colorize_syntax "$PLAIN_SYNTAX") - - # Calculate padding to place syntax in its column - LEFT_LEN=${#CMD_DESC_STR} - SYNTAX_LEN=${#PLAIN_SYNTAX} - - # Place syntax at fixed position (right-aligned within safe width) - # Use fixed spacing to create consistent column layout - PADDING=$((SAFE_WIDTH - LEFT_LEN - SYNTAX_LEN - 2)) - [ $PADDING -lt 3 ] && PADDING=3 - - SPACES=$(printf '%*s' "$PADDING" '') - - # Format line with colors - formatted_line="\033[0;36m${CMD_NAME}\033[0m: ${DESC_PART}${SPACES}${COLORIZED_SYNTAX}" - - FORMATTED_COMMANDS+=("$formatted_line") - done + # Reformat commands if terminal was resized + if [ "$NEEDS_REFORMAT" = true ]; then + format_commands_for_display + NEEDS_REFORMAT=false + fi # Show in fzf with formatted display SELECTED=$(printf "%b\n" "${FORMATTED_COMMANDS[@]}" | fzf \