aboutsummaryrefslogtreecommitdiffstats
path: root/keybinds/Binds.js
diff options
context:
space:
mode:
authorDanilo M. <danix@danix.xyz>2026-09-25 19:08:15 +0200
committerDanilo M. <danix@danix.xyz>2026-09-25 19:08:15 +0200
commitea063fa984ef775950c840013462a49355576d0b (patch)
tree958d2618693ae83586f932e7b3a131ce68d823ee /keybinds/Binds.js
parent2fb72210ad5d8151718930b87fb7194467e600a4 (diff)
downloadquickshell-ea063fa984ef775950c840013462a49355576d0b.tar.gz
quickshell-ea063fa984ef775950c840013462a49355576d0b.zip
feat(keybinds): group hyprctl binds by description
Binds.js parses hyprctl binds -j output into display groups for the upcoming keybind reminder overlay. Group name and row label come from the "Group: Label" convention in each bind's description; a bind without one still surfaces under "Undescribed" rather than vanishing, so a gap in the Hyprland config stays visible. Pure functions with no QML dependency, so test_binds.js checks them directly with node, stripping the .pragma library line the QML runtime requires but node does not understand. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Diffstat (limited to 'keybinds/Binds.js')
-rw-r--r--keybinds/Binds.js50
1 files changed, 50 insertions, 0 deletions
diff --git a/keybinds/Binds.js b/keybinds/Binds.js
new file mode 100644
index 0000000..5c0ce2d
--- /dev/null
+++ b/keybinds/Binds.js
@@ -0,0 +1,50 @@
+.pragma library
+// Copyright (C) 2026 Danilo M. <danix@danix.xyz>
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License version 2 as
+// published by the Free Software Foundation.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// hyprctl binds -j into display groups. Pure, so node can check it:
+// see test_binds.js.
+
+// Modmask bits, in the order they are written in keybindings.lua.
+const MODS = [[64, "SUPER"], [4, "CTRL"], [8, "ALT"], [1, "SHIFT"]];
+
+function mods(mask) {
+ return MODS.filter(m => mask & m[0]).map(m => m[1]);
+}
+
+function keys(bind) {
+ return mods(bind.modmask).concat([bind.key]).join(" + ");
+}
+
+// A description reads "Group: Label". A bind without one still shows, last,
+// so a gap in the config is visible rather than silently missing.
+function group(binds) {
+ const groups = [];
+ const byName = {};
+ const undescribed = [];
+ for (const b of binds) {
+ const d = b.description || "";
+ if (!d) {
+ undescribed.push({ keys: keys(b), label: "no description" });
+ continue;
+ }
+ const i = d.indexOf(": ");
+ const name = i < 0 ? "Other" : d.slice(0, i);
+ const label = i < 0 ? d : d.slice(i + 2);
+ if (!byName[name]) {
+ byName[name] = { name: name, rows: [] };
+ groups.push(byName[name]);
+ }
+ byName[name].rows.push({ keys: keys(b), label: label });
+ }
+ if (undescribed.length) groups.push({ name: "Undescribed", rows: undescribed });
+ return groups;
+}