diff --git a/etc/skel/.config/nwg-wrapper/help.sh b/etc/skel/.config/nwg-wrapper/help.sh
new file mode 100755
index 0000000..c7a7f90
--- /dev/null
+++ b/etc/skel/.config/nwg-wrapper/help.sh
@@ -0,0 +1,2 @@
+#!/bin/sh
+/usr/share/sway/scripts/sbdp.py $HOME/.config/sway/config | 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/sway/config.d/40-autostart-applications.conf b/etc/sway/config.d/40-autostart-applications.conf
index 3da6ac4..e81453a 100644
--- a/etc/sway/config.d/40-autostart-applications.conf
+++ b/etc/sway/config.d/40-autostart-applications.conf
@@ -8,6 +8,7 @@ exec {
$wlsunset
$autotiling
$term_server
+ $help_menu
$cliphist_store
$cliphist_watch
$autoname_workspaces
diff --git a/etc/sway/variables b/etc/sway/variables
index 8c6849a..d21d124 100644
--- a/etc/sway/variables
+++ b/etc/sway/variables
@@ -15,7 +15,7 @@ set $term_cwd $term -D "$(/usr/share/sway/scripts/swaycwd.sh 2>/dev/null || echo
set $term_server foot --server
set $term_float footclient -a floating_shell
-# rofi theme
+# Rofi theme
set $rofi_theme "* {lightbg: $base; background: $base; lightfg: $blue; foreground: $text; border-color: $blue;} window {border: 2;}"
# Your preferred application launcher
@@ -33,7 +33,7 @@ set $volume_bar /usr/share/sway/scripts/volume-notify.sh
# Brightness notification
set $brightness_bar /usr/share/sway/scripts/brightness-notify.sh
-# brightness control
+# Brightness control
set $brightness_step bash -c 'echo $(( $(light -Mr) / 100 * 5 < 1 ? 1 : $(( $(light -Mr) / 100 * 5 )) ))'
set $brightness_up light -r -A $($brightness_step) && $brightness_bar
set $brightness_down light -r -U $($brightness_step) && $brightness_bar
@@ -43,16 +43,22 @@ set $volume_down pulsemixer --change-volume -5 && $volume_bar
set $volume_up pulsemixer --change-volume +5 && $volume_bar
set $volume_mute pulsemixer --toggle-mute && $volume_bar
-# clipboard history
+# Clipboard history
set $clipboard cliphist list | rofi -dmenu -font "$gui-font" -p "Select item to copy:" -lines 10 -width 35 | cliphist decode | wl-copy
set $clipboard-del cliphist list | rofi -dmenu -font "$gui-font" -p "Select item to delete:" -lines 10 -width 35 | cliphist delete
# Pulseaudo command
set $pulseaudio $term_float pulsemixer
-# calendar application
+# Calendar application
set $calendar $term_float calcurse
+# Help overlay
+set $help_menu '[ -x "$(command -v nwg-wrapper)" ] && [ -f $HOME/.config/nwg-wrapper/help.sh ] && /usr/share/sway/scripts/help.sh'
+
+# Help overlay command
+set $help /usr/share/sway/scripts/help.sh --toggle
+
### Idle configuration
# This will lock your screen after 300 seconds of inactivity, then turn off
# your displays after another 300 seconds, and turn your screens back on when
@@ -71,7 +77,7 @@ set $idle swayidle -w \
before-sleep $lock \
lock $lock &
-# workspace names
+# Workspace names
set $ws1 number 1
set $ws2 number 2
set $ws3 number 3
@@ -83,7 +89,7 @@ set $ws8 number 8
set $ws9 number 9
set $ws10 number 10
-# screenshot
+# Screenshot
set $grimshot /usr/bin/grimshot
set $pipe_output $grimshot save output -
set $pipe_selection $grimshot save window -
diff --git a/usr/share/sway/scripts/help.sh b/usr/share/sway/scripts/help.sh
new file mode 100755
index 0000000..4e4e455
--- /dev/null
+++ b/usr/share/sway/scripts/help.sh
@@ -0,0 +1,15 @@
+#!/bin/sh
+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
+ for output in $(swaymsg -t get_outputs --raw | jq -r '.[].name'); do
+ nwg-wrapper -o "$output" -sv ${VISIBILITY_SIGNAL} -sq ${QUIT_SIGNAL} -s help.sh -p left -a end &
+ done
+fi
diff --git a/usr/share/sway/scripts/sbdp.py b/usr/share/sway/scripts/sbdp.py
new file mode 100755
index 0000000..4a0a09c
--- /dev/null
+++ b/usr/share/sway/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 = '/etc/sway/config'
+
+
+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(' ')[1]
+
+
+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))