diff --git a/README.md b/README.md index 8e471ec..22a94b6 100644 --- a/README.md +++ b/README.md @@ -30,3 +30,11 @@ Run the following command: ```sh $ ln -s ~/dotfiles/tmux.conf ~/.tmux.conf ``` + +## Configure gnome-terminal + +Run the following command: + +```sh +$ ~/dotfiles/style-gnome-terminal.sh gruvbox8 +``` diff --git a/style-gnome-terminal.sh b/style-gnome-terminal.sh new file mode 100755 index 0000000..82276e9 --- /dev/null +++ b/style-gnome-terminal.sh @@ -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 "$@"