#!/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 "$@"