From def2127ed6e421a4433aeb439f3e42e29fbc15ff Mon Sep 17 00:00:00 2001 From: rootiest Date: Mon, 4 May 2026 21:44:01 -0400 Subject: [PATCH] feat: add dependency check and refactor global state - Implement check_deps function and --check-deps flag for environment validation. - Add truecolor support detection for terminal swatches. - Colorize --install output and stylized logo. - Refactor script to use global constants for colors and paths. - Improve installation logic with robust directory creation. - Update README.md and --help with new flag and detailed prerequisites. --- README.md | 49 ++++-- color-tool | 426 ++++++++++++++++++++++++++++++++--------------------- 2 files changed, 297 insertions(+), 178 deletions(-) diff --git a/README.md b/README.md index eb71338..1b65bbb 100644 --- a/README.md +++ b/README.md @@ -16,30 +16,56 @@ A feature-rich, portable CLI color utility for Linux, specializing in color pick ## 📋 Prerequisites -To utilize all features, ensure the following are installed: -- **KDE Plasma + Wayland:** Required for the `--pick` functionality. -- **Python 3 + PyQt6:** Required for the picker helper. -- **curl + jq:** Required for color naming support. -- **wl-clipboard** (Wayland) or **xclip** (X11): Required for clipboard support. -- **libnotify:** Required for desktop notifications (`notify-send`). -- **ImageMagick (`magick` or `convert`):** Required for generating visual color swatches in desktop notifications. +### Required Core Dependencies +These are mandatory for the script to run and perform basic color conversions: +- **Python 3:** Handles all color space math and conversions. +- **jq:** Powers JSON formatting and internal data parsing. + +### Optional Feature Dependencies +These enable specific functionality and can be installed as needed: +- **KDE Plasma (Wayland):** Required for screen color picking (`--pick`). +- **Python 3 PyQt6:** Required for the KDE color picker DBus interface. +- **wl-clipboard** or **xclip:** Enables copying results to the system clipboard (`--copy`). +- **curl:** Required for fetching human-readable color names from the web (`--name`). +- **libnotify:** Enables desktop notifications (`--notify`). +- **ImageMagick:** Generates visual color swatch icons for notifications (`--swatch`). +- **Truecolor Terminal Emulator:** Required for accurate visual swatches in terminal output (`--swatch`). + +> **Tip:** Use `color-tool --check-deps` to quickly see which dependencies are currently met on your system. ## 🚀 Installation +### Automatic Installation (Recommended) + You can download the script directly from the [latest release](https://git.rootiest.dev/rootiest/color-tool/releases/latest) and install it: ```bash -curl -sSLO https://git.rootiest.dev/rootiest/color-tool/releases/download/latest/color-tool -chmod +x color-tool -./color-tool --install +# Download and install the latest version of the color-tool script +curl -sSLO https://git.rootiest.dev/rootiest/color-tool/releases/download/latest/color-tool && bash color-tool --install && rm ./color-tool ``` This will: -1. Move the script to `~/.local/share/color-tool/`. +1. Install the script to `~/.local/share/color-tool/`. 2. Symlink the binary to `~/.local/bin/color-tool`. 3. Generate a sample configuration at `~/.config/color-tool/config.toml`. 4. Create a `.desktop` entry so you can launch the picker from your application menu. 5. Verify and warn about any missing optional or required system dependencies. +6. Clean up the downloaded script after installation. + +### Manual Usage + +Alternatively, you can [download the script](https://git.rootiest.dev/rootiest/color-tool/releases/latest) manually. +Then run it from any location without installation: + +```bash +# Make script executable +chmod +x color-tool +# Run script directly +./color-tool --pick --output hex,rgb +``` + +However, this will not add the script to your `$PATH` or create a desktop entry, +so you won't be able to launch it from the app menu or use it globally without specifying the path. ## 🛠 Usage @@ -58,6 +84,7 @@ Options: --get-config Print the current configuration --set-config Update the configuration (e.g. --set-config desktop --copy) --reset-config Restore the configuration file to its default values + --check-deps Check system dependencies and environment support --install Install to ~/.local/share/ and symlink to ~/.local/bin/ --help, -h Show this help message ``` diff --git a/color-tool b/color-tool index a74cbd4..0be1e2e 100755 --- a/color-tool +++ b/color-tool @@ -25,6 +25,31 @@ SCRIPT_DIR="$(dirname "$(readlink -f "$0")")" CONFIG_FILE="$HOME/.config/color-tool/config.toml" REPO_URL="https://git.rootiest.dev/rootiest/color-tool" +# Colors and styles +BOLD='\033[1m' +DIM='\033[2m' +RESET='\033[0m' +CYAN='\033[36m' +YELLOW='\033[33m' +GREEN='\033[32m' +MAG='\033[35m' +RED='\033[31m' + +# Gradient logo colors +C1='\033[38;2;255;80;80m' # Red-ish +C2='\033[38;2;255;160;0m' # Orange +C3='\033[38;2;220;210;0m' # Yellow +C4='\033[38;2;80;200;80m' # Green +C5='\033[38;2;80;160;255m' # Blue + +# Path constants +DATA_DIR="$HOME/.local/share/color-tool" +BIN_DIR="$HOME/.local/bin" +BIN_PATH="$BIN_DIR/color-tool" +CONFIG_DIR="$HOME/.config/color-tool" +APP_DIR="$HOME/.local/share/applications" +DESKTOP_FILE="$APP_DIR/color-tool.desktop" + # ── Initial Defaults ────────────────────────────────────────────────────────── # Hardcoded base defaults @@ -64,7 +89,7 @@ get_config() { echo "Error: Config file not found at $CONFIG_FILE" >&2 exit 1 fi - + local first_section=1 while IFS= read -r line || [[ -n "$line" ]]; do local stripped="${line%%#*}" @@ -72,7 +97,7 @@ get_config() { if [[ -z "$stripped" ]]; then continue fi - + if [[ "$stripped" =~ ^\[([A-Za-z_-]+)\]$ ]]; then if [[ $first_section -eq 0 ]]; then echo "" @@ -84,7 +109,7 @@ get_config() { local val="${BASH_REMATCH[2]}" printf "%-6s = %s\n" "$key" "$val" fi - done < "$CONFIG_FILE" + done <"$CONFIG_FILE" } set_config() { @@ -98,7 +123,7 @@ set_config() { shift fi fi - + local new_output="" local new_json="" local new_swatch="" @@ -110,34 +135,34 @@ set_config() { while [[ $# -gt 0 ]]; do case "$1" in - --output=*) new_output="${1#*=}" ;; - output=*) new_output="${1#*=}" ;; - --json) new_json="true" ;; - --no-json) new_json="false" ;; - --alpha) new_alpha="true" ;; - --no-alpha) new_alpha="false" ;; - --name) new_name="true" ;; - --no-name) new_name="false" ;; - --swatch) new_swatch="true" ;; - --no-swatch) new_swatch="false" ;; - --copy) new_copy="true" ;; - --no-copy) new_copy="false" ;; - --notify) new_notify="true" ;; - --no-notify) new_notify="false" ;; - --pick) new_pick="true" ;; - --no-pick) new_pick="false" ;; - -*) - echo "Error: Unknown option for --set-config: $1" >&2 - exit 1 - ;; - *) - echo "Error: Unknown argument for --set-config: $1" >&2 - exit 1 - ;; + --output=*) new_output="${1#*=}" ;; + output=*) new_output="${1#*=}" ;; + --json) new_json="true" ;; + --no-json) new_json="false" ;; + --alpha) new_alpha="true" ;; + --no-alpha) new_alpha="false" ;; + --name) new_name="true" ;; + --no-name) new_name="false" ;; + --swatch) new_swatch="true" ;; + --no-swatch) new_swatch="false" ;; + --copy) new_copy="true" ;; + --no-copy) new_copy="false" ;; + --notify) new_notify="true" ;; + --no-notify) new_notify="false" ;; + --pick) new_pick="true" ;; + --no-pick) new_pick="false" ;; + -*) + echo "Error: Unknown option for --set-config: $1" >&2 + exit 1 + ;; + *) + echo "Error: Unknown argument for --set-config: $1" >&2 + exit 1 + ;; esac shift done - + if [[ -n "$new_output" ]]; then new_output="${new_output#\"}" new_output="${new_output%\"}" @@ -147,91 +172,91 @@ set_config() { echo "Error: Config file not found at $CONFIG_FILE. Run --install first." >&2 exit 1 fi - + local temp_file temp_file="$(mktemp)" local current_section="" - + while IFS= read -r line || [[ -n "$line" ]]; do local original_line="$line" local parsed_line="${line%%#*}" - + if [[ "$parsed_line" =~ ^\[([A-Za-z_-]+)\]$ ]]; then current_section="${BASH_REMATCH[1]}" - echo "$original_line" >> "$temp_file" + echo "$original_line" >>"$temp_file" continue fi - + if [[ "$current_section" == "$target_section" && "$parsed_line" =~ ^[[:space:]]*([A-Za-z_]+)[[:space:]]*= ]]; then local key="${BASH_REMATCH[1]}" local new_val="" case "$key" in - output) - if [[ -n "$new_output" ]]; then new_val="\"$new_output\""; fi - ;; - json) - if [[ -n "$new_json" ]]; then new_val="$new_json"; fi - ;; - alpha) - if [[ -n "$new_alpha" ]]; then new_val="$new_alpha"; fi - ;; - swatch) - if [[ -n "$new_swatch" ]]; then new_val="$new_swatch"; fi - ;; - name) - if [[ -n "$new_name" ]]; then new_val="$new_name"; fi - ;; - copy) - if [[ -n "$new_copy" ]]; then new_val="$new_copy"; fi - ;; - pick) - if [[ -n "$new_pick" ]]; then new_val="$new_pick"; fi - ;; - notify) - if [[ -n "$new_notify" ]]; then new_val="$new_notify"; fi - ;; + output) + if [[ -n "$new_output" ]]; then new_val="\"$new_output\""; fi + ;; + json) + if [[ -n "$new_json" ]]; then new_val="$new_json"; fi + ;; + alpha) + if [[ -n "$new_alpha" ]]; then new_val="$new_alpha"; fi + ;; + swatch) + if [[ -n "$new_swatch" ]]; then new_val="$new_swatch"; fi + ;; + name) + if [[ -n "$new_name" ]]; then new_val="$new_name"; fi + ;; + copy) + if [[ -n "$new_copy" ]]; then new_val="$new_copy"; fi + ;; + pick) + if [[ -n "$new_pick" ]]; then new_val="$new_pick"; fi + ;; + notify) + if [[ -n "$new_notify" ]]; then new_val="$new_notify"; fi + ;; esac - + if [[ -n "$new_val" ]]; then if [[ "$original_line" =~ ^([[:space:]]*[A-Za-z_]+[[:space:]]*=[[:space:]]*)([^[:space:]#]+)(.*)$ ]]; then - local prefix="${BASH_REMATCH[1]}" - local old_val="${BASH_REMATCH[2]}" - local suffix="${BASH_REMATCH[3]}" - - # Adjust whitespace to keep comments aligned if the value length changed - if [[ "$key" != "output" ]]; then - local old_len=${#old_val} - local new_len=${#new_val} - local diff=$((old_len - new_len)) - - if [[ $diff -gt 0 ]]; then - # new value is shorter, add spaces to suffix - local spaces="" - for ((i=0; i> "$temp_file" - continue + local prefix="${BASH_REMATCH[1]}" + local old_val="${BASH_REMATCH[2]}" + local suffix="${BASH_REMATCH[3]}" + + # Adjust whitespace to keep comments aligned if the value length changed + if [[ "$key" != "output" ]]; then + local old_len=${#old_val} + local new_len=${#new_val} + local diff=$((old_len - new_len)) + + if [[ $diff -gt 0 ]]; then + # new value is shorter, add spaces to suffix + local spaces="" + for ((i = 0; i < diff; i++)); do spaces+=" "; done + suffix="$spaces$suffix" + elif [[ $diff -lt 0 ]]; then + # new value is longer, remove spaces from suffix + local remove=$((-diff)) + for ((i = 0; i < remove; i++)); do + if [[ "$suffix" == " "* ]]; then + suffix="${suffix# }" + fi + done + fi + fi + + echo "$prefix$new_val$suffix" >>"$temp_file" + continue elif [[ "$original_line" =~ ^([[:space:]]*[A-Za-z_]+[[:space:]]*=[[:space:]]*)(.*)$ ]]; then - echo "${BASH_REMATCH[1]}$new_val" >> "$temp_file" - continue + echo "${BASH_REMATCH[1]}$new_val" >>"$temp_file" + continue fi fi fi - - echo "$original_line" >> "$temp_file" - done < "$CONFIG_FILE" - + + echo "$original_line" >>"$temp_file" + done <"$CONFIG_FILE" + mv "$temp_file" "$CONFIG_FILE" } @@ -312,43 +337,37 @@ reset_config() { # ── Help ────────────────────────────────────────────────────────────────────── show_help() { - local bold='\033[1m' - local dim='\033[2m' - local reset='\033[0m' - local cyan='\033[36m' - local yellow='\033[33m' - local mag='\033[35m' - printf "\n" # Title: "color" in a rainbow gradient, "-tool" in bold - printf " ${bold}\033[38;2;255;80;80mc\033[38;2;255;160;0mo\033[38;2;220;210;0ml\033[38;2;80;200;80mo\033[38;2;80;160;255mr${reset}${bold}-tool${reset}" - printf " ${dim}— pick, convert, and format colors${reset}\n\n" + printf " ${BOLD}${C1}c${C2}o${C3}l${C4}o${C5}r${RESET}${BOLD}-tool${RESET}" + printf " ${DIM}— pick, convert, and format colors${RESET}\n\n" - printf " ${bold}${yellow}Usage${reset} ${cyan}${0##*/}${reset} ${dim}[OPTIONS]${reset} [COLOR ...]\n\n" + printf " ${BOLD}${YELLOW}Usage${RESET} ${CYAN}${0##*/}${RESET} ${DIM}[OPTIONS]${RESET} [COLOR ...]\n\n" - printf " ${bold}${yellow}Options${reset}\n" - printf " ${bold}${cyan}--[no-]pick${reset} Open the KDE Plasma color picker ${dim}(requires KDE + Wayland)${reset}\n" - printf " ${bold}${cyan}--output${reset} ${dim}FMT${reset} Format(s) to output: ${cyan}hex, rgb, hsl, rgba, hsla, hexa, all${reset} ${dim}(comma-separated)${reset}\n" - printf " ${bold}${cyan}--[no-]json${reset} Output as a JSON table of selected formats\n" - printf " ${bold}${cyan}--[no-]name${reset} Fetch nearest color name from thecolorapi.com ${dim}(requires curl, jq)${reset}\n" - printf " ${bold}${cyan}--[no-]swatch${reset} Include a color swatch in the terminal output and desktop notification\n" - printf " ${bold}${cyan}--[no-]copy${reset} Copy result to clipboard ${dim}(wl-clipboard preferred, xclip as fallback)${reset}\n" - printf " ${bold}${cyan}--[no-]notify${reset} Show desktop notification ${dim}(on by default in --desktop)${reset}\n" - printf " ${bold}${cyan}--desktop${reset} GUI mode: pick → copy → notify ${dim}(for app menu / .desktop launcher)${reset}\n" - printf " ${bold}${cyan}--get-config${reset} Print the current configuration\n" - printf " ${bold}${cyan}--set-config${reset} Update the configuration ${dim}(e.g. --set-config desktop --copy)${reset}\n" - printf " ${bold}${cyan}--reset-config${reset} Restore the configuration file to its default values\n" - printf " ${bold}${cyan}--install${reset} Install to ~/.local/share/color-tool/ and symlink into ~/.local/bin/\n" - printf " ${bold}${cyan}--help${reset}, ${bold}${cyan}-h${reset} Show this help message\n\n" + printf " ${BOLD}${YELLOW}Options${RESET}\n" + printf " ${BOLD}${CYAN}--[no-]pick${RESET} Open the KDE Plasma color picker ${DIM}(requires KDE + Wayland)${RESET}\n" + printf " ${BOLD}${CYAN}--output${RESET} ${DIM}FMT${RESET} Format(s) to output: ${CYAN}hex, rgb, hsl, rgba, hsla, hexa, all${RESET} ${DIM}(comma-separated)${RESET}\n" + printf " ${BOLD}${CYAN}--[no-]json${RESET} Output as a JSON table of selected formats\n" + printf " ${BOLD}${CYAN}--[no-]name${RESET} Fetch nearest color name from thecolorapi.com ${DIM}(requires curl, jq)${RESET}\n" + printf " ${BOLD}${CYAN}--[no-]swatch${RESET} Include a color swatch in the terminal output and desktop notification\n" + printf " ${BOLD}${CYAN}--[no-]copy${RESET} Copy result to clipboard ${DIM}(wl-clipboard preferred, xclip as fallback)${RESET}\n" + printf " ${BOLD}${CYAN}--[no-]notify${RESET} Show desktop notification ${DIM}(on by default in --desktop)${RESET}\n" + printf " ${BOLD}${CYAN}--desktop${RESET} GUI mode: pick → copy → notify ${DIM}(for app menu / .desktop launcher)${RESET}\n" + printf " ${BOLD}${CYAN}--get-config${RESET} Print the current configuration\n" + printf " ${BOLD}${CYAN}--set-config${RESET} Update the configuration ${DIM}(e.g. --set-config desktop --copy)${RESET}\n" + printf " ${BOLD}${CYAN}--reset-config${RESET} Restore the configuration file to its default values\n" + printf " ${BOLD}${CYAN}--check-deps${RESET} Check system dependencies and environment support\n" + printf " ${BOLD}${CYAN}--install${RESET} Install to ~/.local/share/color-tool/ and symlink into ~/.local/bin/\n" + printf " ${BOLD}${CYAN}--help${RESET}, ${BOLD}${CYAN}-h${RESET} Show this help message\n\n" - printf " ${bold}${yellow}Examples${reset}\n" - printf " ${cyan}${0##*/}${reset} ${mag}\"#534145\"${reset} --swatch\n" - printf " ${cyan}${0##*/}${reset} --pick --output rgb,hsl --json\n" - printf " ${cyan}${0##*/}${reset} \"rgb(255, 100, 0)\" --output hex,hsla\n\n" + printf " ${BOLD}${YELLOW}Examples${RESET}\n" + printf " ${CYAN}${0##*/}${RESET} ${MAG}\"#534145\"${RESET} --swatch\n" + printf " ${CYAN}${0##*/}${RESET} --pick --output rgb,hsl --json\n" + printf " ${CYAN}${0##*/}${RESET} \"rgb(255, 100, 0)\" --output hex,hsla\n\n" - printf " ${bold}${yellow}Config${reset} ${dim}~/.config/color-tool/config.toml${reset}\n" - printf " ${dim}[defaults]${reset} keys: ${cyan}output json swatch name copy pick notify${reset}\n" - printf " ${dim}[desktop]${reset} keys: ${cyan}output json name notify copy swatch${reset} ${dim}(pick always on)${reset}\n\n" + printf " ${BOLD}${YELLOW}Config${RESET} ${DIM}~/.config/color-tool/config.toml${RESET}\n" + printf " ${DIM}[defaults]${RESET} keys: ${CYAN}output json swatch name copy pick notify${RESET}\n" + printf " ${DIM}[desktop]${RESET} keys: ${CYAN}output json name notify copy swatch${RESET} ${DIM}(pick always on)${RESET}\n\n" } # ── Environment detection ───────────────────────────────────────────────────── @@ -365,6 +384,26 @@ check_kde_wayland() { fi } +check_truecolor() { + # Standard way to check for truecolor support + if [[ "${COLORTERM:-}" == "truecolor" || "${COLORTERM:-}" == "24bit" ]]; then + return 0 + fi + # Some terminals report color count via tput + if command -v tput >/dev/null 2>&1; then + local colors + colors=$(tput colors 2>/dev/null || echo 0) + if [[ $colors -ge 16777216 ]]; then + return 0 + fi + fi + # Check for direct color in TERM + if [[ "${TERM:-}" == *"-direct"* ]]; then + return 0 + fi + return 1 +} + # ── Clipboard & Notifications ───────────────────────────────────────────────── copy_to_clipboard() { @@ -479,49 +518,92 @@ run_color_picker() { suggest_path_add() { local bin_dir="$1" is_fish=0 + # Direct check [[ "${SHELL:-}" == */fish ]] && is_fish=1 + + # Parent process check (good for sub-shells) if [[ $is_fish -eq 0 ]]; then local parent parent=$(ps -p "$PPID" -o comm= 2>/dev/null || true) [[ "$parent" == *fish* ]] && is_fish=1 fi + if [[ $is_fish -eq 1 ]]; then - printf " Run: fish_add_path %s\n" "$bin_dir" + printf " ${CYAN}Run:${RESET} fish_add_path %s\n" "$bin_dir" + elif [[ "${SHELL:-}" == */zsh ]]; then + printf " ${CYAN}Add to ~/.zshrc:${RESET} export PATH=\"%s:\$PATH\"\n" "$bin_dir" else - printf " For bash/zsh: export PATH=\"%s:\$PATH\"\n" "$bin_dir" - printf " For fish: fish_add_path %s\n" "$bin_dir" + # Fallback for Bash or unknown + printf " ${CYAN}Add to ~/.bashrc:${RESET} export PATH=\"%s:\$PATH\"\n" "$bin_dir" + printf " ${DIM}(Or use fish_add_path if using Fish)${RESET}\n" fi } +check_deps() { + printf "\n ${BOLD}Dependency Check${RESET}\n\n" + + _check() { + local label="$1" + local cmd="$2" + local desc="$3" + local required="${4:-0}" + + printf " " + if eval "$cmd"; then + printf "${GREEN}✔${RESET} " + else + if [[ $required -eq 1 ]]; then + printf "${RED}✘${RESET} " + else + printf "${YELLOW}⚠${RESET} " + fi + fi + + printf "%-25s ${DIM}%s${RESET}\n" "$label" "$desc" + } + + _check "python3" "command -v python3 >/dev/null" "Core logic and color conversions" 1 + _check "python3-pyqt6" "python3 -c 'import PyQt6.QtDBus' 2>/dev/null" "KDE color picker interface" 0 + _check "jq" "command -v jq >/dev/null" "JSON output and data parsing" 1 + _check "curl" "command -v curl >/dev/null" "Fetching color names from API" 0 + _check "wl-clipboard / xclip" "command -v wl-copy >/dev/null || command -v xclip >/dev/null" "System clipboard integration" 0 + _check "libnotify" "command -v notify-send >/dev/null" "Desktop notifications" 0 + _check "ImageMagick" "command -v magick >/dev/null || command -v convert >/dev/null" "Color swatches in notifications" 0 + _check "KDE Plasma (Wayland)" "[[ -n \"${WAYLAND_DISPLAY:-}\" ]] && { local d=\"${XDG_CURRENT_DESKTOP:-}\"; [[ \"\$d\" == *KDE* || -n \"${KDE_FULL_SESSION:-}\" ]]; }" "Required for screen color picking" 0 + _check "Truecolor Support" "check_truecolor" "Color swatches in terminal output" 0 + + printf "\n ${DIM}Legend: ${GREEN}✔${DIM} Found ${YELLOW}⚠${DIM} Missing (Optional) ${RED}✘${DIM} Missing (Required)${RESET}\n\n" +} + check_dependencies() { local missing=() - + if ! command -v magick >/dev/null 2>&1 && ! command -v convert >/dev/null 2>&1; then missing+=("ImageMagick (magick or convert) — required for notification color swatches") fi - + if ! command -v wl-copy >/dev/null 2>&1 && ! command -v xclip >/dev/null 2>&1; then missing+=("wl-clipboard (wl-copy) or xclip — required for clipboard copy support") fi - + if ! command -v python3 >/dev/null 2>&1; then missing+=("python3 — required for color conversions and picker GUI") elif ! python3 -c "import PyQt6.QtDBus" >/dev/null 2>&1; then missing+=("python3-pyqt6 — required for the KDE color picker DBus interface") fi - + if ! command -v jq >/dev/null 2>&1; then missing+=("jq — required for JSON formatting and color names") fi - + if ! command -v curl >/dev/null 2>&1; then missing+=("curl — required for fetching color names from the API") fi - + if ! command -v notify-send >/dev/null 2>&1; then missing+=("libnotify (notify-send) — required for desktop notifications") fi - + local env_ok=1 if [[ -z "${WAYLAND_DISPLAY:-}" ]]; then env_ok=0 @@ -530,71 +612,77 @@ check_dependencies() { if [[ "$desktop" != *KDE* ]] && [[ -z "${KDE_FULL_SESSION:-}" ]]; then env_ok=0 fi - + if [[ $env_ok -eq 0 ]]; then missing+=("KDE Plasma on Wayland — required for the screen color picker feature") fi - + + if ! check_truecolor; then + missing+=("Truecolor support not detected — the --swatch feature in the terminal may not work as intended") + fi + if [[ ${#missing[@]} -gt 0 ]]; then - local yellow='\033[33m' - local bold='\033[1m' - local reset='\033[0m' - printf "\n ${bold}${yellow}Warnings — Missing optional dependencies:${reset}\n" + printf "\n ${BOLD}${YELLOW}Warnings — Missing optional dependencies:${RESET}\n" for item in "${missing[@]}"; do printf " - %s\n" "$item" done - printf " ${yellow}Functionality will be limited without these installed.${reset}\n" + printf " ${YELLOW}Functionality will be limited without these installed.${RESET}\n" fi } do_install() { - local data_dir="$HOME/.local/share/color-tool" - local bin_dir="$HOME/.local/bin" - local bin_link="$bin_dir/color-tool" local src_script src_script="$(readlink -f "$0")" - mkdir -p "$data_dir" "$bin_dir" - cp "$src_script" "$data_dir/color-tool" - chmod +x "$data_dir/color-tool" - generate_picker_script "$data_dir/wl-colorpicker-plasma.py" - ln -sf "$data_dir/color-tool" "$bin_link" + printf "\n ${BOLD}Installing ${C1}c${C2}o${C3}l${C4}o${C5}r${RESET}${BOLD}-tool...${RESET}\n\n" - local config_dir="$HOME/.config/color-tool" - local config_file="$config_dir/config.toml" - if [[ ! -f "$config_file" ]]; then + # Efficient Directory Creation Loop + local dirs=("$BIN_DIR" "$DATA_DIR" "$CONFIG_DIR" "$APP_DIR") + for dir in "${dirs[@]}"; do + if [[ ! -d "$dir" ]]; then + printf " ${DIM}Creating %s...${RESET}\n" "$dir" + mkdir -p "$dir" + fi + done + + # Core installation steps + cp "$src_script" "$DATA_DIR/color-tool" + chmod +x "$DATA_DIR/color-tool" + generate_picker_script "$DATA_DIR/wl-colorpicker-plasma.py" + ln -sf "$DATA_DIR/color-tool" "$BIN_PATH" + + # Config setup + if [[ ! -f "$CONFIG_FILE" ]]; then write_default_config - printf " config %s (sample created)\n" "$config_file" + printf " ${BOLD}${GREEN}config${RESET} %s ${DIM}(sample created)${RESET}\n" "$CONFIG_FILE" else - printf " config %s\n" "$config_file" + printf " ${BOLD}${GREEN}config${RESET} %s\n" "$CONFIG_FILE" fi - local app_dir="$HOME/.local/share/applications" - local desktop_file="$app_dir/color-tool.desktop" - local bin_path="$HOME/.local/bin/color-tool" - mkdir -p "$app_dir" - cat >"$desktop_file" <"$DESKTOP_FILE" < %s\n" "$bin_link" "$data_dir/color-tool" + # Summary output + printf " ${BOLD}${GREEN}app${RESET} %s\n" "$DESKTOP_FILE" + printf " ${BOLD}${GREEN}data${RESET} %s/\n" "$DATA_DIR" + printf " ${BOLD}${GREEN}bin${RESET} %s -> %s\n" "$BIN_PATH" "$DATA_DIR/color-tool" - if [[ ":$PATH:" != *":$bin_dir:"* ]]; then - printf "\nNote: %s is not in your PATH.\n" "$bin_dir" - suggest_path_add "$bin_dir" + # Path verification + if [[ ":$PATH:" != *":$BIN_DIR:"* ]]; then + printf "\n${BOLD}${YELLOW}Warning:${RESET} %s is not in your PATH.\n" "$BIN_DIR" + suggest_path_add "$BIN_DIR" fi check_dependencies @@ -800,6 +888,10 @@ while [[ $# -gt 0 ]]; do reset_config exit 0 ;; + --check-deps) + check_deps + exit 0 + ;; -*) echo "Unknown option: $1" >&2 exit 1 -- 2.52.0