diff --git a/functions/__fish_palette.fish b/functions/__fish_palette.fish new file mode 100644 index 0000000..7097f39 --- /dev/null +++ b/functions/__fish_palette.fish @@ -0,0 +1,63 @@ +# Copyright (C) 2026 Rootiest +# SPDX-License-Identifier: AGPL-3.0-or-later + +# SYNOPSIS +# __fish_palette +# +# DESCRIPTION +# Defines the shared terminal-output colour roles used by the +# user-facing functions in this configuration. Declared +# --no-scope-shadowing and using a bare `set`, so the variables are +# created in the CALLER's scope -- a consumer just calls it and then +# interpolates $c_head, $c_err and friends exactly as it did when the +# declarations were inline. +# +# Call it where the local declarations used to sit, once per contiguous +# block that needs the palette. set_color runs at call time, so the +# values track $TERM exactly as inline declarations did. (Measured: +# set_color output is identical across every TERM tested except +# TERM=dumb, which yields empty strings, and is unaffected by whether +# stdout is a tty or a pipe.) +# +# A role is a semantic slot, not a colour. c_flag and c_warn are both +# yellow but stay separate, as do c_ok and c_accent (both green) -- +# merging either pair would foreclose ever restyling one without the +# other. c_accent is the command name in logs and smart_exit, which +# style it green where the rest of the config styles it bold. +# +# ARGUMENTS +# none +# +# EXIT STATUS +# 0 always +# +# EXAMPLE +# function mytool +# __fish_palette +# echo "$c_head""Usage:$c_reset $c_cmd""mytool$c_reset" +# end +# +# NOTES +# Calling this at top level (outside any function) creates GLOBAL +# variables. Every consumer calls it from inside a function, where the +# variables stay function-local and do not leak. +# +# functions/fish_prompt.fish deliberately does NOT use this palette. Its +# c_* values are Catppuccin hex strings passed as ARGUMENTS to set_color +# (`set_color --bold $c_green`), not captured escape sequences -- colour +# inputs rather than rendered output, a different concern. + +function __fish_palette --no-scope-shadowing --description 'Define the shared output colour palette in the caller scope' + set c_reset (set_color normal) + set c_head (set_color --bold cyan) + set c_cmd (set_color --bold) + set c_arg (set_color cyan) + set c_flag (set_color yellow) + set c_warn (set_color yellow) + set c_err (set_color red) + set c_ok (set_color green) + set c_accent (set_color green) + set c_dim (set_color brblack) + set c_sel (set_color --bold magenta) + set c_hi (set_color --bold white) +end diff --git a/tests/functional.fish b/tests/functional.fish index e4d1651..68c64e8 100644 --- a/tests/functional.fish +++ b/tests/functional.fish @@ -97,6 +97,33 @@ function test_vault_dir_honors_override test "$got" = /tmp/vault-override-check end +function test_palette_roles_defined + functions -q __fish_palette + or begin + echo " __fish_palette is not defined" + return 1 + end + # Called from inside a function, the palette must land in THIS scope. + __fish_palette + set -l missing + for role in c_reset c_head c_cmd c_arg c_flag c_warn c_err c_ok \ + c_accent c_dim c_sel c_hi + if not set -q $role; or test -z "$$role" + set -a missing $role + end + end + if test (count $missing) -gt 0 + echo " palette roles empty or unset: $missing" + return 1 + end + # Nothing may leak to global scope. + if set -q -g c_reset + echo " __fish_palette leaked c_reset into global scope" + return 1 + end + return 0 +end + function functional_test_main set -l names (functions -a | string match 'test_*' | sort) set -l failed 0