2 Commits

Author SHA1 Message Date
rootiest e5bbc5ae19 Merge pull request 'feat: dependency check system and global refactor' (#12) from feat/dependency-check-and-refactor into main
Reviewed-on: #12
2026-05-05 01:46:26 +00:00
rootiest def2127ed6 feat: add dependency check and refactor global state
Auto Label PRs / label (pull_request) Successful in 2s
Test PR / test (pull_request) Successful in 7s
Release on Merge / release (pull_request) Successful in 5s
- 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.
2026-05-04 21:44:01 -04:00
2 changed files with 297 additions and 178 deletions
+38 -11
View File
@@ -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
```
+259 -167
View File
@@ -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<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
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" <<EOF
# Desktop Entry (using consolidated BIN_PATH)
cat >"$DESKTOP_FILE" <<EOF
[Desktop Entry]
Version=1.1
Type=Application
Name=Color Tool
Comment=Pick a color and copy it to the clipboard
Exec=$bin_path --desktop
Exec=$BIN_PATH --desktop
Icon=color-picker
Categories=Utility;Graphics;
Keywords=color;picker;hex;rgb;clipboard;
Terminal=false
NoDisplay=false
EOF
printf " app %s\n" "$desktop_file"
printf "Installed:\n"
printf " data %s/\n" "$data_dir"
printf " bin %s -> %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