Add keybindings help overlay

This commit is contained in:
Aleksey Samoilov 2024-01-27 23:26:08 +04:00
parent cdc68187e0
commit d96b91f97b
8 changed files with 228 additions and 48 deletions

View file

@ -0,0 +1,2 @@
#!/bin/sh
/usr/share/river/scripts/sbdp.py $HOME/.config/river/keybindings.sh | jq --raw-output 'sort_by(.category) | .[] | .action + ": <b>" + .keybinding + "</b>"'

View file

@ -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;
}

View file

@ -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

View file

@ -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

View file

@ -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"

View file

@ -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;
}

13
usr/share/river/scripts/help.sh Executable file
View file

@ -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

136
usr/share/river/scripts/sbdp.py Executable file
View file

@ -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<category>.+?) // (?P<action>.+?)\s+(// (?P<keybinding>.+?))*##"
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<variable>\$.+?)\s(?P<value>.+)?"
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))