| @ -0,0 +1,242 @@ | |||||
| #!/bin/bash | |||||
| # vim: tw=80 ts=2 sw=2: | |||||
| set -eu | |||||
| ROOT_DCONF_DIR='/org/gnome/terminal/legacy/profiles:/' | |||||
| # ansi_colors COLOR1 ... COLOR16 | |||||
| function ansi_colors() { | |||||
| echo -n "['$1'" | |||||
| for i in {2..16}; do | |||||
| echo -n ",'${!i}'" | |||||
| done | |||||
| echo "]" | |||||
| } | |||||
| # colorscheme NAME FG_COLOR BG_COLOR ANSI_COLORS | |||||
| function colorscheme() { | |||||
| NAME="$1" | |||||
| FG_COLOR="$2" | |||||
| BG_COLOR="$3" | |||||
| ANSI_COLORS="$4" | |||||
| echo "${NAME};${FG_COLOR};${BG_COLOR};${ANSI_COLORS}" | |||||
| } | |||||
| function unpack_colorscheme_field(){ | |||||
| PACKED="$1" | |||||
| FIELD="$2" | |||||
| echo "${PACKED}" | cut -d ';' -f "${FIELD}" | |||||
| } | |||||
| # colorscheme_name COLORSCHEME | |||||
| function colorscheme_name() { | |||||
| unpack_colorscheme_field "$1" 1 | |||||
| } | |||||
| # colorscheme_fg_color COLORSCHEME | |||||
| function colorscheme_fg_color() { | |||||
| unpack_colorscheme_field "$1" 2 | |||||
| } | |||||
| # colorscheme_bg_color COLORSCHEME | |||||
| function colorscheme_bg_color() { | |||||
| unpack_colorscheme_field "$1" 3 | |||||
| } | |||||
| # colorscheme_ansi_colors COLORSCHEME | |||||
| function colorscheme_ansi_colors() { | |||||
| unpack_colorscheme_field "$1" 4 | |||||
| } | |||||
| GRUVBOX8_COLORSCHEME=$(colorscheme "gruvbox8" \ | |||||
| "#ebdbb2" \ | |||||
| "#1d2021" \ | |||||
| $(ansi_colors \ | |||||
| "#1d2021" \ | |||||
| "#cc241d" \ | |||||
| "#98971a" \ | |||||
| "#d79921" \ | |||||
| "#458588" \ | |||||
| "#b16286" \ | |||||
| "#689d6a" \ | |||||
| "#a89984" \ | |||||
| "#928374" \ | |||||
| "#fb4934" \ | |||||
| "#b8bb26" \ | |||||
| "#fabd2f" \ | |||||
| "#83a598" \ | |||||
| "#d3869b" \ | |||||
| "#8ec07c" \ | |||||
| "#ebdbb2" | |||||
| ) | |||||
| ) | |||||
| COLORSCHEMES=( | |||||
| "${GRUVBOX8_COLORSCHEME}" | |||||
| ) | |||||
| # log ARGS... | |||||
| # echo for stderr | |||||
| function log() { | |||||
| echo 1>&2 "$@" | |||||
| } | |||||
| # die ARGS... | |||||
| # log then exit with an error code | |||||
| function die() { | |||||
| log "$@" | |||||
| exit 1 | |||||
| } | |||||
| function get_profile_property() { | |||||
| PROFILE="$1" | |||||
| PROPERTY="$2" | |||||
| dconf read "${PROFILE}${PROPERTY}" | |||||
| } | |||||
| # get_profile_name PROFILE | |||||
| # Echoes the human-readable name for a gnome-terminal profile subdirectory. | |||||
| function get_profile_name() { | |||||
| get_profile_property "$1" "visible-name" | |||||
| } | |||||
| # choose_number BASE_PROMPT MIN MAX | |||||
| # Asks the user to choose a number between MIN and MAX, inclusive. | |||||
| # BASE_PROMPT should not end in a newline. | |||||
| function choose_number() { | |||||
| PROMPT="$1" | |||||
| MIN_NUMBER="$2" | |||||
| MAX_NUMBER="$3" | |||||
| while true; do | |||||
| read -p "$1 [${MIN_NUMBER} to ${MAX_NUMBER}]: " CHOSEN_NUMBER | |||||
| if [ "${CHOSEN_NUMBER}" -lt "${MIN_NUMBER}" ]; then | |||||
| continue | |||||
| fi | |||||
| if [ "${CHOSEN_NUMBER}" -gt "${MAX_NUMBER}" ]; then | |||||
| continue | |||||
| fi | |||||
| echo "${CHOSEN_NUMBER}" | |||||
| break | |||||
| done | |||||
| } | |||||
| # choose_profile | |||||
| # Echoes the path to a valid gnome-terminal profile to modify. | |||||
| function choose_profile() { | |||||
| # Build an array of profile subdirectories. | |||||
| PROFILES=() | |||||
| for PROFILE_SUBDIR in $(dconf list "${ROOT_DCONF_DIR}"); do | |||||
| PROFILES+=("${ROOT_DCONF_DIR}${PROFILE_SUBDIR}") | |||||
| done | |||||
| NUM_PROFILES="${#PROFILES[@]}" | |||||
| if [ "${NUM_PROFILES}" -eq 0 ]; then | |||||
| die "Error: found no gnome-terminal profiles to style." | |||||
| fi | |||||
| if [ "${NUM_PROFILES}" -eq 1 ]; then | |||||
| PROFILE="${PROFILES[0]}" | |||||
| PROFILE_NAME=$(get_profile_name "${PROFILE}") | |||||
| log "Found single gnome-terminal profile ${PROFILE_NAME}, using it." | |||||
| echo "${PROFILE}" | |||||
| return | |||||
| fi | |||||
| log "Available gnome-terminal profiles:" | |||||
| for i in $(seq 1 "${NUM_PROFILES}"); do | |||||
| PROFILE="${PROFILES[$(($i - 1))]}" | |||||
| PROFILE_NAME=$(get_profile_name "${PROFILE}") | |||||
| log " #$i: ${PROFILE_NAME}" | |||||
| done | |||||
| choose_number "Choose a profile" 1 "${NUM_PROFILES}" | |||||
| } | |||||
| # find_colorscheme COLORSCHEME_NAME | |||||
| # Echoes the colorscheme if it exists. | |||||
| # Dies otherwise with a useful message. | |||||
| function find_colorscheme() { | |||||
| COLORSCHEME_NAME="$1" | |||||
| NAMES=() | |||||
| for COLORSCHEME in "${COLORSCHEMES[@]}"; do | |||||
| NAME=$(colorscheme_name ${COLORSCHEME}) | |||||
| NAMES+=("${NAME}") | |||||
| if [ "${NAME,,}" == "${NAME,,}" ]; then | |||||
| echo "${COLORSCHEME}" | |||||
| return | |||||
| fi | |||||
| done | |||||
| log "Error: no such colorscheme '${COLORSCHEME_NAME}'. Options are:" | |||||
| for NAME in "${NAMES[@]}"; do | |||||
| log " - ${NAME}" | |||||
| done | |||||
| exit 1 | |||||
| } | |||||
| # apply_colorscheme PROFILE COLORSCHEME | |||||
| # Applies the given packed colorscheme to the given gnome-terminal profile. | |||||
| function apply_colorscheme() { | |||||
| PROFILE="$1" | |||||
| COLORSCHEME="$2" | |||||
| FG_COLOR=$(colorscheme_fg_color "${COLORSCHEME}") | |||||
| BG_COLOR=$(colorscheme_bg_color "${COLORSCHEME}") | |||||
| ANSI_COLORS=$(colorscheme_ansi_colors "${COLORSCHEME}") | |||||
| dconf write "${PROFILE}foreground-color" "'${FG_COLOR}'" | |||||
| dconf write "${PROFILE}background-color" "'${BG_COLOR}'" | |||||
| dconf write "${PROFILE}palette" "${ANSI_COLORS}" | |||||
| } | |||||
| function main() { | |||||
| if [ "$#" -le 0 ]; then | |||||
| die "USAGE: style-gnome-terminal COLORSCHEME_NAME" | |||||
| fi | |||||
| # TODO: Subcommands: | |||||
| # | |||||
| # Profiles: | |||||
| # | |||||
| # - profile list | |||||
| # - profile show NAME_OR_ID | |||||
| # | |||||
| # Styling: | |||||
| # | |||||
| # These all take an optional [profile NAME_OR_ID] clause to specify a profile | |||||
| # by name or UUID. If unspecified, the program searches for profiles. If there | |||||
| # exists a single profile, the program uses it. Otherwise, an interactive | |||||
| # choice is presented to the user. | |||||
| # | |||||
| # - font get | |||||
| # - font set FONT | |||||
| # - foreground-color get | |||||
| # - foreground-color set COLOR | |||||
| # - background-color get | |||||
| # - background-color set COLOR | |||||
| # - palette get | |||||
| # - palette set COLORS | |||||
| # - colorscheme show NAME | |||||
| # - colorscheme apply NAME | |||||
| # | |||||
| # The colorscheme subcommand should probably read colorschemes from files | |||||
| # instead, for easier integration with other people's colorschemes. Otherwise | |||||
| # all colorschemes need to be defined in this script. The main question is the | |||||
| # file format. We'd like something easy enough to write, that does not execute | |||||
| # arbitrary code (rules our source-ing .sh files containing variables), that | |||||
| # does not require onerous dependencies to parse. | |||||
| COLORSCHEME_NAME="$1" | |||||
| COLORSCHEME=$(find_colorscheme "${COLORSCHEME_NAME}") | |||||
| PROFILE=$(choose_profile) | |||||
| apply_colorscheme "${PROFILE}" "${COLORSCHEME}" | |||||
| } | |||||
| main "$@" | |||||