diff options
| author | aristote <quentin.aristote@irif.fr> | 2025-07-30 00:12:49 +0200 |
|---|---|---|
| committer | aristote <quentin.aristote@irif.fr> | 2025-07-30 00:12:49 +0200 |
| commit | 414e9b5ae2c3a565c5826027c7e1f775cdafc32a (patch) | |
| tree | 65d0bc0af6813e5d6c3ec7f85d65cffdc9f20bbd /modules/home-manager/personal/gui/x | |
| parent | b3686c3a4848ea3f99c7735b4da21a4677a6e321 (diff) | |
home: i3: barista -> i3status-rust
Diffstat (limited to 'modules/home-manager/personal/gui/x')
| -rw-r--r-- | modules/home-manager/personal/gui/x/i3/bar.nix | 101 | ||||
| -rw-r--r-- | modules/home-manager/personal/gui/x/i3/bar/default.nix | 32 | ||||
| -rw-r--r-- | modules/home-manager/personal/gui/x/i3/bar/i3status.go | 281 | ||||
| -rw-r--r-- | modules/home-manager/personal/gui/x/i3/default.nix | 2 |
4 files changed, 102 insertions, 314 deletions
diff --git a/modules/home-manager/personal/gui/x/i3/bar.nix b/modules/home-manager/personal/gui/x/i3/bar.nix new file mode 100644 index 0000000..2389a8a --- /dev/null +++ b/modules/home-manager/personal/gui/x/i3/bar.nix @@ -0,0 +1,101 @@ +{ + config, + lib, + pkgs, + ... +}: +let + cfg = config.personal.x.i3; + cfgStylix = config.stylix.targets.i3; + mkDeviceOption = lib.mkOption { + type = with lib.types; nullOr str; + default = null; + }; + ifDevice = device: attrs: lib.optional (device != null) ({ inherit device; } // attrs); +in +{ + options.personal.x.i3 = { + devices = { + wifi = mkDeviceOption; + eth = mkDeviceOption; + vpn = mkDeviceOption // { + default = "tun0"; + }; + }; + }; + + config = lib.mkIf cfg.enable { + xsession.windowManager.i3.config.bars = [ + { + statusCommand = "${pkgs.i3status-rust}/bin/i3status-rs ~/.config/i3status-rust/config-default.toml"; + fonts = { inherit (cfgStylix.exportedBarConfig.fonts) size; }; + } + ]; + + programs.i3status-rust = { + enable = true; + bars = { + default = { + icons = "material-nf"; + blocks = + (ifDevice cfg.devices.wifi { + block = "net"; + device = cfg.devices.wifi; + format = " ^icon_net_wireless $ssid "; + }) + ++ (ifDevice cfg.devices.eth { + block = "net"; + device = cfg.devices.eth; + format = " ^icon_net_wired $ip "; + inactive_format = " ^icon_net_wired × "; + missing_format = " ^icon_net_wired × "; + }) + ++ (ifDevice cfg.devices.vpn { + block = "net"; + device = cfg.devices.vpn; + format = " ^icon_net_vpn $ip "; + inactive_format = " ^icon_net_vpn × "; + missing_format = " ^icon_net_vpn × "; + }) + ++ [ + { + block = "disk_space"; + info_type = "used"; + path = "/"; + warning = 50.0; + alert = 90.0; + format = " $icon $percentage "; + } + ( + let + format = " $icon $percentage "; + in + { + block = "battery"; + inherit format; + full_format = format; + charging_format = format; + empty_format = format; + not_charging_format = format; + } + ) + { + block = "backlight"; + } + { + block = "sound"; + } + { + block = "sound"; + } + { + block = "time"; + interval = 1; + format = " $timestamp.datetime(f:'%a. %b. %d, %H:%M:%S') "; + } + ]; + }; + }; + }; + }; +} diff --git a/modules/home-manager/personal/gui/x/i3/bar/default.nix b/modules/home-manager/personal/gui/x/i3/bar/default.nix deleted file mode 100644 index 132e850..0000000 --- a/modules/home-manager/personal/gui/x/i3/bar/default.nix +++ /dev/null @@ -1,32 +0,0 @@ -{ - config, - lib, - pkgs, - ... -}: -let - statusPackage = pkgs.personal.barista.override { i3statusGo = ./i3status.go; }; -in -{ - xsession.windowManager.i3.config.bars = [ - ( - { - statusCommand = "${statusPackage}/bin/i3status"; - } - // (config.lib.stylix.i3.targets.i3.exportedBarConfig or { colors.background = "#111111"; }) - // { - fonts = { - names = [ "roboto" ]; - size = 11.0; - }; - } - ) - ]; - - home.packages = - with pkgs; - lib.optionals (config.xsession.enable && config.xsession.windowManager.i3.enable) [ - material-design-icons - roboto - ]; -} diff --git a/modules/home-manager/personal/gui/x/i3/bar/i3status.go b/modules/home-manager/personal/gui/x/i3/bar/i3status.go deleted file mode 100644 index 4e1b0f5..0000000 --- a/modules/home-manager/personal/gui/x/i3/bar/i3status.go +++ /dev/null @@ -1,281 +0,0 @@ -package main - -import ( - "io" - "net/http" - "os" - "regexp" - "strconv" - "time" - - "barista.run" - "barista.run/bar" - "barista.run/base/click" - "barista.run/colors" - "barista.run/group" - "barista.run/modules/battery" - "barista.run/modules/clock" - "barista.run/modules/diskspace" - "barista.run/modules/funcs" - "barista.run/modules/netinfo" - "barista.run/modules/systemd" - "barista.run/modules/volume" - "barista.run/modules/volume/pulseaudio" - "barista.run/modules/wlan" - "barista.run/outputs" - "barista.run/pango" - "barista.run/pango/icons/mdi" -) - -func main() { - // Constants - colors.LoadFromMap(map[string]string{ - // Color palette of Cezanne's Vue de la Baie de Marseille - "good": "#C5D294", - "degraded": "#E9CC67", - "bad": "#FFBC88", - }) - mdi.Load() // repo path will be inserted at build time - - // Display status of several services - outputServiceStatus := func(goodState systemd.State, degradedState systemd.State, goodIcon *pango.Node, degradedIcon *pango.Node, badIcon *pango.Node) func(systemd.ServiceInfo) bar.Output { - return func(i systemd.ServiceInfo) bar.Output { - state := i.UnitInfo.State - var colorScheme string - var output *pango.Node - switch { - case state == goodState: - colorScheme = "good" - output = goodIcon - case state == degradedState: - colorScheme = "degraded" - output = degradedIcon - default: - colorScheme = "bad" - output = badIcon - } - return outputs.Pango(output).Color(colors.Scheme(colorScheme)).OnClick(click.Right(func() { - i.Restart() - })) - } - } - updateSuccessIcon := pango.Icon("mdi-reload") - updatingIcon := pango.Icon("mdi-update") - updateFailIcon := pango.Icon("mdi-reload-alert") - garbageFullIcon := pango.Icon("mdi-delete") - garbageEmptyingIcon := pango.Icon("mdi-delete-restore") - garbageEmptyIcon := pango.Icon("mdi-delete-outline") - barista.Add(group.Simple(systemd.Service("nixos-upgrade").Output(outputServiceStatus(systemd.StateInactive, systemd.StateActivating, updateSuccessIcon, updatingIcon, updateFailIcon)), - systemd.Service("nix-gc").Output(outputServiceStatus(systemd.StateInactive, systemd.StateActivating, garbageEmptyIcon, garbageEmptyingIcon, garbageFullIcon)))) - emacsIcon := pango.Icon("mdi-alpha-e-circle") - barista.Add(systemd.UserService("emacs").Output(outputServiceStatus(systemd.StateActive, systemd.StateActivating, emacsIcon, emacsIcon, emacsIcon))) - - // Display space left on / - storageIcon := pango.Icon("mdi-database") - barista.Add(diskspace.New("/").Output(func(i diskspace.Info) bar.Output { - used := i.UsedPct() - var colorScheme string - if used >= 90 { - colorScheme = "bad" - } else if used >= 50 { - colorScheme = "degraded" - } else { - colorScheme = "good" - } - return outputs.Pango(storageIcon, pango.Textf(" %d%%", used)).Color(colors.Scheme(colorScheme)) - })) - - // Check connection to the Mullvad VPN - mullvadIsUpRe := regexp.MustCompile(`^You are connected to Mullvad`) - mullvadServerRe := regexp.MustCompile(`\(server (.*)\)`) - mullvadIpRe := regexp.MustCompile(`Your IP address is (.*)`) - client := &http.Client{Timeout: 3 * time.Second} - incognitoIcon := pango.Icon("mdi-incognito") - incognitoOffIcon := pango.Icon("mdi-incognito-off") - barista.Add(funcs.Every(5*time.Second, func(s bar.Sink) { - icon := incognitoOffIcon - message := pango.Text("") - colorScheme := "bad" - res, err := client.Get("https://am.i.mullvad.net/connected") - if !s.Error(err) { - status, err := io.ReadAll(res.Body) - res.Body.Close() - if !s.Error(err) { - var re *regexp.Regexp - if mullvadIsUpRe.Match(status) { - re = mullvadServerRe - colorScheme = "good" - icon = incognitoIcon - } else { - re = mullvadIpRe - colorScheme = "degraded" - } - result := re.FindSubmatch(status) - if len(result) >= 2 { - message = pango.Textf(" %s", result[1]) - } - } - } - client.CloseIdleConnections() - s.Output(outputs.Pango(icon, message).Color(colors.Scheme(colorScheme))) - })) - - // Display the wifi status - wifiOffIcon := pango.Icon("mdi-wifi-off") - wifiRefreshIcon := pango.Icon("mdi-wifi-refresh") - wifiOnIcon := pango.Icon("mdi-wifi") - barista.Add(wlan.Any().Output(func(w wlan.Info) bar.Output { - var output *pango.Node - var colorScheme string - switch { - case w.Connected(): - output = pango.New(wifiOnIcon, pango.Textf(" %s", w.SSID)) - colorScheme = "good" - case w.Connecting(): - output = wifiRefreshIcon - colorScheme = "degraded" - default: - output = wifiOffIcon - colorScheme = "bad" - } - return outputs.Pango(output).Color(colors.Scheme(colorScheme)) - })) - - // Display the ethernet status - ethernetCableOnIcon := pango.Icon("mdi-ethernet-cable") - ethernetCableOffIcon := pango.Icon("mdi-ethernet-cable-off") - barista.Add(netinfo.Prefix("e").Output(func(s netinfo.State) bar.Output { - var output *pango.Node - var colorScheme string - switch { - case s.Connected(): - ip := "<no ip>" - if len(s.IPs) > 0 { - ip = s.IPs[0].String() - } - output = pango.New(ethernetCableOnIcon, pango.Textf(" %s", ip)) - colorScheme = "good" - case s.Connecting(): - output = ethernetCableOnIcon - colorScheme = "degraded" - default: - output = ethernetCableOffIcon - colorScheme = "bad" - } - return outputs.Pango(output).Color(colors.Scheme(colorScheme)) - })) - - // Display the battery status - batteryIcons := [11]*pango.Node{pango.Icon("mdi-battery-outline"), - pango.Icon("mdi-battery-10"), - pango.Icon("mdi-battery-20"), - pango.Icon("mdi-battery-30"), - pango.Icon("mdi-battery-40"), - pango.Icon("mdi-battery-50"), - pango.Icon("mdi-battery-60"), - pango.Icon("mdi-battery-70"), - pango.Icon("mdi-battery-80"), - pango.Icon("mdi-battery-90"), - pango.Icon("mdi-battery")} - batteryChargingIcons := [11]*pango.Node{pango.Icon("mdi-battery-charging-outline"), - pango.Icon("mdi-battery-charging-10"), - pango.Icon("mdi-battery-charging-20"), - pango.Icon("mdi-battery-charging-30"), - pango.Icon("mdi-battery-charging-40"), - pango.Icon("mdi-battery-charging-50"), - pango.Icon("mdi-battery-charging-60"), - pango.Icon("mdi-battery-charging-70"), - pango.Icon("mdi-battery-charging-80"), - pango.Icon("mdi-battery-charging-90"), - pango.Icon("mdi-battery-charging-100")} - barista.Add(battery.All().Output(func(b battery.Info) bar.Output { - switch b.Status { - case battery.Disconnected, battery.Unknown: - return nil - default: - var icons [11]*pango.Node - var colorScheme string - if b.Status == battery.Charging { - icons = batteryChargingIcons - colorScheme = "good" - } else { - icons = batteryIcons - if b.RemainingPct() <= 10 { - colorScheme = "bad" - } else if b.RemainingPct() <= 20 { - colorScheme = "degraded" - } else { - colorScheme = "good" - } - } - icon := icons[b.RemainingPct()/10] - return outputs.Pango(icon, pango.Textf(" %d%%", b.RemainingPct())).Color(colors.Scheme(colorScheme)) - } - })) - - // Display brightness - brightnessHighIcon := pango.Icon("mdi-lightbulb-on") - brightnessMidIcon := pango.Icon("mdi-lightbulb-on-outline") - brightnessLowIcon := pango.Icon("mdi-lightbulb-outline") - ReadBrightness := func(name string) (int, error) { - valueStr, err := os.ReadFile("/sys/class/backlight/intel_backlight/" + name) - if err != nil { - return 0, err - } - return strconv.Atoi(string(valueStr[:len(valueStr)-1])) - } - brightnessMax, _ := ReadBrightness("max_brightness") // always non-zero, unless there's an error - barista.Add(funcs.Every(time.Second, func(s bar.Sink) { - brightness, err := ReadBrightness("brightness") - if !s.Error(err) { - value := (brightness * 100) / brightnessMax - var icon *pango.Node - if value <= 30 { - icon = brightnessLowIcon - } else if value < 70 { - icon = brightnessMidIcon - } else { - icon = brightnessHighIcon - } - s.Output(outputs.Pango(icon, pango.Textf(" %d%%", value))) - } - })) - - // Display output volume - volumeOffIcon := pango.Icon("mdi-volume-variant-off") - volumeLowIcon := pango.Icon("mdi-volume-low") - volumeMidIcon := pango.Icon("mdi-volume-medium") - volumeHighIcon := pango.Icon("mdi-volume-high") - barista.Add(volume.New(pulseaudio.DefaultSink()).Output(func(v volume.Volume) bar.Output { - volume := v.Pct() - var icon *pango.Node - if volume == 0 || v.Mute { - icon = volumeOffIcon - } else if volume <= 30 { - icon = volumeLowIcon - } else if volume <= 70 { - icon = volumeMidIcon - } else { - icon = volumeHighIcon - } - return outputs.Pango(icon, pango.Textf(" %d%%", volume)) - })) - - // Display microphone volume - microphoneOffIcon := pango.Icon("mdi-microphone-off") - microphoneIcon := pango.Icon("mdi-microphone") - barista.Add(volume.New(pulseaudio.DefaultSource()).Output(func(v volume.Volume) bar.Output { - volume := v.Pct() // the value returned by pulseaudio may be weird - var icon *pango.Node - if volume == 0 || v.Mute { - icon = microphoneOffIcon - } else { - icon = microphoneIcon - } - return outputs.Pango(icon, pango.Textf(" %d%%", volume)) - })) - - barista.Add(clock.Local().OutputFormat("2006-01-02 15:04:05")) - - panic(barista.Run()) -} diff --git a/modules/home-manager/personal/gui/x/i3/default.nix b/modules/home-manager/personal/gui/x/i3/default.nix index 483a0d4..657affc 100644 --- a/modules/home-manager/personal/gui/x/i3/default.nix +++ b/modules/home-manager/personal/gui/x/i3/default.nix @@ -9,7 +9,7 @@ let in { imports = [ - ./bar + ./bar.nix ./keybindings.nix ./startup.nix ]; |
