From 2c81a48fe9b5a0ffb322348fdced4489513bafb3 Mon Sep 17 00:00:00 2001 From: fatalerrors Date: Thu, 21 May 2026 16:12:56 +0200 Subject: [PATCH] added rainbow --- README.md | 2 + doc/profile.conf.example | 4 + profile.d/help.sh | 1 + profile.d/rain.sh | 198 ++++++++++++++++++++++++++++++++++++++- 4 files changed, 202 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index a359b85..914d0ed 100644 --- a/README.md +++ b/README.md @@ -116,6 +116,7 @@ A bar-style prompt showing current time, execution time of the last command | `profile_upgrade` | updates | Upgrade profile to the latest version (git pull or archive) | | `pwdscore` | pwd | Calculate the strength score of a given password | | `rain` | rain | Console screensaver with falling-rain effect (multiple color themes) | +| `rainbow` | rain | Full-screen rainbow screensaver using only background colors, with horizontal color shifting | | `rmhost` | ssh | Remove host (name and IP) from SSH known_hosts; supports `--all-users` as root | | `rmspc` | filefct | Replace spaces in filenames with underscores (or a custom character) | | `setc` | lang | Set locale to standard C (POSIX) | @@ -189,6 +190,7 @@ change the default without having to pass flags every time. | `RAIN_DEFAULT_SPEED` | `0.1` | Falling speed for `rain` | | `RAIN_DEFAULT_COLOR` | `Green` | Colour for `rain` | | `RAIN_DEFAULT_DENSITY` | dynamic | Maximum number of simultaneous falling elements for `rain` | +| `RAINBOW_DEFAULT_SPEED` | `0.04` | Horizontal color shift speed for `rainbow` | | `MATRIX_DEFAULT_SPEED` | `0.05` | Falling speed for `matrix` | | `MATRIX_DEFAULT_COLOR` | `Green` | Colour for `matrix` | | `MATRIX_DEFAULT_DENSITY` | dynamic | Maximum number of simultaneous falling elements for `matrix` | diff --git a/doc/profile.conf.example b/doc/profile.conf.example index d21e707..ae3b28f 100755 --- a/doc/profile.conf.example +++ b/doc/profile.conf.example @@ -233,6 +233,10 @@ TERM=xterm-256color # Leave unset to keep the terminal-size-based dynamic default. #RAIN_DEFAULT_DENSITY=80 +# rainbow: Horizontal color shift speed — integer/100 gives seconds (4 → 0.04 s). +# Values < 1 are used as raw seconds. +#RAINBOW_DEFAULT_SPEED=4 + # matrix: Falling speed. #MATRIX_DEFAULT_SPEED=3.5 diff --git a/profile.d/help.sh b/profile.d/help.sh index 5c3dc34..cfb26ac 100644 --- a/profile.d/help.sh +++ b/profile.d/help.sh @@ -89,6 +89,7 @@ help() printf "profile_upgrade\tUpgrade profile to the latest version (git pull or archive)\n" printf "pwdscore\tCalculate the strength score of a given password\n" printf "rain\t\tConsole screensaver with falling-rain effect (multiple color themes)\n" + printf "rainbow\t\tFull-screen rainbow screensaver using background colors only\n" printf "rmhost\t\tRemove host (name and IP) from SSH known_hosts; supports --all-users as root\n" printf "rmspc\t\tReplace spaces in filenames with underscores (or a custom character)\n" printf "setlocale\tSet console locale to any installed locale\n" diff --git a/profile.d/rain.sh b/profile.d/rain.sh index a5fa50d..86598e0 100644 --- a/profile.d/rain.sh +++ b/profile.d/rain.sh @@ -121,6 +121,76 @@ _rain_normalize_density() printf "%s" "$raw_density" } +_rainbow_supports_truecolor() +{ + case "${COLORTERM:-}" in + *truecolor*|*24bit*) + return 0 + ;; + esac + + case "${TERM:-}" in + *direct*|*truecolor*) + return 0 + ;; + esac + + return 1 +} + +_rainbow_build_palette() +{ + local palette_width="$1" + local use_truecolor="$2" + local x=0 wheel_pos=0 band=0 blend=0 + local red=0 green=0 blue=0 + + RAINBOW_BG_PALETTE=() + + if (( palette_width < 1 )); then + RAINBOW_BG_PALETTE+=("\e[41m") + return 0 + fi + + if (( use_truecolor )); then + for ((x = 0; x < palette_width; x++)); do + wheel_pos=$((x * 1536 / palette_width)) + band=$((wheel_pos / 256)) + blend=$((wheel_pos % 256)) + + case "$band" in + 0) + red=255; green=$blend; blue=0 + ;; + 1) + red=$((255 - blend)); green=255; blue=0 + ;; + 2) + red=0; green=255; blue=$blend + ;; + 3) + red=0; green=$((255 - blend)); blue=255 + ;; + 4) + red=$blend; green=0; blue=255 + ;; + *) + red=255; green=0; blue=$((255 - blend)) + ;; + esac + + RAINBOW_BG_PALETTE+=("\e[48;2;${red};${green};${blue}m") + done + else + local ansi_palette=(41 101 43 103 42 102 46 106 44 104 45 105) + local ansi_count=${#ansi_palette[@]} + + for ((x = 0; x < palette_width; x++)); do + RAINBOW_BG_PALETTE+=("\e[${ansi_palette[x * ansi_count / palette_width]}m") + done + fi +} + _rain_engine() { local step_duration="$1" @@ -152,7 +222,6 @@ _rain_engine() local term_area=0 local frame_sleep="$step_duration" - local sigwinch sigwinch() { term_width=$(tput cols) @@ -194,13 +263,11 @@ _rain_engine() fi } - local do_exit do_exit() { exit_st=1 } - local do_render do_render() { local idx=0 y=0 drop_color="" current_char="" render_color="" @@ -497,6 +564,131 @@ matrix() _rain_engine "$step_duration" "$base_color" "matrix" "$charset" "$density_override" } export -f matrix + +# ------------------------------------------------------------------------------ +# Full-screen rainbow screensaver +# Usage: rainbow [OPTIONS] +rainbow() +{ + local PARSED + + PARSED=$(getopt -o hs: --long help,speed: -n 'rainbow' -- "$@") + # shellcheck disable=SC2181 # getopt return code is checked immediately after + if [[ $? -ne 0 ]]; then + disp E "Invalid options, use \"rainbow --help\" to display usage." + return 1 + fi + + local _raw_speed="${RAINBOW_DEFAULT_SPEED:-4}" + local frame_sleep + frame_sleep=$(_rain_normalize_speed "$_raw_speed") || frame_sleep=0.040 + + eval set -- "$PARSED" + while true; do + case "$1" in + -h|--help) + printf "Usage: rainbow [OPTIONS]\n" + printf "Options:\n" + printf "\t-s, --speed NUM\tSet horizontal color shift speed (default: 4 => 0.040s).\n" + printf "\t\t\t\tValues >=1 use a /100 scale (4 => 0.04s).\n" + printf "\t\t\t\tValues <1 are interpreted as raw seconds.\n" + printf "\t-h, --help\t\tDisplay this help message and exit.\n\n" + printf "The rainbow fills the whole terminal with background colors only.\n" + printf "It uses truecolor when supported, otherwise ANSI bright backgrounds.\n" + printf "Press q to quit.\n" + return 0 + ;; + -s|--speed) + frame_sleep=$(_rain_normalize_speed "$2") || { + disp E "--speed requires a numeric value." + return 1 + } + shift 2 + ;; + --) + shift + break + ;; + *) + disp E "Invalid options, use \"rainbow --help\" to display usage." + return 1 + ;; + esac + done + + command -v tput >/dev/null 2>&1 || { + disp E "The program 'tput' is required but not installed." + return 1 + } + + local exit_st=0 + local term_height=0 term_width=0 + local use_truecolor=0 + local offset=0 row=0 col=0 palette_width=0 idx=0 + local row_line="" ch="" + + sigwinch() + { + term_width=$(tput cols) + term_height=$(tput lines) + ((term_width < 1)) && term_width=1 + ((term_height < 1)) && term_height=1 + + if _rainbow_supports_truecolor; then + use_truecolor=1 + else + use_truecolor=0 + fi + + palette_width=$term_width + _rainbow_build_palette "$palette_width" "$use_truecolor" + } + + do_exit() + { + exit_st=1 + } + + trap do_exit TERM INT + trap sigwinch WINCH + stty -echo + printf "\e[?25l" + printf "\e[2J" + + sigwinch + while ((exit_st <= 0)); do + read -r -n 1 -t "$frame_sleep" ch + case "$ch" in + q|Q) + do_exit + ;; + esac + + row_line="" + for ((col = 0; col < term_width; col++)); do + idx=$((col - offset)) + while ((idx < 0)); do + ((idx += palette_width)) + done + idx=$((idx % palette_width)) + row_line+="${RAINBOW_BG_PALETTE[idx]} " + done + row_line+=$'\e[0m' + + for ((row = 1; row <= term_height; row++)); do + printf "\e[%d;1H%b" "$row" "$row_line" + done + + ((offset = (offset + 1) % palette_width)) + done + + printf "\e[0m\e[2J\e[H" + printf "\e[?25h" + stty echo + trap - TERM INT + trap - WINCH +} +export -f rainbow # ------------------------------------------------------------------------------ load_conf "rain"