[3/6] color: add colors to zone and ports

Submitted by Jonatan Schlag on June 9, 2017, 10:17 a.m.

Details

Message ID 1497003452-10190-3-git-send-email-jonatan.schlag@ipfire.org
State Superseded
Headers show

Commit Message

Jonatan Schlag June 9, 2017, 10:17 a.m.
The following patch adds color support for zone and ports

color_cli()
Is the cli function to parse the options submitted by a user.

color_set()
Write a given color into the color config file of a zone or port.

color_read()
Read a color out of color config file of a zone or port.
If this is unsuccessful we use white.

color_format_filename()
Formats the color config file name.

color_hex_is_valid()
Check if a color hex is valid.

color_hex2rgb()
Converts a color hex into rgb values.

_find_nearest_rgb_value()
Find the nearest value to an rgb value out of:
0; 95; 135; 175; 215; 255;

color_rgb2shell()
Converts a rgb value triple into an xterm color code.

_set_color()
Set the shell color which unfourtunately does not work for putty.

shell_set_color()
Function to set the back and foreground color at once.

shell_reset_color()
Reset the shell color.

Signed-off-by: Jonatan Schlag <jonatan.schlag@ipfire.org>
---
 src/functions/functions.colors | 196 +++++++++++++++++++++++++++++++++++++++++
 1 file changed, 196 insertions(+)

Patch hide | download patch | download mbox

diff --git a/src/functions/functions.colors b/src/functions/functions.colors
index 8d7193c..9a3a529 100644
--- a/src/functions/functions.colors
+++ b/src/functions/functions.colors
@@ -73,3 +73,199 @@  MSG_STP_DISCARDING="${CLR_RED_BG}${CLR_WHITE_B} DISCARDING ${CLR_RESET}"
 MSG_STP_LEARNING="${CLR_YELLOW_BG}${CLR_WHITE_B}  LEARNING   ${CLR_RESET}"
 MSG_STP_LISTENING="${CLR_YELLOW_BG}${CLR_WHITE_B}  LISTENING  ${CLR_RESET}"
 MSG_STP_BLOCKING="${CLR_RED_BG}${CLR_WHITE_B}  BLOCKING   ${CLR_RESET}"
+
+color_cli() {
+	local type=${1}
+	local name=${2}
+	local action=${3}
+	shift 3
+
+	case ${action} in
+		set)
+			color_set ${type} ${name} ${@}
+			;;
+		reset)
+			# We set the color to white.
+			color_set ${type} ${name} "ffffff"
+			;;
+		*)
+			error "Invalid argument: ${action}"
+			;;
+	esac
+
+}
+
+
+
+color_set() {
+
+	local type=${1}
+	local name=${2}
+	local COLOR=${3}
+	# Check if we get to many arguments
+	shift 3
+	if [ $# -gt 0 ]; then
+		error "Too many arguments: $@"
+		return ${EXIT_ERROR}
+	fi
+	# Check if the color code is valid
+	if ! color_hex_is_valid ${COLOR}; then
+		error "Hexadecimal color code '${COLOR}' is not valid"
+		return ${EXIT_ERROR}
+	fi
+
+	local file=$(color_format_filename ${type} ${name})
+	settings_write ${file} COLOR
+}
+
+color_read() {
+	local type=${1}
+	local name=${2}
+
+	local file=$(color_format_filename ${type} ${name})
+
+	local COLOR
+
+	if ! settings_read ${file} COLOR; then
+		COLOR="ffffff"
+	fi
+
+	print "${COLOR}"
+}
+
+color_format_filename() {
+	local type=${1}
+	local name=${2}
+	case ${type} in
+		zone)
+			echo "$(zone_dir ${name})/color"
+			;;
+		port)
+			echo "$(port_dir ${name})/color"
+			;;
+	esac
+}
+
+color_hex_is_valid() {
+	[[ ${1} =~ ^[0-9a-fA-F]{6}$ ]]
+}
+
+color_hex2rgb() {
+	local hex=${1}
+
+	assert [ ${#hex} -eq 6 ]
+
+	for (( i = 0; i < 6; i += 2 )); do
+		hex2dec ${hex:${i}:2}
+	done | tr '\n' ' '
+
+	print # newline
+}
+
+_find_nearest_rgb_value() {
+	# For the calculation of the xterm value the rgb values must be:
+	# 0; 95; 135; 175; 215; 255;
+	# this function find the closest value of these 6 numbers for a give rgb number
+	local rgb=${1}
+
+	local best_value
+	local best_value_index
+
+	local values=( 0 95 135 175 215 255 )
+	local result
+	local i=0
+
+	local value
+	for value in ${values[@]}; do
+		result=$(( ${value} - ${rgb} ))
+		result=$(abs ${result})
+
+		if [ -z ${best_value} ]; then
+			best_value=${result}
+			best_value_index=${i}
+
+		# In the first iteration best_value is empty and so set to ${result}
+		# two lines above. So if statement must use -le because in the first iteration
+		# is the best_value eqal to result
+		elif [ ${result} -le ${best_value} ]; then
+			best_value=${result}
+			best_value_index=${i}
+		fi
+
+		(( i++ ))
+	done
+
+	echo "${best_value_index}"
+}
+
+color_rgb2shell() {
+	assert [ $# -eq 3 ]
+
+	local red=${1}
+	local green=${2}
+	local blue=${3}
+
+	local color
+	for color in red green blue; do
+		printf -v "${color}" $(_find_nearest_rgb_value ${!color})
+	done
+
+	print $(( 16 + 36 * ${red} + 6 * ${green} + ${blue} ))
+}
+
+_set_color() {
+	local where=${1}
+	local color=${2}
+
+	local prefix
+	case "${where}" in
+		fg)
+			prefix="\e[38"
+			;;
+		bg)
+			prefix="\e[48"
+			;;
+	esac
+
+	# Convert color from hex to RGB
+	local red green blue
+	read red green blue <<< $(color_hex2rgb ${color})
+
+	# Set standard shell color
+	local shell_color=$(color_rgb2shell ${red} ${green} ${blue})
+	printf "${prefix};5;${shell_color}m"
+
+	# For shells that support it, we will try to set the RGB color code
+	case "${TERM}" in
+		putty*)
+			# PuTTY us a piece of garbage and does not know
+			# how to handle colors at all although it has nice
+			# checkboxes to enable them, but they actually make
+			# things even worse. So no colors for you Windows
+			# users.
+			;;
+		*)
+			printf "${prefix};2;${red};${green};${blue}m"
+			;;
+	esac
+}
+
+shell_set_color() {
+	local fg=${1}
+	local bg=${2}
+
+	local i
+	for i in fg bg; do
+		# Skip if color is empty
+		[ -n "${!i}" ] || continue
+
+		# Skip for dash
+		[ "${!i}" = "-" ] && continue
+
+		_set_color ${i} ${!i}
+	done
+}
+
+shell_reset_color() {
+	printf "\e[0m"
+}

Comments

Michael Tremer June 14, 2017, 9 p.m.
Hi,

On Fri, 2017-06-09 at 12:17 +0200, Jonatan Schlag wrote:
> The following patch adds color support for zone and ports

These comments about what the functions do should actually be in the
code.

> color_cli()
> Is the cli function to parse the options submitted by a user.
> 
> color_set()
> Write a given color into the color config file of a zone or port.
> 
> color_read()
> Read a color out of color config file of a zone or port.
> If this is unsuccessful we use white.
> 
> color_format_filename()
> Formats the color config file name.
> 
> color_hex_is_valid()
> Check if a color hex is valid.
> 
> color_hex2rgb()
> Converts a color hex into rgb values.
> 
> _find_nearest_rgb_value()
> Find the nearest value to an rgb value out of:
> 0; 95; 135; 175; 215; 255;
> 
> color_rgb2shell()
> Converts a rgb value triple into an xterm color code.
> 
> _set_color()
> Set the shell color which unfourtunately does not work for putty.
> 
> shell_set_color()
> Function to set the back and foreground color at once.
> 
> shell_reset_color()
> Reset the shell color.
> 
> Signed-off-by: Jonatan Schlag <jonatan.schlag@ipfire.org>
> ---
>  src/functions/functions.colors | 196
> +++++++++++++++++++++++++++++++++++++++++
>  1 file changed, 196 insertions(+)
> 
> diff --git a/src/functions/functions.colors
> b/src/functions/functions.colors
> index 8d7193c..9a3a529 100644
> --- a/src/functions/functions.colors
> +++ b/src/functions/functions.colors
> @@ -73,3 +73,199 @@ MSG_STP_DISCARDING="${CLR_RED_BG}${CLR_WHITE_B}
> DISCARDING ${CLR_RESET}"
>  MSG_STP_LEARNING="${CLR_YELLOW_BG}${CLR_WHITE_B}  LEARNING   ${CLR_R
> ESET}"
>  MSG_STP_LISTENING="${CLR_YELLOW_BG}${CLR_WHITE_B}  LISTENING  ${CLR_
> RESET}"
>  MSG_STP_BLOCKING="${CLR_RED_BG}${CLR_WHITE_B}  BLOCKING   ${CLR_RESE
> T}"
> +
> +color_cli() {
> +	local type=${1}
> +	local name=${2}
> +	local action=${3}
> +	shift 3
> +
> +	case ${action} in
> +		set)
> +			color_set ${type} ${name} ${@}
> +			;;
> +		reset)
> +			# We set the color to white.
> +			color_set ${type} ${name} "ffffff"
> +			;;
> +		*)
> +			error "Invalid argument: ${action}"
> +			;;
> +	esac
> +
> +}
> +
> +
> +
> +color_set() {

... There is a little bit too much whitespace before color_set()
starts.

> +
> +	local type=${1}
> +	local name=${2}
> +	local COLOR=${3}
> +	# Check if we get to many arguments
> +	shift 3
> +	if [ $# -gt 0 ]; then
> +		error "Too many arguments: $@"
> +		return ${EXIT_ERROR}
> +	fi

This will just print the message "Too many arguments" without telling
what function is actually complaining about anything.

> +	# Check if the color code is valid
> +	if ! color_hex_is_valid ${COLOR}; then
> +		error "Hexadecimal color code '${COLOR}' is not
> valid"
> +		return ${EXIT_ERROR}
> +	fi
> +
> +	local file=$(color_format_filename ${type} ${name})
> +	settings_write ${file} COLOR
> +}
> +
> +color_read() {
> +	local type=${1}
> +	local name=${2}
> +
> +	local file=$(color_format_filename ${type} ${name})
> +
> +	local COLOR
> +
> +	if ! settings_read ${file} COLOR; then
> +		COLOR="ffffff"
> +	fi
> +
> +	print "${COLOR}"
> +}
> +
> +color_format_filename() {
> +	local type=${1}
> +	local name=${2}
> +	case ${type} in
> +		zone)
> +			echo "$(zone_dir ${name})/color"
> +			;;
> +		port)
> +			echo "$(port_dir ${name})/color"
> +			;;
> +	esac
> +}
> +
> +color_hex_is_valid() {
> +	[[ ${1} =~ ^[0-9a-fA-F]{6}$ ]]
> +}
> +
> +color_hex2rgb() {
> +	local hex=${1}
> +
> +	assert [ ${#hex} -eq 6 ]
> +
> +	for (( i = 0; i < 6; i += 2 )); do
> +		hex2dec ${hex:${i}:2}
> +	done | tr '\n' ' '
> +
> +	print # newline
> +}
> +
> +_find_nearest_rgb_value() {
> +	# For the calculation of the xterm value the rgb values must
> be:
> +	# 0; 95; 135; 175; 215; 255;
> +	# this function find the closest value of these 6 numbers
> for a give rgb number
> +	local rgb=${1}
> +
> +	local best_value
> +	local best_value_index
> +
> +	local values=( 0 95 135 175 215 255 )
> +	local result
> +	local i=0
> +
> +	local value
> +	for value in ${values[@]}; do
> +		result=$(( ${value} - ${rgb} ))
> +		result=$(abs ${result})
> +
> +		if [ -z ${best_value} ]; then
> +			best_value=${result}
> +			best_value_index=${i}
> +
> +		# In the first iteration best_value is empty and so
> set to ${result}
> +		# two lines above. So if statement must use -le
> because in the first iteration
> +		# is the best_value eqal to result
> +		elif [ ${result} -le ${best_value} ]; then
> +			best_value=${result}
> +			best_value_index=${i}
> +		fi
> +
> +		(( i++ ))
> +	done
> +
> +	echo "${best_value_index}"
> +}
> +
> +color_rgb2shell() {
> +	assert [ $# -eq 3 ]
> +
> +	local red=${1}
> +	local green=${2}
> +	local blue=${3}
> +
> +	local color
> +	for color in red green blue; do
> +		printf -v "${color}" $(_find_nearest_rgb_value
> ${!color})
> +	done
> +
> +	print $(( 16 + 36 * ${red} + 6 * ${green} + ${blue} ))
> +}
> +
> +_set_color() {
> +	local where=${1}
> +	local color=${2}
> +
> +	local prefix
> +	case "${where}" in
> +		fg)
> +			prefix="\e[38"
> +			;;
> +		bg)
> +			prefix="\e[48"
> +			;;
> +	esac
> +
> +	# Convert color from hex to RGB
> +	local red green blue
> +	read red green blue <<< $(color_hex2rgb ${color})
> +
> +	# Set standard shell color
> +	local shell_color=$(color_rgb2shell ${red} ${green} ${blue})
> +	printf "${prefix};5;${shell_color}m"
> +
> +	# For shells that support it, we will try to set the RGB
> color code
> +	case "${TERM}" in
> +		putty*)
> +			# PuTTY us a piece of garbage and does not
> know
> +			# how to handle colors at all although it
> has nice
> +			# checkboxes to enable them, but they
> actually make
> +			# things even worse. So no colors for you
> Windows
> +			# users.
> +			;;
> +		*)
> +			printf
> "${prefix};2;${red};${green};${blue}m"
> +			;;
> +	esac
> +}

The shell functions should probably be moved to an own functions file
(ending with .shell of course), or should be renamed to cli_*, because
I think that is where they actually fit in best.

> +
> +shell_set_color() {
> +	local fg=${1}
> +	local bg=${2}
> +
> +	local i
> +	for i in fg bg; do
> +		# Skip if color is empty
> +		[ -n "${!i}" ] || continue
> +
> +		# Skip for dash
> +		[ "${!i}" = "-" ] && continue
> +
> +		_set_color ${i} ${!i}
> +	done
> +}
> +
> +shell_reset_color() {
> +	printf "\e[0m"
> +}