diff --git a/etc/skel/.config/nwg-wrapper/help.sh b/etc/skel/.config/nwg-wrapper/help.sh
new file mode 100755
index 0000000..ff67bce
--- /dev/null
+++ b/etc/skel/.config/nwg-wrapper/help.sh
@@ -0,0 +1,2 @@
+#!/bin/sh
+/usr/share/river/scripts/sbdp.py $HOME/.config/river/keybindings.sh | jq --raw-output 'sort_by(.category) | .[] | .action + ": " + .keybinding + ""'
diff --git a/etc/skel/.config/nwg-wrapper/style.css b/etc/skel/.config/nwg-wrapper/style.css
new file mode 100644
index 0000000..5b0309c
--- /dev/null
+++ b/etc/skel/.config/nwg-wrapper/style.css
@@ -0,0 +1,13 @@
+window {
+ background-color: @theme_bg_color;
+ font-size: medium;
+ color: #cad3f5;
+}
+
+#box-inner {
+ border-radius: 0px;
+ border-style: solid;
+ border-width: 2px;
+ border-color: #8aadf4;
+ padding: 10px;
+}
diff --git a/etc/skel/.config/river/init b/etc/skel/.config/river/init
index ebee194..33029d2 100755
--- a/etc/skel/.config/river/init
+++ b/etc/skel/.config/river/init
@@ -45,6 +45,9 @@ riverctl spawn $HOME/.azotebg
# Include keybindings
riverctl spawn $HOME/.config/river/keybindings.sh
+# Keybindings help overlay
+riverctl spawn /usr/share/river/scripts/help.sh & disown
+
# Clipboard daemon
pkill wl-paste
wl-paste --watch cliphist store & disown
diff --git a/etc/skel/.config/river/keybindings.sh b/etc/skel/.config/river/keybindings.sh
index ea7447a..91a3efe 100755
--- a/etc/skel/.config/river/keybindings.sh
+++ b/etc/skel/.config/river/keybindings.sh
@@ -25,106 +25,108 @@ riverctl map normal "$mod" Print spawn "/usr/bin/river-grimshot save area - | sw
# Set keyboard layout. See man riverctl
# riverctl keyboard-layout -options "grp:caps_toggle" "us,ru"
-# Binding to reload the configuration (good for edits on bindings or adding new stuff
+## Action // Reload River Configuration // $mod+R ##
riverctl map normal $mod R spawn $HOME/.config/river/init
-# $mod+Shift+Return to start an instance of terminal
+## Launch // Terminal // $mod+Return ##
riverctl map normal $mod Return spawn $term
-# $mod+D to start an instance of application launcher
+## Launch // Launcher // $mod+D ##
riverctl map normal $mod D spawn "$launcher"
-# $mod+Q to close the focused view
-riverctl map normal $mod+Shift Q close
-
-# $mod+Shift+E to run nwg-bar (logout, restart, shutdown, etc)
+## Action // Exit River // $mod+Shift+E ##
riverctl map normal $mod+Shift E spawn nwg-bar
-# $mod+J and $mod+K to focus the next/previous view in the layout stack
+## Action // Kill focused window // $mod+Q ##
+riverctl map normal $mod+Shift Q close
+
+## Navigation // Focus the next/previous view in the layout stack // $mod+{J,K} ##
riverctl map normal $mod J focus-view next
riverctl map normal $mod K focus-view previous
-# $mod+Shift+J and $mod+Shift+K to swap the focused view with the next/previous
-# view in the layout stack
+## Navigation // Swap the focused view in the layout stack // $mod+Shift+{J,K} ##
riverctl map normal $mod+Shift J swap next
riverctl map normal $mod+Shift K swap previous
-# $mod+Period and $mod+Comma to focus the next/previous output
+## Navigation // Focus the next/previous output // $mod+{, .} ##
riverctl map normal $mod Period focus-output next
riverctl map normal $mod Comma focus-output previous
-# $mod+Shift+{Period,Comma} to send the focused view to the next/previous output
+## Navigation // Send the focused view to the next/previous output // $mod+Shift+{, .} ##
riverctl map normal $mod+Shift Period send-to-output next
riverctl map normal $mod+Shift Comma send-to-output previous
-# $mod+Return to bump the focused view to the top of the layout stack
+## Navigation // Bump the focused view to the top of the layout stack // $mod+Shift+Return ##
riverctl map normal $mod+Shift Return zoom
-# $mod+H and $mod+L to decrease/increase the main ratio of rivertile(1)
+## Navigation // Decrease/increase the main ratio of rivertile // $mod+{H,L} ##
riverctl map normal $mod H send-layout-cmd rivertile "main-ratio -0.05"
riverctl map normal $mod L send-layout-cmd rivertile "main-ratio +0.05"
-# $mod+Shift+H and $mod+Shift+L to increment/decrement the main count of rivertile(1)
+## Navigation // Increment/decrement the main count of rivertile // $mod+Shift+{H,L} ##
riverctl map normal $mod+Shift H send-layout-cmd rivertile "main-count +1"
riverctl map normal $mod+Shift L send-layout-cmd rivertile "main-count -1"
-# $mod+Alt+{H,J,K,L} to move views
+## Navigation // Move views // $mod+Alt+{H,J,K,L} ##
riverctl map normal $mod+Alt H move left 100
riverctl map normal $mod+Alt J move down 100
riverctl map normal $mod+Alt K move up 100
riverctl map normal $mod+Alt L move right 100
-# $mod+Alt+Control+{H,J,K,L} to snap views to screen edges
+## Navigation // Snap views to screen edges // $mod+Alt+Control+{H,J,K,L}##
riverctl map normal $mod+Alt+Control H snap left
riverctl map normal $mod+Alt+Control J snap down
riverctl map normal $mod+Alt+Control K snap up
riverctl map normal $mod+Alt+Control L snap right
-# $mod+Alt+Shift+{H,J,K,L} to resize views
+## Navigation // Resize views // $mod+Alt+Shift+{H,J,K,L} ##
riverctl map normal $mod+Alt+Shift H resize horizontal -100
riverctl map normal $mod+Alt+Shift J resize vertical 100
riverctl map normal $mod+Alt+Shift K resize vertical -100
riverctl map normal $mod+Alt+Shift L resize horizontal 100
-# $mod + Left Mouse Button to move views
+## Navigation // Move views with mouse // $mod + Left Mouse Button ##
riverctl map-pointer normal $mod BTN_LEFT move-view
-# $mod + Right Mouse Button to resize views
+## Navigation // Resize views with mouse // $mod + Right Mouse Button ##
riverctl map-pointer normal $mod BTN_RIGHT resize-view
-# $mod + Middle Mouse Button to toggle float
+## Navigation // Toggle float // $mod + Middle Mouse Button ##
riverctl map-pointer normal $mod BTN_MIDDLE toggle-float
+# Tags navigation
+
+## Navigation // Focus tag [0-8] // $mod+[1-9] ##
+## Navigation // Tag focused view with tag [0-8] // $mod+Shift+[1-9] ##
+## Navigation // Toggle focus of tag [0-8] // mod+Control+[1-9] ##
+## Navigation // Toggle tag [0-8] of focused view // $mod+Shift+Control+[1-9] ##
+
for i in $(seq 1 9)
do
tags=$((1 << ($i - 1)))
- # $mod+[1-9] to focus tag [0-8]
riverctl map normal $mod $i set-focused-tags $tags
- # $mod+Shift+[1-9] to tag focused view with tag [0-8]
riverctl map normal $mod+Shift $i set-view-tags $tags
- # $mod+Control+[1-9] to toggle focus of tag [0-8]
riverctl map normal $mod+Control $i toggle-focused-tags $tags
- # $mod+Shift+Control+[1-9] to toggle tag [0-8] of focused view
riverctl map normal $mod+Shift+Control $i toggle-view-tags $tags
done
-# $mod+0 to focus all tags
-# $mod+Shift+0 to tag focused view with all tags
+## Navigation // Focus all tags // $mod+0 ##
+## Navigation // Tag focused view with all tags // $mod+Shift+0 ##
all_tags=$(((1 << 32) - 1))
riverctl map normal $mod 0 set-focused-tags $all_tags
riverctl map normal $mod+Shift 0 set-view-tags $all_tags
-# $mod+Space to toggle float
+## Action // Toggle floating // $mod+Space ##
riverctl map normal $mod Space toggle-float
-# $mod+F to toggle fullscreen
+## Action // Toggle fullscreen // $mod+F ##
riverctl map normal $mod F toggle-fullscreen
-# $mod+{Up,Right,Down,Left} to change layout orientation
+## Navigation // Change layout orientation // $mod+{↑ ↓ ← →} ##
riverctl map normal $mod Up send-layout-cmd rivertile "main-location top"
riverctl map normal $mod Right send-layout-cmd rivertile "main-location right"
riverctl map normal $mod Down send-layout-cmd rivertile "main-location bottom"
@@ -134,10 +136,10 @@ riverctl map normal $mod Left send-layout-cmd rivertile "main-location left"
# normal mode. This makes it useful for testing a nested wayland compositor
riverctl declare-mode passthrough
-# $mod+F11 to enter passthrough mode
+## Action // Enter passthrough mode // $mod+F11 ##
riverctl map normal $mod F11 enter-mode passthrough
-# $mod+F11 to return to normal mode
+## Action // Return to normal mode // $mod+F11 ##
riverctl map passthrough $mod F11 enter-mode normal
# Various media key mapping examples for both normal and locked mode which do
diff --git a/etc/skel/.config/waybar/config.jsonc b/etc/skel/.config/waybar/config.jsonc
index 8401411..ca77d8d 100644
--- a/etc/skel/.config/waybar/config.jsonc
+++ b/etc/skel/.config/waybar/config.jsonc
@@ -7,6 +7,7 @@
"modules-right": [
"tray",
"custom/playerctl",
+ "custom/help",
"custom/wlsunset",
"idle_inhibitor",
"custom/dunst",
@@ -51,6 +52,12 @@
"signal": 5
},
+ "custom/help": {
+ "format": "",
+ "on-click": "/usr/share/river/scripts/help.sh --toggle",
+ "tooltip": "false"
+ },
+
"custom/wlsunset": {
"interval": "once",
"tooltip": true,
@@ -73,7 +80,6 @@
"activated": "",
"deactivated": ""
},
- "start-activated": true,
"tooltip": true,
"tooltip-format-activated": "power-saving disabled",
"tooltip-format-deactivated": "power-saving enabled"
diff --git a/etc/skel/.config/waybar/style.css b/etc/skel/.config/waybar/style.css
index 912de60..4a7bcf3 100644
--- a/etc/skel/.config/waybar/style.css
+++ b/etc/skel/.config/waybar/style.css
@@ -76,6 +76,7 @@ window#waybar.hidden {
}
#clock,
+#custom-help,
#custom-playerctl,
#custom-power,
#custom-wlsunset,
@@ -113,42 +114,46 @@ window#waybar.hidden {
#tray {
padding-left: 5px;
padding-right: 5px;
- color: @rosewater;
-}
-
-#custom-playerctl {
color: @flamingo;
}
-#custom-wlsunset {
+#custom-playerctl {
color: @pink;
}
-#idle_inhibitor {
+#custom-help {
color: @mauve;
}
-#custom-dunst {
+#custom-wlsunset {
color: @red;
}
-#custom-clipboard {
+#idle_inhibitor {
color: @maroon;
}
-#cpu {
+#custom-dunst {
color: @peach;
}
-#memory {
+#custom-clipboard {
color: @yellow;
}
+#cpu {
+ color: @green;
+}
+
+#memory {
+ color: @teal;
+}
+
#battery {
animation-timing-function: linear;
animation-iteration-count: infinite;
animation-direction: alternate;
- color: @green;
+ color: @sky;
}
#battery.warning {
@@ -174,7 +179,7 @@ label:focus {
}
#network {
- color: @teal;
+ color: @sapphire;
}
#network.disconnected {
@@ -182,7 +187,7 @@ label:focus {
}
#bluetooth {
- color: @sky;
+ color: @blue;
}
#bluetooth.disabled {
@@ -190,7 +195,7 @@ label:focus {
}
#pulseaudio {
- color: @sapphire;
+ color: @lavender;
}
#pulseaudio.muted {
@@ -198,5 +203,5 @@ label:focus {
}
#custom-power {
- color: @lavender;
+ color: @text;
}
diff --git a/usr/share/river/scripts/help.sh b/usr/share/river/scripts/help.sh
new file mode 100755
index 0000000..6d506da
--- /dev/null
+++ b/usr/share/river/scripts/help.sh
@@ -0,0 +1,13 @@
+#!/bin/bash
+set -x
+# toggles the help wrapper state
+
+VISIBILITY_SIGNAL=30
+QUIT_SIGNAL=31
+
+if [ "$1" = "--toggle" ]; then
+ pkill -f -${VISIBILITY_SIGNAL} nwg-wrapper
+else
+ pkill -f -${QUIT_SIGNAL} nwg-wrapper
+ nwg-wrapper -i -sv ${VISIBILITY_SIGNAL} -sq ${QUIT_SIGNAL} -s help.sh -p left -a end &
+fi
diff --git a/usr/share/river/scripts/sbdp.py b/usr/share/river/scripts/sbdp.py
new file mode 100755
index 0000000..332c736
--- /dev/null
+++ b/usr/share/river/scripts/sbdp.py
@@ -0,0 +1,136 @@
+#!/usr/bin/python3
+import sys
+import glob
+import re
+from typing import Text
+import json
+
+if len(sys.argv) >= 2:
+ rootPath = sys.argv[1]
+else:
+ rootPath = './keybindings.sh'
+
+
+def readFile(filePath):
+ try:
+ paths = glob.glob(filePath)
+ except (Exception, IndexError):
+ print("couldn't resolve glob:", filePath)
+ paths = []
+
+ allLines: list[str] = []
+ for path in paths:
+ allLines = allLines + open(path, "r").readlines()
+
+ finalLines: list[str] = []
+ for line in allLines:
+ if re.search(r'^include\s+(.+?)$', line):
+ nextPath = re.findall(r'^include\s+(.+?)$', line)[0]
+ finalLines = finalLines + readFile(nextPath)
+ else:
+ finalLines = finalLines + [line]
+
+ return finalLines
+
+
+lines = readFile(rootPath)
+
+
+def findKeybindingForLine(lineNumber: int, lines: list[str]):
+ return lines[lineNumber + 1].split(' ')[3]
+
+
+class DocsConfig:
+ category: Text
+ action: Text
+ keybinding: Text
+
+
+def getDocsConfig(lines: list[str]):
+ docsLineRegex = r"^## (?P.+?) // (?P.+?)\s+(// (?P.+?))*##"
+ docsConfig: list[DocsConfig] = []
+ for index, line in enumerate(lines):
+ match = re.match(docsLineRegex, line)
+ if match:
+ config = DocsConfig()
+ config.category = match.group('category')
+ config.action = match.group('action')
+ config.keybinding = match.group('keybinding')
+ if config.keybinding is None:
+ config.keybinding = findKeybindingForLine(index, lines)
+ docsConfig = docsConfig + [config]
+ return docsConfig
+
+
+def getSymbolDict(lines: list[str]):
+ setRegex = r"^set\s+(?P\$.+?)\s(?P.+)?"
+ dictionary = {}
+ for line in lines:
+ match = re.match(setRegex, line)
+ if match:
+ if match.group('variable'):
+ dictionary[match.group('variable')] = match.group('value')
+ return dict(dictionary)
+
+
+translations = {
+ 'Mod1': "Alt",
+ 'Mod2': "NumLk",
+ 'Mod3': "בּ",
+ 'Mod4': "",
+ 'Mod5': "Scroll",
+ 'question': "?",
+ 'space': "␣",
+ 'minus': "-",
+ 'plus': '+',
+ 'Return': "Enter",
+ 'XF86AudioRaiseVolume': "",
+ 'XF86AudioLowerVolume': "",
+ 'XF86AudioMute': "",
+ 'XF86AudioMicMute': '',
+ 'XF86MonBrightnessUp': "",
+ 'XF86MonBrightnessDown': "",
+ 'XF86PowerOff': "",
+ 'XF86TouchpadToggle': "Toggle Touchpad"
+}
+
+
+def translate(word: Text, dictionary: dict):
+ try:
+ return dictionary[word.strip()]
+ except KeyError:
+ return word.strip()
+
+
+def replaceBindingFromMap(binding: Text, dictionary: dict):
+ elements = binding.split('+')
+ resultElements = []
+ for el in elements:
+ translation = translate(translate(el, dictionary), translations)
+ resultElements = resultElements + [translation]
+
+ return " + ".join(resultElements)
+
+
+def sanitize(configs: list[DocsConfig], symbolDict: dict):
+ for index, config in enumerate(configs):
+ config.keybinding = replaceBindingFromMap(
+ config.keybinding, symbolDict)
+ configs[index] = config
+ return configs
+
+
+def getDocsList(lines: list[str]):
+ docsConfig = getDocsConfig(lines)
+ symbolDict = getSymbolDict(lines)
+ sanitizedConfig = sanitize(docsConfig, symbolDict)
+ return sanitizedConfig
+
+
+docsList = getDocsList(lines)
+
+result = []
+for config in docsList:
+ result = result + [{'category': config.category,
+ 'action': config.action, 'keybinding': config.keybinding}]
+print(json.dumps(result))