Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 20 additions & 13 deletions install.sh
Original file line number Diff line number Diff line change
Expand Up @@ -394,8 +394,9 @@ apply_patches() {
chmod +x "${patch_script}"

local patch_args=("${statusline_file}" "${working_dir}/messages/${language}.json")
[[ "${components}" != *"messages"* ]] && patch_args+=("--no-messages")
[[ "${components}" != *"cost"* ]] && patch_args+=("--no-cost")
[[ "${components}" != *"messages"* ]] && patch_args+=("--no-messages")
[[ "${components}" != *"cost"* ]] && patch_args+=("--no-cost")
[[ "${components}" != *"rainbow-wave"* ]] && patch_args+=("--no-rainbow-wave")

"${patch_script}" "${patch_args[@]}" || {
error "Patching failed"
Expand Down Expand Up @@ -449,28 +450,34 @@ prompt_component_selection() {
piped_status=$?
set -e
if [[ ${piped_status} -eq 0 ]]; then
echo "messages cost"
echo "messages cost rainbow-wave"
return
fi

echo "" >&2
echo -e "${CYAN}Select features:${NC}" >&2
echo "" >&2
echo " 1) All features (messages + cost)" >&2
echo " 2) Messages only" >&2
echo " 3) Cost only" >&2
echo " 4) Minimal (no messages, no cost)" >&2
echo " 1) All features (messages + cost + rainbow-wave)" >&2
echo " 2) Messages + Cost" >&2
echo " 3) Messages + Rainbow Wave" >&2
echo " 4) Messages only" >&2
echo " 5) Cost only" >&2
echo " 6) Rainbow Wave only" >&2
echo " 7) Minimal (no messages, no cost, no rainbow-wave)" >&2
echo "" >&2
printf "Enter selection [1]: " >&2
read -r selection < /dev/tty || selection=""
selection="${selection:-1}"

case "${selection}" in
1) echo "messages cost" ;;
2) echo "messages" ;;
3) echo "cost" ;;
4) echo "" ;;
*) echo "messages cost" ;;
1) echo "messages cost rainbow-wave" ;;
2) echo "messages cost" ;;
3) echo "messages rainbow-wave" ;;
4) echo "messages" ;;
5) echo "cost" ;;
6) echo "rainbow-wave" ;;
7) echo "" ;;
*) echo "messages cost rainbow-wave" ;;
esac
}

Expand Down Expand Up @@ -572,7 +579,7 @@ NODEEOF

main() {
local selected_language="en"
local selected_components="messages cost"
local selected_components="messages cost rainbow-wave"
local total_steps=5
local current_step=0
local status=0
Expand Down
24 changes: 16 additions & 8 deletions patch-statusline.sh
Original file line number Diff line number Diff line change
Expand Up @@ -23,18 +23,20 @@ set -euo pipefail # Exit on error, undefined vars, pipe failures
# ============================================================

show_usage() {
echo "Usage: $0 <statusline-file> [language-json] [--no-messages] [--no-cost]"
echo "Usage: $0 <statusline-file> [language-json] [--no-messages] [--no-cost] [--no-rainbow-wave]"
echo ""
echo "Arguments:"
echo " statusline-file Path to statusline.sh file (required)"
echo " language-json Path to JSON messages file (optional)"
echo " --no-messages Disable context messages"
echo " --no-cost Disable cost tracking"
echo " statusline-file Path to statusline.sh file (required)"
echo " language-json Path to JSON messages file (optional)"
echo " --no-messages Disable context messages"
echo " --no-cost Disable cost tracking"
echo " --no-rainbow-wave Disable rainbow wave progress bar"
echo ""
echo "Examples:"
echo " $0 statusline.sh messages/pt.json"
echo " $0 statusline.sh --no-messages"
echo " $0 statusline.sh messages/es.json --no-cost"
echo " $0 statusline.sh --no-rainbow-wave"
}

fail() {
Expand Down Expand Up @@ -68,9 +70,11 @@ replace_config_block() {
local file="$1"
local show_messages="$2"
local show_cost="$3"
local show_rainbow_wave="$4"
local content
content="readonly SHOW_MESSAGES=${show_messages}
readonly SHOW_COST=${show_cost}"
readonly SHOW_COST=${show_cost}
readonly SHOW_RAINBOW_WAVE=${show_rainbow_wave}"
_replace_marker_block "${file}" '@CONFIG_START' '@CONFIG_END' "${content}"
}

Expand Down Expand Up @@ -129,6 +133,7 @@ main() {
local language_json=""
local show_messages=true
local show_cost=true
local show_rainbow_wave=true

# Parse remaining args
shift
Expand All @@ -140,6 +145,9 @@ main() {
--no-cost)
show_cost=false
;;
--no-rainbow-wave)
show_rainbow_wave=false
;;
*.json)
language_json="${arg}"
;;
Expand Down Expand Up @@ -180,8 +188,8 @@ main() {
echo "Patching ${statusline_file}..."

# 1. Replace CONFIG block
replace_config_block "${statusline_file}" "${show_messages}" "${show_cost}"
echo " ✓ Updated configuration (SHOW_MESSAGES=${show_messages}, SHOW_COST=${show_cost})"
replace_config_block "${statusline_file}" "${show_messages}" "${show_cost}" "${show_rainbow_wave}"
echo " ✓ Updated configuration (SHOW_MESSAGES=${show_messages}, SHOW_COST=${show_cost}, SHOW_RAINBOW_WAVE=${show_rainbow_wave})"

# 2. Replace MESSAGES block (if language JSON provided)
if [[ -n "${language_json}" ]]; then
Expand Down
86 changes: 62 additions & 24 deletions statusline.sh
Original file line number Diff line number Diff line change
Expand Up @@ -35,12 +35,17 @@ readonly STATE_DIRTY="dirty"
readonly BAR_FILLED="█"
readonly BAR_EMPTY="░"

# Wave animation colors (256-color palette rainbow)
readonly WAVE_COLORS=(196 208 220 226 118 46 48 51 33 21 93 201)
readonly NUM_WAVE_COLORS=12

# ============================================================
# RUNTIME CONFIGURATION (Patched by patch-statusline.sh)
# ============================================================
# @CONFIG_START
readonly SHOW_MESSAGES=true
readonly SHOW_COST=true
readonly SHOW_RAINBOW_WAVE=true
# @CONFIG_END

# ============================================================
Expand Down Expand Up @@ -305,31 +310,42 @@ build_progress_bar() {
local filled=$((percent * BAR_WIDTH / 100))
local empty=$((BAR_WIDTH - filled))

# Determine bar color based on tier
local tier bar_color
tier=$(get_context_tier "${percent}")
local filled_bar="" i

case "${tier}" in
0) bar_color="${GREEN}" ;; # Very low
1) bar_color="${CYAN}" ;; # Low
2) bar_color="${ORANGE}" ;; # Medium
3) bar_color="${ORANGE}" ;; # High
4) bar_color="${RED}" ;; # Critical
*) bar_color="${GRAY}" ;; # Fallback
esac
if [[ "${SHOW_RAINBOW_WAVE}" == "true" ]]; then
# Build filled portion with rainbow wave animation
local color_idx
local time_phase=$(( ${_wave_time:-0} % NUM_WAVE_COLORS ))
for ((i=0; i<filled; i++)); do
color_idx=$(( (i + time_phase) % NUM_WAVE_COLORS ))
filled_bar+="\033[38;5;${WAVE_COLORS[${color_idx}]}m${BAR_FILLED}"
done
else
# Build filled portion with tier-based color
local tier bar_color
tier=$(get_context_tier "${percent}")
case "${tier}" in
0) bar_color="${GREEN}" ;;
1) bar_color="${CYAN}" ;;
2) bar_color="${ORANGE}" ;;
3) bar_color="${ORANGE}" ;;
4) bar_color="${RED}" ;;
*) bar_color="${GRAY}" ;;
esac
for ((i=0; i<filled; i++)); do
filled_bar+="${BAR_FILLED}"
done
filled_bar="${bar_color}${filled_bar}"
fi

# Build filled and empty portions (pure bash - UTF-8 safe)
local filled_bar="" empty_bar=""
local i
for ((i=0; i<filled; i++)); do
filled_bar+="${BAR_FILLED}"
done
# Build empty portion (stays gray)
local empty_bar=""
for ((i=0; i<empty; i++)); do
empty_bar+="${BAR_EMPTY}"
done

# Output with colors
echo -n "${bar_color}${filled_bar}${NC}${GRAY}${empty_bar}${NC}"
# Output: colored filled blocks + reset + gray empty blocks + reset
echo -n "${filled_bar}${NC}${GRAY}${empty_bar}${NC}"
}

# Get random context message based on usage percentage
Expand Down Expand Up @@ -415,7 +431,9 @@ get_git_info() {
local git_opts=()

# Validate and set git directory option
if is_present "${current_dir}"; then
local is_dir_present_rc=0
is_present "${current_dir}" || is_dir_present_rc=$?
if [[ "${is_dir_present_rc}" -eq 0 ]]; then
# Invoke validation separately to avoid masking return value
local validation_result=0
validate_directory "${current_dir}"
Expand Down Expand Up @@ -532,7 +550,14 @@ build_directory_component() {
local current_dir="$1"
local dir_name

if is_present "${current_dir}" && validate_directory "${current_dir}"; then
local present_rc=0 valid_rc=0
is_present "${current_dir}" || present_rc=$?
if [[ "${present_rc}" -eq 0 ]]; then
validate_directory "${current_dir}" || valid_rc=$?
else
valid_rc=1
fi
if [[ "${valid_rc}" -eq 0 ]]; then
dir_name=$(get_dirname "${current_dir}")
else
dir_name=$(get_dirname "${PWD}")
Expand Down Expand Up @@ -574,7 +599,9 @@ build_files_component() {
local file_count="$1"

# Only show if there are modified files
if is_present "${file_count}" && [[ "${file_count}" != "0" ]]; then
local has_files_rc=0
is_present "${file_count}" || has_files_rc=$?
if [[ "${has_files_rc}" -eq 0 ]] && [[ "${file_count}" != "0" ]]; then
echo "${CHANGE_ICON} ${ORANGE}changes${NC}"
fi
}
Expand All @@ -586,7 +613,9 @@ build_cost_component() {
[[ "${SHOW_COST}" != "true" ]] && return

# Validate cost is numeric before printf (prevents format string injection)
if is_present "${cost_usd}" && [[ "${cost_usd}" != "0" ]]; then
local has_cost_rc=0
is_present "${cost_usd}" || has_cost_rc=$?
if [[ "${has_cost_rc}" -eq 0 ]] && [[ "${cost_usd}" != "0" ]]; then
# Check if value is a valid number (integer or decimal)
if [[ "${cost_usd}" =~ ^[0-9]+(\.[0-9]+)?$ ]]; then
# Use LC_NUMERIC=C to ensure decimal point (not comma) for printf on Windows
Expand Down Expand Up @@ -694,9 +723,18 @@ EOF

# Strip carriage returns (Windows line endings compatibility)
for _v in model_name current_dir context_size current_usage context_percent cost_usd; do
declare "$_v=${!_v%$'\r'}"
declare "${_v}=${!_v%$'\r'}"
done

# Capture epoch time for wave animation (EPOCHSECONDS is free on bash 5+)
if [[ "${SHOW_RAINBOW_WAVE}" == "true" ]]; then
if [[ -n "${EPOCHSECONDS:-}" ]]; then
_wave_time="${EPOCHSECONDS}"
else
_wave_time=$(date +%s)
fi
fi

# Build components (read toggle flags from global constants)
local model_part context_part dir_part git_part cost_part files_part
model_part=$(build_model_component "${model_name}")
Expand Down