From 2757bc6f16f1896c8b8c97abffdcebb05479e915 Mon Sep 17 00:00:00 2001 From: Mari Date: Fri, 6 Aug 2021 03:12:26 -0400 Subject: [PATCH] Updates for barista bar --- TODO.md | 7 +- bash/bash_aliases.sh | 2 + bash/bash_tmux.sh | 2 +- borgmatic/borgmatic-daily.service | 56 +++ borgmatic/borgmatic-daily.timer | 9 + borgmatic/borgmatic-hourly.service | 56 +++ borgmatic/borgmatic-hourly.timer | 9 + borgmatic/borgmatic-monthly.service | 56 +++ borgmatic/borgmatic-monthly.timer | 9 + borgmatic/borgmatic-weekly.service | 56 +++ borgmatic/borgmatic-weekly.timer | 9 + i3/.gitignore | 1 - i3/config | 100 +++--- i3/helpers/barista/.gitignore | 2 + i3/helpers/barista/.idea/.gitignore | 8 + i3/helpers/barista/.idea/barista.iml | 17 + i3/helpers/barista/.idea/modules.xml | 8 + i3/helpers/barista/barista-bar.go | 371 ++------------------ i3/helpers/barista/build-barista-bar.sh | 7 +- i3/helpers/barista/cache-for-testing.go.bak | 10 + i3/helpers/barista/color-scheme.go | 23 ++ i3/helpers/barista/format.go | 31 ++ i3/helpers/barista/go.mod | 5 +- i3/helpers/barista/go.sum | 28 +- i3/helpers/barista/media.go | 55 +++ i3/helpers/barista/nerdfont-process-css.go | 157 +++++++++ i3/helpers/barista/nerdfont-provider.go | 21 ++ i3/helpers/barista/oauth.go | 46 +++ i3/helpers/barista/power.go | 91 +++++ i3/helpers/barista/system.go | 81 +++++ i3/helpers/barista/user.go | 34 ++ ssh/config | 1 + zsh/customizations/zsh_aliases.zsh | 2 + zsh/customizations/zsh_tmux.zsh | 2 +- zsh/ohmyzsh | 2 +- 35 files changed, 963 insertions(+), 411 deletions(-) create mode 100644 borgmatic/borgmatic-daily.service create mode 100644 borgmatic/borgmatic-daily.timer create mode 100644 borgmatic/borgmatic-hourly.service create mode 100644 borgmatic/borgmatic-hourly.timer create mode 100644 borgmatic/borgmatic-monthly.service create mode 100644 borgmatic/borgmatic-monthly.timer create mode 100644 borgmatic/borgmatic-weekly.service create mode 100644 borgmatic/borgmatic-weekly.timer delete mode 100644 i3/.gitignore create mode 100644 i3/helpers/barista/.gitignore create mode 100644 i3/helpers/barista/.idea/.gitignore create mode 100644 i3/helpers/barista/.idea/barista.iml create mode 100644 i3/helpers/barista/.idea/modules.xml create mode 100644 i3/helpers/barista/cache-for-testing.go.bak create mode 100644 i3/helpers/barista/color-scheme.go create mode 100644 i3/helpers/barista/format.go create mode 100644 i3/helpers/barista/media.go create mode 100644 i3/helpers/barista/nerdfont-process-css.go create mode 100644 i3/helpers/barista/nerdfont-provider.go create mode 100644 i3/helpers/barista/oauth.go create mode 100644 i3/helpers/barista/power.go create mode 100644 i3/helpers/barista/system.go create mode 100644 i3/helpers/barista/user.go 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