forked from base16-manager/base16-manager
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathbase16-manager
executable file
·665 lines (563 loc) · 16.2 KB
/
base16-manager
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
#!/bin/bash
# Install base16 templates and set themes globally.
# Source https://github.com/AuditeMarlow/base16-manager
readonly DATA_PATH="${XDG_DATA_HOME:-$HOME/.local/share}/base16-manager"
err() {
echo "ERROR: $*" >&2
}
bug() {
echo "A bug occured. Please copy the following message and report the bug here: https://github.com/AuditeMarlow/base16-manager."
echo "$*"
}
usage() {
echo "Usage: base16-manager [option]"
echo "Options:"
echo " set 'base16-theme' Sets the theme"
echo " set-random Sets to a random installed theme"
echo " install 'username/repository' Installs a new template"
echo " uninstall 'username/repository' Uninstalls a template"
echo " list Lists installed templates"
echo " list-support Lists supported templates"
echo " list-installable Lists installable templates"
echo " list-themes Lists installed themes"
echo " update Updates installed templates"
echo " clean Cleans up leftovers"
}
# print short list of possible commands (set, set-random, install, ...)
usage_short() {
base16-manager | sed 1,2d | cut -s -d ' ' -f 2
}
# return true, if directory exists, otherwise false
dir_exists() {
local dir=$1
if [[ -d "$dir" ]]; then
true
else
false
fi
}
# return true, if file exists, otherwise false
file_exists() {
local file=$1
if [[ -f "$file" ]]; then
true
else
false
fi
}
# CREATE directory $1 if it doesn't already exists.
check_dir() {
local dir=$1
if ! dir_exists "$dir"; then
mkdir "$dir"
fi
}
# move old config to new data directory or create new one
# if it doesn't already exists
check_data_dir() {
local OLD_CONFIG_PATH="$HOME/.base16-manager"
if dir_exists "$OLD_CONFIG_PATH"; then
cat <<EOT
Old config data detected!
-------------------------
1. Move your base16-manager data to new location
mv "${OLD_CONFIG_PATH}" "${DATA_PATH}"
2. Set your favorite theme again, something like:
base16-manager set solarized-dark
EOT
exit 1
fi
dir_exists "$DATA_PATH" || mkdir "$DATA_PATH"
}
# if the length of $1 is zero, print base16-manager's help text.
check_arg() {
local arg=$1
if [[ -z "$arg" ]]; then
usage
exit
fi
}
# check if there is new line at the end of file
# add it if not
#
# Rationale: We often need to append something to config file, but if newline
# is missing at end of file, our string will be appended to same line as
# last line in config file causing failure
check_eof_nl() {
local file=$1
# add newline to eof if it is missing
local eof
eof=$(tail -c 1 "$file")
if [ -n "$eof" ]; then
printf "\\n" >> "$file"
fi
}
# return true, if OS is mac
is_mac() {
[[ "$(uname)" == "Darwin" ]]
}
# return true, if OS is linux
is_linux() {
[[ "$(uname)" == "Linux" ]]
}
# check if there is line in file($1) corresponding to pattern($2)
# if not, add line($3) to the end of file
#
# pattern is matched using extended-regexp
line_in_file() {
local file=$1
local pattern=$2
local line=$3
if ! file_exists "$file" || \
! grep -iqE "$pattern" "$file"
then
check_eof_nl "$file"
echo "$line" >> "$file"
fi
}
# install the repo $1, e.g. $1="USER/NAME"
install() {
local template=$1
local repository="https://github.com/$template"
check_data_dir
if ! git ls-remote --exit-code -h "$repository" > /dev/null; then
err "Template repository not found."
exit
fi
git clone "$repository" "$DATA_PATH/$template"
}
# uninstall the repo $1, e.g. $1="USER/NAME"
uninstall() {
local template=$1
check_dir "$DATA_PATH/$template"
rm -rf "${DATA_PATH:?}/${template:?}"
echo "Uninstalled $template."
}
# print all installed templates
list() {
# iterate over each MAINTAINER and REPOSITORY stored in $DATA_PATH
for MAINTAINER in "$DATA_PATH"/*; do
for REPOSITORY in "$MAINTAINER"/*; do
[[ -e "$REPOSITORY" ]] || break # handle empty $DATA_PATH
[[ -d "$REPOSITORY" ]] || break # handle files
echo "$(basename -- "$MAINTAINER")/$(basename -- "$REPOSITORY")"
done
done
}
# print all installed themes
list_themes() {
local sort_option=( "$@" )
find "$DATA_PATH" -type f -name 'base16-*' | \
sed "s/.*\\/base16-//" | \
sed "s/\\..*//" | \
sort "${sort_option[@]}" | uniq
}
# print currently supported templates
list_support() {
echo "0xdec/base16-rofi"
echo "chriskempson/base16-shell"
echo "chriskempson/base16-vim"
echo "pinpox/base16-xresources"
echo "khamer/base16-dunst"
echo "khamer/base16-termite"
echo "fnune/base16-fzf"
echo "nicodebo/base16-zathura"
echo "theova/base16-qutebrowser"
echo "rkubosz/base16-sway"
}
# print uninstalled packages which are supported
list_installable() {
local RESULT=""
for REPO in $(list_support); do
if ! grep -q "$REPO" <<< "$(list)" ; then
if [[ -z $RESULT ]]; then
RESULT="$REPO"
else
local NEWLINE=$'\n'
RESULT="$RESULT$NEWLINE$REPO"
fi
fi
done
echo "$RESULT"
}
# update the themes in all templates
update() {
local packages
packages=$(list)
if [[ -z "$packages" ]]; then
err "No packages installed."
exit
fi
for package in $packages; do
cd "$DATA_PATH"/"$package" || exit
git pull -f origin master
done
echo "All packages updated."
}
# remove all empty directories in $DATA_PATH
clean() {
find "$DATA_PATH" -maxdepth 1 -type d -empty -delete
check_data_dir
echo "Cleaned up $DATA_PATH."
}
# set themes for all installed templates
set_theme() {
local theme=$1
local packages
packages=$(list)
if [[ -z "$packages" ]]; then
err "No packages installed."
exit
fi
for package in $packages; do
case "$package" in
"0xdec/base16-rofi")
set_rofi "$package" "$theme"
;;
"chriskempson/base16-shell")
set_shell "$package" "$theme"
;;
"chriskempson/base16-vim")
set_vim "$package" "$theme"
;;
"pinpox/base16-xresources")
set_xresources "$package" "$theme"
;;
"khamer/base16-dunst")
set_dunst "$package" "$theme"
;;
"fnune/base16-fzf")
set_fzf "$package" "$theme"
;;
"nicodebo/base16-zathura")
set_generic "$package" "$theme" "#" ' ' \
"$HOME/.config/zathura/zathurarc"
;;
"khamer/base16-termite")
set_generic "$package" "$theme" "#" "=" "$HOME/.config/termite/config"
killall -USR1 termite # Reload termite configuration in-place.
;;
"theova/base16-qutebrowser")
# handle different locations of config
if is_mac; then
QUTEBROWSERCONF="$HOME/.qutebrowser/config.py"
elif is_linux; then
QUTEBROWSERCONF="$HOME/.config/qutebrowser/config.py"
else
bug "Unkown OS: $(uname)"
return
fi
# set theme
set_generic "$package" "$theme" "#" "=" "$QUTEBROWSERCONF"
;;
"rkubosz/base16-sway")
set_by_copy "$package" "$theme" "$HOME/.config/sway/colorscheme" "config"
;;
*)
err "Package $package is not (yet) supported."
;;
esac
done
echo "Set theme to $theme. You may need to restart DE and terminals."
}
# Use template ($1) to set theme ($2).
# This is done by deleting all lines in user's config ($5) containing the
# left-hand side of any assignement (marked by the assignement string $4) in the
# theme file. All comments directly above the deleted line are also deleted.
set_generic() {
local package=$1
local theme=$2
local cmnt_string=$3
local assign_string=$4
local config=$5
local config_tmp
local file
local left
local line
local number
# get template and handling for inexisting templates
if ls "$DATA_PATH/$package"/*/"base16-$theme."* &>/dev/null; then
file=$(ls "$DATA_PATH/$package"/*/"base16-$theme."* )
else
err "$package: theme $theme not found."
return 1
fi
if [[ ! -f "$config" ]]; then
mkdir -p "$(dirname "$config")"
cp "$file" "$config"
return
fi
# work with a temporary config copy
config_tmp=/tmp/base16_manager_$(basename "$config")
cp "$config" "$config_tmp"
while read -r line; do
# get left side of each assignement
left=$(echo "$line" | cut -d "$assign_string" -f 1)
left=$(echo "$left" | xargs) # remove trailing whitespaces
left=$(echo "$left" | sed 's/\//\\\//g') # escape slashes
# if $left found, then
# delete all lines ($line) containing $left
# delte all comments above $line
if [[ -n $left ]]; then
lines=$(grep -Fohn "$left" "$config_tmp" | cut -d : -f 1)
for number in $lines; do
sed -i.bak "$number"'d' "$config_tmp"
while (( number > 1 )) && sed "$(( number - 1 ))"'!d' "$config_tmp" | grep -q "^$cmnt_string"; do
sed -i.bak "$(( number - 1 ))"'s/.*//' "$config_tmp"
number=$((number - 1))
done
done
fi
done <"$file"
#remove special strings (e.g. in template headers)
sed -i.bak '/'"^$cmnt_string"'.*[b,B]ase16/d' "$config_tmp"
sed -i.bak '/'"^$cmnt_string"'.*scheme by/d' "$config_tmp"
sed -i.bak '/'"^$cmnt_string"'.*Author:/d' "$config_tmp"
# remove parts with more than one empty line
sed -i.bak '$!N; /^\(.*\)\n\1$/!P; D' "$config_tmp"
# remove first line, if it's empty
sed -i.bak '1{/^[[:space:]]*$/d;}' "$config_tmp"
# create a backup
cp "$config" "$config.bac"
# append a line break, if last line is not empty.
if [[ -n $(tail -1 "$config_tmp") ]]; then
printf "\\n" >> "$config_tmp"
fi
# append colorscheme
cat "$file" >> "$config_tmp"
# copy temporary file to the right place
cp "$config_tmp" "$config"
# remove temporay files
rm "$config_tmp".bak "$config_tmp"
}
# Use template ($1) to set theme ($2).
# This is done by copying the theme to the config's ($3) location.
# If the package provides themes with several endings, you have to specify it ($4).
set_by_copy() {
local package=$1
local theme=$2
local config=$3
local ending=$4
local file
# get template and handling for inexisting templates
if ls "$DATA_PATH/$package"/*/"base16-$theme."* &>/dev/null; then
file=$(ls "$DATA_PATH/$package"/*/"base16-$theme."*"$ending" )
else
err "$package: theme $theme not found."
return 1
fi
# create a backup
cp "$config" "$config.bac"
# copy template to the config location.
cp "$file" "$config"
}
set_dunst() {
local package=$1
local theme=$2
local file="$DATA_PATH/$package/themes/base16-$theme.dunstrc"
local config="$HOME/.config/dunst/dunstrc"
if ! file_exists "$file"; then
err "Dunst theme not found."
else
sed '/^frame_color = .*$/,/^\s+foreground(.*)$/d' "$config" > /tmp/dunstrc
[[ -f "$config.bac" ]] && rm "$config.bac"
mv "$config" "$config.bac"
cat /tmp/dunstrc "$file" > "$config"
# Kill dunst to force reload new configuration.
[[ -n "$(pidof dunst)" ]] && killall dunst
fi
}
set_fzf() {
local package=$1
local theme=$2
local theme_files=(
"$HOME/.fzf.colors" # bash
"$HOME/.fzf.colors" # zsh
"$HOME/.fzf.colors.fish" # fish
)
local config_lines=(
"[ -f ~/.fzf.colors ] && source ~/.fzf.colors" # bash
"[ -f ~/.fzf.colors ] && source ~/.fzf.colors" # zsh
"[ -f ~/.fzf.colors.fish ] && source ~/.fzf.colors.fish" # fish
)
local configs=(
".bashrc" # bash
".zshrc" # zsh
".config/fish/config.fish" # fish
)
local files=(
"$DATA_PATH/$package/bash/base16-$theme.config" # bash
"$DATA_PATH/$package/bash/base16-$theme.config" # zsh
"$DATA_PATH/$package/fish/base16-$theme.fish" # fish
)
for i in ${!configs[@]}; do
theme_file=${theme_files[$i]}
config=${configs[$i]}
config_line=${config_lines[$i]}
file=${files[$i]}
if ! file_exists "$file"; then
err "FZF theme not found."
else
cp "$file" "$theme_file"
if file_exists "$HOME/$config" && ! grep -Fxq "$config_line" "$HOME/$config"; then
echo "$config_line" >> "$HOME/$config"
fi
fi
done
}
set_shell() {
local package=$1
local theme=$2
local file="$DATA_PATH/$package/scripts/base16-$theme.sh"
local helper="$DATA_PATH/$package/profile_helper.sh"
local fish_dir="$HOME/.config/fish"
local fish_config="$fish_dir/config.fish"
local fish_string="# Base16 Shell
if status --is-interactive
eval sh $file
end"
if ! file_exists "$helper"; then
err "Shell helper not found."
elif ! file_exists "$file"; then
err "Shell theme not found."
else
eval "$($helper)"
_base16 "$file"
if command -v fish >/dev/null 2>&1; then
# Make fish theme permanent
[[ ! -d "$fish_dir" ]] && mkdir "$fish_dir"
[[ ! -f "$fish_config" ]] && touch "$fish_config"
sed '/^# Base16 Shell$/,/^end$/d' "$fish_config" > /tmp/fish_config
[[ -f "$fish_config.bac" ]] && rm "$fish_config.bac"
mv "$fish_config" "$fish_config.bac"
mv /tmp/fish_config "$fish_config"
echo "$fish_string" >> "$fish_config"
fi
fi
}
set_vim() {
local package=$1
local theme=$2
local file="$DATA_PATH/$package/colors/base16-$theme.vim"
local vim_dirs="$HOME/.vim $HOME/.config/nvim"
if ! file_exists "$file"; then
err "Vim theme not found."
else
for vim_dir in $vim_dirs; do
if dir_exists "$vim_dir"; then
echo "colorscheme base16-$theme" > "$vim_dir/colorscheme.vim"
fi
done
fi
}
set_random() {
set_theme "$(list_themes -R | head -n1 | awk '{print $1;}')"
}
set_rofi() {
local package=$1
local theme=$2
# get template and handling for inexisting templates
if ls "$DATA_PATH/$package/themes/base16-$theme."* &>/dev/null; then
file=$(ls "$DATA_PATH/$package/themes/base16-$theme."*"rasi" )
else
err "$package: theme $theme not found."
return 1
fi
# path to rofi config
local ROFI_CONFIG="${XDG_CONFIG_HOME:-$HOME/.config}/rofi/config"
# remove old theme or new rasi style theme from config
sed -i -e '/^\! Base16 /d' \
-e '/^\! Author:/d' \
-e '/^\! base[[:xdigit:]]\{2\}/d' \
-e '/^\! Enable the extended coloring options/d' \
-e '/^rofi\.color-enabled: true/d' \
-e '/^\! Property Name/d' \
-e '/^rofi\.color-/d' \
-e '/^rofi\.theme/d' \
-e '/^! Set the desired separator style/d' \
-e '/^rofi.separator-style: solid/d' \
-e '/^# Theme set by base16-manager/d' \
-e '/^\s*theme:/d' "$ROFI_CONFIG"
check_eof_nl "$ROFI_CONFIG"
printf "# Theme set by base16-manager\\nrofi.theme: %s\\n" "$file" >> "$ROFI_CONFIG"
}
set_xresources() {
local package=$1
local theme=$2
local xres=$HOME/.Xresources
local file="$DATA_PATH/$package/xresources/base16-$theme.Xresources"
local xres_d="$HOME/.Xresources.d"
local xres_color=".Xresources.d/colors"
if ! file_exists "$file"; then
err "Xresources theme not found."
else
check_dir "$xres_d"
cp "$file" "$HOME/$xres_color"
if file_exists "$xres"; then
# clean $xres and remove all lines containing color definitions
sed -i '/^\#ifdef background_opacity/,+4d' "$xres" #ifdef till #endif
sed -i '/[B|b]ase[[:xdigit:]]/d' "$xres" # base16
sed -i '/^\! Scheme/d' "$xres" # comments
sed -i '$!N; /^\(.*\)\n\1$/!P; D' "$xres" #remove newlines
fi
# add new line to include colors to Xresources
line_in_file "$xres" \
"^#include\\s+\".*$xres_color\"$" \
"#include \"$xres_color\""
xrdb -load "$xres" # reload colors
fi
}
main() {
local option=$1
local arg=$2
check_data_dir
if [[ -z "$option" ]]; then
usage
exit
fi
case $option in
"install")
check_arg "$arg"
install "$arg"
;;
"uninstall")
check_arg "$arg"
uninstall "$arg"
;;
"list")
list
;;
"list-themes")
list_themes
;;
"list-support")
list_support
;;
"list-installable")
list_installable
;;
"update")
update
;;
"set")
check_arg "$arg"
set_theme "$arg"
;;
"clean")
clean
;;
"set-random")
# shellcheck disable=SC2119
set_random
;;
"usage-short")
usage_short
;;
*)
usage
;;
esac
exit
}
main "$@"
# vim: ts=2 sw=2 et