fontctrl/fontctrl
2023-08-03 05:02:08 +02:00

241 lines
10 KiB
Bash
Executable file

#!/bin/sh
# fontctrl
# Minimal font manager for GNU/Linux.
# https://git.speedie.site/speedie/fontctrl
#
# Copyright (C) 2022-2023 speedie
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>.
# hardcoded base directories, can however be overriden by exporting these
FONTCTRL_BASEDIR_USER="${FONTCTRL_BASEDIR_USER:-$HOME/.config/fontctrl}"
FONTCTRL_BASEDIR_GLOBAL="${FONTCTRL_BASEDIR_GLOBAL:-/etc/fontctrl}"
FONTCTRL_VER="${FONTCTRL_VER:-1.3}"
GLOBALFONTDIR="${GLOBALFONTDIR:-/usr/share/fonts/fonts}"
USERFONTDIR="${USERFONTDIR:-$HOME/.local/share/fonts}"
# wrapper functions to clean up codebase
die() { stderr "$@"; exit 1; }
msg() { [ -n "$*" ] && printf "%s\n" "$@"; }
msg_n() { [ -n "$*" ] && printf "%s" "$@"; }
stderr() { msg "$@" >&2; }
is_narg() { echo "$carg" | grep -qE "$copt|--global|--user" && return 1 || return 0; }
# help argument
ls_args() {
msg "fontctrl - minimal font manager for POSIX compliant shells."
msg "usage: [stdin] fontctrl [install FONT] [remove FONT] [list] [enable FONT] [disable FONT] [license] [help] [version] [arg]"
msg "--global perform the action as a superuser."
msg "--user perform the action as the current user."
}
# create base for fontctrl
mk() {
# create base directories where font symlinks and configurations for fonts will be placed.
[ "$(id -u)" = "0" ] && \
mkdir -p $FONTCTRL_BASEDIR_GLOBAL/fonts && isroot=true; \
mkdir -p "$FONTCTRL_BASEDIR_USER/fonts"
echo "$arg" | grep -q "global" && isglobal=true
FAIL_NOROOT() {
[ -z "$isroot" ] || return
die "This action must be used as root."
}
echo "$arg" | grep -q "global" && FAIL_NOROOT
}
# function to parse arguments and install fonts
install_font() {
exitcode=0 # exit code
[ -z "$2" ] && die "You must specify a font to install."
# loop through arguments
for i in $(seq "$argc"); do
carg="$(printf "%s\n" "$@" | sed -n "${i}","${i}"p)"
copt=install
is_narg || continue
[ ! -e "$carg" ] && exitcode=1 && stderr "Font '$carg' does not exist." && continue || arg2="$carg"
[ ! -e "$carg" ] && die "Failed to install '$carg': Not a valid font, exiting." || msg "Installing font '$carg'."
# install the font
[ "$isroot" != "true" ] && cp -f "$arg2" "$FONTCTRL_BASEDIR_USER/fonts/" && msg "Font '$arg2' installed successfully for $(whoami)." && hi=true && continue
[ "$isroot" = "true" ] && cp -f "$arg2" "$FONTCTRL_BASEDIR_GLOBAL/fonts/" && msg "Font '$arg2' installed globally successfully." && hi=true && continue
done
[ "$hi" != "true" ] && die "Font does not exist."
if [ "$isroot" != "true" ]; then
msg "Run fontctrl list --user followed by fontctrl enable <font> --user to enable the font."
else
msg "Run fontctrl list --global followed by fontctrl enable <font> --global to enable the font."
fi
return $exitcode # return the exit code
}
# function to parse arguments and remove fonts
rm_font() {
exitcode=0 # exit code
[ -z "$2" ] && die "You must specify a font to remove."
for i in $(seq "$argc"); do
carg="$(printf "%s\n" "$@" | sed -n "${i}","${i}"p)"
copt=remove
is_narg || continue
[ -z "$arg2" ] && msg "You must specify a font to remove." && exit 1
# remove globally
if [ "$isglobal" = "true" ]; then
selfont="$(find "$FONTCTRL_BASEDIR_GLOBAL"/fonts/*"$carg"* -type f 2>/dev/null | head -n 1)" # Head in case there are multiple matches
[ ! -e "$selfont" ] && exitcode=1 && stderr "No fonts matching '$carg' found." && continue
msg "Removing font '$selfont' globally."
hi=true
rm -f "$FONTCTRL_BASEDIR_GLOBAL/fonts/$selfont" && msg "Font '$selfont' removed successfully. Run fontctrl list to see available fonts."
else # for the user
selfont="$(find "$FONTCTRL_BASEDIR_USER"/fonts/*"$carg"* -type f 2>/dev/null | head -n 1)" # Head in case there are multiple matches
[ ! -e "$selfont" ] && exitcode=1 && stderr "No fonts matching '$carg' found." && continue
msg "Removing font '$selfont' for $(whoami)"
hi=true
rm -f "$selfont" && msg "Font '$selfont' removed successfully. Run fontctrl list to see available fonts."
fi
done
[ "$hi" != "true" ] && die "Font does not exist."
return $exitcode # return the exit code
}
# function to parse arguments and enable fonts
enable_font() {
exitcode=0 # exit code
[ -z "$2" ] && die "You must specify a font to enable."
for i in $(seq "$argc"); do
carg="$(printf "%s\n" "$@" | sed -n "${i}","${i}"p)"
copt=enable
is_narg || continue
if [ "$isglobal" != "true" ]; then # user
selfont="$(find "$FONTCTRL_BASEDIR_USER"/fonts/*"$carg"* -type f 2>/dev/null | head -n 1)" # Head in case there are multiple matches
b_selfont="$(basename "$selfont")"
[ ! -e "$selfont" ] && exitcode=1 && stderr "No fonts matching '$carg' found." && continue
msg "Enabling font '$b_selfont' for $(whoami)"
mkdir -p "$USERFONTDIR/fontctrl-fonts"
rm -f "$USERFONTDIR/fontctrl-fonts/$b_selfont"
hi=true
[ -e "$FONTCTRL_BASEDIR_USER/fonts/$b_selfont" ] && ln -s "$FONTCTRL_BASEDIR_USER/fonts/$b_selfont" "$USERFONTDIR/fontctrl-fonts/$b_selfont" && msg "Font '$b_selfont' enabled successfully." && continue
exit 1
else # global
selfont="$(find "$FONTCTRL_BASEDIR_GLOBAL"/fonts/*"$carg"* -type f 2>/dev/null | head -n 1)" # Head in case there are multiple matches
b_selfont="$(basename "$selfont")"
[ ! -e "$selfont" ] && stderr "No fonts matching '$carg' found." && exitcode=1 && continue
msg "Enabling font '$b_selfont' globally."
mkdir -p "$GLOBALFONTDIR/fontctrl-fonts"
rm -f "$GLOBALFONTDIR/fontctrl-fonts/$b_selfont"
hi=true
[ -e "$FONTCTRL_BASEDIR_GLOBAL/fonts/$selfont" ] && ln -s "$FONTCTRL_BASEDIR_GLOBAL/fonts/$selfont" "$GLOBALFONTDIR/fontctrl-fonts/$b_selfont" && msg "Font '$selfont' enabled successfully." && continue
exit 1
fi
done
[ "$hi" != "true" ] && die "Font does not exist."
return $exitcode # return the exit code
}
# function to parse arguments and disable fonts
disable_font() {
exitcode=0 # exit code
[ -z "$2" ] && die "You must specify a font to disable."
for i in $(seq "$argc"); do
carg="$(printf "%s\n" "$@" | sed -n "${i}","${i}"p)"
copt=disable
is_narg || continue
if [ "$isglobal" != "true" ]; then # user
selfont="$(find "$FONTCTRL_BASEDIR_USER"/fonts/*"$carg"* -type f 2>/dev/null | head -n 1)" # Head in case there are multiple matches
b_selfont="$(basename "$selfont")"
[ ! -e "$selfont" ] && exitcode=1 && stderr "No fonts matching '$carg' found." && continue
msg "Disabling font '$b_selfont' for $(whoami)"
hi=true
rm -f "$USERFONTDIR/fontctrl-fonts/$b_selfont" && msg "Font '$selfont' disabled successfully." && continue
exit 1
else # global
selfont="$(find "$FONTCTRL_BASEDIR_GLOBAL"/fonts/*"$carg"* -type f 2>/dev/null | head -n 1)" # Head in case there are multiple matches
b_selfont="$(basename "$selfont")"
[ ! -e "$selfont" ] && exitcode=1 && stderr "No fonts matching '$carg' found." && continue
msg "Disabling font '$b_selfont' globally."
hi=true
rm -f "$GLOBALFONTDIR/fontctrl-fonts/$b_selfont" && msg "Font '$b_selfont' disabled successfully." && continue
exit 1
fi
done
[ "$hi" != "true" ] && die "Font does not exist."
return $exitcode # return the exit code
}
# list fonts
ls_font() {
msg "List of all installed fonts:"
[ "$isglobal" = "true" ] && basename "$(find "$FONTCTRL_BASEDIR_GLOBAL/fonts/" -type f)" || find "$FONTCTRL_BASEDIR_USER/fonts/" -type f -printf '\033[0;35m%f\033[0m\n'
msg "Use fontctrl enable/disable to enable/disable a font. See fontctrl help for more information." && return || exit 1
}
# print version information
print_ver() {
[ -z "$arg3" ] || die "This option does not take a third argument."
[ -n "$arg2" ] && die "Invalid argument: '$arg2'"
msg "$FONTCTRL_VER"
}
# print license information
print_license() {
[ -z "$arg2" ] && msg "fontctrl is free software, licensed under the GNU General Public License version 3.0. See https://git.speedie.site/speedie/fontctrl for more information." || die "This option does not take an argument."
}
# set everything up
main() {
# convenient variables
arg="$*"
arg1="$1"
arg2="$2"
arg3="$3"
mk "$@"
# arg count, this is used many times so why not set it here
argc="$(printf "%s\n" "$@" | grep -c '')"
case "$arg1" in
"install") arg=recognized && install_font "$@" && exit 0 || exit 1 ;;
"remove") arg=recognized && rm_font "$@" && exit 0 || exit 1 ;;
"enable") arg=recognized && enable_font "$@" && exit 0 || exit 1 ;;
"disable") arg=recognized && disable_font "$@" && exit 0 || exit 1 ;;
"list") arg=recognized && ls_font "$@" && exit 0 || exit 1 ;;
"help") arg=recognized && ls_args "$@" && exit 0 || exit 1 ;;
"version") arg=recognized && print_ver "$@" && exit 0 || exit 1 ;;
"license") arg=recognized && print_license "$@" && exit 0 || exit 1 ;;
"") arg=recognized && ls_args "$@" && exit 0 || exit 1 ;;
esac
[ "$arg" != "recognized" ] && msg "Invalid argument: '$arg1'" && die "Run fontctrl help or with no arguments for help."
}
# take stdin
[ -p /proc/self/fd/0 ] && read stdin && set -- "$@" $stdin
main "$@"