# When the keyboard-layout indicator earns a place in the bar, and how a # whole-swap bar is held to the same answer (BACKLOG #109). # # Pure so checks.waybar-language can unit-test the contract without building # a bar. Consumed by modules/home/waybar.nix. { lib }: rec { # The session's layouts are the comma-separated kb_layout. # nomarchy.keyboard.layouts is deliberately NOT among them — hyprland.nix # keeps it as the pool the new-keyboard picker offers first and never # merges it into kb_layout — so listing candidates cannot by itself make # the current layout ambiguous. sessionLayouts = layout: lib.filter (l: l != "") (lib.splitString "," layout); # The indicator answers "which layout am I typing in?", so it is worth bar # space exactly when that has more than one answer. # # devices = declared nomarchy.keyboard.devices (submodules with .layout) # remembered = settings.keyboard.devices from the in-flake state: what the # new-keyboard watcher writes the moment a layout is chosen. # These only graduate into `devices` at the next rebuild, so a # bar reading `devices` alone stays wrong for exactly as long # as the memory is fresh — which is when it matters most. # # Counting devices rather than layouts is the trap: remembering "us" for a # device on a "us" session adds no second answer, and the rows a keyboard's # extra HID collections leave behind are all of that kind. show = { layout, devices ? { }, remembered ? { } }: let session = sessionLayouts layout; perDevice = lib.mapAttrsToList (_: d: d.layout) devices ++ lib.attrValues remembered; in lib.length session > 1 || lib.any (l: ! lib.elem l session) perDevice; # A whole-swap authors its bar in full and every one of them lists the # language module unconditionally, so without this a single-layout setup # showed on a swapped bar what the generated bar hides. Filter the swap # through the one answer rather than asking four hand-written files to # re-derive it (CONVENTIONS: the parity rule). gate = showLanguage: bar: if showLanguage then bar else lib.mapAttrs (n: v: if lib.hasPrefix "modules-" n && builtins.isList v then lib.filter (m: m != "hyprland/language") v else v) bar; }