diff options
Diffstat (limited to 'dotfiles')
-rw-r--r-- | dotfiles/.config/zsh/.zshrc | 6 | ||||
-rwxr-xr-x | dotfiles/.local/bin/chcolors | 5 | ||||
-rwxr-xr-x | dotfiles/.local/bin/shtheme | 669 | ||||
-rw-r--r-- | dotfiles/.profile | 2 |
4 files changed, 676 insertions, 6 deletions
diff --git a/dotfiles/.config/zsh/.zshrc b/dotfiles/.config/zsh/.zshrc index a7f3000..aa1bc69 100644 --- a/dotfiles/.config/zsh/.zshrc +++ b/dotfiles/.config/zsh/.zshrc @@ -69,7 +69,11 @@ zle -N zle-keymap-select [ -f "$HOME/.config/zsh/shortcuts" ] && . "$HOME/.config/zsh/shortcuts" -[ -f "$HOME/.cache/colorscheme" ] && trap "source $HOME/.cache/colorscheme" DEBUG +if [ -f "$HOME/.cache/colorscheme" ]; then + trap "source $HOME/.cache/colorscheme && shtheme ultramar-\$COLORSCHEME" SIGUSR1 + source $HOME/.cache/colorscheme + shtheme ultramar-$COLORSCHEME +fi if [ -f /usr/share/zsh/plugins/zsh-syntax-highlighting/zsh-syntax-highlighting.zsh ] then diff --git a/dotfiles/.local/bin/chcolors b/dotfiles/.local/bin/chcolors index e62b047..9cd4270 100755 --- a/dotfiles/.local/bin/chcolors +++ b/dotfiles/.local/bin/chcolors @@ -13,8 +13,5 @@ case $COLORSCHEME in COLORSCHEME="dark" ;; esac -sed -i --follow-symlinks \ - "s/^colors:.*/colors: \*$COLORSCHEME/g" \ - $HOME/.config/alacritty/alacritty.yml - echo "export COLORSCHEME=$COLORSCHEME" > $HOME/.cache/colorscheme +pkill -SIGUSR1 zsh diff --git a/dotfiles/.local/bin/shtheme b/dotfiles/.local/bin/shtheme new file mode 100755 index 0000000..2071019 --- /dev/null +++ b/dotfiles/.local/bin/shtheme @@ -0,0 +1,669 @@ +#!/bin/sh + +# Written by Aetnaeus. +# Source: https://github.com/lemnos/theme.sh. +# Licensed under the WTFPL provided this notice is preserved. + +# Find a broken theme? Want to add a missing one? PRs are welcome. + +VERSION=v1.1.5 + +# Use truecolor sequences to simulate the end result. + +preview() { + awk -F": " -v target="$1" ' + BEGIN { + "tput cols" | getline nc + "tput lines" | getline nr + nc = int(nc) + nr = int(nr) + } + + /^# Themes/ { start++;next } + !start { next } + + function hextorgb(s) { + hexchars = "0123456789abcdef" + s = tolower(s) + + r = (index(hexchars, substr(s, 2, 1))-1)*16+(index(hexchars, substr(s, 3, 1))-1) + g = (index(hexchars, substr(s, 4, 1))-1)*16+(index(hexchars, substr(s, 5, 1))-1) + b = (index(hexchars, substr(s, 6, 1))-1)*16+(index(hexchars, substr(s, 7, 1))-1) + } + + function fgesc(col) { + hextorgb(col) + return sprintf("\x1b[38;2;%d;%d;%dm", r, g, b) + } + + function bgesc(col) { + hextorgb(col) + return sprintf("\x1b[48;2;%d;%d;%dm", r, g, b) + } + + $0 == target {s++} + + s && /^foreground:/ { fg = $2 } + s && /^background:/ { bg = $2 } + s && /^[0-9]+:/ { a[$1] = $2 } + + /^ *$/ {s=0} + + function puts(s, len, i, normesc, filling) { + normesc = sprintf("\x1b[0m%s%s", fgesc(fg), bgesc(bg)) + + len=s + gsub(/\033\[[^m]*m/, "", len) + len=length(len) + + filling="" + for(i=0;i<(nc-len);i++) filling=filling" " + + printf "%s%s%s%s\n", normesc, s, normesc, filling, "" + nr-- + } + + END { + puts("") + for (i = 0;i<16;i++) + puts(sprintf(" %s Color %d\x1b[0m", fgesc(a[i]), i)) + + # Note: Some terminals use different colors for bolded text and may produce slightly different ls output. + + puts("") + puts(" # ls --color -F") + puts(sprintf(" file")) + puts(sprintf(" \x1b[1m%sdir/", fgesc(a[4]))) + puts(sprintf(" \x1b[1m%sexecutable", fgesc(a[10]))) + puts(sprintf(" \x1b[1m%ssymlink\x1b[0m%s%s", fgesc(a[6]), fgesc(fg), bgesc(bg))) + + + while(nr > 0) puts("") + + printf "\x1b[0m" + } + ' < "$0" +} + +# Alphabetize and dedupe theme list. + +normalize_themes() { + awk ' + # We could eliminate the sorting logic by using gnu extensions but that would reduce portability. + + function cmp(a,b,ordTbl, i,c1,c2,n) { + n = length(a) > length(b) ? length(b) : length(a) + for(i = 1;i <= n;i++) { + c1 = substr(a, i, 1) + c2 = substr(b, i, 1) + + if(c1 != c2) + return ordTbl[c1] < ordTbl[c2] + } + + return length(a) < length(b) + } + + function sort(a,n, i,j,tmp,ordTbl) { + for(i = 0;i < 256;i++) ordTbl[sprintf("%c", i)] = i + + for(i = 0;i < n;i++) { + tmp = a[i] + j = i-1 + while(j >= 0 && cmp(tmp, a[j], ordTbl)) { + a[j+1] = a[j] + j-- + } + + a[j+1] = tmp + } + } + + function sortKeys(a,keys, n,k) { + for(k in a) + keys[n++] = k + sort(keys, n) + return n + } + + /^ *$/ { inTheme = 0;next } + !inTheme { name = $0;inTheme=1;themes[name] = "";next } + inTheme { themes[name] = themes[name]$0"\n" } + + END { + n = sortKeys(themes, names) + + print "" + for(i = 0;i < n;i++) { + print names[i] + print tolower(themes[names[i]]) + } + } + ' "$@" +} + +# Generate themes from one or more supplied kitty config files. + +generate_themes() { + awk -v argc=$# ' + function chkProp(prop) { + if(!props[prop]) { + printf "ABORTING: %s is missing required property '\''%s'\''\n", currentFile, prop > "/dev/stderr" + aborted++ + exit -1 + } + } + + function printTheme( name,i,prop) { + name = currentFile + gsub(/.*\//, "", name) + gsub(/\.conf$/, "", name) + + print name + + for (i = 0;i < 16;i++) { + prop = sprintf("color%d", i) + + chkProp(prop) + printf "%d: %s\n", i, props[prop] + } + + chkProp("foreground") + chkProp("background") + chkProp("cursor") + + print "foreground: "props["foreground"] + print "background: "props["background"] + print "cursor: "props["cursor"] + print "" + } + + FILENAME != currentFile { + if(currentFile) + printTheme() + + currentFile = FILENAME + delete props + } + + { props[$1] = $2 } + + END { if(!aborted) printTheme() } + ' "$@" +} + +# Add themes to the script from one or more supplied kitty config files. + +add() { + tmp1="$(mktemp)" + tmp2="$(mktemp)" + + awk 'i { print } /^# Themes/ { i++ }' "$0" > "$tmp1" + echo "" >> "$tmp1" + generate_themes "$@" >> "$tmp1" || exit $? + + awk '{print} /^# Themes/ { exit }' "$0" > "$tmp2" + normalize_themes "$tmp1" >> "$tmp2" + + + rm "$tmp1" + cat "$tmp2" > "$0" || exit $? + + printf 'Successfully annexed %d themes. More! Feed me more!\n' $# +} + +preview2() { + INHIBIT_THEME_HIST=1 "$0" "$1" + + printf '\033[30mColor 0\n' + printf '\033[31mColor 1\n' + printf '\033[32mColor 2\n' + printf '\033[33mColor 3\n' + printf '\033[34mColor 4\n' + printf '\033[35mColor 5\n' + printf '\033[36mColor 6\n' + printf '\033[37mColor 7\n' + + printf '\033[90mColor 8\n' + printf '\033[91mColor 9\n' + printf '\033[92mColor 10\n' + printf '\033[93mColor 11\n' + printf '\033[94mColor 12\n' + printf '\033[95mColor 13\n' + printf '\033[96mColor 14\n' + printf '\033[97mColor 15\n' + + printf '\n\033[0m' + printf '# ls --color -F\n' + printf ' file\n' + printf ' \033[01;34mdir/\033[0m\n' + printf ' \033[01;32mexecutable\033[0m*\n' + printf ' \033[01;36msymlink\033[0m\n' + + printf '\033[0m' +} + +# Consumes a theme.sh definition from STDIN and applies it. + +apply_theme() { +awk ' + function tmuxesc(s) { return sprintf("\033Ptmux;\033%s\033\\", s) } + function normalize_term() { + # Term detection voodoo + + if(ENVIRON["TERM_PROGRAM"] == "iTerm.app") + term="iterm" + else if(ENVIRON["TMUX"]) { + "tmux display-message -p \"#{client_termname}\"" | getline term + "tmux display-message -p \"#{client_termtype}\"" | getline termname + + if(substr(termname, 1, 5) == "iTerm") + term="iterm" + is_tmux++ + } else + term=ENVIRON["TERM"] + } + + BEGIN { + normalize_term() + + if(term == "iterm") { + bgesc="\033]Ph%s\033\\" + fgesc="\033]Pg%s\033\\" + colesc="\033]P%x%s\033\\" + curesc="\033]Pl%s\033\\" + } else { + #Terms that play nice :) + + fgesc="\033]10;#%s\007" + bgesc="\033]11;#%s\007" + curesc="\033]12;#%s\007" + colesc="\033]4;%d;#%s\007" + } + + if(is_tmux) { + fgesc=tmuxesc(fgesc) + bgesc=tmuxesc(bgesc) + curesc=tmuxesc(curesc) + colesc=tmuxesc(colesc) + } + } + + /^foreground:/ { printf fgesc, substr($2, 2) > "/dev/tty" } + /^background:/ { printf bgesc, substr($2, 2) > "/dev/tty" } + /^cursor:/ { printf curesc, substr($2, 2) > "/dev/tty" } + /^[0-9]+:/ { printf colesc, $1, substr($2, 2) > "/dev/tty" } +' +} + +# Sets the current theme given a name and does the requisite bookkeeping. + +set_current_theme() { + awk -F": " -v target="$1" -v script="$0" ' + /^# Themes/ { start++;next; } + !start { next } + + $0 == target { found++;next; } + + found { theme = theme $0 "\n" } + found && /^ *$/ { exit } + + END { + if(found) { + printf "%s", theme | script + + config_dir = (ENVIRON["XDG_CONFIG_HOME"] ? ENVIRON["XDG_CONFIG_HOME"] : ENVIRON["HOME"]) + + histfile = config_dir"/.theme_history" + inhibit_hist=ENVIRON["INHIBIT_THEME_HIST"] + + if(!inhibit_hist) { + while((getline < histfile) > 0) + if($0 != target) + out = out $0 "\n" + close(histfile) + + out = out target + print out > histfile + } + } else { + printf "Theme not found: %s\n", target > "/dev/stderr" + exit(-1) + } + } + ' < "$0" +} + +# Dump the current theme in a format consumable by theme.sh +# by attempting to read it from the terminal. +# +# NOTE: Many terms don't support this properly (e.g alacritty) + +# Refs + +# https://github.com/microsoft/terminal/issues/3718 +# https://github.com/alacritty/alacritty/blob/master/alacritty_terminal/src/ansi.rs#L972 + +print_current_theme() { + awk ' + function print_response(s) { + names["10;"] = "foreground" + names["11;"] = "background" + names["12;"] = "cursor" + for (i = 0; i < 16; i++) + names[sprintf("4;%d;", i)] = i + + split(s, a, "]") + for (i in a) { + if (match(a[i], /rgb:/)) { + key = substr(a[i], 1, RSTART-1) + + r=substr(a[i], RSTART+4, 2) + g=substr(a[i], RSTART+9, 2) + b=substr(a[i], RSTART+14, 2) + + printf "%s: %s\n", names[key], "#"r g b + } + } + } + + # We cant just use RS/getline for this since + # mawk does input buffering :(. + + function read_response() { + buf = "" + + # Accrue data until we encounter the terminating CSI response + while ((end=index(buf,"[")) == 0) { + # poor POSIX mans read :/ + cmd="dd if=/dev/tty bs=1024 count=1 2> /dev/null" + + while (cmd|getline data) + buf = buf data + + close(cmd) + } + + buf = substr(buf, 1, end-1) + return buf + } + + BEGIN { + system("stty cbreak -echo") + + tty = "/dev/tty" + + # Yo dawg, I heard you like multiplexers... + if (ENVIRON["TMUX"]) { + # If we are running inside tmux we sent the request sequences + # to the currently attached terminal. Note that we still + # read the result from the virtual terminal. + + # Flow: + # theme.sh (request) -> tty (response) -> pts (response) -> theme.sh + # where pts is the tmux pseudoterminal. + + "tmux display-message -p \"#{client_tty}\""|getline tty + } + + # Terminals may ignore these. + + for(i=0;i<16;i++) + printf "\033]4;%d;?\007", i > tty + + printf "\033]10;?\007" > tty + printf "\033]11;?\007" > tty + printf "\033]12;?\007" > tty + + # Use a CSI DA1 sequence (supported by all terms) + # as a sentinel value to indicate end-of-response. + # (assumes request-response order is fifo) + + printf "\033[c" > tty + + print_response(read_response()) + + system("stty -cbreak echo") + } + ' +} + +isColorTerm() { + if [ -z "$TMUX" ]; then + [ -n "$COLORTERM" ] + else + tmux display-message -p '#{client_termfeatures}'|grep -q RGB + fi +} + +list() { + case "$filterFlag" in + --light) filter=2 ;; + --dark) filter=1 ;; + *) filter=0 ;; + esac + + awk -v filter="$filter" -F": " ' + BEGIN { + config_dir = ENVIRON["XDG_CONFIG_HOME"] ? ENVIRON["XDG_CONFIG_HOME"] : ENVIRON["HOME"] + + histfile = config_dir"/.theme_history" + while((getline < histfile) > 0) { + mru[nmru++] = $0 + mruIndex[$0] = 1 + } + } + + function luma(s, r,g,b,hexchars) { + hexchars = "0123456789abcdef" + s = tolower(s) + + r = (index(hexchars, substr(s, 2, 1))-1)*16+(index(hexchars, substr(s, 3, 1))-1) + g = (index(hexchars, substr(s, 4, 1))-1)*16+(index(hexchars, substr(s, 5, 1))-1) + b = (index(hexchars, substr(s, 6, 1))-1)*16+(index(hexchars, substr(s, 7, 1))-1) + + return 0.2126 * r + 0.7152 * g + 0.0722 * b + } + + /^# Theme/ { st++;next } + !st { next } + + /^ *$/ { inner = 0;next } + !inner { name = $0;inner++;next } + + /^background/ { + if((filter == 1 && luma($2) > 130) || + (filter == 2 && luma($2) <= 130)) + next + + candidates[name] = 1 + } + + END { + for(c in candidates) { + if(!mruIndex[c]) + print(c) + } + + for(i = 0;i < nmru;i++) + if(candidates[mru[i]]) + print(mru[i]) + } + ' < "$0" +} + + +if [ -z "$1" ]; then + if [ -t 0 ]; then + echo "usage: $(basename "$0") [-v] [-h] <option>|<theme>" + exit 255 + else + apply_theme + exit 0 + fi +fi + +case "$1" in + --dark|--light) + filterFlag=$1 + shift + ;; +esac + +case "$1" in +-h|--help) + cat << "!" +usage: theme.sh [--light] | [--dark] <option> | <theme> + + If <theme> is provided it will immediately be set. Otherwise --dark or + --light optionally act as filters on the supplied option. Theme history is + stored in ~/.theme_history or ($XDG_CONFIG_HOME/.theme_history if set) by + default and will be used for ordering the otherwise alphabetical theme list + in the relevant options (-l/-i/-i2). + + E.G: + 'theme.sh --dark -i' + + will start an interactive selection of dark themes with the user's + most recently selected themes at the bottom of the list. + + Theme definitions consistent with the internal format can also be piped + directly into the script. + + E.G: + + # theme.sh < input + + Where input has the form: + + 0: #4d4d4d + 1: #4d4d4d + ... + foreground: #dcdccc + background: #3f3f3f + cursor: #dcdccc + +OPTIONS + -l,--list Print all available themes. + -i,--interactive Start the interactive selection mode (requires fzf). + -i2,--interactive2 Interactive mode #2. This shows the theme immediately + instead of showing it in the preview window. Useful + if your terminal does have TRUECOLOR support. + -r,--random Set a random theme and print its name to stdout. + -a,--add <kitty config> Annexes the given kitty config file. + -p,--print-theme Attempt to read the current theme from the terminal + and print it to stdout in a format consumable by theme.sh. + NOTE: not all terminals support this option, + do not rely on it in scripts. + -v,--version Print the version and exit. + +SCRIPTING + If used from within a script, you will probably want to set + INHIBIT_THEME_HIST=1 to avoid mangling the user's theme history. +! + ;; +-p|--print-theme) + print_current_theme + ;; +-i2|--interactive2) + command -v fzf > /dev/null 2>&1 || { echo "ERROR: -i requires fzf" >&2; exit 1; } + "$0" $filterFlag -l|fzf\ + --tac\ + --bind "enter:execute-silent($0 {})+accept"\ + --bind "ctrl-c:execute($0 -l|tail -n1|xargs $0)+abort"\ + --bind "esc:execute($0 {};echo {})+abort"\ + --exact\ + --no-sort\ + --preview "$0 --preview2 {}" + ;; +-r|--random) + # Sort -R is not portable :/ + + theme=$($0 $filterFlag -l|awk '{a[n++]=$0};END{srand();print(a[int(rand()*n)])}') + $0 "$theme" + echo "Theme: $theme" + ;; +-i|--interactive) + command -v fzf > /dev/null 2>&1 || { echo "ERROR: -i requires fzf" >&2; exit 1; } + if ! isColorTerm; then + printf "WARNING: This does not appear to be a truecolor terminal, falling back to -i2 + (use -i2 explicitly to get rid of this message or set COLORTERM)\n\n" >&2 + "$0" $filterFlag -i2 + else + "$0" $filterFlag -l|fzf\ + --tac\ + --exact\ + --bind "ctrl-c:abort"\ + --bind "esc:execute(echo {})+abort"\ + --bind "enter:execute-silent($0 {})+accept"\ + --no-sort\ + --preview "$0 --preview {}" + fi + ;; +-l|--list) + list + ;; +-a|--add) + shift + add "$@" + ;; +--preview2) + preview2 "$2" + ;; +--preview) + preview "$2" + ;; +-v|--version) + echo "$VERSION (original source https://github.com/lemnos/theme.sh)" + ;; +*) + set_current_theme "$1" + ;; +esac + +exit $? + +# Themes start here (avoid editing by hand) + +ultramar-dark +0: #33333a +1: #b73030 +2: #6d974b +3: #b2872f +4: #3f6e90 +5: #9c6992 +6: #5b8277 +7: #b0afa8 +8: #676775 +9: #c45c5c +10: #92b078 +11: #e2b55a +12: #81acc1 +13: #b48ead +14: #7fac96 +15: #faf6e5 +foreground: #fcf8e2 +background: #151517 +cursor: #ffffff + +ultramar-light +0: #151517 +1: #b73030 +2: #6d974b +3: #b2872f +4: #3f6e90 +5: #9c6992 +6: #5b8277 +7: #91908d +8: #33333a +9: #c45c5c +10: #92b078 +11: #e2b55a +12: #75a2b8 +13: #b48ead +14: #7fac96 +15: #b0afa8 +foreground: #1b1e25 +background: #faf6e5 +cursor: #000000 + diff --git a/dotfiles/.profile b/dotfiles/.profile index 0627bdd..320c1ae 100644 --- a/dotfiles/.profile +++ b/dotfiles/.profile @@ -44,7 +44,7 @@ export $(dbus-launch) # Start sway automatically upon login on tty1 or tty2 if [ -z $DISPLAY ] && [ $(tty) = /dev/tty1 ] || [ $(tty) = /dev/tty2 ]; then # DBUS variables (for Artix) - sway -d 2> ~/.cache/sway.log 1> /dev/null && clear && exit + exec sway -d 2> ~/.cache/sway.log 1> /dev/null && clear && exit mv ~/.cache/sway.log ~/.cache/sway-crash-$(date +"%Y-%m-%dT%H:%M").log fi |