diff --git a/dotfiles/.local/bin/dotfile-system-prune b/dotfiles/.local/bin/dotfile-system-prune
deleted file mode 100644
index c94049b0..00000000
--- a/dotfiles/.local/bin/dotfile-system-prune
+++ /dev/null
@@ -1,10 +0,0 @@
-#!/usr/bin/env bash
-
-# Clean up macOS-specific files if they are present
-if [ -d /Library ] && [ -d /System ]; then
- # System is macOS
-else
- if [ -d ~/Library ]; then
- rm -rf ~/Library
- fi
-fi
diff --git a/dotfiles/.local/share/chezmoi/dot_local/assets/Betelgeuse.macOS.terminal b/dotfiles/.local/share/chezmoi/dot_local/assets/Betelgeuse.macOS.terminal
new file mode 100644
index 00000000..cad43730
--- /dev/null
+++ b/dotfiles/.local/share/chezmoi/dot_local/assets/Betelgeuse.macOS.terminal
@@ -0,0 +1,55 @@
+
+
+
+
+
+ name
+ Betelgeuse
+ type
+ Window Settings
+ BackgroundColor
+ YnBsaXN0MDDUAQIDBAUGFRZYJHZlcnNpb25YJG9iamVjdHNZJGFyY2hpdmVyVCR0b3ASAAGGoKMHCA9VJG51bGzTCQoLDA0OVU5TUkdCXE5TQ29sb3JTcGFjZVYkY2xhc3NPECcwLjA4NjI3NDUwOTggMC4wOTgwMzkyMTU3IDAuMTQ1MDk4MDM5MgAQAYAC0hAREhNaJGNsYXNzbmFtZVgkY2xhc3Nlc1dOU0NvbG9yohIUWE5TT2JqZWN0XxAPTlNLZXllZEFyY2hpdmVy0RcYVHJvb3SAAQgRGiMtMjc7QUhOW2KMjpCVoKmxtL3P0tcAAAAAAAABAQAAAAAAAAAZAAAAAAAAAAAAAAAAAAAA2Q==
+ TextColor
+ YnBsaXN0MDDUAQIDBAUGFRZYJHZlcnNpb25YJG9iamVjdHNZJGFyY2hpdmVyVCR0b3ASAAGGoKMHCA9VJG51bGzTCQoLDA0OVU5TUkdCXE5TQ29sb3JTcGFjZVYkY2xhc3NPECcwLjY2NjY2NjY2NjcgMC42ODIzNTI5NDEyIDAuNzIxNTY4NjI3NQAQAYAC0hAREhNaJGNsYXNzbmFtZVgkY2xhc3Nlc1dOU0NvbG9yohIUWE5TT2JqZWN0XxAPTlNLZXllZEFyY2hpdmVy0RcYVHJvb3SAAQgRGiMtMjc7QUhOW2KMjpCVoKmxtL3P0tcAAAAAAAABAQAAAAAAAAAZAAAAAAAAAAAAAAAAAAAA2Q==
+ BoldTextColor
+ YnBsaXN0MDDUAQIDBAUGFRZYJHZlcnNpb25YJG9iamVjdHNZJGFyY2hpdmVyVCR0b3ASAAGGoKMHCA9VJG51bGzTCQoLDA0OVU5TUkdCXE5TQ29sb3JTcGFjZVYkY2xhc3NPECcwLjc2NDcwNTg4MjQgMC43ODAzOTIxNTY5IDAuODE5NjA3ODQzMQAQAYAC0hAREhNaJGNsYXNzbmFtZVgkY2xhc3Nlc1dOU0NvbG9yohIUWE5TT2JqZWN0XxAPTlNLZXllZEFyY2hpdmVy0RcYVHJvb3SAAQgRGiMtMjc7QUhOW2KMjpCVoKmxtL3P0tcAAAAAAAABAQAAAAAAAAAZAAAAAAAAAAAAAAAAAAAA2Q==
+ CursorColor
+ YnBsaXN0MDDUAQIDBAUGFRZYJHZlcnNpb25YJG9iamVjdHNZJGFyY2hpdmVyVCR0b3ASAAGGoKMHCA9VJG51bGzTCQoLDA0OVU5TUkdCXE5TQ29sb3JTcGFjZVYkY2xhc3NPECcwLjc2NDcwNTg4MjQgMC43ODAzOTIxNTY5IDAuODE5NjA3ODQzMQAQAYAC0hAREhNaJGNsYXNzbmFtZVgkY2xhc3Nlc1dOU0NvbG9yohIUWE5TT2JqZWN0XxAPTlNLZXllZEFyY2hpdmVy0RcYVHJvb3SAAQgRGiMtMjc7QUhOW2KMjpCVoKmxtL3P0tcAAAAAAAABAQAAAAAAAAAZAAAAAAAAAAAAAAAAAAAA2Q==
+ SelectionColor
+ YnBsaXN0MDDUAQIDBAUGFRZYJHZlcnNpb25YJG9iamVjdHNZJGFyY2hpdmVyVCR0b3ASAAGGoKMHCA9VJG51bGzTCQoLDA0OVU5TUkdCXE5TQ29sb3JTcGFjZVYkY2xhc3NPECcwLjc4MDM5MjE1NjkgMC4zMDE5NjA3ODQzIDAuNTM3MjU0OTAyMAAQAYAC0hAREhNaJGNsYXNzbmFtZVgkY2xhc3Nlc1dOU0NvbG9yohIUWE5TT2JqZWN0XxAPTlNLZXllZEFyY2hpdmVy0RcYVHJvb3SAAQgRGiMtMjc7QUhOW2KMjpCVoKmxtL3P0tcAAAAAAAABAQAAAAAAAAAZAAAAAAAAAAAAAAAAAAAA2Q==
+ ANSIBlackColor
+ YnBsaXN0MDDUAQIDBAUGFRZYJHZlcnNpb25YJG9iamVjdHNZJGFyY2hpdmVyVCR0b3ASAAGGoKMHCA9VJG51bGzTCQoLDA0OVU5TUkdCXE5TQ29sb3JTcGFjZVYkY2xhc3NPECcwLjA4NjI3NDUwOTggMC4wOTgwMzkyMTU3IDAuMTQ1MDk4MDM5MgAQAYAC0hAREhNaJGNsYXNzbmFtZVgkY2xhc3Nlc1dOU0NvbG9yohIUWE5TT2JqZWN0XxAPTlNLZXllZEFyY2hpdmVy0RcYVHJvb3SAAQgRGiMtMjc7QUhOW2KMjpCVoKmxtL3P0tcAAAAAAAABAQAAAAAAAAAZAAAAAAAAAAAAAAAAAAAA2Q==
+ ANSIRedColor
+ YnBsaXN0MDDUAQIDBAUGFRZYJHZlcnNpb25YJG9iamVjdHNZJGFyY2hpdmVyVCR0b3ASAAGGoKMHCA9VJG51bGzTCQoLDA0OVU5TUkdCXE5TQ29sb3JTcGFjZVYkY2xhc3NPECcwLjkyOTQxMTc2NDcgMC4xNDUwOTgwMzkyIDAuMzA1ODgyMzUyOQAQAYAC0hAREhNaJGNsYXNzbmFtZVgkY2xhc3Nlc1dOU0NvbG9yohIUWE5TT2JqZWN0XxAPTlNLZXllZEFyY2hpdmVy0RcYVHJvb3SAAQgRGiMtMjc7QUhOW2KMjpCVoKmxtL3P0tcAAAAAAAABAQAAAAAAAAAZAAAAAAAAAAAAAAAAAAAA2Q==
+ ANSIGreenColor
+ YnBsaXN0MDDUAQIDBAUGFRZYJHZlcnNpb25YJG9iamVjdHNZJGFyY2hpdmVyVCR0b3ASAAGGoKMHCA9VJG51bGzTCQoLDA0OVU5TUkdCXE5TQ29sb3JTcGFjZVYkY2xhc3NPECcwLjQ0MzEzNzI1NDkgMC45Njg2Mjc0NTEwIDAuNjIzNTI5NDExOAAQAYAC0hAREhNaJGNsYXNzbmFtZVgkY2xhc3Nlc1dOU0NvbG9yohIUWE5TT2JqZWN0XxAPTlNLZXllZEFyY2hpdmVy0RcYVHJvb3SAAQgRGiMtMjc7QUhOW2KMjpCVoKmxtL3P0tcAAAAAAAABAQAAAAAAAAAZAAAAAAAAAAAAAAAAAAAA2Q==
+ ANSIYellowColor
+ YnBsaXN0MDDUAQIDBAUGFRZYJHZlcnNpb25YJG9iamVjdHNZJGFyY2hpdmVyVCR0b3ASAAGGoKMHCA9VJG51bGzTCQoLDA0OVU5TUkdCXE5TQ29sb3JTcGFjZVYkY2xhc3NPECcwLjk3NjQ3MDU4ODIgMC44NjI3NDUwOTgwIDAuMzYwNzg0MzEzNwAQAYAC0hAREhNaJGNsYXNzbmFtZVgkY2xhc3Nlc1dOU0NvbG9yohIUWE5TT2JqZWN0XxAPTlNLZXllZEFyY2hpdmVy0RcYVHJvb3SAAQgRGiMtMjc7QUhOW2KMjpCVoKmxtL3P0tcAAAAAAAABAQAAAAAAAAAZAAAAAAAAAAAAAAAAAAAA2Q==
+ ANSIBlueColor
+ YnBsaXN0MDDUAQIDBAUGFRZYJHZlcnNpb25YJG9iamVjdHNZJGFyY2hpdmVyVCR0b3ASAAGGoKMHCA9VJG51bGzTCQoLDA0OVU5TUkdCXE5TQ29sb3JTcGFjZVYkY2xhc3NPECcwLjQ4NjI3NDUwOTggMC43MTc2NDcwNTg4IDEuMDAwMDAwMDAwMAAQAYAC0hAREhNaJGNsYXNzbmFtZVgkY2xhc3Nlc1dOU0NvbG9yohIUWE5TT2JqZWN0XxAPTlNLZXllZEFyY2hpdmVy0RcYVHJvb3SAAQgRGiMtMjc7QUhOW2KMjpCVoKmxtL3P0tcAAAAAAAABAQAAAAAAAAAZAAAAAAAAAAAAAAAAAAAA2Q==
+ ANSIMagentaColor
+ YnBsaXN0MDDUAQIDBAUGFRZYJHZlcnNpb25YJG9iamVjdHNZJGFyY2hpdmVyVCR0b3ASAAGGoKMHCA9VJG51bGzTCQoLDA0OVU5TUkdCXE5TQ29sb3JTcGFjZVYkY2xhc3NPECcwLjc4MDM5MjE1NjkgMC4zMDE5NjA3ODQzIDAuNTM3MjU0OTAyMAAQAYAC0hAREhNaJGNsYXNzbmFtZVgkY2xhc3Nlc1dOU0NvbG9yohIUWE5TT2JqZWN0XxAPTlNLZXllZEFyY2hpdmVy0RcYVHJvb3SAAQgRGiMtMjc7QUhOW2KMjpCVoKmxtL3P0tcAAAAAAAABAQAAAAAAAAAZAAAAAAAAAAAAAAAAAAAA2Q==
+ ANSICyanColor
+ YnBsaXN0MDDUAQIDBAUGFRZYJHZlcnNpb25YJG9iamVjdHNZJGFyY2hpdmVyVCR0b3ASAAGGoKMHCA9VJG51bGzTCQoLDA0OVU5TUkdCXE5TQ29sb3JTcGFjZVYkY2xhc3NPECcwLjAwMDAwMDAwMDAgMC43NTY4NjI3NDUxIDAuODk0MTE3NjQ3MQAQAYAC0hAREhNaJGNsYXNzbmFtZVgkY2xhc3Nlc1dOU0NvbG9yohIUWE5TT2JqZWN0XxAPTlNLZXllZEFyY2hpdmVy0RcYVHJvb3SAAQgRGiMtMjc7QUhOW2KMjpCVoKmxtL3P0tcAAAAAAAABAQAAAAAAAAAZAAAAAAAAAAAAAAAAAAAA2Q==
+ ANSIWhiteColor
+ YnBsaXN0MDDUAQIDBAUGFRZYJHZlcnNpb25YJG9iamVjdHNZJGFyY2hpdmVyVCR0b3ASAAGGoKMHCA9VJG51bGzTCQoLDA0OVU5TUkdCXE5TQ29sb3JTcGFjZVYkY2xhc3NPECcwLjY2NjY2NjY2NjcgMC42ODIzNTI5NDEyIDAuNzIxNTY4NjI3NQAQAYAC0hAREhNaJGNsYXNzbmFtZVgkY2xhc3Nlc1dOU0NvbG9yohIUWE5TT2JqZWN0XxAPTlNLZXllZEFyY2hpdmVy0RcYVHJvb3SAAQgRGiMtMjc7QUhOW2KMjpCVoKmxtL3P0tcAAAAAAAABAQAAAAAAAAAZAAAAAAAAAAAAAAAAAAAA2Q==
+ ANSIBrightBlackColor
+ YnBsaXN0MDDUAQIDBAUGFRZYJHZlcnNpb25YJG9iamVjdHNZJGFyY2hpdmVyVCR0b3ASAAGGoKMHCA9VJG51bGzTCQoLDA0OVU5TUkdCXE5TQ29sb3JTcGFjZVYkY2xhc3NPECcwLjE4NDMxMzcyNTUgMC4xOTYwNzg0MzE0IDAuMjQzMTM3MjU0OQAQAYAC0hAREhNaJGNsYXNzbmFtZVgkY2xhc3Nlc1dOU0NvbG9yohIUWE5TT2JqZWN0XxAPTlNLZXllZEFyY2hpdmVy0RcYVHJvb3SAAQgRGiMtMjc7QUhOW2KMjpCVoKmxtL3P0tcAAAAAAAABAQAAAAAAAAAZAAAAAAAAAAAAAAAAAAAA2Q==
+ ANSIBrightRedColor
+ YnBsaXN0MDDUAQIDBAUGFRZYJHZlcnNpb25YJG9iamVjdHNZJGFyY2hpdmVyVCR0b3ASAAGGoKMHCA9VJG51bGzTCQoLDA0OVU5TUkdCXE5TQ29sb3JTcGFjZVYkY2xhc3NPECcwLjg5MDE5NjA3ODQgMC4zMDU4ODIzNTI5IDAuNDM1Mjk0MTE3NgAQAYAC0hAREhNaJGNsYXNzbmFtZVgkY2xhc3Nlc1dOU0NvbG9yohIUWE5TT2JqZWN0XxAPTlNLZXllZEFyY2hpdmVy0RcYVHJvb3SAAQgRGiMtMjc7QUhOW2KMjpCVoKmxtL3P0tcAAAAAAAABAQAAAAAAAAAZAAAAAAAAAAAAAAAAAAAA2Q==
+ ANSIBrightGreenColor
+ YnBsaXN0MDDUAQIDBAUGFRZYJHZlcnNpb25YJG9iamVjdHNZJGFyY2hpdmVyVCR0b3ASAAGGoKMHCA9VJG51bGzTCQoLDA0OVU5TUkdCXE5TQ29sb3JTcGFjZVYkY2xhc3NPECcwLjUyNTQ5MDE5NjEgMC45MjE1Njg2Mjc1IDAuNjc0NTA5ODAzOQAQAYAC0hAREhNaJGNsYXNzbmFtZVgkY2xhc3Nlc1dOU0NvbG9yohIUWE5TT2JqZWN0XxAPTlNLZXllZEFyY2hpdmVy0RcYVHJvb3SAAQgRGiMtMjc7QUhOW2KMjpCVoKmxtL3P0tcAAAAAAAABAQAAAAAAAAAZAAAAAAAAAAAAAAAAAAAA2Q==
+ ANSIBrightYellowColor
+ YnBsaXN0MDDUAQIDBAUGFRZYJHZlcnNpb25YJG9iamVjdHNZJGFyY2hpdmVyVCR0b3ASAAGGoKMHCA9VJG51bGzTCQoLDA0OVU5TUkdCXE5TQ29sb3JTcGFjZVYkY2xhc3NPECcwLjkyNTQ5MDE5NjEgMC44NDMxMzcyNTQ5IDAuNDc0NTA5ODAzOQAQAYAC0hAREhNaJGNsYXNzbmFtZVgkY2xhc3Nlc1dOU0NvbG9yohIUWE5TT2JqZWN0XxAPTlNLZXllZEFyY2hpdmVy0RcYVHJvb3SAAQgRGiMtMjc7QUhOW2KMjpCVoKmxtL3P0tcAAAAAAAABAQAAAAAAAAAZAAAAAAAAAAAAAAAAAAAA2Q==
+ ANSIBrightBlueColor
+ YnBsaXN0MDDUAQIDBAUGFRZYJHZlcnNpb25YJG9iamVjdHNZJGFyY2hpdmVyVCR0b3ASAAGGoKMHCA9VJG51bGzTCQoLDA0OVU5TUkdCXE5TQ29sb3JTcGFjZVYkY2xhc3NPECcwLjU1Njg2Mjc0NTEgMC43MzMzMzMzMzMzIDAuOTU2ODYyNzQ1MQAQAYAC0hAREhNaJGNsYXNzbmFtZVgkY2xhc3Nlc1dOU0NvbG9yohIUWE5TT2JqZWN0XxAPTlNLZXllZEFyY2hpdmVy0RcYVHJvb3SAAQgRGiMtMjc7QUhOW2KMjpCVoKmxtL3P0tcAAAAAAAABAQAAAAAAAAAZAAAAAAAAAAAAAAAAAAAA2Q==
+ ANSIBrightMagentaColor
+ YnBsaXN0MDDUAQIDBAUGFRZYJHZlcnNpb25YJG9iamVjdHNZJGFyY2hpdmVyVCR0b3ASAAGGoKMHCA9VJG51bGzTCQoLDA0OVU5TUkdCXE5TQ29sb3JTcGFjZVYkY2xhc3NPECcwLjc3NjQ3MDU4ODIgMC40MjM1Mjk0MTE4IDAuNjA3ODQzMTM3MwAQAYAC0hAREhNaJGNsYXNzbmFtZVgkY2xhc3Nlc1dOU0NvbG9yohIUWE5TT2JqZWN0XxAPTlNLZXllZEFyY2hpdmVy0RcYVHJvb3SAAQgRGiMtMjc7QUhOW2KMjpCVoKmxtL3P0tcAAAAAAAABAQAAAAAAAAAZAAAAAAAAAAAAAAAAAAAA2Q==
+ ANSIBrightCyanColor
+ YnBsaXN0MDDUAQIDBAUGFRZYJHZlcnNpb25YJG9iamVjdHNZJGFyY2hpdmVyVCR0b3ASAAGGoKMHCA9VJG51bGzTCQoLDA0OVU5TUkdCXE5TQ29sb3JTcGFjZVYkY2xhc3NPECcwLjE5MjE1Njg2MjcgMC43NjQ3MDU4ODI0IDAuODc0NTA5ODAzOQAQAYAC0hAREhNaJGNsYXNzbmFtZVgkY2xhc3Nlc1dOU0NvbG9yohIUWE5TT2JqZWN0XxAPTlNLZXllZEFyY2hpdmVy0RcYVHJvb3SAAQgRGiMtMjc7QUhOW2KMjpCVoKmxtL3P0tcAAAAAAAABAQAAAAAAAAAZAAAAAAAAAAAAAAAAAAAA2Q==
+ ANSIBrightWhiteColor
+ YnBsaXN0MDDUAQIDBAUGFRZYJHZlcnNpb25YJG9iamVjdHNZJGFyY2hpdmVyVCR0b3ASAAGGoKMHCA9VJG51bGzTCQoLDA0OVU5TUkdCXE5TQ29sb3JTcGFjZVYkY2xhc3NPECcwLjc2NDcwNTg4MjQgMC43ODAzOTIxNTY5IDAuODE5NjA3ODQzMQAQAYAC0hAREhNaJGNsYXNzbmFtZVgkY2xhc3Nlc1dOU0NvbG9yohIUWE5TT2JqZWN0XxAPTlNLZXllZEFyY2hpdmVy0RcYVHJvb3SAAQgRGiMtMjc7QUhOW2KMjpCVoKmxtL3P0tcAAAAAAAABAQAAAAAAAAAZAAAAAAAAAAAAAAAAAAAA2Q==
+ Font
+ YnBsaXN0MDDUAQIDBAUGBwpYJHZlcnNpb25ZJGFyY2hpdmVyVCR0b3BYJG9iamVjdHMSAAGGoF8QD05TS2V5ZWRBcmNoaXZlctEICVRyb290gAGkCwwVFlUkbnVsbNQNDg8QERITFFZOU1NpemVYTlNmRmxhZ3NWTlNOYW1lViRjbGFzcyNAJgAAAAAAABAQgAKAA18QGUhhY2tOZXJkRm9udENvbXBsZXRlLUJvbGTSFxgZGlokY2xhc3NuYW1lWCRjbGFzc2VzVk5TRm9udKIZG1hOU09iamVjdAgRGiQpMjdJTFFTWF5nbnd+hY6QkpSwtcDJ0NMAAAAAAAABAQAAAAAAAAAcAAAAAAAAAAAAAAAAAAAA3A==
+
+
diff --git a/dotfiles/.local/share/chezmoi/dot_local/bin/executable_chrome-profile-export b/dotfiles/.local/share/chezmoi/dot_local/bin/executable_chrome-profile-export
new file mode 100644
index 00000000..8b137891
--- /dev/null
+++ b/dotfiles/.local/share/chezmoi/dot_local/bin/executable_chrome-profile-export
@@ -0,0 +1 @@
+
diff --git a/dotfiles/.local/share/chezmoi/dot_local/bin/executable_chrome-profile-import b/dotfiles/.local/share/chezmoi/dot_local/bin/executable_chrome-profile-import
new file mode 100644
index 00000000..e69de29b
diff --git a/dotfiles/.local/share/chezmoi/dot_local/bin/executable_firefox-profile-export b/dotfiles/.local/share/chezmoi/dot_local/bin/executable_firefox-profile-export
new file mode 100644
index 00000000..e69de29b
diff --git a/dotfiles/.local/share/chezmoi/dot_local/bin/executable_firefox-profile-import b/dotfiles/.local/share/chezmoi/dot_local/bin/executable_firefox-profile-import
new file mode 100644
index 00000000..f1f641af
--- /dev/null
+++ b/dotfiles/.local/share/chezmoi/dot_local/bin/executable_firefox-profile-import
@@ -0,0 +1 @@
+#!/usr/bin/env bash
diff --git a/dotfiles/.local/share/chezmoi/dot_local/bin/executable_install-dotfiles b/dotfiles/.local/share/chezmoi/dot_local/bin/executable_install-dotfiles
new file mode 100644
index 00000000..ba233498
--- /dev/null
+++ b/dotfiles/.local/share/chezmoi/dot_local/bin/executable_install-dotfiles
@@ -0,0 +1,133 @@
+#!/usr/bin/env bash
+
+# Alias logg function to true if it is not available
+if ! command -v logg > /dev/null; then
+ alias logg='true'
+fi
+
+# Clear ZSH cached stuff
+if [ -f "$HOME/.zshrc.zwc" ]; then
+ rm -f "$HOME/.zshrc.zwc"
+fi
+if [ -d "$HOME/.local/antigen" ]; then
+ rm -rf "$HOME/.local/antigen"
+fi
+if [ -d "$HOME/.zsh_sessions" ]; then
+ rm -rf "$HOME/.zsh_sessions"
+fi
+
+if [ -f '/etc/qubes-release' ]; then
+ # Qubes dom0
+ logg info 'Ensuring provision VM is present'
+ qvm-create --label red --template debian-11 provision &> /dev/null || EXIT_CODE=$?
+ logg info 'Downloading dotfile assets with provision VM'
+ qvm-run --pass-io provision 'if [ -d ~/Downloads/professor-dotfiles ]; then cd ~/Downloads/professor-dotfiles && git config pull.rebase false && rm -rf dotfiles/.local/asdf && rm -rf dotfiles/.local/common/shared && git pull origin master && git clone https://github.com/asdf-vm/asdf.git dotfiles/.local/asdf --branch v0.10.2 && mkdir -p dotfiles/.local/common/shared && git clone https://gitlab.com/megabyte-labs/common/shared.git dotfiles/.local/common/shared; else git clone https://gitlab.com/megabyte-labs/dotfiles.git ~/Downloads/professor-dotfiles; cd ~/Downloads/professor-dotfiles/dotfiles/.local && git clone https://github.com/asdf-vm/asdf.git asdf --branch v0.10.2 && mkdir common && git clone https://gitlab.com/megabyte-labs/common/shared.git common/shared; fi; cd ~/Downloads; tar -zcvf /tmp/professor-dotfiles.tar.gz professor-dotfiles'
+ logg info 'Transferring dotfiles to dom0 from provision VM'
+ qvm-run --pass-io provision "cat /tmp/professor-dotfiles.tar.gz" > "/tmp/dotfiles.tar.gz"
+ logg info 'Unpacking dotfile assets to /usr/local/src/professor-dotfiles'
+ tar -xzf "/tmp/dotfiles.tar.gz" -C "$HOME"
+ rm -f "/tmp/dotfiles.tar.gz"
+ sudo rm -rf /usr/local/src/professor-dotfiles
+ sudo mv "$HOME/professor-dotfiles" /usr/local/src/professor-dotfiles
+else
+ if [ ! -w /usr/local/src/professor-dotfiles ]; then
+ logg info 'Using sudo because /usr/local/src/professor-dotfiles is not writable'
+ SUDO_PREFIX="sudo"
+ fi
+ if [ -d /usr/local/src/professor-dotfiles/.git ]; then
+ logg info 'Updating dotfiles already present in /usr/local/src/professor-dotfiles'
+ cd /usr/local/src/professor-dotfiles
+ ${SUDO_PREFIX} git config pull.rebase false
+ ${SUDO_PREFIX} rm -rf dotfiles/.local/asdf
+ ${SUDO_PREFIX} rm -rf dotfiles/.local/common/shared
+ ${SUDO_PREFIX} git pull origin master
+ ${SUDO_PREFIX} git clone https://github.com/asdf-vm/asdf.git dotfiles/.local/asdf --branch v0.10.2
+ ${SUDO_PREFIX} git clone https://gitlab.com/megabyte-labs/common/shared.git dotfiles/.local/common/shared
+ ${SUDO_PREFIX} chown -Rf "$USER":"$(id -g -n)" /usr/local/src/professor-dotfiles
+ cd ~/
+ else
+ logg info 'Cloning new dotfiles to /usr/local/src/professor-dotfiles'
+ ${SUDO_PREFIX} rm -rf /usr/local/src/professor-dotfiles
+ ${SUDO_PREFIX} git clone https://gitlab.com/megabyte-labs/dotfiles.git /usr/local/src/professor-dotfiles
+ ${SUDO_PREFIX} git clone https://github.com/asdf-vm/asdf.git /usr/local/src/professor-dotfiles/dotfiles/.local/asdf --branch v0.10.2
+ ${SUDO_PREFIX} mkdir -p /usr/local/src/professor-dotfiles/dotfiles/.local/common/shared
+ ${SUDO_PREFIX} git clone https://gitlab.com/megabyte-labs/common/shared.git /usr/local/src/professor-dotfiles/dotfiles/.local/common/shared
+ ${SUDO_PREFIX} chown -Rf "$USER":"$(id -g -n)" /usr/local/src/professor-dotfiles
+ fi
+ if [ -n "$CREATE_PACKAGE" ]; then
+ logg info 'Creating /tmp/professor-dotfiles.tar.gz'
+ cd /usr/local/src
+ ${SUDO_PREFIX} tar -zcvf /tmp/professor-dotfiles.tar.gz professor-dotfiles
+ cd ~/
+ fi
+fi
+
+# Copy dotfile folders
+logg info 'Copying dotfiles folders to user $HOME directory'
+while read DOTFILE_FOLDER; do
+ BASENAME_FOLDER="$(basename "$DOTFILE_FOLDER")"
+ if [ ! -d "$HOME/$BASENAME_FOLDER" ]; then
+ mkdir -p "$HOME/$BASENAME_FOLDER"
+ fi
+ cp -rf "$DOTFILE_FOLDER/"* "$HOME/$BASENAME_FOLDER"
+done < <(find /usr/local/src/professor-dotfiles/dotfiles -maxdepth 1 -mindepth 1 -type d)
+
+# Copy dotfile files
+logg info 'Copying dotfiles files to user $HOME directory'
+while read DOTFILE_FILE; do
+ BASENAME_FILE="$(basename "$DOTFILE_FILE")"
+ cp "$DOTFILE_FILE" "$HOME/$BASENAME_FILE"
+ chmod 600 "$HOME/$BASENAME_FILE"
+done < <(find /usr/local/src/professor-dotfiles/dotfiles -maxdepth 1 -mindepth 1 -type f)
+
+# Ensure .local/bin contents are executable
+logg info 'Ensuring programs in ~/.local/bin are executable'
+while read LOCAL_BIN; do
+ chmod +x "${LOCAL_BIN}"
+done < <(find "$HOME/.local/bin" -maxdepth 1 -mindepth 1 -type f)
+
+if [ -d /Applications ] && [ -d /System ]; then
+ logg info 'Adding Hack font to ~/Library/Fonts'
+ mkdir -p "$HOME/Library/Fonts"
+ cp "$HOME/.local/share/fonts/Hack Bold Nerd Font Complete.ttf" "$HOME/Library/Fonts/Hack Bold Nerd Font Complete.ttf"
+ logg info 'Configuring the Terminal.app'
+ theme=$(<$HOME/.local/theme/Betelgeuse.macOS.terminal)
+ plutil -replace Window\ Settings.Betelgeuse -xml "$theme" ~/Library/Preferences/com.apple.Terminal.plist
+ defaults write com.apple.Terminal "Default Window Settings" -string "Betelgeuse"
+ defaults write com.apple.Terminal "Startup Window Settings" -string "Betelgeuse"
+ /usr/libexec/PlistBuddy -c "Add :Window\ Settings:Betelgeuse:columnCount integer 124" ~/Library/Preferences/com.apple.Terminal.plist
+ /usr/libexec/PlistBuddy -c "Add :Window\ Settings:Betelgeuse:rowCount integer 35" ~/Library/Preferences/com.apple.Terminal.plist
+ /usr/libexec/PlistBuddy -c "Add :Window\ Settings:Betel-Bash:columnCount integer 124" ~/Library/Preferences/com.apple.Terminal.plist
+ /usr/libexec/PlistBuddy -c "Add :Window\ Settings:Betel-Bash:rowCount integer 35" ~/Library/Preferences/com.apple.Terminal.plist
+
+ # macOS desktop background
+ if command -v m > /dev/null; then
+ logg info 'Updating desktop wallpaper'
+ m wallpaper "/Users/$(whoami)/.local/theme/background.jpg"
+ fi
+fi
+
+# Update local Betelgeuse theme files (if not on macOS system)
+if [ ! -d /Applications ] && [ ! -d /Library ]; then
+ logg info 'Updating Betelgeuse theme files'
+ if [ -f '/etc/qubes-release' ]; then
+ # Qubes dom0
+ qvm-create --label red --template debian-11 provision &> /dev/null || EXIT_CODE=$?
+ qvm-run --pass-io provision 'rm -f ~/Downloads/betelgeuse-master.tar.gz && curl -sSL https://gitlab.com/megabyte-labs/misc/betelgeuse/-/archive/master/betelgeuse-master.tar.gz > /tmp/betelgeuse-master.tar.gz'
+ qvm-run --pass-io provision "cat /tmp/betelgeuse-master.tar.gz" > "/tmp/betelgeuse-master.tar.gz"
+ cd /tmp
+ tar -xvf betelgeuse-master.tar.gz > /dev/null
+ rm betelgeuse-master.tar.gz
+ cp -rf betelgeuse-master/share/ "$HOME/.local/share"
+ rm -rf betelgeuse-master
+ else
+ curl -sSL https://gitlab.com/megabyte-labs/misc/betelgeuse/-/archive/master/betelgeuse-master.tar.gz > betelgeuse-master.tar.gz
+ tar -xzf betelgeuse-master.tar.gz > /dev/null
+ rm betelgeuse-master.tar.gz
+ cp -rf betelgeuse-master/share/ "$HOME/.local/share"
+ rm -rf betelgeuse-master
+ fi
+fi
+
+# grep -q QT_QPA_PLATFORMTHEME=qt5ct /etc/environment || echo QT_QPA_PLATFORMTHEME=qt5ct | sudo tee -a /etc/environment
+# sudo cp -rv "$HOME/.local/share/qt5ct" /usr/share
diff --git a/dotfiles/.local/share/chezmoi/dot_local/bin/executable_install-terminal-theme b/dotfiles/.local/share/chezmoi/dot_local/bin/executable_install-terminal-theme
new file mode 100644
index 00000000..6aa20ab5
--- /dev/null
+++ b/dotfiles/.local/share/chezmoi/dot_local/bin/executable_install-terminal-theme
@@ -0,0 +1,1060 @@
+#!/usr/bin/env bash
+# @file ~/.local/bin/install-terminal-theme
+# @brief Applies the Sweet KDE (Betelgeuse) theme [found here](https://store.kde.org/p/1297008/)
+# @description
+# This script will create the necessary color profile for the Betelgeuse theme
+# to any terminal. Before applying the theme, it will display the color palette
+# in the terminal and prompt for whether or not it should be applied. It might
+# also be necessary to apply the terminal theme which should be available in the
+# terminals settings after it is generated.
+
+# Themer.dev: https://themer.dev/?calculateIntermediaryShades.dark=true&colors.dark.shade0=%23161925&colors.dark.shade7=%23C3C7D1&colors.dark.accent0=%23ED254E&colors.dark.accent3=%2371F79F&colors.dark.accent2=%23F9DC5C&colors.dark.accent4=%2300C1E4&colors.dark.accent5=%237CB7FF&colors.dark.accent7=%23C74D89&colors.dark.accent6=%23C3C7D1&colors.dark.accent1=%23DCDFE4&colors.light.accent0=%23FF4972&colors.light.accent3=%2395FFC3&colors.light.accent2=%23FFFF80&colors.light.accent5=%23A0DBFF&colors.light.accent7=%23EB71AD&colors.light.accent6=%234C5058&colors.light.shade7=%234C5058&colors.light.shade0=%23FFFFFF&colors.light.accent4=%2324E5FF&colors.light.accent1=%23DCDFE4&activeColorSet=dark
+
+export COLOR_01="#282C34" # Black
+export COLOR_02="#ED254E" # Red
+export COLOR_03="#71F79F" # Green
+export COLOR_04="#F9DC5C" # Yellow
+export COLOR_05="#7CB7FF" # Blue
+export COLOR_06="#C74D89" # Magenta
+export COLOR_07="#00C1E4" # Cyan
+export COLOR_08="#DCDFE4" # Light gray
+
+export COLOR_09="#4C5058" # Dark gray
+export COLOR_10="#FF4972" # Light Red
+export COLOR_11="#95FFC3" # Light Green
+export COLOR_12="#FFFF80" # Light Yellow
+export COLOR_13="#A0DBFF" # Light Blue
+export COLOR_14="#EB71AD" # Light Magenta
+export COLOR_15="#24E5FF" # Light Cyan
+export COLOR_16="#FFFFFF" # White
+
+export BACKGROUND_COLOR="#161925" # Background Color
+export FOREGROUND_COLOR="#C3C7D1" # Foreground Color (text)
+export CURSOR_COLOR="$FOREGROUND_COLOR" # Cursor color
+export PROFILE_NAME="Betelgeuse"
+
+if [ ! -e gconftool-2 ] && [ -f /etc/debian_version ]; then
+ sudo apt-get update
+ sudo apt-get install -y gconf2
+fi
+
+# |
+# | Early pre-requisites check
+# | ===========================================
+UUIDGEN="${UUIDGEN:-$(command -v uuidgen | xargs echo)}"
+DCONF="${DCONF:-$(command -v dconf | xargs echo)}"
+GCONF="${GCONF:-$(command -v gconftool-2 | xargs echo)}"
+GS="${GS:-$(command -v gsettings | xargs echo)}"
+# Note: xargs echo is to make the command sucessful even if it was not
+# otherwise the script will exit if the command does not exist (elementary os)
+
+# |
+# | Make sure all exported variables get unset no matter what
+# | Defining this in this script because it gets called even if
+# | gogh.sh was not called. Exported variables in gogh.sh gets
+# | handled there in case there was en error before this script was called
+# | ============================================
+GLOBAL_VAR_CLEANUP() {
+ unset PROFILE_NAME
+ unset PROFILE_SLUG
+ unset scratchdir
+ unset TILIX_RES
+ unset TERMINAL
+ unset LOOP
+ unset OPTLENGTH
+
+ for c in $(seq -s " " -w 16); do
+ unset DEMO_COLOR_${c}
+ unset COLOR_${c}
+ done
+
+ unset BACKGROUND_COLOR
+ unset FOREGROUND_COLOR
+ unset CURSOR_COLOR
+ unset HIGHLIGHT_FG_COLOR
+ unset HIGHLIGHT_BG_COLOR
+ unset USE_SYS_TRANSPARENCY
+ unset PROFILE_NAME
+}
+
+# Note: Since all scripts gets invoked in a subshell the traps from the parent shell
+# will not get inherited. Hence traps defined in gogh.sh and print-themes.sh will still trigger
+trap 'GLOBAL_VAR_CLEANUP; trap - EXIT' EXIT HUP INT QUIT PIPE TERM
+
+# |
+# | Second test for TERMINAL in case user ran
+# | theme script directly instead of gogh.sh
+# | ============================================
+if [[ -z "${TERMINAL:-}" ]]; then
+
+ # |
+ # | Check for the terminal name (depening on os)
+ # | ===========================================
+ OS="$(uname)"
+ if [[ "$TERM" = "xterm-kitty" ]]; then
+ TERMINAL="kitty"
+ elif [[ "$OS" = "Darwin" ]]; then
+ TERMINAL=$TERM_PROGRAM
+ elif [[ "${OS#CYGWIN}" != "${OS}" ]]; then
+ TERMINAL="mintty"
+ else
+ # |
+ # | Depending on how the script was invoked, we need
+ # | to loop until pid is no longer a subshell
+ # | ===========================================
+ pid="$$"
+ TERMINAL="$(ps -h -o comm -p $pid)"
+ while [[ "${TERMINAL:(-2)}" == "sh" ]]; do
+ pid="$(ps -h -o ppid -p $pid)"
+ TERMINAL="$(ps -h -o comm -p $pid)"
+ done
+ fi
+fi
+
+
+case "${TERMINAL}" in
+ pantheon-terminal|io.elementary.t* )
+ if [[ -z "${GS}" ]]; then
+ printf '\n%s\n' "Error gsettings not found"
+ printf '%s\n' "sudo apt install dconf?"
+ printf '%s\n\n' "or export GS=/path/to/gsettings"
+ exit 1
+ fi
+ ;;
+
+ mintty )
+ CFGFILE="${HOME}/.minttyrc"
+ if [[ ! -f "${CFGFILE}" ]]; then
+ printf '\n%s\n' "Warning: Couldn't find an existing configuration file, so one will be created for you."
+ printf '%s\n\n' "Warning: Are you really running Cygwin's mintty?"
+ touch "${CFGFILE}"
+ fi
+ ;;
+
+ guake|tilix|mate-terminal|gnome-terminal* )
+ case "${TERMINAL}" in
+ guake|gnome-terminal* )
+ if [[ -z "${DCONF}" ]] && [[ -z "${GCONF}" ]]; then
+ printf '\n%s\n' "Error gconftool not found!"
+ printf '%s\n' "sudo apt install gconftool?"
+ printf '%s\n\n' "or export GCONF=/path/to/gconftool-2/"
+ exit 1
+ fi
+ ;;
+ esac
+ if [[ -z "${DCONF}" ]]; then
+ printf '\n%s\n' "Error dconf not found"
+ printf '%s\n' "sudo apt install dconf?"
+ printf '%s\n\n' "or export DCONF=/path/to/dconf"
+ exit 1
+ fi
+ ;;
+
+ foot )
+ CFGFILE="${HOME}/.config/foot/foot.ini"
+ if [[ ! -f "${CFGFILE}" ]]; then
+ printf '\n%s\n' "Error: Couldn't find an existing configuration file."
+ exit 1
+ fi
+ ;;
+
+ kitty )
+ if [[ -z "${KITTY_CONFIG_DIRECTORY:-}" ]]; then
+ KITTY_CONFIG_DIRECTORY="${HOME}/.config/kitty"
+ fi
+ CFGFILE="${KITTY_CONFIG_DIRECTORY}/kitty.conf"
+ if [[ ! -f "${CFGFILE}" ]]; then
+ printf '\n%s\n' "Error: Couldn't find an existing configuration file for Kitty."
+ exit 1
+ fi
+ ;;
+
+ konsole )
+ CFGFILE="${HOME}/.config/konsolerc"
+ if [[ ! -f "${CFGFILE}" ]]; then
+ printf '\n%s\n' "Error: Couldn't find an existing configuration file for Konsole."
+ exit 1
+ fi
+ ;;
+esac
+
+
+# |
+# | Convert RGB to gnome colors
+# | ===========================================
+gnome_color () {
+
+ AA=${1:1:2}
+ BB=${1:3:2}
+ CC=${1:5:2}
+
+ if [[ -n "${AA:-}" ]]; then
+ echo "#${AA}${AA}${BB}${BB}${CC}${CC}"
+ fi
+}
+
+hexToDec () {
+ echo "$((16#${1}))"
+}
+
+hexRGBtoDecRGB () {
+ R="$(hexToDec "${1:1:2}")"
+ G="$(hexToDec "${1:3:2}")"
+ B="$(hexToDec "${1:5:2}")"
+
+ echo "${R}" "${G}" "${B}"
+}
+
+convertRGBtoMac () {
+ local color="${1}"
+ set --
+ set -- $(hexRGBtoDecRGB "${color}")
+ R=${1}; shift; G=${1}; shift; B=${1}; shift
+
+ R=$(echo "${R} / 255" | bc -l)
+ G=$(echo "${G} / 255" | bc -l)
+ B=$(echo "${B} / 255" | bc -l)
+
+ echo "${R}" "${G}" "${B}"
+}
+
+createMinttyEntry () {
+ local name="${1}"
+ local color="${2}"
+ set --
+ set -- $(hexRGBtoDecRGB "${color}")
+ R=${1}; shift; G=${1}; shift; B=${1}; shift
+
+ echo "${name}=${R},${G},${B}"
+}
+
+updateMinttyConfig () {
+ local config="${1}"
+ local color="${2}"
+ local name="${3}"
+
+ sed -i -r -e "s/^${name}=.+/$(createMinttyEntry "${name}" "${color}")/g" "${config}"
+}
+
+updateFootConfig () {
+ local config="${1}"
+ local color="${2}"
+ local name="${3}"
+
+ sed -i -r -e "s/^${name}=.+/${name}=${color/\#/}/g" "${config}"
+}
+
+createKonsoleEntry () {
+ local name="${1}"
+ local color="${2}"
+ set --
+ set -- $(hexRGBtoDecRGB "${color}")
+ R=${1}; shift; G=${1}; shift; B=${1}; shift
+
+ echo -e "[$name]\nColor=${R},${G},${B}\n"
+}
+
+createKonsoleTriple () {
+ local name="${1}"
+ local colorn="${2}" # normal and faint
+ local colori="${3}" # intense
+
+ createKonsoleEntry "${name}" "${colorn}"
+ createKonsoleEntry "${name}Faint" "${colorn}"
+ createKonsoleEntry "${name}Intense" "${colori}"
+}
+
+convertNameAndRGBtoITerm() {
+ local name="${1}"
+ local color="${2}"
+ set --
+ set -- $(convertRGBtoMac "${color}")
+ R=${1}; shift; G=${1}; shift; B=${1}; shift
+
+ echo "${name}Blue Component${B}Green Component${G}Red Component${R}"
+}
+
+dset() {
+ local key="${1}"; shift
+ local val="${1}"
+
+ "${DCONF}" write "${PROFILE_KEY}/${key}" "${val}"
+}
+
+# Because dconf still doesn't have "append"
+dlist_append() {
+ local key="${1}"; shift
+ local val="${1}"; shift
+ local entries
+
+ entries="$(
+ {
+ "${DCONF}" read "${key}" | tr -d "[]" | tr , "\n" | grep -F -v "${val}"
+ echo "'${val}'"
+ } | head -c-1 | tr "\n" ,
+ )"
+
+ "${DCONF}" write "${key}" "[${entries}]"
+}
+
+gcset() {
+ local type="${1}"; shift
+ local key="${1}"; shift
+ local val="${1}"
+
+ "${GCONF}" --set --type "${type}" "${PROFILE_KEY}/${key}" -- "${val}"
+}
+
+# Because gconftool doesn't have "append"
+glist_append() {
+ local type="${1}"; shift
+ local key="${1}"; shift
+ local val="${1}"; shift
+ local entries
+
+ entries="$(
+ {
+ "${GCONF}" --get "${key}" | tr -d "[]" | tr , "\n" | grep -F -v "${val}"
+ echo "${val}"
+ } | head -c-1 | tr "\n" ,
+ )"
+
+ "${GCONF}" --set --type list --list-type "${type}" "${key}" "[${entries}]"
+}
+
+gset() {
+ local key="${1}"; shift
+ local val="${1}"
+
+ "${GS}" set "${PROFILE_KEY}" "${key}" "${val}"
+}
+
+set_theme() {
+ dset visible-name "'${PROFILE_NAME}'"
+ dset background-color "'${BACKGROUND_COLOR}'"
+ dset foreground-color "'${FOREGROUND_COLOR}'"
+ dset cursor-colors-set "true"
+ dset cursor-background-color "'${CURSOR_COLOR}'"
+ dset cursor-foreground-color "'${BACKGROUND_COLOR}'"
+
+ if [[ -n "${HIGHLIGHT_BG_COLOR:-}" ]]; then
+ dset highlight-colors-set "true"
+ dset highlight-background-color "'${HIGHLIGHT_BG_COLOR}'"
+ if [[ -n "${HIGHLIGHT_FG_COLOR:-}" ]]; then
+ dset highlight-foreground-color "'${HIGHLIGHT_FG_COLOR}'"
+ fi
+ fi
+
+ if [[ -n "${BOLD_COLOR:-}" ]]; then
+ dset bold-color "'${BOLD_COLOR}'"
+ dset bold-color-same-as-fg "false"
+ else
+ dset bold-color "'${FOREGROUND_COLOR}'"
+ dset bold-color-same-as-fg "true"
+ fi
+ dset use-theme-colors "false"
+ dset use-theme-background "false"
+ dset use-theme-transparency "${USE_SYS_TRANSPARENCY:-false}"
+}
+
+legacy_set_theme() {
+ gcset string visible_name "${PROFILE_NAME}"
+ gcset string background_color "${BACKGROUND_COLOR}"
+ gcset string foreground_color "${FOREGROUND_COLOR}"
+
+ if [[ -n "${BOLD_COLOR:-}" ]]; then
+ gcset string bold_color "${BOLD_COLOR}"
+ gcset bool bold_color_same_as_fg "false"
+ else
+ gcset string bold_color "${FOREGROUND_COLOR}"
+ gcset bool bold_color_same_as_fg "true"
+ fi
+ gcset bool use_theme_colors "false"
+ gcset bool use_theme_background "false"
+}
+
+
+
+# |
+# | If terminal supports truecolor then we can show theme colors without applying the theme
+# | ===========================================
+if [[ "${COLORTERM:-}" == "truecolor" ]] || [[ "${COLORTERM:-}" == "24bit" ]]; then
+ # gogh_colors have been moved here to avoid multiple definitions
+ function gogh_colors () {
+ # Build up the color string to avoid visual rendering
+ local color_str
+ # Note: {01..16} does not work on OSX
+ for c in $(seq -s " " -w 16); do
+ local color="COLOR_$c"
+ set -- $(hexRGBtoDecRGB "${!color}")
+ color_str+="\033[38;2;${1};${2};${3}m█████$(tput sgr0)"
+ [[ ${GOGH_DRY_RUN:-0} -eq 1 ]] && export "DEMO_COLOR_$c=\033[38;2;${1};${2};${3}m"
+ [[ "$c" == "08" ]] && color_str+="\n" # new line
+ done
+ printf '\n%b\n\n\n' "${color_str}"
+ unset color_str
+ }
+else
+ function gogh_colors () {
+ # Build up the color string to avoid visual rendering
+ local color_str
+ for c in {0..15}; do
+ color_str+="$(tput setaf $c)█████$(tput sgr0)"
+ [[ $c == 7 ]] && color_str+="\n" # new line
+ done
+ printf '\n%b\n\n' "${color_str}"
+ unset color_str
+ }
+fi
+
+
+# |
+# | Print theme colors
+# | ===========================================
+gogh_colors
+if [[ ${GOGH_DRY_RUN:-0} -eq 1 ]]; then
+ color
+ # End here if dry run was initiated
+ exit 0
+fi
+
+
+apply_elementary() {
+ # |
+ # | Applying values on elementary/pantheon terminal
+ # | ===========================================
+
+ local BG_COLOR="${BACKGROUND_COLOR}"
+
+ # If the background color is in the format #rrggbb, convert it to rgba(r,g,b,0.95).
+ # This makes it 5% transparent, which is the default in elementary OS.
+ if [[ ${BACKGROUND_COLOR} =~ ^#[[:xdigit:]]{6}$ ]]; then
+ local R="$((16#${BACKGROUND_COLOR:1:2}))"
+ local G="$((16#${BACKGROUND_COLOR:3:2}))"
+ local B="$((16#${BACKGROUND_COLOR:5:2}))"
+ BG_COLOR="rgba($R,$G,$B,0.95)"
+ fi
+
+ gset background "${BG_COLOR}"
+ gset foreground "${FOREGROUND_COLOR}"
+ gset cursor-color "${CURSOR_COLOR}"
+ gset palette "${COLOR_01}:${COLOR_02}:${COLOR_03}:${COLOR_04}:${COLOR_05}:${COLOR_06}:${COLOR_07}:${COLOR_08}:${COLOR_09}:${COLOR_10}:${COLOR_11}:${COLOR_12}:${COLOR_13}:${COLOR_14}:${COLOR_15}:${COLOR_16}"
+}
+
+apply_cygwin() {
+ # |
+ # | Applying values on mintty (cygwin)
+ # | ===========================================
+
+ echo "Patching mintty configuration file (${CFGFILE}) with new colors..."
+
+ updateMinttyConfig "$CFGFILE" "$COLOR_01" "Black"
+ updateMinttyConfig "$CFGFILE" "$COLOR_02" "Red"
+ updateMinttyConfig "$CFGFILE" "$COLOR_03" "Green"
+ updateMinttyConfig "$CFGFILE" "$COLOR_04" "Yellow"
+ updateMinttyConfig "$CFGFILE" "$COLOR_05" "Blue"
+ updateMinttyConfig "$CFGFILE" "$COLOR_06" "Magenta"
+ updateMinttyConfig "$CFGFILE" "$COLOR_07" "Cyan"
+ updateMinttyConfig "$CFGFILE" "$COLOR_08" "White"
+
+ updateMinttyConfig "$CFGFILE" "$COLOR_09" "BoldBlack"
+ updateMinttyConfig "$CFGFILE" "$COLOR_10" "BoldRed"
+ updateMinttyConfig "$CFGFILE" "$COLOR_11" "BoldGreen"
+ updateMinttyConfig "$CFGFILE" "$COLOR_12" "BoldYellow"
+ updateMinttyConfig "$CFGFILE" "$COLOR_13" "BoldBlue"
+ updateMinttyConfig "$CFGFILE" "$COLOR_14" "BoldMagenta"
+ updateMinttyConfig "$CFGFILE" "$COLOR_15" "BoldCyan"
+ updateMinttyConfig "$CFGFILE" "$COLOR_16" "BoldWhite"
+
+ updateMinttyConfig "$CFGFILE" "$BACKGROUND_COLOR" "Backgroundcolor"
+ updateMinttyConfig "$CFGFILE" "$FOREGROUND_COLOR" "Foregroundcolor"
+ updateMinttyConfig "$CFGFILE" "$CURSOR_COLOR" "Cursorcolor"
+
+ echo "Done - please reopen your Cygwin terminal to see the changes"
+}
+
+apply_alacritty() {
+ # |
+ # | Applying values on Alacritty
+ # | ===========================================
+
+ json_str="\
+ { \
+ \"colors\": \
+ {\
+ \"primary\":\
+ {\
+ \"background\": \"$BACKGROUND_COLOR\",\
+ \"foreground\": \"$FOREGROUND_COLOR\"\
+ },\
+ \"normal\":\
+ {\
+ \"black\": \"$COLOR_01\",\
+ \"red\": \"$COLOR_02\",\
+ \"green\": \"$COLOR_03\",\
+ \"yellow\":\"$COLOR_04\",\
+ \"blue\":\"$COLOR_05\",\
+ \"magenta\": \"$COLOR_06\",\
+ \"cyan\":\"$COLOR_07\",\
+ \"white\": \"$COLOR_08\"\
+ },\
+ \"bright\":\
+ {\
+ \"black\":\"$COLOR_09\",\
+ \"red\":\"$COLOR_10\",\
+ \"green\":\"$COLOR_11\",\
+ \"yellow\": \"$COLOR_12\",\
+ \"blue\": \"$COLOR_13\",\
+ \"magenta\":\"$COLOR_14\",\
+ \"cyan\": \"$COLOR_15\",\
+ \"white\":\"$COLOR_16\"\
+ } \
+ }\
+ }"
+
+ SCRIPT_PATH="${SCRIPT_PATH:-$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)}"
+ PARENT_PATH="$(dirname "${SCRIPT_PATH}")"
+
+ # Allow developer to change url to forked url for easier testing
+ # IMPORTANT: Make sure you export this variable if your main shell is not bash
+ BASE_URL=${BASE_URL:-"https://raw.githubusercontent.com/Gogh-Co/Gogh/master"}
+
+
+ if [[ -e "${SCRIPT_PATH}/apply-alacritty.py" ]]; then
+ python3 "${SCRIPT_PATH}/apply-alacritty.py" "$json_str"
+ else
+ if [[ "$(uname)" = "Darwin" ]]; then
+ # OSX ships with curl and ancient bash
+ python3 -c "$(curl -so- "${BASE_URL}/apply-alacritty.py")" "$json_str"
+ else
+ # Linux ships with wget
+ python3 -c "$(wget -qO- "${BASE_URL}/apply-alacritty.py")" "$json_str"
+ fi
+ fi
+
+}
+
+apply_foot() {
+ # |
+ # | Applying values on foot
+ # | ===========================================
+
+ echo "Patching foot configuration file (${CFGFILE}) with new colors..."
+
+ updateFootConfig "$CFGFILE" "$COLOR_01" "regular0"
+ updateFootConfig "$CFGFILE" "$COLOR_02" "regular1"
+ updateFootConfig "$CFGFILE" "$COLOR_03" "regular2"
+ updateFootConfig "$CFGFILE" "$COLOR_04" "regular3"
+ updateFootConfig "$CFGFILE" "$COLOR_05" "regular4"
+ updateFootConfig "$CFGFILE" "$COLOR_06" "regular5"
+ updateFootConfig "$CFGFILE" "$COLOR_07" "regular6"
+ updateFootConfig "$CFGFILE" "$COLOR_08" "regular7"
+
+ updateFootConfig "$CFGFILE" "$COLOR_09" "bright0"
+ updateFootConfig "$CFGFILE" "$COLOR_10" "bright1"
+ updateFootConfig "$CFGFILE" "$COLOR_11" "bright2"
+ updateFootConfig "$CFGFILE" "$COLOR_12" "bright3"
+ updateFootConfig "$CFGFILE" "$COLOR_13" "bright4"
+ updateFootConfig "$CFGFILE" "$COLOR_14" "bright5"
+ updateFootConfig "$CFGFILE" "$COLOR_15" "bright6"
+ updateFootConfig "$CFGFILE" "$COLOR_16" "bright7"
+
+ updateFootConfig "$CFGFILE" "$BACKGROUND_COLOR" "background"
+ updateFootConfig "$CFGFILE" "$FOREGROUND_COLOR" "foreground"
+
+ echo "Done - please reopen your foot terminal to see the changes"
+
+}
+
+apply_kitty() {
+ # |
+ # | Applying values on Kitty
+ # | ===========================================
+
+ echo "Patching kitty configuration file ($CFGFILE) with include of color theme file..."
+
+ COLOR_FILE="colors.conf"
+
+ if ! grep -q "^include $COLOR_FILE$" "$CFGFILE" ; then
+ echo "" >> "$CFGFILE"
+ echo "# Added by Gogh" >> "$CFGFILE"
+ echo "include $COLOR_FILE" >> "$CFGFILE"
+ fi
+
+ CFGFILE="${KITTY_CONFIG_DIRECTORY}/$COLOR_FILE"
+
+ echo "Updating color theme file ($CFGFILE) with theme..."
+
+ rm -f "$CFGFILE"
+
+ echo "# Color theme: $PROFILE_NAME" >> "$CFGFILE"
+ echo "# Auto-generated by Gogh (https://Gogh-Co.github.io/Gogh/)" >> "$CFGFILE"
+ echo "" >> "$CFGFILE"
+ echo "color0 $COLOR_01" >> "$CFGFILE"
+ echo "color1 $COLOR_02" >> "$CFGFILE"
+ echo "color2 $COLOR_03" >> "$CFGFILE"
+ echo "color3 $COLOR_04" >> "$CFGFILE"
+ echo "color4 $COLOR_05" >> "$CFGFILE"
+ echo "color5 $COLOR_06" >> "$CFGFILE"
+ echo "color6 $COLOR_07" >> "$CFGFILE"
+ echo "color7 $COLOR_08" >> "$CFGFILE"
+ echo "color8 $COLOR_09" >> "$CFGFILE"
+ echo "color9 $COLOR_10" >> "$CFGFILE"
+ echo "color10 $COLOR_11" >> "$CFGFILE"
+ echo "color11 $COLOR_12" >> "$CFGFILE"
+ echo "color12 $COLOR_13" >> "$CFGFILE"
+ echo "color13 $COLOR_14" >> "$CFGFILE"
+ echo "color14 $COLOR_15" >> "$CFGFILE"
+ echo "color15 $COLOR_16" >> "$CFGFILE"
+
+ echo "background $BACKGROUND_COLOR" >> "$CFGFILE"
+ echo "foreground $FOREGROUND_COLOR" >> "$CFGFILE"
+
+ [ -n "$HIGHLIGHT_FG_COLOR" ] && echo "selection_foreground $HIGHLIGHT_FG_COLOR" >> "$CFGFILE"
+ [ -n "$HIGHLIGHT_BG_COLOR" ] && echo "selection_background $HIGHLIGHT_BG_COLOR" >> "$CFGFILE"
+
+ echo "cursor $CURSOR_COLOR" >> "$CFGFILE"
+
+ echo "Done - please reopen your kitty terminal to see the changes"
+}
+
+apply_konsole() {
+ # |
+ # | Applying values on Konsole
+ # | ===========================================
+
+ PARENT=$(grep -o "^DefaultProfile=.*$" ${CFGFILE} | cut -d '=' -f 2)
+ if [[ -z "${PARENT}" ]]; then
+ PARENT="FALLBACK/"
+ fi
+
+ if [[ -z "${XDG_DATA_HOME:-}" ]]; then
+ KDIR="${HOME}/.local/share/konsole"
+ else
+ KDIR="${XDG_DATA_HOME}/konsole"
+ fi
+
+ KPROFILE="${KDIR}/${PROFILE_NAME}.profile"
+ if [[ -f "${KPROFILE}" ]]; then
+ echo "Profile ${PROFILE_NAME} already exists in Konsole confiuration (${KONSOLE_DIR}); Skipping ..."
+ exit 0
+ fi
+
+ touch "${KPROFILE}"
+ echo -e "[Appearance]\nColorScheme=${PROFILE_NAME}\n" >> "${KPROFILE}"
+ echo -e "[General]\nName=${PROFILE_NAME}\nParent=$PARENT" >> "${KPROFILE}"
+
+ KCOLORSCHEME="${KDIR}/${PROFILE_NAME}.colorscheme"
+ if [[ -f "${KCOLORSCHEME}" ]]; then
+ echo "Color Scheme ${PROFILE_NAME} already exists in Konsole confiuration (${KONSOLE_DIR}); Skipping ..."
+ exit 0
+ fi
+
+ touch "${KCOLORSCHEME}"
+ createKonsoleTriple "Background" "${BACKGROUND_COLOR}" "${BACKGROUND_COLOR}" >> "${KCOLORSCHEME}"
+ createKonsoleTriple "Color0" "${COLOR_01}" "${COLOR_09}" >> "${KCOLORSCHEME}"
+ createKonsoleTriple "Color1" "${COLOR_02}" "${COLOR_10}" >> "${KCOLORSCHEME}"
+ createKonsoleTriple "Color2" "${COLOR_03}" "${COLOR_11}" >> "${KCOLORSCHEME}"
+ createKonsoleTriple "Color3" "${COLOR_04}" "${COLOR_12}" >> "${KCOLORSCHEME}"
+ createKonsoleTriple "Color4" "${COLOR_05}" "${COLOR_13}" >> "${KCOLORSCHEME}"
+ createKonsoleTriple "Color5" "${COLOR_06}" "${COLOR_14}" >> "${KCOLORSCHEME}"
+ createKonsoleTriple "Color6" "${COLOR_07}" "${COLOR_15}" >> "${KCOLORSCHEME}"
+ createKonsoleTriple "Color7" "${COLOR_08}" "${COLOR_16}" >> "${KCOLORSCHEME}"
+ createKonsoleTriple "Foreground" "${FOREGROUND_COLOR}" "${FOREGROUND_COLOR}" >> "${KCOLORSCHEME}"
+ echo "[General]" >> "${KCOLORSCHEME}"
+ echo "Blur=false" >> "${KCOLORSCHEME}"
+ echo "ColorRandomization=false" >> "${KCOLORSCHEME}"
+ echo "Description=${PROFILE_NAME}" >> "${KCOLORSCHEME}"
+ echo "Opacity=1" >> "${KCOLORSCHEME}"
+ echo "Wallpaper=" >> "${KCOLORSCHEME}"
+}
+
+apply_darwin() {
+ # |
+ # | Applying values on iTerm2
+ # | ===========================================
+
+ BACKGROUND_COLOR=$(convertNameAndRGBtoITerm "Background Color" "$BACKGROUND_COLOR")
+ FOREGROUND_COLOR=$(convertNameAndRGBtoITerm "Foreground Color" "$FOREGROUND_COLOR")
+ COLOR_01=$(convertNameAndRGBtoITerm "Ansi 0 Color" "$COLOR_01")
+ COLOR_02=$(convertNameAndRGBtoITerm "Ansi 1 Color" "$COLOR_02")
+ COLOR_03=$(convertNameAndRGBtoITerm "Ansi 2 Color" "$COLOR_03")
+ COLOR_04=$(convertNameAndRGBtoITerm "Ansi 3 Color" "$COLOR_04")
+ COLOR_05=$(convertNameAndRGBtoITerm "Ansi 4 Color" "$COLOR_05")
+ COLOR_06=$(convertNameAndRGBtoITerm "Ansi 5 Color" "$COLOR_06")
+ COLOR_07=$(convertNameAndRGBtoITerm "Ansi 6 Color" "$COLOR_07")
+ COLOR_08=$(convertNameAndRGBtoITerm "Ansi 7 Color" "$COLOR_08")
+ COLOR_09=$(convertNameAndRGBtoITerm "Ansi 8 Color" "$COLOR_09")
+ COLOR_10=$(convertNameAndRGBtoITerm "Ansi 9 Color" "$COLOR_10")
+ COLOR_11=$(convertNameAndRGBtoITerm "Ansi 10 Color" "$COLOR_11")
+ COLOR_12=$(convertNameAndRGBtoITerm "Ansi 11 Color" "$COLOR_12")
+ COLOR_13=$(convertNameAndRGBtoITerm "Ansi 12 Color" "$COLOR_13")
+ COLOR_14=$(convertNameAndRGBtoITerm "Ansi 13 Color" "$COLOR_14")
+ COLOR_15=$(convertNameAndRGBtoITerm "Ansi 14 Color" "$COLOR_15")
+ COLOR_16=$(convertNameAndRGBtoITerm "Ansi 15 Color" "$COLOR_16")
+
+ # Assemble color scheme file contents
+ ITERMCOLORS=''${BACKGROUND_COLOR}${FOREGROUND_COLOR}${COLOR_01}${COLOR_02}${COLOR_03}${COLOR_04}${COLOR_05}${COLOR_06}${COLOR_07}${COLOR_08}${COLOR_09}${COLOR_10}${COLOR_11}${COLOR_12}${COLOR_13}${COLOR_14}${COLOR_15}''
+
+ # Dump iTerm color scheme to file and import it by opening it
+ echo "${ITERMCOLORS}" > "${PROFILE_NAME}.itermcolors"
+ open "${PROFILE_NAME}.itermcolors"
+ rm "${PROFILE_NAME}.itermcolors"
+}
+
+apply_gtk() {
+ # |
+ # | Applying values to gnome/mate/tilix
+ # | ===========================================
+
+ local legacy="${1:-}"
+
+ # This is to avoid doing the profile loop definition twice
+ if [[ -z "${legacy}" ]]; then
+ CONFTOOL="${DCONF} read"
+ VISIBLE_NAME="visible-name"
+ else
+ CONFTOOL="${GCONF} --get"
+ VISIBLE_NAME="visible_name"
+ fi
+
+ # Check first wether profile already exists
+ profile_hashes=($(${CONFTOOL} "${PROFILE_LIST_KEY}" | tr "[]'," " "))
+ for profile in "${profile_hashes[@]}"; do
+ if [[ "$(${CONFTOOL} "${BASE_DIR}${profile}/${VISIBLE_NAME}" | tr -d "'")" == "${PROFILE_NAME}" ]]; then
+ printf '%s\n' "Profile already exists" "Skipping..."
+ exit 0
+ fi
+ done
+
+ # Fallback if there is no default profile
+ set -- $(${CONFTOOL} ${PROFILE_LIST_KEY} | tr "[]'," " ")
+ : ${DEFAULT_SLUG:="$1"}
+
+ : ${PROFILE_NAME:="Default"}
+ : ${PROFILE_SLUG:="Default"}
+
+ DEFAULT_KEY="${BASE_DIR}${DEFAULT_SLUG:-}"
+ PROFILE_KEY="${BASE_DIR}${PROFILE_SLUG:-}"
+
+ if [[ -z "${legacy}" ]]; then
+ if [[ -z "$(${DCONF} list ${BASE_DIR%:})" ]]; then
+ # Provide a user friendly error text if no saved profile exists, otherwise it will display "Error gconftool not found!"
+ # it could happen on a newly installed system. (happened on CentOS 7)
+ printf '%s\n' \
+ "Error, no saved profiles found!" \
+ "Possible fix, new a profile (Terminal > Edit > Preferences > Profiles > New, then Close) and try again." \
+ "You can safely delete the created profile after the installation."
+ exit 1
+ fi
+
+ BACKGROUND_COLOR=$(gnome_color "$BACKGROUND_COLOR")
+ FOREGROUND_COLOR=$(gnome_color "$FOREGROUND_COLOR")
+ CURSOR_COLOR=$(gnome_color "$CURSOR_COLOR")
+ HIGHLIGHT_BG_COLOR=$(gnome_color "$HIGHLIGHT_BG_COLOR")
+ HIGHLIGHT_FG_COLOR=$(gnome_color "$HIGHLIGHT_FG_COLOR")
+ COLOR_01=$(gnome_color "$COLOR_01")
+ COLOR_02=$(gnome_color "$COLOR_02")
+ COLOR_03=$(gnome_color "$COLOR_03")
+ COLOR_04=$(gnome_color "$COLOR_04")
+ COLOR_05=$(gnome_color "$COLOR_05")
+ COLOR_06=$(gnome_color "$COLOR_06")
+ COLOR_07=$(gnome_color "$COLOR_07")
+ COLOR_08=$(gnome_color "$COLOR_08")
+ COLOR_09=$(gnome_color "$COLOR_09")
+ COLOR_10=$(gnome_color "$COLOR_10")
+ COLOR_11=$(gnome_color "$COLOR_11")
+ COLOR_12=$(gnome_color "$COLOR_12")
+ COLOR_13=$(gnome_color "$COLOR_13")
+ COLOR_14=$(gnome_color "$COLOR_14")
+ COLOR_15=$(gnome_color "$COLOR_15")
+ COLOR_16=$(gnome_color "$COLOR_16")
+
+ # copy existing settings from default profile
+ $DCONF dump "${DEFAULT_KEY}/" | $DCONF load "${PROFILE_KEY}/"
+
+ # add new copy to global list of profiles
+ dlist_append "${PROFILE_LIST_KEY}" "${PROFILE_SLUG#:}"
+
+ set_theme
+ dset palette "${LEFT_WRAPPER:-}'${COLOR_01}${PALETTE_DELIM}${COLOR_02}${PALETTE_DELIM}${COLOR_03}${PALETTE_DELIM}${COLOR_04}${PALETTE_DELIM}${COLOR_05}${PALETTE_DELIM}${COLOR_06}${PALETTE_DELIM}${COLOR_07}${PALETTE_DELIM}${COLOR_08}${PALETTE_DELIM}${COLOR_09}${PALETTE_DELIM}${COLOR_10}${PALETTE_DELIM}${COLOR_11}${PALETTE_DELIM}${COLOR_12}${PALETTE_DELIM}${COLOR_13}${PALETTE_DELIM}${COLOR_14}${PALETTE_DELIM}${COLOR_15}${PALETTE_DELIM}${COLOR_16}'${RIGHT_WRAPPER:-}"
+ ${LEGACY_BOLD:-} && dset allow-bold "true" # mate
+ else
+ # Append the Base16 profile to the profile list
+ glist_append string "${PROFILE_LIST_KEY}" "${PROFILE_SLUG}"
+
+ legacy_set_theme
+ gcset string palette "${COLOR_01}:${COLOR_02}:${COLOR_03}:${COLOR_04}:${COLOR_05}:${COLOR_06}:${COLOR_07}:${COLOR_08}:${COLOR_09}:${COLOR_10}:${COLOR_11}:${COLOR_12}:${COLOR_13}:${COLOR_14}:${COLOR_15}:${COLOR_16}"
+ ${LEGACY_BOLD:-} && gcset bool allow-bold "true"
+ fi
+}
+
+apply_guake() {
+ # |
+ # | Applying values to guake
+ # | ===========================================
+
+ local legacy="${1:-}"
+ PROFILE_KEY="/apps/guake/style/font"
+
+ if [[ -z "${legacy}" ]]; then
+ dset palette "'${COLOR_01}:${COLOR_02}:${COLOR_03}:${COLOR_04}:${COLOR_05}:${COLOR_06}:${COLOR_07}:${COLOR_08}:${COLOR_09}:${COLOR_10}:${COLOR_11}:${COLOR_12}:${COLOR_13}:${COLOR_14}:${COLOR_15}:${COLOR_16}:${FOREGROUND_COLOR}:${BACKGROUND_COLOR}'"
+ dset palette-name "'${PROFILE_NAME}'"
+ dset allow-bold 'true'
+ else
+ gcset string color "${FOREGROUND_COLOR}"
+ gcset string palette "${COLOR_01}:${COLOR_02}:${COLOR_03}:${COLOR_04}:${COLOR_05}:${COLOR_06}:${COLOR_07}:${COLOR_08}:${COLOR_09}:${COLOR_10}:${COLOR_11}:${COLOR_12}:${COLOR_13}:${COLOR_14}:${COLOR_15}:${COLOR_16}"
+ gcset string palette-name "${PROFILE_NAME}"
+ PROFILE_KEY="/apps/guake/style/background"
+ gcset string color "${BACKGROUND_COLOR}"
+
+ fi
+}
+
+appy_tilixschemes() {
+ # |
+ # | Applying values to tilix colorschemes
+ # | ===========================================
+
+ if [[ ${TILIX_RES::1} =~ ^(y|Y)$ ]]; then
+ [[ -d "${HOME}/.config/tilix/schemes" ]] || mkdir -p "${HOME}/.config/tilix/schemes"
+
+ TILIXCOLORS='{\n\t"name": "'${PROFILE_NAME}'",\n\t"comment": "Generated by Gogh",\n\t"foreground-color": "'${FOREGROUND_COLOR}'",\n\t"background-color":"'${BACKGROUND_COLOR}'",\n\t"cursor-background-color": "'${CURSOR_COLOR}'",\n\t"palette": [\n\t\t"'${COLOR_01}'",\n\t\t"'${COLOR_02}'",\n\t\t"'${COLOR_03}'",\n\t\t"'${COLOR_04}'",\n\t\t"'${COLOR_05}'",\n\t\t"'${COLOR_06}'",\n\t\t"'${COLOR_07}'",\n\t\t"'${COLOR_08}'",\n\t\t"'${COLOR_09}'",\n\t\t"'${COLOR_10}'",\n\t\t"'${COLOR_11}'",\n\t\t"'${COLOR_12}'",\n\t\t"'${COLOR_13}'",\n\t\t"'${COLOR_14}'",\n\t\t"'${COLOR_15}'",\n\t\t"'${COLOR_16}'"\n\t],\n\t"use-badge-color": false,\n\t"use-bold-color": false,\n\t"use-cursor-color": false,\n\t"use-highlight-color": false,\n\t"use-theme-colors": false\n}'
+ echo -e "${TILIXCOLORS}" > "${scratchdir}/${PROFILE_NAME}.json"
+
+ # Note: Tilix does not store color scheme name in dconf
+ # so we have to update color palette for the current profile in order to switch to the new theme
+ # but only set the palette on the last loop to avoid a flashing terminal
+ if ((LOOP == OPTLENGTH)); then
+ cp -f ${scratchdir}/* "$HOME/.config/tilix/schemes/"
+ rm -rf "${scratchdir}"
+ read -r -p "All done - apply new theme? [y/N] " -n 1 TILIX_RES
+ if [[ ${TILIX_RES::1} =~ ^(y|Y)$ ]]; then
+ PROFILE_KEY="${BASE_DIR}${DEFAULT_SLUG}"
+ PROFILE_NAME="$(${DCONF} read ${PROFILE_KEY}/visible-name | tr -d \')"
+ set_theme
+ dset palette "['${COLOR_01}', '${COLOR_02}', '${COLOR_03}', '${COLOR_04}', '${COLOR_05}', '${COLOR_06}', '${COLOR_07}', '${COLOR_08}', '${COLOR_09}', '${COLOR_10}', '${COLOR_11}', '${COLOR_12}', '${COLOR_13}', '${COLOR_14}', '${COLOR_15}', '${COLOR_16}']"
+ fi
+ fi
+
+ unset PROFILE_NAME
+ unset PROFILE_SLUG
+ unset TILIXCOLORS
+ exit 0
+ fi
+}
+
+apply_xfce4-terminal() {
+ # XFCE4 terminal has no profiles, instead it uses color presets
+ SCHEMEDIR="${HOME}/.local/share/xfce4/terminal/colorschemes"
+ CONFFILE="${HOME}/.config/xfce4/terminal/terminalrc"
+
+ if [[ ! (-w "${CONFFILE}") ]]; then
+ if [[ -r "${XDG_CONFIG_DIRS%%:*}/Terminal/terminalrc" ]]; then
+ cp "${XDG_CONFIG_DIRS%%:*}/Terminal/terminalrc" ${CONFFILE}
+ else
+ echo "ERROR: config file not present or not writable!"
+ exit 1
+ fi
+ fi
+
+ [[ -d "${SCHEMEDIR}" ]] || mkdir -p "${SCHEMEDIR}"
+
+ F_NAME=${PROFILE_NAME// /-}
+ F_NAME=$(echo ${F_NAME} | tr -d ":()")
+ F_NAME=$(echo "${F_NAME}" | awk '{print tolower($0)}')
+
+ FF_NAME="${SCHEMEDIR}/${F_NAME}.theme"
+
+ touch "${FF_NAME}"
+
+ L_COLORCURSOR="ColorCursor=${CURSOR_COLOR}"
+ L_COLORPALETTE="ColorPalette=${COLOR_01};${COLOR_02};${COLOR_03};${COLOR_04};${COLOR_05};${COLOR_06};${COLOR_07};${COLOR_08};${COLOR_09};${COLOR_10};${COLOR_11};${COLOR_12};${COLOR_13};${COLOR_14};${COLOR_15};${COLOR_16}"
+
+ printf '%s\n' \
+ "; Generated by Gogh" \
+ "; https://Gogh-Co.github.io/Gogh" \
+ "[Scheme]" \
+ "Name=${PROFILE_NAME}" \
+ "ColorForeground=${FOREGROUND_COLOR}" \
+ "ColorBackground=${BACKGROUND_COLOR}" \
+ "${L_COLORCURSOR}" \
+ "${L_COLORPALETTE}" \
+ "ColorCursorUseDefault=FALSE" > ${FF_NAME}
+
+ # apply last theme in queue
+ # xfce4-terminal monitors its rc file and doesn't reference
+ # any of the themes in there. The color settings need to
+ # be written there directly.
+ if ((LOOP == OPTLENGTH)); then
+ read -r -p "All done - apply new theme? [y/N] " -n 1 XFCE4_APPLY_CURR_THEME
+ if [[ ${XFCE4_APPLY_CURR_THEME::1} =~ ^(y|Y)$ ]]; then
+ if grep -q "^ColorPalette=" "${CONFFILE}"; then
+ sed -i -r -e "s/^ColorPalette=.*/${L_COLORPALETTE}/" "${CONFFILE}"
+ else
+ echo "${L_COLORPALETTE}" >> "${CONFFILE}"
+ fi
+
+ if grep -q "^ColorCursor=" "${CONFFILE}"; then
+ sed -i -r -e "s/^ColorCursor=.*/${L_COLORCURSOR}/" "${CONFFILE}"
+ else
+ echo "${L_COLORCURSOR}" >> "${CONFFILE}"
+ fi
+
+ if grep -q "^ColorForeground=" "${CONFFILE}"; then
+ sed -i -r -e "s/^ColorForeground=.*/ColorForeground=${FOREGROUND_COLOR}/" "${CONFFILE}"
+ else
+ echo "ColorForeground=${FOREGROUND_COLOR}" >> "${CONFFILE}"
+ fi
+
+ if grep -q "^ColorBackground=" "${CONFFILE}"; then
+ sed -i -r -e "s/^ColorBackground=.*/ColorBackground=${BACKGROUND_COLOR}/" "${CONFFILE}"
+ else
+ echo "ColorBackground=${BACKGROUND_COLOR}" >> "${CONFFILE}"
+ fi
+
+ if grep -q "^ColorCursorUseDefault=FALSE" "${CONFFILE}"; then
+ true
+ else
+ echo "ColorCursorUseDefault=FALSE" >> "${CONFFILE}"
+ fi
+ fi
+ fi
+
+ unset SCHEMEDIR
+ unset CONFFILE
+ unset PROFILE_NAME
+ unset F_NAME
+ unset FF_NAME
+ unset L_COLORCURSOR
+ unset L_COLORPALETTE
+ exit 0
+}
+
+[[ -n "${UUIDGEN}" ]] && PROFILE_SLUG="$(uuidgen)"
+
+case "${TERMINAL}" in
+ pantheon-terminal|io.elementary.t* )
+ if [[ "${TERMINAL}" == "pantheon-terminal" ]]; then
+ PROFILE_KEY="org.pantheon.terminal.settings"
+ else
+ PROFILE_KEY="io.elementary.terminal.settings"
+ fi
+ apply_elementary
+ ;;
+
+ iTerm.app )
+ apply_darwin
+ ;;
+
+ mintty )
+ apply_cygwin
+ ;;
+
+ guake )
+ if [[ -n "$(${DCONF} list /apps/guake/style/)" ]]; then
+ apply_guake
+ else
+ apply_guake legacy
+ fi
+ ;;
+
+ gnome-terminal* )
+ if [[ -n "$(${DCONF} list /org/gnome/terminal/)" ]]; then
+ BASE_DIR="/org/gnome/terminal/legacy/profiles:/:"
+ PROFILE_LIST_KEY="${BASE_DIR%:}list"
+ PROFILE_SLUG="${PROFILE_SLUG}"
+
+ # Note -- ${BASE_DIR%s} is a workaround to avoid doing additional conditional testing for existing profiles
+ # if terminal is set to gnome-terminal
+ : ${DEFAULT_SLUG:="$(${DCONF} read ${BASE_DIR%:}default | tr -d \')"}
+
+ LEFT_WRAPPER="["
+ RIGHT_WRAPPER="]"
+ PALETTE_DELIM="', '"
+
+ apply_gtk
+ else
+ BASE_DIR="/apps/gnome-terminal/profiles/"
+ PROFILE_LIST_KEY="${BASE_DIR/profiles/global}profile_list"
+ LEGACY_BOLD=true
+
+ : ${DEFAULT_SLUG:="$(${GCONF} read ${BASE_DIR}default_profile)"}
+
+ apply_gtk legacy
+ fi
+ ;;
+
+ mate-terminal )
+ BASE_DIR="/org/mate/terminal/profiles/"
+ PROFILE_LIST_KEY="${BASE_DIR/profiles/global}profile-list"
+ LEGACY_BOLD=true
+
+ : ${DEFAULT_SLUG:="$(${DCONF} read ${BASE_DIR/profiles/global}default-profile | tr -d \')"}
+
+ PALETTE_DELIM=":"
+
+ apply_gtk
+ ;;
+
+ tilix )
+ BASE_DIR="/com/gexperts/Tilix/profiles/"
+ PROFILE_LIST_KEY="${BASE_DIR}list"
+
+ : ${DEFAULT_SLUG:="$(${DCONF} read ${BASE_DIR}default | tr -d \')"}
+
+ LEFT_WRAPPER="["
+ RIGHT_WRAPPER="]"
+ PALETTE_DELIM="', '"
+
+ appy_tilixschemes
+ apply_gtk
+ ;;
+
+ xfce4-terminal )
+ apply_xfce4-terminal
+ ;;
+
+ alacritty )
+ apply_alacritty
+ ;;
+
+ foot )
+ apply_foot
+ ;;
+
+ kitty )
+ apply_kitty
+ ;;
+
+ konsole )
+ apply_konsole
+ ;;
+
+ * )
+ printf '%s\n' \
+ "Unsupported terminal!" \
+ "" \
+ "Supported terminals:" \
+ " mintty and deriviates" \
+ " guake" \
+ " iTerm2" \
+ " elementary terminal (pantheon/elementary)" \
+ " mate-terminal" \
+ " gnome-terminal" \
+ " tilix" \
+ " xfce4-terminal" \
+ " foot" \
+ " kitty" \
+ " konsole" \
+ "" \
+ "If you believe you have received this message in error," \
+ "try manually setting \`TERMINAL', hint: ps -h -o comm -p \$PPID"
+ exit 1
+ ;;
+
+esac
+
+unset PROFILE_NAME
+unset PROFILE_SLUG
+unset DEFAULT_SLUG
diff --git a/dotfiles/.local/share/chezmoi/dot_local/bin/executable_ksetwallpaper b/dotfiles/.local/share/chezmoi/dot_local/bin/executable_ksetwallpaper
new file mode 100644
index 00000000..c52d8e66
--- /dev/null
+++ b/dotfiles/.local/share/chezmoi/dot_local/bin/executable_ksetwallpaper
@@ -0,0 +1,107 @@
+#!/usr/bin/env python3
+import time
+import dbus
+import argparse
+import glob
+import random
+import os
+import subprocess
+from pathlib import Path
+HOME = str(Path.home())
+SCREEN_LOCK_CONFIG = HOME+"/.config/kscreenlockerrc"
+def setwallpaper(filepath, plugin='org.kde.image'):
+ jscript = """
+ var allDesktops = desktops();
+ print (allDesktops);
+ for (i=0;i 0:
+ wallpaper_count = len(wallapapers)
+ delta_s = timer
+ s = int(delta_s % 60)
+ m = int((delta_s / 60) % 60)
+ h = int((delta_s / 3600) % 3600)
+ if h > 0:
+ timer_show = f"{h}h {m}m {s}s"
+ elif m > 0:
+ timer_show = f"{m}m {s}s"
+ elif s > 0:
+ timer_show = f"{s}s"
+ print(
+ f"Looping through {wallpaper_count} wallpapers every {timer_show}")
+ while True:
+ if is_locked() != True:
+ random_int = random.randint(0, wallpaper_count-1)
+ wallpaper_now = wallapapers[random_int]
+ setwallpaper(wallpaper_now, plugin)
+ if lock_screen == True:
+ set_lockscreen_wallpaper(wallpaper_now, plugin)
+ time.sleep(timer)
+ else:
+ raise ValueError('Invalid --timer value')
+
+
+if __name__ == '__main__':
+ parser = argparse.ArgumentParser(description='KDE Wallpaper setter')
+ parser.add_argument('--file','-f', help='Wallpaper file name', default=None)
+ parser.add_argument(
+ '--plugin', '-p', help='Wallpaper plugin (default is org.kde.image)', default='org.kde.image')
+ parser.add_argument('--dir', '-d', type=str,
+ help='Absolute path of folder containging your wallpapers for slideshow', default=None)
+ parser.add_argument('--timer', '-t', type=int,
+ help='Time in seconds between wallpapers', default=900)
+ parser.add_argument('--lock-screen', '-l', action="store_true",
+ help="Set lock screen wallpaper")
+ args = parser.parse_args()
+
+ if args.file != None:
+ setwallpaper(filepath=args.file, plugin=args.plugin)
+ if args.lock_screen == True:
+ set_lockscreen_wallpaper(filepath=args.file, plugin=args.plugin)
+
+ elif args.dir != None:
+ wallpapers = get_walls_from_folder(args.dir)
+
+ wallpaper_slideshow(wallapapers=wallpapers,
+ plugin=args.plugin, timer=args.timer,lock_screen=args.lock_screen)
+ else:
+ print("Need help? use -h or --help")
diff --git a/dotfiles/.local/share/chezmoi/dot_local/bin/executable_logg b/dotfiles/.local/share/chezmoi/dot_local/bin/executable_logg
new file mode 100644
index 00000000..37566fbd
--- /dev/null
+++ b/dotfiles/.local/share/chezmoi/dot_local/bin/executable_logg
@@ -0,0 +1,393 @@
+#!/usr/bin/env bash
+
+# @file .config/log
+# @brief Logger / prompt library that logs pretty console messages and provides several prompt methods
+# @description
+# This file contains several functions that log content in different formats. It also provides an
+# interface for [Gum](https://github.com/charmbracelet/gum) based prompts. The available methods include:
+#
+# * `choose` - Prompt user with choices
+# * `confirm` - Fancy Yes/No confirmation prompt
+# * `error` - Logs an error message
+# * `filter` - Filterable list of choices (with choices passed in as a line-return seperated file)
+# * `info` - Logs a regular message
+# * `input` - Prompt for a text input
+# * `md` - Render a markdown file with [Glow](https://github.com/charmbracelet/glow)
+# * `password` - Prompt for text that is masked by the prompt
+# * `prompt` - Log a description for a prompt that follows
+# * `spin` - Show a spinner while background job completes
+# * `star` - Logs a message with a star icon at the beginning
+# * `start` - Log a job start message
+# * `success` - Logs a success message
+# * `warn` - Logs a warning message
+# * `write` - Multi-line input prompt
+#
+# If the `docker` environment variable is not set, the script / library will ensure both Gum and Glow are installed.
+
+# @description Installs glow (a markdown renderer) from GitHub releases
+# @example installGlow
+installGlow() {
+ # TODO: Add support for other architecture types
+ if [ -d '/Applications' ] && [ -d '/Library' ] && [ -d '/Users' ]; then
+ GLOW_DOWNLOAD_URL="https://github.com/charmbracelet/glow/releases/download/v1.4.1/glow_1.4.1_Darwin_x86_64.tar.gz"
+ elif [ -f '/etc/ubuntu-release' ] || [ -f '/etc/debian_version' ] || [ -f '/etc/redhat-release' ] || [ -f '/etc/SuSE-release' ] || [ -f '/etc/arch-release' ] || [ -f '/etc/alpine-release' ]; then
+ GLOW_DOWNLOAD_URL="https://github.com/charmbracelet/glow/releases/download/v1.4.1/glow_1.4.1_linux_x86_64.tar.gz"
+ fi
+ if type curl &> /dev/null; then
+ if { [ -d '/Applications' ] && [ -d '/Library' ] && [ -d '/Users' ]; } || [ -f '/etc/ubuntu-release' ] || [ -f '/etc/debian_version' ] || [ -f '/etc/redhat-release' ] || [ -f '/etc/SuSE-release' ] || [ -f '/etc/arch-release' ] || [ -f '/etc/alpine-release' ]; then
+ TMP="$(mktemp)"
+ TMP_DIR="$(dirname "$TMP")"
+ curl -sSL "$GLOW_DOWNLOAD_URL" > "$TMP"
+ tar -xzf "$TMP" -C "$TMP_DIR"
+ if [ -n "$HOME" ]; then
+ if mkdir -p "$HOME/.local/bin" && mv "$TMP_DIR/glow" "$HOME/.local/bin/glow"; then
+ GLOW_PATH="$HOME/.local/bin/glow"
+ else
+ GLOW_PATH="$(dirname "${BASH_SOURCE[0]}")/glow"
+ mv "$TMP_DIR/gum" "$GLOW_PATH"
+ fi
+ chmod +x "$GLOW_PATH"
+ else
+ echo "WARNING: The HOME environment variable is not set! (Glow)"
+ fi
+ else
+ echo "WARNING: Unable to detect system type. (Glow)"
+ fi
+ fi
+}
+
+# @description Installs gum (a logging CLI) from GitHub releases
+# @example installGum
+installGum() {
+ # TODO: Add support for other architecture types
+ if [ -d '/Applications' ] && [ -d '/Library' ] && [ -d '/Users' ]; then
+ GUM_DOWNLOAD_URL="https://github.com/charmbracelet/gum/releases/download/v0.4.0/gum_0.4.0_Darwin_x86_64.tar.gz"
+ elif [ -f '/etc/ubuntu-release' ] || [ -f '/etc/debian_version' ] || [ -f '/etc/redhat-release' ] || [ -f '/etc/SuSE-release' ] || [ -f '/etc/arch-release' ] || [ -f '/etc/alpine-release' ]; then
+ GUM_DOWNLOAD_URL="https://github.com/charmbracelet/gum/releases/download/v0.4.0/gum_0.4.0_linux_x86_64.tar.gz"
+ fi
+ if type curl &> /dev/null; then
+ if { [ -d '/Applications' ] && [ -d '/Library' ] && [ -d '/Users' ]; } || [ -f '/etc/ubuntu-release' ] || [ -f '/etc/debian_version' ] || [ -f '/etc/redhat-release' ] || [ -f '/etc/SuSE-release' ] || [ -f '/etc/arch-release' ] || [ -f '/etc/alpine-release' ]; then
+ TMP="$(mktemp)"
+ TMP_DIR="$(dirname "$TMP")"
+ curl -sSL "$GUM_DOWNLOAD_URL" > "$TMP"
+ tar -xzf "$TMP" -C "$TMP_DIR"
+ if [ -n "$HOME" ]; then
+ if mkdir -p "$HOME/.local/bin" && mv "$TMP_DIR/gum" "$HOME/.local/bin/gum"; then
+ GUM_PATH="$HOME/.local/bin/gum"
+ else
+ GUM_PATH="$(dirname "${BASH_SOURCE[0]}")/gum"
+ mv "$TMP_DIR/gum" "$GLOW_PATH"
+ fi
+ chmod +x "$GUM_PATH"
+ else
+ echo "WARNING: The HOME environment variable is not set! (Gum)"
+ fi
+ else
+ echo "WARNING: Unable to detect system type. (Gum)"
+ fi
+ fi
+}
+
+# @description Configure the logger to use echo or gum
+if [ "${container:=}" != 'docker' ]; then
+ # Acquire gum's path or attempt to install it
+ if type gum &> /dev/null; then
+ GUM_PATH="$(which gum)"
+ elif [ -f "$HOME/.local/bin/gum" ]; then
+ GUM_PATH="$HOME/.local/bin/gum"
+ elif [ -f "$(dirname "${BASH_SOURCE[0]}")/gum" ]; then
+ GUM_PATH="$(dirname "${BASH_SOURCE[0]}")/gum"
+ elif type brew &> /dev/null; then
+ brew install gum
+ GUM_PATH="$(which gum)"
+ else
+ installGum
+ fi
+
+ # If gum's path was set, then turn on enhanced logging
+ if [ -n "$GUM_PATH" ]; then
+ chmod +x "$GUM_PATH"
+ ENHANCED_LOGGING=true
+ fi
+fi
+
+# @description Disable logging for Semantic Release because it tries to parse it as JSON
+if [ -n "$SEMANTIC_RELEASE" ]; then
+ NO_LOGGING=true
+fi
+
+# @description Logs using Node.js
+# @example logger info "An informative log"
+logger() {
+ if [ "$1" == 'error' ]; then
+ "$GUM_PATH" style --border="thick" "$("$GUM_PATH" style --foreground="#ff0000" "✖") $("$GUM_PATH" style --bold --background="#ff0000" --foreground="#ffffff" " ERROR ") $("$GUM_PATH" style --bold "$(format "$2")")"
+ elif [ "$1" == 'info' ]; then
+ "$GUM_PATH" style " $("$GUM_PATH" style --foreground="#00ffff" "○") $2"
+ elif [ "$1" == 'md' ]; then
+ # @description Ensure glow is installed
+ if [ "${container:=}" != 'docker' ]; then
+ if type glow &> /dev/null; then
+ GLOW_PATH="$(which glow)"
+ elif [ -f "$HOME/.local/bin/glow" ]; then
+ GLOW_PATH="$HOME/.local/bin/glow"
+ elif [ -f "$(dirname "${BASH_SOURCE[0]}")/glow" ]; then
+ GLOW_PATH="$(dirname "${BASH_SOURCE[0]}")/glow"
+ elif type brew &> /dev/null; then
+ brew install glow
+ GLOW_PATH="$(which glow)"
+ else
+ installGlow
+ fi
+
+ if [ -n "$GLOW_PATH" ]; then
+ chmod +x "$GLOW_PATH"
+ ENHANCED_LOGGING=true
+ fi
+ fi
+ "$GLOW_PATH" "$2"
+ elif [ "$1" == 'prompt' ]; then
+ "$GUM_PATH" style " $("$GUM_PATH" style --foreground="#00008b" "▶") $("$GUM_PATH" style --bold "$(format "$2")")"
+ elif [ "$1" == 'star' ]; then
+ "$GUM_PATH" style " $("$GUM_PATH" style --foreground="#d1d100" "◆") $("$GUM_PATH" style --bold --underline "$(format "$2")")"
+ elif [ "$1" == 'start' ]; then
+ "$GUM_PATH" style " $("$GUM_PATH" style --foreground="#00ff00" "▶") $("$GUM_PATH" style --bold "$(format "$2")")"
+ elif [ "$1" == 'success' ]; then
+ "$GUM_PATH" style "$("$GUM_PATH" style --foreground="#00ff00" "✔") $("$GUM_PATH" style --bold "$(format "$2")")"
+ elif [ "$1" == 'warn' ]; then
+ "$GUM_PATH" style " $("$GUM_PATH" style --foreground="#d1d100" "◆") $("$GUM_PATH" style --bold --background="#ffff00" --foreground="#000000" " WARNING ") $("$GUM_PATH" style --bold --italic "$(format "$2")")"
+ else
+ echo "WARNING: Unknown log type"
+ echo "$2"
+ fi
+}
+
+format() {
+ # shellcheck disable=SC2001,SC2016
+ ANSI_STR="$(echo "$1" | sed 's/^\([^`]*\)`\([^`]*\)`/\1\\u001b[47;1;30m \2 \\e[0;39m/')"
+ if [[ $ANSI_STR == *'`'*'`'* ]]; then
+ ANSI_STR="$(format "$ANSI_STR")"
+ fi
+ echo -e "$ANSI_STR"
+}
+
+# @description Display prompt that allows you to choose between options
+# @example RESPONSE="$(.config/log choose "file.png" "another-file.jpg")"
+choose() {
+ if type gum &> /dev/null; then
+ CHOOSE_ARGS="gum choose"
+ for CURRENT_VAR in "$@"; do
+ CHOOSE_ARGS="$CHOOSE_ARGS \"$CURRENT_VAR\""
+ done
+ eval $CHOOSE_ARGS
+ else
+ echo "ERROR: gum is not installed!"
+ fi
+}
+
+# @description Display a confirmation prompt that returns an exit code if "No" is selected
+# @example RESPONSE="$(.config/log confirm "Are you sure?" "Yeah" "Naa")"
+confirm() {
+ if type gum &> /dev/null; then
+ GUM_OPTS=""
+ if [ -n "$2" ]; then
+ # shellcheck disable=SC089
+ GUM_OPTS="$GUM_OPTS --affirmative=""'$2'"
+ fi
+ if [ -n "$3" ]; then
+ GUM_OPTS="$GUM_OPTS --negative=""'$3'"
+ fi
+ if [ -n "$1" ]; then
+ if [ -n "$GUM_OPTS" ]; then
+ gum confirm "$1" "$GUM_OPTS"
+ else
+ gum confirm "$1"
+ fi
+ else
+ gum confirm
+ fi
+ else
+ echo "ERROR: gum is not installed!"
+ fi
+}
+
+# @description Logs an error message
+# @example .config/log error "Something happened!"
+error() {
+ if [ -z "$NO_LOGGING" ]; then
+ if [ -n "$ENHANCED_LOGGING" ]; then
+ logger error "$1"
+ else
+ echo -e "\e[1;41m ERROR \e[0m $(format "$1")\e[0;39m"
+ fi
+ fi
+}
+
+# @description Display a filterable prompt that is populated with options from a text file
+# @example echo Strawberry >> flavors.text && echo Banana >> flavors.text && RESPONSE="$(.config/log filter flavors.txt)"
+filter() {
+ if type gum &> /dev/null; then
+ TMP="$(mktemp)"
+ gum filter < "$1"
+ else
+ echo "ERROR: gum is not installed!"
+ fi
+}
+
+# @description Logs an info message
+# @example .config/log info "Here is some information"
+info() {
+ if [ -z "$NO_LOGGING" ]; then
+ if [ -n "$ENHANCED_LOGGING" ]; then
+ logger info "$1"
+ else
+ echo -e "\e[1;46m INFO \e[0m $(format "$1")\e[0;39m"
+ fi
+ fi
+}
+
+# @description Displays an input with masked characters
+# @example INPUT="$(.config/log input 'Enter the value..')"
+input() {
+ if type gum &> /dev/null; then
+ if [ -n "$1" ]; then
+ gum input --placeholder="$1"
+ else
+ gum input
+ fi
+ else
+ echo "ERROR: gum is not installed!"
+ fi
+}
+
+# @description Logs a message written in markdown
+# @example .config/log md "[styled_link](https://google.com)"
+# @example .config/log md mymarkdown/file.md
+md() {
+ if [ ! -f "$1" ]; then
+ echo "ERROR: A markdown file must be passed in as the parameter" && exit 1
+ fi
+ if [ -n "$ENHANCED_LOGGING" ]; then
+ logger md "$1"
+ fi
+}
+
+# @description Displays an input with masked characters
+# @example PASSWORD="$(.config/log password 'Enter the Ansible vault password')"
+password() {
+ if type gum &> /dev/null; then
+ if [ -n "$1" ]; then
+ gum input --password --placeholder="$1"
+ else
+ gum input --password
+ fi
+ else
+ echo "ERROR: gum is not installed!"
+ fi
+}
+
+# @description Logs a message that describes a prompt
+# @example .config/log prompt "Enter text into the following prompt"
+prompt() {
+ if [ -z "$NO_LOGGING" ]; then
+ if [ -n "$ENHANCED_LOGGING" ]; then
+ logger prompt "$1"
+ else
+ echo -e "\e[1;104m PROMPT \e[0m $(format "$1")\e[0;39m"
+ fi
+ fi
+}
+
+# @description Display a spinner that stays until a command is completed
+# @example .config/log spin "brew install yq" "Installing yq..")"
+spin() {
+ if type gum &> /dev/null; then
+ if [ -n "$1" ] && [ -n "$2" ]; then
+ gum spin --title="$2" "$1"
+ elif [ -n "$1" ]; then
+ gum spin "$1"
+ else
+ gum input
+ fi
+ else
+ echo "ERROR: gum is not installed!"
+ fi
+}
+
+# @description Logs a message that starts with a star emoji
+# @example .config/log star "Congratulations"
+star() {
+ if [ -z "$NO_LOGGING" ]; then
+ if [ -n "$ENHANCED_LOGGING" ]; then
+ logger star "$1"
+ else
+ echo -e "\e[1;104m LINK \e[0m $(format "$1")\e[0;39m"
+ fi
+ fi
+}
+
+# @description Logs a message at the beginning of a task
+# @example .config/log start "Starting the process.."
+start() {
+ if [ -z "$NO_LOGGING" ]; then
+ if [ -n "$ENHANCED_LOGGING" ]; then
+ logger start "$1"
+ else
+ echo -e "\e[1;46m START \e[0m $(format "$1")\e[0;39m"
+ fi
+ fi
+}
+
+# @description Logs a success message
+# @example .config/log success "Yay!"
+success() {
+ if [ -z "$NO_LOGGING" ]; then
+ if [ -n "$ENHANCED_LOGGING" ]; then
+ logger success "$1"
+ else
+ echo -e "\e[1;42m SUCCESS \e[0m $(format "$1")\e[0;39m"
+ fi
+ fi
+}
+
+# @description Logs a warning message
+# @example .config/log warn "Just so you know.."
+warn() {
+ if [ -z "$NO_LOGGING" ]; then
+ if [ -n "$ENHANCED_LOGGING" ]; then
+ logger warn "$1"
+ else
+ echo -e "\e[1;43m WARNING \e[0m $(format "$1")\e[0;39m"
+ fi
+ fi
+}
+
+# @description Displays a multi-line prompt for text input
+# @example .config/log write "Write something..")"
+write() {
+ if type gum &> /dev/null; then
+ if [ -n "$1" ]; then
+ gum write --placeholder="$1"
+ else
+ gum write
+ fi
+ else
+ echo "ERROR: gum is not installed!"
+ fi
+}
+
+if [ -n "$1" ] && [ -n "$2" ]; then
+ # Public functions that require at least two parameters to be used
+ if [ "$1" == 'warn' ] || [ "$1" == 'success' ] || [ "$1" == 'star' ] || [ "$1" == 'info' ] \
+ || [ "$1" == 'error' ] || [ "$1" == 'md' ] || [ "$1" == 'write' ] || [ "$1" == 'start' ] \
+ || [ "$1" == 'spin' ] || [ "$1" == 'prompt' ] || [ "$1" == 'filter' ] || [ "$1" == 'input' ] \
+ || [ "$1" == 'confirm' ] || [ "$1" == 'password' ]; then
+ "$1" "$2"
+ elif [[ "$1" == 'choose' ]]; then
+ "$@"
+ fi
+elif [ -n "$1" ]; then
+ # Public functions that can run with only one argument passed to .config/log (i.e. `.config/log password`)
+ if [ "$1" == 'write' ] || [ "$1" == 'password' ] || [ "$1" == 'confirm' ] || [ "$1" == 'input' ]; then
+ "$1"
+ fi
+fi
diff --git a/dotfiles/.local/share/chezmoi/dot_local/bin/executable_opener b/dotfiles/.local/share/chezmoi/dot_local/bin/executable_opener
new file mode 100644
index 00000000..5e9f4203
--- /dev/null
+++ b/dotfiles/.local/share/chezmoi/dot_local/bin/executable_opener
@@ -0,0 +1,259 @@
+#!/usr/bin/env bash
+
+# @file /usr/bin/opener
+# @brief Opens a file type with the appropriate program based on the mime-type
+# @description
+# This script heavily borrows from [opener](https://github.com/Docbroke/shell_tools/blob/main/opener).
+# It makes some minor tweaks including linting fixes. It is configured
+# to properly work with [Gas Station](https://github.com/megabyte-labs/Gas-Station).
+# It is used to handle cross-VM links when Gas Station is used to provision [Qubes](https://www.qubes-os.org/).
+# When called with -d, the default program is used.
+
+# shellcheck disable=SC2124
+getopts d: name
+case $name in
+ d) file=$OPTARG
+ default=true ;;
+ *) file="$@" ;;
+esac
+
+[[ -z $file || ! -e $file ]] &&
+ exit 1
+
+## mimetype from perl-file-mimeinfo gives better results compared to file
+type mimetype &> /dev/null && mime_type="$(mimetype -b "$file")" || \
+ mime_type="$(file -b --mime-type "$file")"
+
+## create some lists
+XBROWSERS=("firefox" "chromium" "vimb" "qutebrowser" "weaver" "vivaldi")
+TBROWSERS=("w3m" "links" "lynx" "elinks")
+XEDITORS=("gvim" "geany" "leafpad" "mousepad")
+TEDITORS=("cat" "less" "vim" "vis" "nano" "micro")
+XFMS=("pcmanfm" "nautilus" "rof" "thunar")
+TFMS=("ncdu" "du -h" "vifm" "ranger" "mc" "fff" "nnn" "clifm")
+PDFVIEWERS=("llpp" "xournalpp" "mupdf" "qpdfview")
+DOCVIEWERS=("llpp" "foliate" "mupdf" "qpdfview")
+CHMVIEWERS=("kchmviewer" "xchm" "chmopen")
+BOOKVIEWERS=("$TERMINAL --geometry=1920x1050 -p Large -x epy.py" "foliate" "llpp" "mupdf")
+ARCHIVERS=("als" "lsar" "unar" "aunpack -D")
+VIEWERS=("feh" "sxiv" "gifview -a" "display" "mtpaint" "gimp" "viewnoir" "fbi" "lp")
+VPLAYERS=("mpv --player-operation-mode=pseudo-gui" "vlc" "cvlc" "ffplay" "ffprobe" "mediainfo")
+APLAYERS=("mpv --player-operation-mode=pseudo-gui" "vlc" "cvlc" "ffplay" "ffprobe" "mediainfo" "soxi" "mpg123")
+
+## some defaults
+if [[ -n "$DISPLAY" ]]; then
+ PLAYER="mpv --player-operation-mode=pseudo-gui"
+else
+ PLAYER="mpv --vo=drm"
+fi
+if [[ -n "$DISPLAY" ]]; then
+ VIEWER="sxiv -fbq $file $PWD"
+else
+ VIEWER=fbi
+fi
+TERMINAL=terminator
+EDITOR=vis
+BROWSER=weaver
+PDFVIEWER=llpp
+DOCVIEWER=llpp
+CHMVIEWER=kchmviewer
+BOOKVIEWER="$TERMINAL --geometry=1920x1050 -p Large -x epy.py"
+
+case "$mime_type" in
+ text/html|text/xml|application/x-mimearchive|message/rfc822)
+ if [[ $default == true ]]; then
+ $BROWSER "$file" && exit
+ elif [[ $TERM = linux && -n $DISPLAY ]]; then
+ select ops in exit "${XBROWSERS[@]}" "${TBROWSERS[@]}" $EDITOR; do
+ [[ $ops = exit ]] && exit
+ [[ $ops = w3m || $ops = links || $ops = elinks || $EDITOR ]] && $TERMINAL -x "$ops" "$file" &
+ "$ops" "$file" &> /dev/null &
+ done
+ elif [[ $TERM != linux && -n $DISPLAY ]]; then
+ select ops in exit "${XBROWSERS[@]}" "${TBROWSERS[@]}" $EDITOR; do
+ [[ $ops = exit ]] && exit
+ "$ops" "$file"
+ done
+ else
+ select ops in exit "${TBROWSERS[@]}" $EDITOR; do
+ [[ $ops = exit ]] && exit
+ "$ops" "$file"
+ done
+ fi
+ ;;
+
+ text/*|*/xml|application/x-httpd-php3|application/x-httpd-php4|application/x-httpd-php5|application/x-shellscript)
+ [[ $default == true ]] && \
+ if [[ $TERM = linux && -n $DISPLAY ]]; then
+ $TERMINAL -x "${VISUAL:-${EDITOR:-vis}}" "$file"
+ else
+ "${VISUAL:-${EDITOR:-vis}}" "$file"
+ fi && exit
+ select ops in exit "${XEDITORS[@]}" "${TEDITORS[@]}"; do
+ [[ $ops = exit ]] && exit
+ "$ops" "$file"
+ done
+ ;;
+
+ image/*)
+ [[ $default == true ]] && $VIEWER "$file" && exit
+ select ops in exit "${VIEWERS[@]}"; do
+ [[ $ops = exit ]] && break
+ $ops "$file" &> /dev/null &
+ done
+ ;;
+
+ video/*|application/x-matroska)
+ [[ $default == true ]] && $PLAYER "$file" && exit
+ if [[ -n $DISPLAY ]]; then
+ select ops in exit "${VPLAYERS[@]}"; do
+ [[ $ops = exit ]] && break
+ $ops "$file" &
+ done
+ else
+ mpv --vo=drm -- "$file"
+ fi
+ ;;
+
+ audio/*| application/ogg|application/x-ogg|application/mxf|application/sdp|application/smil|application/x-smil|application/streamingmedia|application/x-streamingmedia|application/vnd.rn-realmedia|application/vnd.rn-realmedia-vbr)
+ [[ $default == true ]] && $PLAYER "$file" && exit
+ select ops in exit "${APLAYERS[@]}"; do
+ [[ $ops = exit ]] && break
+ $ops "$file" &
+ done
+ ;;
+
+ application/pdf|application/x-pdf)
+ [[ $default == true ]] && $PDFVIEWER "$file" && exit
+ if [[ -n $DISPLAY ]]; then
+ select ops in exit "${PDFVIEWERS[@]}"; do
+ [[ $ops = exit ]] && break
+ $ops "$file" &> /dev/null &
+ done
+ else
+ fbgs "$file"
+ fi
+ ;;
+
+ application/x-cbz|applilcation/oxps|application/vnd.ms-xpsdocument)
+ [[ $default == true ]] && $DOCVIEWER "$file" && exit
+ select ops in exit "${DOCVIEWERS[@]}"; do
+ [[ $ops = exit ]] && break
+ $ops "$file" &> /dev/null &
+ done
+ ;;
+ application/octet-stream)
+ case "$file" in
+ *.chm|*.CHM)
+ [[ $default == true ]] && $CHMVIEWER "$file" && exit
+ select ops in exit "${CHMVIEWERS[@]}"; do
+ [[ $ops = exit ]] && break
+ $ops "$file" &
+ done
+ ;;
+ *.gpg)
+ gpg -d "$file"
+ ;;
+ *.mobi)
+ [[ $default == true ]] && $BOOKVIEWER "$file" && exit
+ select ops in exit "${BOOKVIEWERS[@]}"; do
+ [[ $ops = exit ]] && break
+ $ops "$file" &> /dev/null &
+ done
+ ;;
+ *)
+ echo "unknow filetype, probably binary"
+ ;;
+ esac
+ ;;
+ application/vnd.ms-htmlhelp)
+ [[ $default == true ]] && $CHMVIEWER "$file" && exit
+ select ops in exit "${CHMVIEWERS[@]}"; do
+ [[ $ops = exit ]] && break
+ $ops "$file" &
+ done
+ ;;
+
+ application/vnd.comicbook*)
+ select ops in exit llpp mupdf foliate; do
+ [[ $ops = exit ]] && break
+ $ops "$file" &
+ done
+ ;;
+
+ application/epub+zip|application/x-mobipocket-ebook)
+ [[ $default == true ]] && $BOOKVIEWER "$file" && exit
+ select ops in exit "${BOOKVIEWERS[@]}"; do
+ [[ $ops = exit ]] && break
+ $ops "$file" &> /dev/null &
+ done
+ ;;
+
+ application/pgp-encrypted)
+ gpg -d "$file"
+ ;;
+
+ application/*zip*|application/x-?ar|application/x-?z*|application/x-compressed*|application/vnd.rar|application/x-*-image|application/x-msi)
+ case "$file" in
+ *.xoj|*.xopp) xournalpp "$file" &> /dev/null ;;
+ *.cb?)
+ select ops in exit llpp mupdf foliate als unar; do
+ [[ $ops = exit ]] && break
+ [[ $ops = als || $ops = unar ]] && "$ops" "$file"
+ "$ops" "$file" &> /dev/null &
+ done
+ ;;
+ *)
+ if [[ $default == true ]]; then
+ mkdir "$file.tmp"
+ archivemount "$file" "$file.tmp"
+ echo -e "$file mounted at $file.tmp directory\n remove with fusermount -u $file.tmp"
+ else
+ select ops in exit "${ARCHIVERS[@]}" ; do
+ [[ $ops = exit ]] && break
+ # [[ $ops = aunpack ]] && aunpack -D "$file"
+ $ops "$file"
+ done
+ fi
+ ;;
+ esac
+ ;;
+
+ *opendocument*|*openxmlformats*|*msword|*ms-excel|*ms-powerpoint|*abiword|*write*)
+ [[ -n $DISPLAY ]] && libreoffice "$file" --norestore &> /dev/null
+ [[ -z $DISPLAY ]] && \
+ case "$file" in
+ *.odt|*.odp|*.ods|*.sxw) odt2txt "$file" ;;
+ *.doc) antiword "$file" ;;
+ *.docx) docx2txt "$file" - | $PAGER ;;
+ *) echo "unable to open" ;;
+ esac
+ ;;
+
+ inode/directory)
+ select ops in exit "${TFMS[@]}" "${XFMS[@]}"; do
+ [[ $ops = exit ]] && break
+ $ops "$file"
+ done
+ ;;
+
+ inode/x-empty)
+ echo "empty file"
+ rm -i "$file"
+ ;;
+
+ inode/mount-point)
+ ## unmount by default
+ # select ops in exit unmount; do
+ # [[ $ops = exit ]] && break
+ # [[ $ops = unmount ]] && fusermount -zu "$file" && rmdir "$file"
+ fusermount -zu "$file" && rmdir "$file" && echo "$file unmounted and removed"
+ # done
+ ;;
+
+ *)
+ case "$file" in
+ *) echo "no filetype association for $file" ;;
+ esac
+ ;;
+esac
diff --git a/dotfiles/.local/share/chezmoi/dot_local/bin/executable_provision b/dotfiles/.local/share/chezmoi/dot_local/bin/executable_provision
new file mode 100644
index 00000000..4e6d6354
--- /dev/null
+++ b/dotfiles/.local/share/chezmoi/dot_local/bin/executable_provision
@@ -0,0 +1,30 @@
+#!/usr/bin/env bash
+
+# Install Homebrew
+if ! type brew &> /dev/null; then
+ if type sudo &> /dev/null && sudo -n true; then
+ echo | /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
+ else
+ /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
+ fi
+fi
+
+# Install Homebrew bundle and go-task
+brew install go-task/tap/go-task
+brew install jq
+brew install yq
+
+# Ensure dotfiles are present
+if [ ! -f "$HOME/.local/bin/install-dotfiles" ]; then
+ bash <(curl -sSL https://gitlab.com/megabyte-labs/misc/dotfiles/-/raw/master/dotfiles/.local/bin/install-dotfiles)
+else
+ chmod +x "$HOME/.local/bin/install-dotfiles"
+ install-dotfiles
+fi
+
+# Use run alias to invoke the `$HOME/.local/Taskfile.yml`
+if [ -z "$1" ]; then
+ run localhost:provision
+else
+ run "localhost:provision:$1"
+fi
diff --git a/dotfiles/.local/share/chezmoi/dot_local/bin/executable_quickstart b/dotfiles/.local/share/chezmoi/dot_local/bin/executable_quickstart
new file mode 100644
index 00000000..eac05f86
--- /dev/null
+++ b/dotfiles/.local/share/chezmoi/dot_local/bin/executable_quickstart
@@ -0,0 +1,16 @@
+#!/usr/bin/env bash
+
+if [ -f ~/.config/autostart/first-boot.desktop ]; then
+ rm ~/.config/autostart/first-boot.desktop
+fi
+
+if type qvm-run &> /dev/null; then
+ mkdir -p "$HOME/.local"
+ qvm-run --pass-io sys-firewall 'curl -sSL https://install.doctor/qubes' > "$HOME/.local/setup.sh" && bash "$HOME/.local/setup.sh"
+elif [ -d '/Applications' ] && [ -d '/Users' ] && [ -d '/Library' ]; then
+ mkdir -p "$HOME/.local"
+ curl -sSL https://install.doctor/quickstart > "$HOME/.local/setup.sh" && bash "$HOME/.local/setup.sh"
+elif [ -f '/etc/os-release' ]; then
+ mkdir -p "$HOME/.local"
+ curl -sSL https://install.doctor/quickstart > "$HOME/.local/setup.sh" && bash "$HOME/.local/setup.sh"
+fi
diff --git a/dotfiles/.local/share/chezmoi/dot_local/bin/executable_ramqube b/dotfiles/.local/share/chezmoi/dot_local/bin/executable_ramqube
new file mode 100644
index 00000000..b48af8c2
--- /dev/null
+++ b/dotfiles/.local/share/chezmoi/dot_local/bin/executable_ramqube
@@ -0,0 +1,28 @@
+#!/usr/bin/env bash
+
+# Creates a Qube on RAM disk and opens Firefox if the Qube does not already exist.
+# If the Qube already exists, then running this will delete it.
+# Source: https://github.com/unman/stuff/blob/main/ramqube.sh
+# Source: https://github.com/unman/stuff/blob/main/rmram.sh
+
+if [ -f '/home/user/RQube' ]; then
+ mkdir /home/user/RQube
+ sudo mount -t tmpfs -o size=2G rqube /home/user/RQube/
+ qvm-pool --add rqubepool file -o revisions_to_keep=1,dir_path=/home/user/RQube/
+ qvm-create rqube -P rqubepool -t debian-11 -l purple --property netvm=tor
+ qvm-run rqube firefox-esr
+else
+ read -p "RAM Qube alredy exists. Press ENTER to delete."
+ qvm-kill rqube
+ qvm-remove -f rqube
+ qvm-pool -r rqubepool
+ sudo umount rqube
+ rm -rf /home/user/RQube
+ sudo rm -rf /var/log/libvirt/libxl/new.log
+ sudo rm -rf /var/log/libvirt/libxl/new.log
+ sudo rm -rf /var/log/qubes/vm-new.log
+ sudo rm -rf /var/log/guid/new.log
+ sudo rm -rf /var/log/qrexec.new.log
+ sudo rm -rf /var/log/pacat.new.log
+ sudo rm -rf /var/log/qubesdb.new.log
+fi
diff --git a/dotfiles/.local/share/chezmoi/dot_local/bin/executable_run b/dotfiles/.local/share/chezmoi/dot_local/bin/executable_run
new file mode 100644
index 00000000..1ae2f2ee
--- /dev/null
+++ b/dotfiles/.local/share/chezmoi/dot_local/bin/executable_run
@@ -0,0 +1,3 @@
+#!/usr/bin/env bash
+
+task --taskfile $HOME/.local/common/shared/Taskfile.yml $@
diff --git a/dotfiles/.local/share/chezmoi/dot_local/bin/executable_squash-symlink b/dotfiles/.local/share/chezmoi/dot_local/bin/executable_squash-symlink
new file mode 100644
index 00000000..b301d26d
--- /dev/null
+++ b/dotfiles/.local/share/chezmoi/dot_local/bin/executable_squash-symlink
@@ -0,0 +1,23 @@
+#!/usr/bin/env bash
+
+# Example: find . -type l -exec /path/tos/script {} +
+
+set -e
+
+for link; do
+ test -h "$link" || continue
+
+ dir=$(dirname "$link")
+ reltarget=$(readlink "$link")
+ case $reltarget in
+ /*) abstarget=$reltarget;;
+ *) abstarget=$dir/$reltarget;;
+ esac
+
+ rm -fv "$link"
+ cp -afv "$abstarget" "$link" || {
+ # on failure, restore the symlink
+ rm -rfv "$link"
+ ln -sfv "$reltarget" "$link"
+ }
+done