diff --git a/TODO.md b/TODO.md
index 0a48b81..de50a62 100644
--- a/TODO.md
+++ b/TODO.md
@@ -10,9 +10,7 @@
* Use dunstify for a notification after reloading the i3 config
* Include the mozc and dunst configs and rofi configs in here
* Install+configure (or is it configure+install?) xst and make it the new i3 terminal
-* Store the Ubuntu NerdFonts on Gubal.
* Wrap the lock process in a wrapper which pauses dunst and then unpauses it
-* Enable automatic gamma shifting with gammastep using the randr method
* Replace i3 shell scripts with Go binaries - or maybe just one Go binary with many options, busybox-style?
* Set up picom as compositor for i3, and embed its config here
* Set up individual desktop entries for the two firefox profiles with their -P and --class settings.
@@ -22,3 +20,8 @@
* Upgrade rofi to the latest - v 1.6.1 - from source
* Add user scripts to rofi to make it prettier and more useful: https://github.com/davatorium/rofi/wiki/User-scripts or https://github.com/topics/rofi
* Set up a desktop background
+* Theme zsh's prompt with the same colors
+* Add the playerctl utility for the play/pause button
+* Take stock of requirements and set up an install script
+* Add temperature and memory and load monitor which provides notifications (including picking a process likely to be responsible) when any or several are critical
+* Add food/drink/etc. reminders when still haven't eaten at some time past meal time
diff --git a/bash/bash_aliases.sh b/bash/bash_aliases.sh
index b2e4afe..5019f4a 100644
--- a/bash/bash_aliases.sh
+++ b/bash/bash_aliases.sh
@@ -11,6 +11,8 @@ if [[ -n $SSH_AUTH_SOCK ]] && [[ $SSH_AUTH_SOCK != $HOME/.ssh/ssh_auth_sock ]];
fi
export SSH_AUTH_SOCK="$HOME/.ssh/ssh_auth_sock"
+# Set TZ if it's not set
+LOCALZONE=$(readlink -e /etc/localtime); export TZ=${TZ:-${LOCALZONE#/usr/share/zoneinfo/}}
# Install EDITOR
export EDITOR='nvim'
# Install PAGER
diff --git a/bash/bash_tmux.sh b/bash/bash_tmux.sh
index bb0fc7d..f250897 100644
--- a/bash/bash_tmux.sh
+++ b/bash/bash_tmux.sh
@@ -11,7 +11,7 @@ function tmux_running() {
}
function tmux_init() {
- tmux -2 new-session -d -s "Nexus" -n "Misc." 'LC_ALL=C.UTF-8 fortune | cowsay -f eyes -W "$COLUMNS"; exec "$SHELL" -i'
+ tmux -2 new-session -d -s "Nexus" 'LC_ALL=C.UTF-8 fortune | cowsay -f eyes -W "$COLUMNS"; exec "$SHELL" -i'
}
function go_tmux ()
diff --git a/borgmatic/borgmatic-daily.service b/borgmatic/borgmatic-daily.service
new file mode 100644
index 0000000..95eea87
--- /dev/null
+++ b/borgmatic/borgmatic-daily.service
@@ -0,0 +1,56 @@
+[Unit]
+Description=borgmatic backup
+Wants=network-online.target
+After=network-online.target
+ConditionACPower=true
+
+[Service]
+Type=simple
+
+# Security settings for systemd running as root
+# For more details about this settings check the systemd manuals
+# https://www.freedesktop.org/software/systemd/man/systemd.exec.html
+LockPersonality=true
+# Certain borgmatic features like Healthchecks integration need MemoryDenyWriteExecute to be off.
+# But you can try setting it to "yes" for improved security if you don't use those features.
+MemoryDenyWriteExecute=no
+NoNewPrivileges=yes
+PrivateDevices=yes
+PrivateTmp=yes
+ProtectClock=yes
+ProtectControlGroups=yes
+ProtectHostname=yes
+ProtectKernelLogs=yes
+ProtectKernelModules=yes
+ProtectKernelTunables=yes
+RestrictAddressFamilies=AF_UNIX AF_INET AF_INET6 AF_NETLINK
+RestrictNamespaces=yes
+RestrictRealtime=yes
+RestrictSUIDSGID=yes
+SystemCallArchitectures=native
+SystemCallFilter=@system-service
+# Restrict write access
+# Change to 'ProtectSystem=strict' and uncomment 'ProtectHome' to make the whole file
+# system read-only be default and uncomment 'ReadWritePaths' for the required write access.
+# Add local repositroy paths to the list of 'ReadWritePaths' like '-/mnt/my_backup_drive'.
+ProtectSystem=strict
+ProtectHome=read-only
+ReadWritePaths=-/root/.config/borg -/root/.cache/borg -/root/.borgmatic /var/backups/postgres -/mnt/backup-1/borg/gubal.borg -/mnt/backup-2/borg/gubal.borg -/mnt/backup-1/borg/goldsaucer.borg -/mnt/backup-2/borg/goldsaucer.borg
+
+CapabilityBoundingSet=CAP_DAC_READ_SEARCH CAP_NET_RAW CAP_SETUID CAP_SETGID CAP_AUDIT_WRITE
+
+# Lower CPU and I/O priority.
+Nice=19
+CPUSchedulingPolicy=batch
+IOSchedulingClass=best-effort
+IOSchedulingPriority=7
+IOWeight=100
+
+Restart=no
+# Prevent rate limiting of borgmatic log events. If you are using an older version of systemd that
+# doesn't support this (pre-240 or so), you may have to remove this option.
+LogRateLimitIntervalSec=0
+
+# Delay start to prevent backups running during boot. Note that systemd-inhibit requires dbus and
+# dbus-user-session to be installed.
+ExecStart=systemd-inhibit --who="borgmatic" --why="Prevent interrupting scheduled backup" /usr/bin/borgmatic -c /etc/borgmatic/configs-nightly /etc/borgmatic/configs-enabled --syslog-verbosity 1 prune create check --only repository --only archives
diff --git a/borgmatic/borgmatic-daily.timer b/borgmatic/borgmatic-daily.timer
new file mode 100644
index 0000000..f5084fd
--- /dev/null
+++ b/borgmatic/borgmatic-daily.timer
@@ -0,0 +1,9 @@
+[Unit]
+Description=Run borgmatic backup
+
+[Timer]
+OnCalendar=Mon..Sat *-*-2..31 11:00:00 UTC
+Persistent=true
+
+[Install]
+WantedBy=timers.target
diff --git a/borgmatic/borgmatic-hourly.service b/borgmatic/borgmatic-hourly.service
new file mode 100644
index 0000000..5dc064b
--- /dev/null
+++ b/borgmatic/borgmatic-hourly.service
@@ -0,0 +1,56 @@
+[Unit]
+Description=borgmatic backup
+Wants=network-online.target
+After=network-online.target
+ConditionACPower=true
+
+[Service]
+Type=simple
+
+# Security settings for systemd running as root
+# For more details about this settings check the systemd manuals
+# https://www.freedesktop.org/software/systemd/man/systemd.exec.html
+LockPersonality=true
+# Certain borgmatic features like Healthchecks integration need MemoryDenyWriteExecute to be off.
+# But you can try setting it to "yes" for improved security if you don't use those features.
+MemoryDenyWriteExecute=no
+NoNewPrivileges=yes
+PrivateDevices=yes
+PrivateTmp=yes
+ProtectClock=yes
+ProtectControlGroups=yes
+ProtectHostname=yes
+ProtectKernelLogs=yes
+ProtectKernelModules=yes
+ProtectKernelTunables=yes
+RestrictAddressFamilies=AF_UNIX AF_INET AF_INET6 AF_NETLINK
+RestrictNamespaces=yes
+RestrictRealtime=yes
+RestrictSUIDSGID=yes
+SystemCallArchitectures=native
+SystemCallFilter=@system-service
+# Restrict write access
+# Change to 'ProtectSystem=strict' and uncomment 'ProtectHome' to make the whole file
+# system read-only be default and uncomment 'ReadWritePaths' for the required write access.
+# Add local repositroy paths to the list of 'ReadWritePaths' like '-/mnt/my_backup_drive'.
+ProtectSystem=strict
+ProtectHome=read-only
+ReadWritePaths=-/root/.config/borg -/root/.cache/borg -/root/.borgmatic /var/backups/postgres -/mnt/backup-1/borg/gubal.borg -/mnt/backup-2/borg/gubal.borg -/mnt/backup-1/borg/goldsaucer.borg -/mnt/backup-2/borg/goldsaucer.borg
+
+CapabilityBoundingSet=CAP_DAC_READ_SEARCH CAP_NET_RAW CAP_SETUID CAP_SETGID CAP_AUDIT_WRITE
+
+# Lower CPU and I/O priority.
+Nice=19
+CPUSchedulingPolicy=batch
+IOSchedulingClass=best-effort
+IOSchedulingPriority=7
+IOWeight=100
+
+Restart=no
+# Prevent rate limiting of borgmatic log events. If you are using an older version of systemd that
+# doesn't support this (pre-240 or so), you may have to remove this option.
+LogRateLimitIntervalSec=0
+
+# Delay start to prevent backups running during boot. Note that systemd-inhibit requires dbus and
+# dbus-user-session to be installed.
+ExecStart=systemd-inhibit --who="borgmatic" --why="Prevent interrupting scheduled backup" /usr/bin/borgmatic -c /etc/borgmatic/configs-enabled --syslog-verbosity 1 create
diff --git a/borgmatic/borgmatic-hourly.timer b/borgmatic/borgmatic-hourly.timer
new file mode 100644
index 0000000..4b6dc34
--- /dev/null
+++ b/borgmatic/borgmatic-hourly.timer
@@ -0,0 +1,9 @@
+[Unit]
+Description=Run borgmatic backup
+
+[Timer]
+OnCalendar=*-*-* 0..10,16..23:00:00 UTC
+Persistent=true
+
+[Install]
+WantedBy=timers.target
diff --git a/borgmatic/borgmatic-monthly.service b/borgmatic/borgmatic-monthly.service
new file mode 100644
index 0000000..574a129
--- /dev/null
+++ b/borgmatic/borgmatic-monthly.service
@@ -0,0 +1,56 @@
+[Unit]
+Description=borgmatic backup
+Wants=network-online.target
+After=network-online.target
+ConditionACPower=true
+
+[Service]
+Type=simple
+
+# Security settings for systemd running as root
+# For more details about this settings check the systemd manuals
+# https://www.freedesktop.org/software/systemd/man/systemd.exec.html
+LockPersonality=true
+# Certain borgmatic features like Healthchecks integration need MemoryDenyWriteExecute to be off.
+# But you can try setting it to "yes" for improved security if you don't use those features.
+MemoryDenyWriteExecute=no
+NoNewPrivileges=yes
+PrivateDevices=yes
+PrivateTmp=yes
+ProtectClock=yes
+ProtectControlGroups=yes
+ProtectHostname=yes
+ProtectKernelLogs=yes
+ProtectKernelModules=yes
+ProtectKernelTunables=yes
+RestrictAddressFamilies=AF_UNIX AF_INET AF_INET6 AF_NETLINK
+RestrictNamespaces=yes
+RestrictRealtime=yes
+RestrictSUIDSGID=yes
+SystemCallArchitectures=native
+SystemCallFilter=@system-service
+# Restrict write access
+# Change to 'ProtectSystem=strict' and uncomment 'ProtectHome' to make the whole file
+# system read-only be default and uncomment 'ReadWritePaths' for the required write access.
+# Add local repositroy paths to the list of 'ReadWritePaths' like '-/mnt/my_backup_drive'.
+ProtectSystem=strict
+ProtectHome=read-only
+ReadWritePaths=-/root/.config/borg -/root/.cache/borg -/root/.borgmatic /var/backups/postgres -/mnt/backup-1/borg/gubal.borg -/mnt/backup-2/borg/gubal.borg -/mnt/backup-1/borg/goldsaucer.borg -/mnt/backup-2/borg/goldsaucer.borg
+
+CapabilityBoundingSet=CAP_DAC_READ_SEARCH CAP_NET_RAW CAP_SETUID CAP_SETGID CAP_AUDIT_WRITE
+
+# Lower CPU and I/O priority.
+Nice=19
+CPUSchedulingPolicy=batch
+IOSchedulingClass=best-effort
+IOSchedulingPriority=7
+IOWeight=100
+
+Restart=no
+# Prevent rate limiting of borgmatic log events. If you are using an older version of systemd that
+# doesn't support this (pre-240 or so), you may have to remove this option.
+LogRateLimitIntervalSec=0
+
+# Delay start to prevent backups running during boot. Note that systemd-inhibit requires dbus and
+# dbus-user-session to be installed.
+ExecStart=systemd-inhibit --who="borgmatic" --why="Prevent interrupting scheduled backup" /usr/bin/borgmatic -c /etc/borgmatic/configs-nightly /etc/borgmatic/configs-enabled --syslog-verbosity 1 prune create check --only repository --only archives --only extract --only data
diff --git a/borgmatic/borgmatic-monthly.timer b/borgmatic/borgmatic-monthly.timer
new file mode 100644
index 0000000..7e7c004
--- /dev/null
+++ b/borgmatic/borgmatic-monthly.timer
@@ -0,0 +1,9 @@
+[Unit]
+Description=Run borgmatic backup
+
+[Timer]
+OnCalendar=*-*-1 11:00:00 UTC
+Persistent=true
+
+[Install]
+WantedBy=timers.target
diff --git a/borgmatic/borgmatic-weekly.service b/borgmatic/borgmatic-weekly.service
new file mode 100644
index 0000000..4abf4cd
--- /dev/null
+++ b/borgmatic/borgmatic-weekly.service
@@ -0,0 +1,56 @@
+[Unit]
+Description=borgmatic backup
+Wants=network-online.target
+After=network-online.target
+ConditionACPower=true
+
+[Service]
+Type=simple
+
+# Security settings for systemd running as root
+# For more details about this settings check the systemd manuals
+# https://www.freedesktop.org/software/systemd/man/systemd.exec.html
+LockPersonality=true
+# Certain borgmatic features like Healthchecks integration need MemoryDenyWriteExecute to be off.
+# But you can try setting it to "yes" for improved security if you don't use those features.
+MemoryDenyWriteExecute=no
+NoNewPrivileges=yes
+PrivateDevices=yes
+PrivateTmp=yes
+ProtectClock=yes
+ProtectControlGroups=yes
+ProtectHostname=yes
+ProtectKernelLogs=yes
+ProtectKernelModules=yes
+ProtectKernelTunables=yes
+RestrictAddressFamilies=AF_UNIX AF_INET AF_INET6 AF_NETLINK
+RestrictNamespaces=yes
+RestrictRealtime=yes
+RestrictSUIDSGID=yes
+SystemCallArchitectures=native
+SystemCallFilter=@system-service
+# Restrict write access
+# Change to 'ProtectSystem=strict' and uncomment 'ProtectHome' to make the whole file
+# system read-only be default and uncomment 'ReadWritePaths' for the required write access.
+# Add local repositroy paths to the list of 'ReadWritePaths' like '-/mnt/my_backup_drive'.
+ProtectSystem=strict
+ProtectHome=read-only
+ReadWritePaths=-/root/.config/borg -/root/.cache/borg -/root/.borgmatic /var/backups/postgres -/mnt/backup-1/borg/gubal.borg -/mnt/backup-2/borg/gubal.borg -/mnt/backup-1/borg/goldsaucer.borg -/mnt/backup-2/borg/goldsaucer.borg
+
+CapabilityBoundingSet=CAP_DAC_READ_SEARCH CAP_NET_RAW CAP_SETUID CAP_SETGID CAP_AUDIT_WRITE
+
+# Lower CPU and I/O priority.
+Nice=19
+CPUSchedulingPolicy=batch
+IOSchedulingClass=best-effort
+IOSchedulingPriority=7
+IOWeight=100
+
+Restart=no
+# Prevent rate limiting of borgmatic log events. If you are using an older version of systemd that
+# doesn't support this (pre-240 or so), you may have to remove this option.
+LogRateLimitIntervalSec=0
+
+# Delay start to prevent backups running during boot. Note that systemd-inhibit requires dbus and
+# dbus-user-session to be installed.
+ExecStart=systemd-inhibit --who="borgmatic" --why="Prevent interrupting scheduled backup" /usr/bin/borgmatic -c /etc/borgmatic/configs-nightly /etc/borgmatic/configs-enabled --syslog-verbosity 1 prune create check --only repository --only archives --only extract
diff --git a/borgmatic/borgmatic-weekly.timer b/borgmatic/borgmatic-weekly.timer
new file mode 100644
index 0000000..36e9cae
--- /dev/null
+++ b/borgmatic/borgmatic-weekly.timer
@@ -0,0 +1,9 @@
+[Unit]
+Description=Run borgmatic backup
+
+[Timer]
+OnCalendar=Sun *-*-2..31 11:00:00 UTC
+Persistent=true
+
+[Install]
+WantedBy=timers.target
diff --git a/i3/.gitignore b/i3/.gitignore
deleted file mode 100644
index 7ea6a9b..0000000
--- a/i3/.gitignore
+++ /dev/null
@@ -1 +0,0 @@
-barista-bar
diff --git a/i3/config b/i3/config
index 184c5b5..242bc2f 100644
--- a/i3/config
+++ b/i3/config
@@ -13,7 +13,7 @@ set $mod Mod4
# Font for window titles. Will also be used by the bar unless a different font
# is used in the bar {} block below.
-font pango:Ubuntu Mono, UbuntuMono Nerd Font 10
+font pango:Ubuntu Mono, UbuntuMono Nerd Font 14
# This font is widely installed, provides lots of unicode glyphs, right-to-left
# text rendering and scalability on retina/hidpi displays (thanks to pango).
@@ -24,61 +24,60 @@ font pango:Ubuntu Mono, UbuntuMono Nerd Font 10
# xss-lock grabs a logind suspend inhibit lock and will use i3lock to lock the
# screen before suspend. Use loginctl lock-session to lock your screen.
-exec --no-startup-id xss-lock --transfer-sleep-lock -- i3lock --nofork -c 0081a7 -e
+exec --no-startup-id exec xss-lock --transfer-sleep-lock -- i3lock --nofork -c 0081a7 -e
# NetworkManager is the most popular way to manage wireless networks on Linux,
# and nm-applet is a desktop environment-independent system tray GUI for it.
-exec --no-startup-id nm-applet
+exec --no-startup-id exec nm-applet
# Set up the gnome settings daemon for better gnome support
-exec --no-startup-id /usr/libexec/gnome-settings-daemon-localeexec
+exec --no-startup-id exec /usr/libexec/gnome-settings-daemon-localeexec
# Fix a bug in gnome-settings-daemon: http://feeding.cloud.geek.nz/posts/creating-a-modern-tiling-desktop-environment-using-i3/
-exec --no-startup-id dconf write /org/gnome/settings-daemon/plugins/cursor/active false
+exec --no-startup-id exec dconf write /org/gnome/settings-daemon/plugins/cursor/active false
# Initialize a tmux session on startup
-exec --no-startup-id zsh -ic "tmux_init"
+exec --no-startup-id exec zsh -ic "tmux_init"
# Start up the gammastep color temperature adjustment daemon.
-exec --no-startup-id gammastep
+exec --no-startup-id exec gammastep
# Enable the relevant xkb options to allow the capslock remapping to proceed
-exec --no-startup-id setxkbmap -option shift:both_capslock,caps:hyper
+exec --no-startup-id exec setxkbmap -option shift:both_capslock,caps:hyper
# Set up xcape to switch input modes for mozc with caps lock
-exec --no-startup-id xcape -e 'Hyper_L=Control_L|grave'
+exec --no-startup-id exec xcape -e 'Hyper_L=Control_L|grave'
# Set up xcape to make control a closer escape instead
-exec --no-startup-id xcape -e 'Control_L=Escape'
+exec --no-startup-id exec xcape -e 'Control_L=Escape'
# Set up xcape to make tapping the super key trigger the tmux modifier key.
-exec --no-startup-id xcape -e 'Super_L=Control_L|a'
+exec --no-startup-id exec xcape -e 'Super_L=Control_L|a'
# Use pactl to adjust volume in PulseAudio.
-set $refresh_i4status killall -SIGUSR1 i3status
-bindsym XF86AudioRaiseVolume exec --no-startup-id ~/.config/i3/helpers/volume.sh up
-bindsym XF86AudioLowerVolume exec --no-startup-id ~/.config/i3/helpers/volume.sh down
-bindsym Shift+XF86AudioLowerVolume exec --no-startup-id ~/.config/i3/helpers/volume.sh off
-bindsym Shift+XF86AudioRaiseVolume exec --no-startup-id ~/.config/i3/helpers/volume.sh max
-bindsym XF86AudioMute exec --no-startup-id ~/.config/i3/helpers/volume.sh toggle_mute
-bindsym Shift+XF86AudioMute exec --no-startup-id ~/.config/i3/helpers/volume.sh full_mute
-bindsym XF86AudioMicMute exec --no-startup-id pactl set-source-mute @DEFAULT_SOURCE@ toggle && $refresh_i3status
+bindsym XF86AudioRaiseVolume exec --no-startup-id exec ~/.config/i3/helpers/volume.sh up
+bindsym XF86AudioLowerVolume exec --no-startup-id exec ~/.config/i3/helpers/volume.sh down
+bindsym Shift+XF86AudioLowerVolume exec --no-startup-id exec ~/.config/i3/helpers/volume.sh off
+bindsym Shift+XF86AudioRaiseVolume exec --no-startup-id exec ~/.config/i3/helpers/volume.sh max
+bindsym XF86AudioMute exec --no-startup-id exec ~/.config/i3/helpers/volume.sh toggle_mute
+bindsym Shift+XF86AudioMute exec --no-startup-id exec ~/.config/i3/helpers/volume.sh full_mute
+bindsym XF86AudioMicMute exec --no-startup-id exec pactl set-source-mute @DEFAULT_SOURCE@ toggle
# Use brightnessctl to adjust screen brightness.
-bindsym XF86MonBrightnessUp exec --no-startup-id ~/.config/i3/helpers/brightness.sh up
-bindsym XF86MonBrightnessDown exec --no-startup-id ~/.config/i3/helpers/brightness.sh down
-bindsym Shift+XF86MonBrightnessUp exec --no-startup-id ~/.config/i3/helpers/brightness.sh max
-bindsym Shift+XF86MonBrightnessDown exec --no-startup-id ~/.config/i3/helpers/brightness.sh off
+bindsym XF86MonBrightnessUp exec --no-startup-id exec ~/.config/i3/helpers/brightness.sh up
+bindsym XF86MonBrightnessDown exec --no-startup-id exec ~/.config/i3/helpers/brightness.sh down
+bindsym Shift+XF86MonBrightnessUp exec --no-startup-id exec ~/.config/i3/helpers/brightness.sh max
+bindsym Shift+XF86MonBrightnessDown exec --no-startup-id exec ~/.config/i3/helpers/brightness.sh off
# Use the screenshot wrapper script.
-bindsym Print --release exec --no-startup-id ~/.config/i3/helpers/screenshot.sh screen
-bindsym Shift+Print --release exec --no-startup-id ~/.config/i3/helpers/screenshot.sh area
+bindsym Print --release exec --no-startup-id exec ~/.config/i3/helpers/screenshot.sh screen
+bindsym Shift+Print --release exec --no-startup-id exec ~/.config/i3/helpers/screenshot.sh area
# This is Alt+Print, but it's actually registered as a different key (on laptops at least).
-bindsym Sys_Req --release exec --no-startup-id ~/.config/i3/helpers/screenshot.sh current_window
-bindsym Shift+Sys_Req --release exec --no-startup-id ~/.config/i3/helpers/screenshot.sh select_window
+bindsym Sys_Req --release exec --no-startup-id exec ~/.config/i3/helpers/screenshot.sh current_window
+bindsym Shift+Sys_Req --release exec --no-startup-id exec ~/.config/i3/helpers/screenshot.sh select_window
# Nonetheless, we bind the same Alt+Printscreen shortcut just in case.
-bindsym Mod1+Print --release exec --no-startup-id ~/.config/i3/helpers/screenshot.sh current_window
-bindsym Shift+Mod1+Print --release exec --no-startup-id ~/.config/i3/helpers/screenshot.sh select_window
+bindsym Mod1+Print --release exec --no-startup-id exec ~/.config/i3/helpers/screenshot.sh current_window
+bindsym Shift+Mod1+Print --release exec --no-startup-id exec ~/.config/i3/helpers/screenshot.sh select_window
# Use Control instead of Alt in case Alt+Printscreen is ignored by i3.
-bindsym Control+Print --release exec --no-startup-id ~/.config/i3/helpers/screenshot.sh current_window
-bindsym Shift+Control+Print --release exec --no-startup-id ~/.config/i3/helpers/screenshot.sh select_window
+bindsym Control+Print --release exec --no-startup-id exec ~/.config/i3/helpers/screenshot.sh current_window
+bindsym Shift+Control+Print --release exec --no-startup-id exec ~/.config/i3/helpers/screenshot.sh select_window
# Use Mouse+$mod to drag floating windows to their wanted position
@@ -88,12 +87,12 @@ floating_modifier $mod
# kill focused window
bindsym $mod+Shift+q kill
-bindsym $mod+Shift+l exec --no-startup-id loginctl lock-session
+bindsym $mod+Shift+l exec --no-startup-id exec loginctl lock-session
# start dmenu (a program launcher)
# bindsym $mod+d exec --no-startup-id dmenu_run
# A more modern dmenu replacement is rofi:
-bindsym $mod+d --release exec "rofi -modi drun,run -show drun -show-icons"
+bindsym $mod+d --release exec "exec rofi -modi drun,run -show drun -show-icons"
# bindcode $mod+40 exec "rofi -modi drun,run -show drun"
# There also is i3-dmenu-desktop which only displays applications shipping a
# .desktop file. It is a wrapper around dmenu, so you need that installed.
@@ -157,7 +156,7 @@ set $ws3 "3: Chat"
set $ws4 "4: IDE"
set $ws5 "5: Terminal"
set $ws6 "6: Files"
-set $ws7 "7"
+set $ws7 "7: Parsec"
set $ws8 "8"
set $ws9 "9"
set $ws10 "10: Lewd Zone"
@@ -187,11 +186,13 @@ bindsym $mod+Shift+9 move container to workspace number $ws9
bindsym $mod+Shift+0 move container to workspace number $ws10
# reload the configuration file
-bindsym $mod+Shift+c reload
+bindsym $mod+Shift+c exec "i3-msg reload && dunstify 'Reloaded i3.' || dunstify 'Failed to reload i3.'"
+bindsym $mod+Control+Shift+c exec "mkdir -p ~/.cache/barista && ~/.config/i3/helpers/barista/build-barista-bar.sh > ~/.cache/barista/build.log 2<&1 && i3-msg reload && dunstify 'Upgraded barista bar and reloaded i3.' || dunstify 'Barista bar could not be upgraded, or i3 could not be reloaded.'"
# restart i3 inplace (preserves your layout/session, can be used to upgrade i3)
-bindsym $mod+Shift+r restart
+bindsym $mod+Shift+r exec "i3-msg restart && dunstify 'Restarted i3.' || dunstify 'Failed to restart i3.'"
+bindsym $mod+Control+Shift+r exec "mkdir -p ~/.cache/barista && ~/.config/i3/helpers/barista/build-barista-bar.sh > ~/.cache/barista/build.log 2<&1 && i3-msg restart && dunstify 'Upgraded barista bar and restarted i3.' || dunstify 'Barista bar could not be upgraded, or i3 could not be restarted.'"
# exit i3 (logs you out of your X session)
-bindsym $mod+Shift+e exec "i3-nagbar -t warning -m 'You pressed the exit shortcut. Do you really want to exit i3? This will end your X session.' -B 'Yes, exit i3' 'i3-msg exit'"
+bindsym $mod+Shift+e exec "exec i3-nagbar -t warning -m 'You pressed the exit shortcut. Do you really want to exit i3? This will end your X session.' -B 'Yes, exit i3' 'i3-msg exit'"
# resize window (you can also use the mouse for that)
mode "resize" {
@@ -227,15 +228,16 @@ hide_edge_borders smart
# Place normal firefox windows on workspace 1.
assign [class="^Firefox\.Main$"] workspace number $ws1
-bindsym $mod+Control+1 workspace $ws1 ; exec firefox -P "Mari" --class "Firefox.Main"
+bindsym $mod+Control+1 workspace $ws1 ; exec exec firefox -P "Mari" --class "Firefox.Main"
# Place Spotify windows on workspace 2.
for_window [class="^Spotify$"] move to workspace number $ws2
-bindsym $mod+Control+2 workspace $ws2 ; exec spotify
+for_window [class="^Sublime-music$"] move to workspace number $ws2
+bindsym $mod+Control+2 workspace $ws2 ; exec exec ~/.local/bin/sublime-music
# Place Discord windows on workspace 3.
assign [class="^discord$"] workspace number $ws3
-bindsym $mod+Control+3 workspace $ws3 ; exec discord
+bindsym $mod+Control+3 workspace $ws3 ; exec exec discord
# Make the JetBrains IDEs' opening windows float
for_window [class="^jetbrains-.*$" title="win0"] floating enable
@@ -244,19 +246,27 @@ assign [class="^jetbrains-.*$"] workspace number $ws4
# start a terminal
assign [class="^Lxterminal$"] workspace number $ws5
-bindsym $mod+Control+5 workspace $ws5 ; exec lxterminal -e '$SHELL -ic "go_tmux -x"'
-bindsym $mod+Return workspace $ws5 ; exec lxterminal -e '$SHELL -ic "go_tmux -x"'
+bindsym $mod+Control+5 workspace $ws5 ; exec exec lxterminal -e '$SHELL -ic "go_tmux -x"'
+bindsym $mod+Return workspace $ws5 ; exec exec lxterminal -e '$SHELL -ic "go_tmux -x"'
# open a file manager
assign [class="^Org\.gnome\.Nautilus$"] workspace number $ws6
-bindsym $mod+Control+6 workspace $ws6 ; exec nautilus
+bindsym $mod+Control+6 workspace $ws6 ; exec exec nautilus
+
+# connect to parsec
+assign [class="^parsecd$"] workspace number $ws7
+bindsym $mod+Control+7 workspace $ws7 ; exec exec parsecd
# Place lewd firefox windows on workspace 10.
assign [class="^Firefox\.Lewd$"] workspace number $ws10
-bindsym $mod+Control+0 workspace $ws10 ; exec firefox -P "Reya" --class "Firefox.Lewd"
+bindsym $mod+Control+0 workspace $ws10 ; exec exec firefox -P "Reya" --class "Firefox.Lewd"
# Start i3bar to display a workspace bar (plus the system information i3status
# finds out, if available)
bar {
- status_command i3status
+ status_command exec ~/.config/i3/helpers/barista/barista-bar
+ colors {
+ background #000000
+ statusline #e8e8e8
+ }
}
diff --git a/i3/helpers/barista/.gitignore b/i3/helpers/barista/.gitignore
new file mode 100644
index 0000000..a24a612
--- /dev/null
+++ b/i3/helpers/barista/.gitignore
@@ -0,0 +1,2 @@
+barista-bar
+nerdfont-provider-data.go
\ No newline at end of file
diff --git a/i3/helpers/barista/.idea/.gitignore b/i3/helpers/barista/.idea/.gitignore
new file mode 100644
index 0000000..73f69e0
--- /dev/null
+++ b/i3/helpers/barista/.idea/.gitignore
@@ -0,0 +1,8 @@
+# Default ignored files
+/shelf/
+/workspace.xml
+# Datasource local storage ignored files
+/dataSources/
+/dataSources.local.xml
+# Editor-based HTTP Client requests
+/httpRequests/
diff --git a/i3/helpers/barista/.idea/barista.iml b/i3/helpers/barista/.idea/barista.iml
new file mode 100644
index 0000000..fe0070f
--- /dev/null
+++ b/i3/helpers/barista/.idea/barista.iml
@@ -0,0 +1,17 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/i3/helpers/barista/.idea/modules.xml b/i3/helpers/barista/.idea/modules.xml
new file mode 100644
index 0000000..990c0c4
--- /dev/null
+++ b/i3/helpers/barista/.idea/modules.xml
@@ -0,0 +1,8 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/i3/helpers/barista/barista-bar.go b/i3/helpers/barista/barista-bar.go
index b0a1360..21cd37c 100644
--- a/i3/helpers/barista/barista-bar.go
+++ b/i3/helpers/barista/barista-bar.go
@@ -17,205 +17,47 @@
package main
import (
- "crypto/rand"
- "encoding/base64"
- "encoding/json"
"fmt"
- "net/http"
- "os"
- "os/user"
- "path/filepath"
+ "math"
"time"
"barista.run"
"barista.run/bar"
"barista.run/base/click"
- "barista.run/base/watchers/netlink"
"barista.run/colors"
- "barista.run/format"
- "barista.run/group/collapsing"
- "barista.run/modules/battery"
"barista.run/modules/clock"
- "barista.run/modules/cputemp"
"barista.run/modules/github"
- "barista.run/modules/media"
- "barista.run/modules/meminfo"
- "barista.run/modules/netspeed"
- "barista.run/modules/sysinfo"
- "barista.run/modules/volume"
- "barista.run/modules/volume/alsa"
"barista.run/modules/weather"
"barista.run/modules/weather/openweathermap"
- "barista.run/oauth"
"barista.run/outputs"
"barista.run/pango"
- "barista.run/pango/icons/fontawesome"
- "barista.run/pango/icons/material"
- "barista.run/pango/icons/mdi"
- "barista.run/pango/icons/typicons"
- "barista.run/testing/httpcache"
-
- colorful "github.com/lucasb-eyer/go-colorful"
- "github.com/martinlindhe/unit"
- keyring "github.com/zalando/go-keyring"
)
-func init() {
- http.DefaultTransport = httpcache.Wrap(http.DefaultTransport)
-}
-
-var spacer = pango.Text(" ").XXSmall()
-
-func truncate(in string, l int) string {
- if len([]rune(in)) <= l {
- return in
- }
- return string([]rune(in)[:l-1]) + "⋯"
-}
-
-func hms(d time.Duration) (h int, m int, s int) {
- h = int(d.Hours())
- m = int(d.Minutes()) % 60
- s = int(d.Seconds()) % 60
- return
-}
-
-func formatMediaTime(d time.Duration) string {
- h, m, s := hms(d)
- if h > 0 {
- return fmt.Sprintf("%d:%02d:%02d", h, m, s)
- }
- return fmt.Sprintf("%d:%02d", m, s)
-}
-
-func mediaFormatFunc(m media.Info) bar.Output {
- if m.PlaybackStatus == media.Stopped || m.PlaybackStatus == media.Disconnected {
- return nil
- }
- artist := truncate(m.Artist, 20)
- title := truncate(m.Title, 40-len(artist))
- if len(title) < 20 {
- artist = truncate(m.Artist, 40-len(title))
- }
- iconAndPosition := pango.Icon("fa-music").Color(colors.Hex("#f70"))
- if m.PlaybackStatus == media.Playing {
- iconAndPosition.Append(
- spacer, pango.Textf("%s/%s",
- formatMediaTime(m.Position()),
- formatMediaTime(m.Length)),
- )
- }
- return outputs.Pango(iconAndPosition, spacer, title, " - ", artist)
-}
-
var startTaskManager = click.RunLeft("xfce4-taskmanager")
-func home(path string) string {
- usr, err := user.Current()
- if err != nil {
- panic(err)
- }
- return filepath.Join(usr.HomeDir, path)
-}
-
-type freegeoipResponse struct {
- Lat float64 `json:"latitude"`
- Lng float64 `json:"longitude"`
+type autoWeatherProvider struct{
+ ApiKey string
}
-func whereami() (lat float64, lng float64, err error) {
- resp, err := http.Get("https://freegeoip.app/json/")
- if err != nil {
- return 0, 0, err
- }
- var res freegeoipResponse
- err = json.NewDecoder(resp.Body).Decode(&res)
- if err != nil {
- return 0, 0, err
- }
- return res.Lat, res.Lng, nil
-}
-
-type autoWeatherProvider struct{}
-
func (a autoWeatherProvider) GetWeather() (weather.Weather, error) {
lat, lng, err := whereami()
if err != nil {
return weather.Weather{}, err
}
return openweathermap.
- New("%%OWM_API_KEY%%").
+ New(a.ApiKey).
Coords(lat, lng).
GetWeather()
}
-func setupOauthEncryption() error {
- const service = "barista-sample-bar"
- var username string
- if u, err := user.Current(); err == nil {
- username = u.Username
- } else {
- username = fmt.Sprintf("user-%d", os.Getuid())
- }
- var secretBytes []byte
- // IMPORTANT: The oauth tokens used by some modules are very sensitive, so
- // we encrypt them with a random key and store that random key using
- // libsecret (gnome-keyring or equivalent). If no secret provider is
- // available, there is no way to store tokens (since the version of
- // sample-bar used for setup-oauth will have a different key from the one
- // running in i3bar). See also https://github.com/zalando/go-keyring#linux.
- secret, err := keyring.Get(service, username)
- if err == nil {
- secretBytes, err = base64.RawURLEncoding.DecodeString(secret)
- }
- if err != nil {
- secretBytes = make([]byte, 64)
- _, err := rand.Read(secretBytes)
- if err != nil {
- return err
- }
- secret = base64.RawURLEncoding.EncodeToString(secretBytes)
- keyring.Set(service, username, secret)
- }
- oauth.SetEncryptionKey(secretBytes)
- return nil
-}
-
-var gsuiteOauthConfig = []byte(`{"installed": {
- "client_id":"%%GOOGLE_CLIENT_ID%%",
- "project_id":"i3-barista",
- "auth_uri":"https://accounts.google.com/o/oauth2/auth",
- "token_uri":"https://www.googleapis.com/oauth2/v3/token",
- "auth_provider_x509_cert_url":"https://www.googleapis.com/oauth2/v1/certs",
- "client_secret":"%%GOOGLE_CLIENT_SECRET%%",
- "redirect_uris":["urn:ietf:wg:oauth:2.0:oob","http://localhost"]
-}}`)
-
func main() {
- material.Load(home("Github/material-design-icons"))
- mdi.Load(home("Github/MaterialDesign-Webfont"))
- typicons.Load(home("Github/typicons.font"))
- fontawesome.Load(home("Github/Font-Awesome"))
-
- colors.LoadBarConfig()
- bg := colors.Scheme("background")
- fg := colors.Scheme("statusline")
- if fg != nil && bg != nil {
- iconColor := fg.Colorful().BlendHcl(bg.Colorful(), 0.5).Clamped()
- colors.Set("dim-icon", iconColor)
- _, _, v := fg.Colorful().Hsv()
- if v < 0.3 {
- v = 0.3
- }
- colors.Set("bad", colorful.Hcl(40, 1.0, v).Clamped())
- colors.Set("degraded", colorful.Hcl(90, 1.0, v).Clamped())
- colors.Set("good", colorful.Hcl(120, 1.0, v).Clamped())
- }
-
if err := setupOauthEncryption(); err != nil {
panic(fmt.Sprintf("Could not setup oauth token encryption: %v", err))
}
+ installNerdFontProvider("UbuntuMono Nerd Font")
+ configureColors()
+
localtime := clock.Local().
Output(time.Second, func(now time.Time) bar.Output {
return outputs.Pango(
@@ -228,194 +70,20 @@ func main() {
// Weather information comes from OpenWeatherMap.
// https://openweathermap.org/api.
- wthr := weather.New(autoWeatherProvider{}).Output(func(w weather.Weather) bar.Output {
- iconName := ""
- switch w.Condition {
- case weather.Thunderstorm,
- weather.TropicalStorm,
- weather.Hurricane:
- iconName = "stormy"
- case weather.Drizzle,
- weather.Hail:
- iconName = "shower"
- case weather.Rain:
- iconName = "downpour"
- case weather.Snow,
- weather.Sleet:
- iconName = "snow"
- case weather.Mist,
- weather.Smoke,
- weather.Whirls,
- weather.Haze,
- weather.Fog:
- iconName = "windy-cloudy"
- case weather.Clear:
- if !w.Sunset.IsZero() && time.Now().After(w.Sunset) {
- iconName = "night"
- } else {
- iconName = "sunny"
- }
- case weather.PartlyCloudy:
- iconName = "partly-sunny"
- case weather.Cloudy, weather.Overcast:
- iconName = "cloudy"
- case weather.Tornado,
- weather.Windy:
- iconName = "windy"
- }
- if iconName == "" {
- iconName = "warning-outline"
- } else {
- iconName = "weather-" + iconName
- }
- return outputs.Pango(
- pango.Icon("typecn-"+iconName), spacer,
- pango.Textf("%.1f℃", w.Temperature.Celsius()),
- pango.Textf(" (provided by %s)", w.Attribution).XSmall(),
- )
- })
-
- buildBattOutput := func(i battery.Info, disp *pango.Node) *bar.Segment {
- if i.Status == battery.Disconnected || i.Status == battery.Unknown {
- return nil
- }
- iconName := "battery"
- if i.Status == battery.Charging {
- iconName += "-charging"
- }
- tenth := i.RemainingPct() / 10
- switch {
- case tenth == 0:
- iconName += "-outline"
- case tenth < 10:
- iconName += fmt.Sprintf("-%d0", tenth)
- }
- out := outputs.Pango(pango.Icon("mdi-"+iconName), disp)
- switch {
- case i.RemainingPct() <= 5:
- out.Urgent(true)
- case i.RemainingPct() <= 15:
- out.Color(colors.Scheme("bad"))
- case i.RemainingPct() <= 25:
- out.Color(colors.Scheme("degraded"))
- }
- return out
- }
- var showBattPct, showBattTime func(battery.Info) bar.Output
-
- batt := battery.All()
- showBattPct = func(i battery.Info) bar.Output {
- out := buildBattOutput(i, pango.Textf("%d%%", i.RemainingPct()))
- if out == nil {
- return nil
- }
- return out.OnClick(click.Left(func() {
- batt.Output(showBattTime)
- }))
- }
- showBattTime = func(i battery.Info) bar.Output {
- rem := i.RemainingTime()
- out := buildBattOutput(i, pango.Textf(
- "%d:%02d", int(rem.Hours()), int(rem.Minutes())%60))
- if out == nil {
- return nil
- }
- return out.OnClick(click.Left(func() {
- batt.Output(showBattPct)
- }))
- }
- batt.Output(showBattPct)
-
- vol := volume.New(alsa.DefaultMixer()).Output(func(v volume.Volume) bar.Output {
- if v.Mute {
- return outputs.
- Pango(pango.Icon("fa-volume-mute"), spacer, "MUT").
- Color(colors.Scheme("degraded"))
- }
- iconName := "off"
- pct := v.Pct()
- if pct > 66 {
- iconName = "up"
- } else if pct > 33 {
- iconName = "down"
- }
+ wthr := weather.New(autoWeatherProvider{ApiKey: "%%OWM_API_KEY%%"}).Output(func(w weather.Weather) bar.Output {
return outputs.Pango(
- pango.Icon("fa-volume-"+iconName),
- spacer,
- pango.Textf("%2d%%", pct),
+ pango.Text("Air").XSmall(), spacer,
+ pango.Textf("%.0f", math.Round(w.Temperature.Celsius())),
+ pango.Text("℃").XSmall(),
)
})
- loadAvg := sysinfo.New().Output(func(s sysinfo.Info) bar.Output {
- out := outputs.Textf("%0.2f %0.2f", s.Loads[0], s.Loads[2])
- // Load averages are unusually high for a few minutes after boot.
- if s.Uptime < 10*time.Minute {
- // so don't add colours until 10 minutes after system start.
- return out
- }
- switch {
- case s.Loads[0] > 128, s.Loads[2] > 64:
- out.Urgent(true)
- case s.Loads[0] > 64, s.Loads[2] > 32:
- out.Color(colors.Scheme("bad"))
- case s.Loads[0] > 32, s.Loads[2] > 16:
- out.Color(colors.Scheme("degraded"))
- }
- out.OnClick(startTaskManager)
- return out
- })
+ batt := batterySegment()
+ vol := volumeSegment()
+ loadAvg := loadAverageSegment()
+ freeMem := memorySegment()
- freeMem := meminfo.New().Output(func(m meminfo.Info) bar.Output {
- out := outputs.Pango(pango.Icon("material-memory"), format.IBytesize(m.Available()))
- freeGigs := m.Available().Gigabytes()
- switch {
- case freeGigs < 0.5:
- out.Urgent(true)
- case freeGigs < 1:
- out.Color(colors.Scheme("bad"))
- case freeGigs < 2:
- out.Color(colors.Scheme("degraded"))
- case freeGigs > 12:
- out.Color(colors.Scheme("good"))
- }
- out.OnClick(startTaskManager)
- return out
- })
-
- temp := cputemp.New().
- RefreshInterval(2 * time.Second).
- Output(func(temp unit.Temperature) bar.Output {
- out := outputs.Pango(
- pango.Icon("mdi-fan"), spacer,
- pango.Textf("%2d℃", int(temp.Celsius())),
- )
- switch {
- case temp.Celsius() > 90:
- out.Urgent(true)
- case temp.Celsius() > 70:
- out.Color(colors.Scheme("bad"))
- case temp.Celsius() > 60:
- out.Color(colors.Scheme("degraded"))
- }
- return out
- })
-
- sub := netlink.Any()
- iface := sub.Get().Name
- sub.Unsubscribe()
- net := netspeed.New(iface).
- RefreshInterval(2 * time.Second).
- Output(func(s netspeed.Speeds) bar.Output {
- return outputs.Pango(
- pango.Icon("fa-upload"), spacer, pango.Textf("%7s", format.Byterate(s.Tx)),
- pango.Text(" ").Small(),
- pango.Icon("fa-download"), spacer, pango.Textf("%7s", format.Byterate(s.Rx)),
- )
- })
-
- rhythmbox := media.New("rhythmbox").Output(mediaFormatFunc)
-
- grp, _ := collapsing.Group(net, temp, freeMem, loadAvg)
+ temp := cputempSegment()
ghNotify := github.New("%%GITHUB_CLIENT_ID%%", "%%GITHUB_CLIENT_SECRET%%").
Output(func(n github.Notifications) bar.Output {
@@ -439,12 +107,13 @@ func main() {
})
panic(barista.Run(
- rhythmbox,
- grp,
+ temp,
+ freeMem,
+ loadAvg,
ghNotify,
vol,
batt,
wthr,
localtime,
))
-}
+}
\ No newline at end of file
diff --git a/i3/helpers/barista/build-barista-bar.sh b/i3/helpers/barista/build-barista-bar.sh
index 4c0088a..076010d 100755
--- a/i3/helpers/barista/build-barista-bar.sh
+++ b/i3/helpers/barista/build-barista-bar.sh
@@ -31,7 +31,9 @@ KEYS=(
'OWM_API_KEY'
)
-TARGET_FILE="$(dirname "$(realpath -e "${BASH_SOURCE[0]}")")/barista-bar.go"
+DESTDIR="$(dirname "$(realpath -e "${BASH_SOURCE[0]}")")"
+cd "$DESTDIR"
+TARGET_FILE="barista-bar.go"
# Save the current sample-bar, so we can revert it after building, to
# prevent accidentally checking in the keys. We can't use git checkout
@@ -55,5 +57,4 @@ done
# Build the sample bar with all the keys set. Pass all arguments to the
# `go build` command, allowing e.g. `./build.sh -o ~/bin/mybar`, or even
# `./build.sh -race -tags debuglog`.
-go build -o "$(dirname ${TARGET_FILE})/barista-bar" "${TARGET_FILE}" "$@"
-
+go build -o "barista-bar" . "$@"
diff --git a/i3/helpers/barista/cache-for-testing.go.bak b/i3/helpers/barista/cache-for-testing.go.bak
new file mode 100644
index 0000000..fda7e3f
--- /dev/null
+++ b/i3/helpers/barista/cache-for-testing.go.bak
@@ -0,0 +1,10 @@
+package main
+
+import (
+ "barista.run/testing/httpcache"
+ "net/http"
+)
+
+func init() {
+ http.DefaultTransport = httpcache.Wrap(http.DefaultTransport)
+}
diff --git a/i3/helpers/barista/color-scheme.go b/i3/helpers/barista/color-scheme.go
new file mode 100644
index 0000000..9f3ad6c
--- /dev/null
+++ b/i3/helpers/barista/color-scheme.go
@@ -0,0 +1,23 @@
+package main
+
+import (
+ "barista.run/colors"
+ "github.com/lucasb-eyer/go-colorful"
+)
+
+func configureColors() {
+ colors.LoadBarConfig()
+ bg := colors.Scheme("background")
+ fg := colors.Scheme("statusline")
+ if fg != nil && bg != nil {
+ iconColor := fg.Colorful().BlendHcl(bg.Colorful(), 0.5).Clamped()
+ colors.Set("dim-icon", iconColor)
+ _, _, v := fg.Colorful().Hsv()
+ if v < 0.3 {
+ v = 0.3
+ }
+ colors.Set("bad", colorful.Hcl(40, 1.0, v).Clamped())
+ colors.Set("degraded", colorful.Hcl(90, 1.0, v).Clamped())
+ colors.Set("good", colorful.Hcl(120, 1.0, v).Clamped())
+ }
+}
diff --git a/i3/helpers/barista/format.go b/i3/helpers/barista/format.go
new file mode 100644
index 0000000..0d4fce2
--- /dev/null
+++ b/i3/helpers/barista/format.go
@@ -0,0 +1,31 @@
+package main
+
+import (
+ "barista.run/pango"
+ "fmt"
+ "time"
+)
+
+var spacer = pango.Text(" ").XXSmall()
+
+func truncate(in string, l int) string {
+ if len([]rune(in)) <= l {
+ return in
+ }
+ return string([]rune(in)[:l-1]) + "⋯"
+}
+
+func hms(d time.Duration) (h int, m int, s int) {
+ h = int(d.Hours())
+ m = int(d.Minutes()) % 60
+ s = int(d.Seconds()) % 60
+ return
+}
+
+func formatMediaTime(d time.Duration) string {
+ h, m, s := hms(d)
+ if h > 0 {
+ return fmt.Sprintf("%d:%02d:%02d", h, m, s)
+ }
+ return fmt.Sprintf("%d:%02d", m, s)
+}
diff --git a/i3/helpers/barista/go.mod b/i3/helpers/barista/go.mod
index 92dca37..33e03ba 100644
--- a/i3/helpers/barista/go.mod
+++ b/i3/helpers/barista/go.mod
@@ -1,9 +1,10 @@
-module i3barista.reya.zone
+module barista
go 1.16
require (
- barista.run v0.0.0-20210701172726-58d911037491
+ barista.run v0.0.0-20210724204839-32474b6f85a7
+ github.com/dustin/go-humanize v1.0.0 // indirect
github.com/lucasb-eyer/go-colorful v1.2.0
github.com/martinlindhe/unit v0.0.0-20210313160520-19b60e03648d
github.com/zalando/go-keyring v0.1.1
diff --git a/i3/helpers/barista/go.sum b/i3/helpers/barista/go.sum
index b50819b..8db5471 100644
--- a/i3/helpers/barista/go.sum
+++ b/i3/helpers/barista/go.sum
@@ -1,5 +1,5 @@
-barista.run v0.0.0-20210701172726-58d911037491 h1:WUQWmDdOjDBDx/xOR0vyCTdD/Wnxc4Ha3XmUAScOm2M=
-barista.run v0.0.0-20210701172726-58d911037491/go.mod h1:sZmKW7UshHL/5R+Tyg2/0WOpOS77ZWPh13L6u2EOv9U=
+barista.run v0.0.0-20210724204839-32474b6f85a7 h1:QP6z7qLYSQJZuHlkc21I0uoWGqrIpSe7K26tnyuLAfs=
+barista.run v0.0.0-20210724204839-32474b6f85a7/go.mod h1:hMYHc1In5djZ/4H/26euwq/6XCFiwx+esya8/JqAex0=
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU=
@@ -22,6 +22,7 @@ cloud.google.com/go v0.79.0/go.mod h1:3bzgcEeQlzbuEAYu4mrWhKqWjmpprinYgKJLgKHnbb
cloud.google.com/go v0.81.0/go.mod h1:mk/AM35KwGk/Nm2YSeZbxXdrNK3KZOYHmLkOqC2V6E0=
cloud.google.com/go v0.83.0/go.mod h1:Z7MJUsANfY0pYPdw0lbnivPx4/vhy/e2FEkSkF7vAVY=
cloud.google.com/go v0.84.0/go.mod h1:RazrYuxIK6Kb7YrzzhPoLmCVzl7Sup4NrbKPg8KHSUM=
+cloud.google.com/go v0.87.0/go.mod h1:TpDYlFy7vuLzZMMZ+B6iRiELaY7z/gJPaqbMx6mlWcY=
cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o=
cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE=
cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc=
@@ -42,6 +43,7 @@ cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9
dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
+github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY=
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
@@ -50,6 +52,7 @@ github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDk
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
+github.com/cncf/xds/go v0.0.0-20210312221358-fbca930ec8ed/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
github.com/coreos/go-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
github.com/danieljoos/wincred v1.1.0 h1:3RNcEpBg4IhIChZdFRSdlQt1QjCp1sMAPIrOnm7Yf8g=
github.com/danieljoos/wincred v1.1.0/go.mod h1:XYlo+eRTsVA9aHGp7NGjFkPla4m+DCL7hqDjlFjiygg=
@@ -64,9 +67,11 @@ github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1m
github.com/envoyproxy/go-control-plane v0.9.7/go.mod h1:cwu0lG7PUMfa9snN8LXBig5ynNVH9qI8YYLbd1fK2po=
github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk=
github.com/envoyproxy/go-control-plane v0.9.9-0.20210217033140-668b12f5399d/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk=
+github.com/envoyproxy/go-control-plane v0.9.9-0.20210512163311-63b5d3c536b0/go.mod h1:hliV/p42l8fGbc6Y9bQ70uLwIvmJyVE5k4iMKlh8wCQ=
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4=
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
+github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
@@ -85,6 +90,7 @@ github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt
github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4=
github.com/golang/mock v1.5.0/go.mod h1:CWnOUgYIOo4TcNZ0wHX3YZCqsaM1I1Jvs6v3mP3KVu8=
+github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs=
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
@@ -135,10 +141,12 @@ github.com/google/pprof v0.0.0-20201203190320-1bf35d6f28c2/go.mod h1:kpwsk12EmLe
github.com/google/pprof v0.0.0-20210122040257-d980be63207e/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
github.com/google/pprof v0.0.0-20210226084205-cbba55b83ad5/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
github.com/google/pprof v0.0.0-20210601050228-01bbb1931b22/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
+github.com/google/pprof v0.0.0-20210609004039-a478d1d731e9/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=
+github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw=
github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
@@ -166,6 +174,7 @@ github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZb
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
github.com/rjeczalik/notify v0.9.2/go.mod h1:aErll2f0sUX9PXZnVNyeiObbmTlk5jnMoCa4QEjJeqM=
+github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ=
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
github.com/spf13/afero v1.6.0 h1:xoax2sJ2DT8S8xA2paPFjDCScCNeWsg75VG0DLRreiY=
@@ -198,6 +207,7 @@ go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk=
go.opencensus.io v0.23.0/go.mod h1:XItmlyltB5F7CS4xOC1DcqMoFqwtC6OG2xF7mCv7P7E=
+go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
@@ -347,8 +357,9 @@ golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210514084401-e8d321eab015/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210603125802-9665404d3644/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.0.0-20210616094352-59db8d763f22 h1:RqytpXGR1iVNX7psjB3ff8y7sNFinVFvkx1c8SjBkio=
golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c h1:F1jZWGFhYfh0Ci55sIpILtKKK8p3i2/krTr0H1rg74I=
+golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
@@ -414,6 +425,7 @@ golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
golang.org/x/tools v0.1.2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
golang.org/x/tools v0.1.3/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
golang.org/x/tools v0.1.4/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
+golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
@@ -443,6 +455,7 @@ google.golang.org/api v0.43.0/go.mod h1:nQsDGjRXMo4lvh5hP0TKqF244gqhGcr/YSIykhUk
google.golang.org/api v0.47.0/go.mod h1:Wbvgpq1HddcWVtzsVLyfLp8lDg6AA241LmgIL59tHXo=
google.golang.org/api v0.48.0/go.mod h1:71Pr1vy+TAZRPkPs/xlCf5SsU8WjuAWv1Pfjbtukyy4=
google.golang.org/api v0.50.0/go.mod h1:4bNT5pAuq5ji4SRZm+5QIkjny9JAyVD/3gaSihNefaw=
+google.golang.org/api v0.51.0/go.mod h1:t4HdrdoNgyN5cbEfm7Lum0lcLDLiise1F8qDKX00sOU=
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
@@ -474,6 +487,7 @@ google.golang.org/genproto v0.0.0-20200312145019-da6875a35672/go.mod h1:55QSHmfG
google.golang.org/genproto v0.0.0-20200331122359-1ee6d9798940/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200430143042-b979b6f78d84/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200511104702-f5ebc3bea380/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
+google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200515170657-fc4c6c6a6587/go.mod h1:YsZOwe1myG/8QRHRsmBRE1LrgQY60beZKjly0O1fX9U=
google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA=
@@ -495,6 +509,8 @@ google.golang.org/genproto v0.0.0-20210602131652-f16073e35f0c/go.mod h1:UODoCrxH
google.golang.org/genproto v0.0.0-20210604141403-392c879c8b08/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0=
google.golang.org/genproto v0.0.0-20210608205507-b6d2f5bf0d7d/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0=
google.golang.org/genproto v0.0.0-20210624195500-8bfb893ecb84/go.mod h1:SzzZ/N+nwJDaO1kznhnlzqS8ocJICar6hYhVyhi++24=
+google.golang.org/genproto v0.0.0-20210713002101-d411969a0d9a/go.mod h1:AxrInvYm1dci+enl5hChSFPOmmUF1+uAa/UsgNRWd7k=
+google.golang.org/genproto v0.0.0-20210716133855-ce7ef5c701ea/go.mod h1:AxrInvYm1dci+enl5hChSFPOmmUF1+uAa/UsgNRWd7k=
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
@@ -508,6 +524,7 @@ google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3Iji
google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
google.golang.org/grpc v1.31.1/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
+google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0=
google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc=
google.golang.org/grpc v1.34.0/go.mod h1:WotjhfgOW/POjDeRt8vscBtXq+2VjORFy659qA51WJ8=
google.golang.org/grpc v1.35.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=
@@ -516,6 +533,7 @@ google.golang.org/grpc v1.36.1/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAG
google.golang.org/grpc v1.37.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM=
google.golang.org/grpc v1.37.1/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM=
google.golang.org/grpc v1.38.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM=
+google.golang.org/grpc v1.39.0/go.mod h1:PImNr+rS9TWYb2O4/emRugxiyHZ5JyHW5F+RPnDzfrE=
google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.1.0/go.mod h1:6Kw0yEErY5E/yWrBtf03jp27GLLJujG4z/JK95pnjjw=
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
@@ -528,13 +546,15 @@ google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpAD
google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4=
google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
-google.golang.org/protobuf v1.26.0 h1:bxAC2xTBsZGibn2RTntX0oH50xLsqy1OxA9tTL3p/lk=
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
+google.golang.org/protobuf v1.27.1 h1:SnqbnDw1V7RiZcXPx5MEeqPv2s79L9i7BJUlG/+RurQ=
+google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
+gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo=
diff --git a/i3/helpers/barista/media.go b/i3/helpers/barista/media.go
new file mode 100644
index 0000000..1e4fdb9
--- /dev/null
+++ b/i3/helpers/barista/media.go
@@ -0,0 +1,55 @@
+package main
+
+import (
+ "barista.run/bar"
+ "barista.run/colors"
+ "barista.run/modules/media"
+ "barista.run/modules/volume"
+ "barista.run/modules/volume/alsa"
+ "barista.run/outputs"
+ "barista.run/pango"
+)
+
+func mediaFormatFunc(m media.Info) bar.Output {
+ if m.PlaybackStatus == media.Stopped || m.PlaybackStatus == media.Disconnected {
+ return nil
+ }
+ artist := truncate(m.Artist, 20)
+ title := truncate(m.Title, 40-len(artist))
+ if len(title) < 20 {
+ artist = truncate(m.Artist, 40-len(title))
+ }
+ iconAndPosition := pango.Icon("nf-fa-music").Color(colors.Hex("#f70"))
+ if m.PlaybackStatus == media.Playing {
+ iconAndPosition.Append(
+ spacer, pango.Textf("%s/%s",
+ formatMediaTime(m.Position()),
+ formatMediaTime(m.Length)),
+ )
+ }
+ return outputs.Pango(iconAndPosition, spacer, title, " - ", artist)
+}
+
+func volumeSegment() bar.Module {
+ return volume.New(alsa.DefaultMixer()).Output(func(v volume.Volume) bar.Output {
+ pct := v.Pct()
+ var indicatorText *pango.Node
+ var pctText *pango.Node
+ if pct > 99 {
+ pctText = pango.Text("MAX")
+ } else {
+ pctText = pango.Textf("%2d%%", pct)
+ }
+ if v.Mute {
+ indicatorText = pango.Text("MUT").Color(colors.Scheme("degraded"))
+ pctText = pctText.Color(colors.Scheme("degraded")).XSmall()
+ } else {
+ indicatorText = pango.Text("Vol").XSmall()
+ }
+ return outputs.Pango(
+ indicatorText,
+ spacer,
+ pctText,
+ )
+ })
+}
diff --git a/i3/helpers/barista/nerdfont-process-css.go b/i3/helpers/barista/nerdfont-process-css.go
new file mode 100644
index 0000000..e1b2bbc
--- /dev/null
+++ b/i3/helpers/barista/nerdfont-process-css.go
@@ -0,0 +1,157 @@
+// This file is run by go generate, and generates nerdfont-provider-data.go.
+// +build generation
+
+package main
+
+import (
+ "bufio"
+ "bytes"
+ "io"
+ "log"
+ "net/http"
+ "os"
+ "strconv"
+ "strings"
+ "text/template"
+ "time"
+ "unicode"
+)
+
+var fileTemplate = template.Must(template.New("").Parse(`// Code generated by go generate; DO NOT EDIT.
+// This file was generated by robots at
+// {{ .Timestamp }}
+// using data from
+// {{ .URL }}
+package main
+
+var NerdFontGlyphs = []Glyph{
+{{- range $key, $rune := .Glyphs }}
+ {
+ Key: {{ printf "%q" $key }},
+ Rune: 0x{{ printf "%x" $rune }},
+ },
+{{- end }}
+}
+`))
+
+const TokenStartString = ".nf-"
+const ClassStartString = ":before {\n content: \"\\"
+const ClassEndString = "\";\n}\n"
+// SplitCSS scans the reader looking for data of the form
+// .nf-(key):before {
+// content: "\(hex)";
+// }
+// and returns (key):(hex) when it finds this data.
+func SplitCSS(data []byte, atEOF bool) (advance int, token []byte, err error) {
+ if !bytes.HasPrefix(data, []byte(TokenStartString)) {
+ // This is not our goal. Skip this line.
+ nextNewline := bytes.IndexRune(data, '\n');
+ if nextNewline == -1 {
+ // Can't skip this line yet because we don't know where it ends!
+ return 0, nil, nil
+ } else {
+ offset := nextNewline + 1
+ // Skip this line in our own head and see if we get a result.
+ advance, token, err = SplitCSS(data[offset:], atEOF)
+ if advance > 0 || token != nil || err != nil {
+ // If we do, return it adjusted by the offset.
+ return advance + offset, token, err
+ } else {
+ // Otherwise, just tell the scanner to skip the line we found and keep going.
+ return offset, nil, nil
+ }
+ }
+ }
+ keyEnd := bytes.Index(data, []byte(ClassStartString))
+ if keyEnd == -1 {
+ // We don't know where the key ends!
+ return 0, nil, nil
+ }
+ key := data[len(TokenStartString):keyEnd]
+ contentEnd := bytes.Index(data, []byte(ClassEndString))
+ if contentEnd == -1 {
+ // We don't know where the content ends!
+ return 0, nil, nil
+ }
+ content := data[keyEnd + len(ClassStartString):contentEnd]
+ token = make([]byte, len(key) + len(content) + 1)
+ copy(token[:len(key)], key)
+ token[len(key)] = ':'
+ copy(token[len(key) + 1:], content)
+ return contentEnd + len(ClassEndString), token, nil
+}
+
+func SplitOnce(s string, sep string) (string, string) {
+ result := strings.SplitN(s, sep, 2)
+ if len(result) == 2 {
+ return result[0], result[1]
+ } else if len(result) == 1 {
+ return result[0], ""
+ } else {
+ panic("How did we get a different number of strings than 1 or 2 out of SplitN(2)?")
+ }
+}
+
+func main() {
+ const url = "https://raw.githubusercontent.com/ryanoasis/nerd-fonts/master/css/nerd-fonts-generated.css"
+
+ rsp, err := http.Get(url)
+ if err != nil {
+ log.Fatalf("failed to get css file: %s", err)
+ }
+ defer func(b io.ReadCloser) {
+ err := b.Close()
+ if err != nil {
+ log.Printf("failed closing the css file: %s", err)
+ }
+ }(rsp.Body)
+
+ sc := bufio.NewScanner(rsp.Body)
+ sc.Split(SplitCSS)
+
+ glyphs := make(map[string]rune)
+
+ for sc.Scan() {
+ key, hex := SplitOnce(sc.Text(), ":")
+ val, err := strconv.ParseInt(hex, 16, 64)
+ if err != nil {
+ log.Printf("val %s for %s cannot be parsed as hex: %s", hex, key, err)
+ continue
+ }
+ if val > int64(unicode.MaxRune) {
+ log.Printf("val 0x%x for %s exceeds MaxRune", val, key)
+ continue
+ }
+ if old, ok := glyphs[key]; ok {
+ log.Printf("already stored %s as 0x%x but got 0x%x, replacing", key, old, val)
+ }
+ glyphs[key] = rune(val)
+ }
+ if sc.Err() != nil {
+ log.Fatalf("failed to scan: %s", sc.Err())
+ }
+
+ f, err := os.Create("nerdfont-provider-data.go")
+ if err != nil {
+ log.Fatalf("failed to open the data file: %s", err)
+ }
+ defer func(f *os.File) {
+ err := f.Close()
+ if err != nil {
+ log.Printf("failed closing the data file: %s", err)
+ }
+ }(f)
+
+ err = fileTemplate.Execute(f, struct {
+ Timestamp time.Time
+ URL string
+ Glyphs map[string]rune
+ }{
+ Timestamp: time.Now(),
+ URL: url,
+ Glyphs: glyphs,
+ })
+ if err != nil {
+ log.Fatalf("failed writing template to the data file: %s", err)
+ }
+}
\ No newline at end of file
diff --git a/i3/helpers/barista/nerdfont-provider.go b/i3/helpers/barista/nerdfont-provider.go
new file mode 100644
index 0000000..e7d4ba2
--- /dev/null
+++ b/i3/helpers/barista/nerdfont-provider.go
@@ -0,0 +1,21 @@
+package main
+
+//go:generate go run nerdfont-process-css.go
+
+import (
+ "barista.run/pango/icons"
+)
+
+type Glyph struct {
+ Key string
+ Rune rune
+}
+
+func installNerdFontProvider(face string) *icons.Provider {
+ nf := icons.NewProvider("nf")
+ nf.Font(face)
+ for _, glyph := range NerdFontGlyphs {
+ nf.Symbol(glyph.Key, string(glyph.Rune))
+ }
+ return nf
+}
\ No newline at end of file
diff --git a/i3/helpers/barista/oauth.go b/i3/helpers/barista/oauth.go
new file mode 100644
index 0000000..1737e8f
--- /dev/null
+++ b/i3/helpers/barista/oauth.go
@@ -0,0 +1,46 @@
+package main
+
+import (
+ "barista.run/oauth"
+ "crypto/rand"
+ "encoding/base64"
+ "fmt"
+ "github.com/zalando/go-keyring"
+ "os"
+ "os/user"
+)
+
+func setupOauthEncryption() error {
+ const service = "reya.zone-barista-bar"
+ var username string
+ if u, err := user.Current(); err == nil {
+ username = u.Username
+ } else {
+ username = fmt.Sprintf("user-%d", os.Getuid())
+ }
+ var secretBytes []byte
+ // IMPORTANT: The oauth tokens used by some modules are very sensitive, so
+ // we encrypt them with a random key and store that random key using
+ // libsecret (gnome-keyring or equivalent). If no secret provider is
+ // available, there is no way to store tokens (since the version of
+ // sample-bar used for setup-oauth will have a different key from the one
+ // running in i3bar). See also https://github.com/zalando/go-keyring#linux.
+ secret, err := keyring.Get(service, username)
+ if err == nil {
+ secretBytes, err = base64.RawURLEncoding.DecodeString(secret)
+ }
+ if err != nil {
+ secretBytes = make([]byte, 64)
+ _, err := rand.Read(secretBytes)
+ if err != nil {
+ return err
+ }
+ secret = base64.RawURLEncoding.EncodeToString(secretBytes)
+ err = keyring.Set(service, username, secret)
+ if err != nil {
+ return err
+ }
+ }
+ oauth.SetEncryptionKey(secretBytes)
+ return nil
+}
\ No newline at end of file
diff --git a/i3/helpers/barista/power.go b/i3/helpers/barista/power.go
new file mode 100644
index 0000000..b1a893a
--- /dev/null
+++ b/i3/helpers/barista/power.go
@@ -0,0 +1,91 @@
+package main
+
+import (
+ "barista.run/bar"
+ "barista.run/base/click"
+ "barista.run/colors"
+ "barista.run/modules/battery"
+ "barista.run/outputs"
+ "barista.run/pango"
+)
+
+func buildBattOutput(i battery.Info, render func (i battery.Info) *pango.Node) *bar.Segment {
+ var indicator, display *pango.Node
+ display = render(i)
+ switch i.Status {
+ case battery.Disconnected:
+ indicator = pango.Text("---")
+ case battery.Full:
+ indicator = pango.Text("AC ")
+ case battery.Charging:
+ indicator = pango.Text("AC+")
+ case battery.Discharging:
+ indicator = pango.Text("Bat")
+ case battery.NotCharging:
+ indicator = pango.Text("AC?")
+ default:
+ indicator = pango.Text("???")
+ }
+ out := outputs.Pango(indicator.XSmall(), spacer, display)
+ switch {
+ case i.RemainingPct() <= 5:
+ out.Urgent(true)
+ case i.RemainingPct() <= 15:
+ out.Color(colors.Scheme("bad"))
+ case i.RemainingPct() <= 25:
+ out.Color(colors.Scheme("degraded"))
+ }
+ return out
+}
+
+func batterySegment() bar.Module {
+ var showBattPct, showBattTime func(battery.Info) bar.Output
+ batt := battery.All()
+ showBattPct = func(i battery.Info) bar.Output {
+ out := buildBattOutput(i, func(i battery.Info) *pango.Node {
+ switch i.Status {
+ case battery.Full, battery.Charging, battery.Discharging, battery.NotCharging:
+ if i.RemainingPct() < 0 {
+ return pango.Text(" 0%")
+ } else if i.RemainingPct() > 99 {
+ return pango.Text("MAX")
+ } else {
+ return pango.Textf("%d%%", i.RemainingPct())
+ }
+ case battery.Disconnected:
+ return pango.Text("---")
+ default:
+ return pango.Text("???")
+ }
+ })
+ if out == nil {
+ return nil
+ }
+ return out.OnClick(click.Left(func() {
+ batt.Output(showBattTime)
+ }))
+ }
+ showBattTime = func(i battery.Info) bar.Output {
+ rem := i.RemainingTime()
+ out := buildBattOutput(i, func(i battery.Info) *pango.Node {
+ switch i.Status {
+ case battery.Full, battery.Charging, battery.Discharging, battery.NotCharging:
+ return pango.Textf("%d:%02d", int(rem.Hours()), int(rem.Minutes())%60)
+ case battery.Disconnected:
+ return pango.Text("-:--")
+ default:
+ return pango.Text("?:??")
+ }
+ })
+
+ if out == nil {
+ return nil
+ }
+ return out.OnClick(click.Left(func() {
+ batt.Output(showBattPct)
+ }))
+ }
+ batt.Output(showBattPct)
+ return batt
+}
+
diff --git a/i3/helpers/barista/system.go b/i3/helpers/barista/system.go
new file mode 100644
index 0000000..4aa1b7d
--- /dev/null
+++ b/i3/helpers/barista/system.go
@@ -0,0 +1,81 @@
+package main
+
+import (
+ "barista.run/bar"
+ "barista.run/colors"
+ "barista.run/modules/cputemp"
+ "barista.run/modules/meminfo"
+ "barista.run/modules/sysinfo"
+ "barista.run/outputs"
+ "barista.run/pango"
+ "github.com/dustin/go-humanize"
+ "github.com/martinlindhe/unit"
+ "strings"
+ "time"
+)
+
+func memorySegment() bar.Module {
+ return meminfo.New().Output(func(m meminfo.Info) bar.Output {
+ h := strings.SplitN(humanize.IBytes(uint64(m.Available().Bytes())), " ", 2)
+ freeText := pango.Text(h[0])
+ if len(h) == 2 {
+ freeText = freeText.Append(spacer, pango.Text(h[1]).Small())
+ }
+ out := outputs.Pango(pango.Text("Mem").XSmall(), spacer, freeText)
+ freeGigs := m.Available().Gigabytes()
+ switch {
+ case freeGigs < 0.5:
+ out.Urgent(true)
+ case freeGigs < 1:
+ out.Color(colors.Scheme("bad"))
+ case freeGigs < 2:
+ out.Color(colors.Scheme("degraded"))
+ case freeGigs > 12:
+ out.Color(colors.Scheme("good"))
+ }
+ out.OnClick(startTaskManager)
+ return out
+ })
+}
+
+func loadAverageSegment() bar.Module {
+ return sysinfo.New().Output(func(s sysinfo.Info) bar.Output {
+ out := outputs.Pango(pango.Text("Load 1m").XSmall(), spacer, pango.Textf("%0.2f", s.Loads[0]), spacer, pango.Text("15m").XSmall(), spacer, pango.Textf("%0.2f", s.Loads[2]))
+ // Load averages are unusually high for a few minutes after boot.
+ if s.Uptime < 10*time.Minute {
+ // so don't add colours until 10 minutes after system start.
+ return out
+ }
+ switch {
+ case s.Loads[0] > 128, s.Loads[2] > 64:
+ out.Urgent(true)
+ case s.Loads[0] > 64, s.Loads[2] > 32:
+ out.Color(colors.Scheme("bad"))
+ case s.Loads[0] > 32, s.Loads[2] > 16:
+ out.Color(colors.Scheme("degraded"))
+ }
+ out.OnClick(startTaskManager)
+ return out
+ })
+}
+
+func cputempSegment() bar.Module {
+ return cputemp.New().
+ RefreshInterval(2 * time.Second).
+ Output(func(temp unit.Temperature) bar.Output {
+ out := outputs.Pango(
+ pango.Text("CPU").XSmall(), spacer,
+ pango.Textf("%2d", int(temp.Celsius())),
+ pango.Text("℃").XSmall(),
+ )
+ switch {
+ case temp.Celsius() > 90:
+ out.Urgent(true)
+ case temp.Celsius() > 70:
+ out.Color(colors.Scheme("bad"))
+ case temp.Celsius() > 60:
+ out.Color(colors.Scheme("degraded"))
+ }
+ return out
+ })
+}
diff --git a/i3/helpers/barista/user.go b/i3/helpers/barista/user.go
new file mode 100644
index 0000000..004f380
--- /dev/null
+++ b/i3/helpers/barista/user.go
@@ -0,0 +1,34 @@
+package main
+
+import (
+ "encoding/json"
+ "net/http"
+ "os/user"
+ "path/filepath"
+)
+
+func home(path string) string {
+ usr, err := user.Current()
+ if err != nil {
+ panic(err)
+ }
+ return filepath.Join(usr.HomeDir, path)
+}
+
+type freegeoipResponse struct {
+ Lat float64 `json:"latitude"`
+ Lng float64 `json:"longitude"`
+}
+
+func whereami() (lat float64, lng float64, err error) {
+ resp, err := http.Get("https://freegeoip.app/json/")
+ if err != nil {
+ return 0, 0, err
+ }
+ var res freegeoipResponse
+ err = json.NewDecoder(resp.Body).Decode(&res)
+ if err != nil {
+ return 0, 0, err
+ }
+ return res.Lat, res.Lng, nil
+}
diff --git a/ssh/config b/ssh/config
index 24fdad1..21f05de 100644
--- a/ssh/config
+++ b/ssh/config
@@ -2,6 +2,7 @@ AddKeysToAgent yes
VisualHostKey yes
Host gubal gubal.reya.zone *.gubal.reya.zone *.gubal
+ SendEnv TZ LANG LANGUAGE LC_*
ForwardAgent yes
StrictHostKeyChecking yes
Hostname gubal.reya.zone
diff --git a/zsh/customizations/zsh_aliases.zsh b/zsh/customizations/zsh_aliases.zsh
index 8f7ead1..9cab04d 100644
--- a/zsh/customizations/zsh_aliases.zsh
+++ b/zsh/customizations/zsh_aliases.zsh
@@ -3,6 +3,8 @@
# Disable the gosh darn XON/XOFF function that serves no purpose but to confuse me when I accidentally press Ctrl+S
stty -ixon
+# Set TZ if it's not set
+LOCALZONE=$(readlink -e /etc/localtime); export TZ=${TZ:-${LOCALZONE#/usr/share/zoneinfo/}}
# Install EDITOR
export EDITOR='nvim'
# Install PAGER
diff --git a/zsh/customizations/zsh_tmux.zsh b/zsh/customizations/zsh_tmux.zsh
index 4b638f1..dc6e1dc 100644
--- a/zsh/customizations/zsh_tmux.zsh
+++ b/zsh/customizations/zsh_tmux.zsh
@@ -6,7 +6,7 @@ function tmux_running() {
}
function tmux_init() {
- tmux -2 new-session -d -s "Nexus" -n "Misc." 'LC_ALL=C.UTF-8 fortune | cowsay -f eyes -W "$COLUMNS"; exec "$SHELL" -i'
+ tmux -2 new-session -d -s "Nexus" 'LC_ALL=C.UTF-8 fortune | cowsay -f eyes -W "$COLUMNS"; exec "$SHELL" -i'
}
function go_tmux() {
diff --git a/zsh/ohmyzsh b/zsh/ohmyzsh
index 079e7bb..5377cc3 160000
--- a/zsh/ohmyzsh
+++ b/zsh/ohmyzsh
@@ -1 +1 @@
-Subproject commit 079e7bb5e0a79171f3356d55d3f6302a82645a39
+Subproject commit 5377cc37c0f71fe22484303a4c6f387aa339f3f5