Add sub-sheet navigation and cross-sheet search to the cheat sheet overlay

cheatsheet_to_shortcuts_json now recognizes a markdown link in a table's
first column (e.g. [Admin & Account Setup](cheatsheet_admin.md) in a
Command/Shortcut/Sheet table) and emits it as a navigable entry instead
of a literal shortcut.

cheatsheet_overlay renders such entries as clickable links; clicking one
loads and displays that file in place of the current one (path resolved
relative to the linking file, arbitrary depth, cycle-safe), with a
"< Back" affordance to return. A new "Search all sheets" checkbox
instead discovers and combines every sheet reachable from the root into
one filterable view. Everything reloads fresh from disk at the moment
it's needed (no caching across a click or toggle), so editing any of
these .md files takes effect on the very next use, same as the existing
per-invocation freshness for the root sheet.

Adds cheatsheet_admin.md as the first real sub-sheet: one-time/occasional
account and host setup tasks (personal dirs, gopass onboarding, PSI
home-sync) pulled out of the main operational reference, linked from a
new "Other cheat sheets" section in cheatsheet.md.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
lemke_handClaude Sonnet 5 committed 2026-09-09 14:55:25 +02:00
1 parent 9c4b29ee76
commit e4ec4376ee
5 files changed
+368 -128

No files matched your search

+13
View File
@@ -14,6 +14,7 @@ to quit.
## Table of contents
- [Other cheat sheets](#other-cheat-sheets)
- [Application & window shortcuts](#application--window-shortcuts)
- [Primary controls terminal only](#primary-controls-terminal-only)
- [Window tiling (gTile)](#window-tiling-gtile)
@@ -27,6 +28,18 @@ supports Markdown anchors, e.g. VS Code or GitHub/GitLab — the
terminal viewer doesn't follow them; use `/` search instead, see
above.)
## Other cheat sheets
In the `Super+F1` overlay, the entry below is clickable: it loads and
shows that file in place of this one, with a "← Back" link to return.
The "Search all sheets" checkbox next to the search box instead
searches this sheet and everything linked from it (however deep) all
at once.
| Sheet | Description |
|-------|--------------|
| [Admin & Account Setup](cheatsheet_admin.md) | One-time/occasional account and host setup tasks — gopass onboarding, personal dirs, PSI home-sync |
## Application & window shortcuts
| Shortcut | Action | Runs |
+28
View File
@@ -0,0 +1,28 @@
# Admin & Account Setup
One-time or occasional account/host setup tasks — not day-to-day
operation shortcuts, which live in the
[main cheat sheet](cheatsheet.md).
## Personal directories & sync
| Command | Description |
|---|---|
| `create_personal_dir.sh` | Create/verify a personal working directory under `/sf/bernina/config/personal/<username>` |
| `create-links-in-home` | Force-apply PSI's Partially Shared Home symlinks now (normally applied automatically at login) |
| `migrate_to_network_drive.sh` | Move a local dotfile onto PSI's Partially Shared Home and register it for sync across hosts |
| `sync_personal_config.sh` | Seed `.ipython`/`.condarc` onto PSI's Partially Shared Home for cross-host sync |
## gopass secrets
| Command | Description |
|---|---|
| `gopass_bernina_setup.sh` | One-shot onboarding for a human PSI account joining the gopass store |
| `gopass_bernina_service_setup.sh` | One-shot setup: give a service account (e.g. `gac-bernina`) access to the gopass store |
This is a hand-picked subset of the full script index (the "Scripts in
this directory" section of the main sheet still lists every one of
these too, alongside everything else) — pulled out here specifically
because they're setup/onboarding tasks a supporter reaches for
occasionally, not something to hunt for in the full operational
reference.
+299 -118
View File
@@ -14,6 +14,19 @@ isn't set), a stale PID number could otherwise get reused by a completely
unrelated process after reboot.
Dismiss: Escape, the close button, or pressing the trigger key again.
Sub-sheets: a shortcut entry with a "link" field (see
cheatsheet_to_shortcuts_json -- a markdown link in a table's first column,
e.g. `[Admin & Account Setup](cheatsheet_admin.md)`) renders as a clickable
link instead of a plain shortcut. Clicking it loads and displays that file
in place of the current one, with a "< Back" affordance to return; the
"Search all sheets" checkbox instead loads the whole reachable set (root
plus everything linked from it, however deep) into one combined, filterable
view. Both always re-read from disk at the moment they're needed -- nothing
is cached across a click or a checkbox toggle, matching the top-level
per-invocation freshness described in wait_for_source() below -- so editing
any of these .md files takes effect immediately, no restart of anything
required.
"""
import json
import os
@@ -30,6 +43,7 @@ gi.require_version("Gdk", "3.0")
from gi.repository import Gdk, GLib, Gtk # noqa: E402
MD_PATH = "/sf/bernina/bin/cheatsheet.md"
ROOT_TITLE = "Bernina Terminal Cheat Sheet"
GENERATOR = "/sf/bernina/bin/cheatsheet_to_shortcuts_json"
PID_FILE = os.path.join(
os.environ.get("XDG_RUNTIME_DIR", tempfile.gettempdir()),
@@ -63,6 +77,18 @@ window.cheatsheet-overlay {
background-color: rgba(255, 255, 255, 0.15);
border-radius: 6px;
}
.cs-back-btn {
color: #8ab4f8;
background: transparent;
border: none;
box-shadow: none;
padding: 2px 10px;
}
.cs-back-btn:hover {
color: #aecbfa;
background-color: rgba(255, 255, 255, 0.1);
border-radius: 6px;
}
.cs-category {
color: #8ab4f8;
font-size: 13px;
@@ -75,6 +101,20 @@ window.cheatsheet-overlay {
font-family: monospace;
font-size: 12px;
}
.cs-link-btn {
color: #8ab4f8;
background: transparent;
border: none;
box-shadow: none;
padding: 0;
}
.cs-link-btn:hover {
color: #aecbfa;
}
.cs-link-btn label {
text-decoration: underline;
font-size: 12px;
}
.cs-desc {
color: #e8eaed;
font-size: 12px;
@@ -88,16 +128,23 @@ window.cheatsheet-overlay {
background-color: rgba(255, 255, 255, 0.08);
color: #ffffff;
border: 1px solid rgba(255, 255, 255, 0.16);
margin-bottom: 8px;
}
.cs-search-all {
color: #9aa0a6;
font-size: 12px;
}
"""
def load_categories():
def load_categories(path):
"""Runs the generator fresh against `path` every call -- no caching --
so any edit to the source .md is picked up the moment it's needed,
whether that's a fresh Super+F1 press or a link/checkbox click on an
already-open overlay."""
with tempfile.NamedTemporaryFile(suffix=".json", delete=False) as tmp:
tmp_path = tmp.name
try:
subprocess.run([GENERATOR, MD_PATH, tmp_path], check=True)
subprocess.run([GENERATOR, path, tmp_path], check=True)
with open(tmp_path, encoding="utf-8") as f:
return json.load(f)
finally:
@@ -107,6 +154,40 @@ def load_categories():
pass
def discover_sheets(root_path, root_label):
"""BFS from root_path following every "link" target reachable from it
(however deep), re-reading each file fresh (see load_categories).
Returns [(path, label, categories), ...], root first; a link target
that fails to load (missing file, bad markdown) is skipped rather than
aborting the whole walk, and an already-visited path (a cycle, or two
sheets linking to the same target) is never re-queued.
Link paths are resolved relative to the *linking* file's own
directory, so a sub-sheet can itself link to siblings without needing
the full path spelled out."""
visited = set()
order = []
queue = [(os.path.normpath(root_path), root_label)]
while queue:
path, label = queue.pop(0)
if path in visited:
continue
visited.add(path)
try:
categories = load_categories(path)
except (subprocess.CalledProcessError, OSError, json.JSONDecodeError):
continue
order.append((path, label, categories))
base_dir = os.path.dirname(path)
for category in categories:
for shortcut in category["shortcuts"]:
link = shortcut.get("link")
if link:
target = os.path.normpath(os.path.join(base_dir, link))
if target not in visited:
queue.append((target, shortcut["key"]))
return order
def _is_our_process(pid):
"""True only if `pid` is actually still running *this* script -- not
just any process that happens to exist. Without this check, a PID
@@ -141,11 +222,13 @@ def already_showing():
return False
def category_box(category):
"""Returns (box, rows) -- rows is [(key_label, desc_label, search_text)],
handed to _apply_filter below so it can show/hide individual shortcuts
(and, via the whole box, an entire category) without rebuilding
anything."""
def category_box(category, on_link):
"""Returns (box, rows) -- rows is [(key_widget, desc_label, search_text)],
handed to _apply_filter so it can show/hide individual shortcuts (and,
via the whole box, an entire category) without rebuilding anything.
key_widget is a plain label for an ordinary shortcut, or a clickable
link-styled button (calling on_link(target) when pressed) for an entry
with a "link" field."""
box = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, spacing=0)
header = Gtk.Label(label=category["name"], xalign=0)
header.get_style_context().add_class("cs-category")
@@ -155,17 +238,27 @@ def category_box(category):
grid = Gtk.Grid(row_spacing=2, column_spacing=10)
rows = []
for row, shortcut in enumerate(category["shortcuts"]):
key_label = Gtk.Label(label=shortcut["key"], xalign=0)
key_label.get_style_context().add_class("cs-key")
key_label.set_line_wrap(True)
link = shortcut.get("link")
if link:
key_widget = Gtk.Button(label=shortcut["key"])
key_widget.get_style_context().add_class("cs-link-btn")
key_widget.set_relief(Gtk.ReliefStyle.NONE)
key_widget.connect(
"clicked",
lambda _b, target=link, label=shortcut["key"]: on_link(target, label),
)
else:
key_widget = Gtk.Label(label=shortcut["key"], xalign=0)
key_widget.get_style_context().add_class("cs-key")
key_widget.set_line_wrap(True)
desc_label = Gtk.Label(label=shortcut["description"], xalign=0)
desc_label.get_style_context().add_class("cs-desc")
desc_label.set_line_wrap(True)
desc_label.set_max_width_chars(40)
grid.attach(key_label, 0, row, 1, 1)
grid.attach(key_widget, 0, row, 1, 1)
grid.attach(desc_label, 1, row, 1, 1)
search_text = (shortcut["key"] + " " + shortcut["description"]).lower()
rows.append((key_label, desc_label, search_text))
rows.append((key_widget, desc_label, search_text))
box.pack_start(grid, False, False, 0)
return box, rows
@@ -179,135 +272,226 @@ def _apply_filter(query, entries):
query = query.strip().lower()
for cat_box, cat_name_lower, rows in entries:
if not query:
for key_label, desc_label, _search_text in rows:
key_label.set_visible(True)
for key_widget, desc_label, _search_text in rows:
key_widget.set_visible(True)
desc_label.set_visible(True)
cat_box.set_visible(True)
continue
cat_matches = query in cat_name_lower
any_visible = False
for key_label, desc_label, search_text in rows:
for key_widget, desc_label, search_text in rows:
match = cat_matches or query in search_text
key_label.set_visible(match)
key_widget.set_visible(match)
desc_label.set_visible(match)
any_visible = any_visible or match
cat_box.set_visible(any_visible)
def search_bar(entries):
entry = Gtk.SearchEntry()
entry.get_style_context().add_class("cs-search")
entry.set_placeholder_text("Search shortcuts... (Ctrl+F)")
entry.connect("changed", lambda e: _apply_filter(e.get_text(), entries))
return entry
class Overlay:
"""Holds the mutable pieces that change as the user navigates between
sheets or toggles "search all sheets", so link clicks and the checkbox
can rebuild just the content area in place rather than tearing down
and recreating the whole window."""
def __init__(self):
self.history = [] # stack of (path, label) visited via links
self.current = (MD_PATH, ROOT_TITLE)
self.search_all = False
self.entries = [] # current [(box, name_lower, rows), ...]
def title_bar(win):
"""Custom title bar: no window decorations are used (they'd break the
floating-overlay look), so dragging and closing are reimplemented by
hand here -- click-drag anywhere on the bar moves the window, the
button on the right closes it."""
bar = Gtk.EventBox()
bar.get_style_context().add_class("cs-titlebar")
def build_chrome(self):
self.win = Gtk.Window(type=Gtk.WindowType.TOPLEVEL)
self.win.set_title(ROOT_TITLE)
self.win.get_style_context().add_class("cheatsheet-overlay")
self.win.set_decorated(False)
self.win.set_position(Gtk.WindowPosition.CENTER)
self.win.set_keep_above(True)
self.win.set_skip_taskbar_hint(True)
self.win.set_skip_pager_hint(True)
self.win.set_type_hint(Gdk.WindowTypeHint.DIALOG)
row = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL)
title = Gtk.Label(label="Bernina Terminal Cheat Sheet", xalign=0)
title.get_style_context().add_class("cs-title")
row.pack_start(title, True, True, 0)
screen = self.win.get_screen()
visual = screen.get_rgba_visual()
if visual and screen.is_composited():
self.win.set_visual(visual)
close_btn = Gtk.Button(label="✕")
close_btn.get_style_context().add_class("cs-close-btn")
close_btn.set_relief(Gtk.ReliefStyle.NONE)
close_btn.connect("clicked", lambda *_: Gtk.main_quit())
row.pack_start(close_btn, False, False, 0)
outer = Gtk.Box(orientation=Gtk.Orientation.VERTICAL)
outer.set_border_width(18)
outer.pack_start(self._title_bar(), False, False, 0)
bar.add(row)
bar.connect(
"button-press-event",
lambda widget, event: win.begin_move_drag(
event.button, int(event.x_root), int(event.y_root), event.time
toolbar = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, spacing=8)
self.back_btn = Gtk.Button(label="← Back")
self.back_btn.get_style_context().add_class("cs-back-btn")
self.back_btn.set_relief(Gtk.ReliefStyle.NONE)
self.back_btn.connect("clicked", lambda *_: self.go_back())
toolbar.pack_start(self.back_btn, False, False, 0)
self.search_entry = Gtk.SearchEntry()
self.search_entry.get_style_context().add_class("cs-search")
self.search_entry.set_placeholder_text("Search shortcuts... (Ctrl+F)")
self.search_entry.connect(
"changed", lambda e: _apply_filter(e.get_text(), self.entries)
)
if event.button == 1
else False,
)
return bar
toolbar.pack_start(self.search_entry, True, True, 0)
self.search_all_check = Gtk.CheckButton(label="Search all sheets")
self.search_all_check.get_style_context().add_class("cs-search-all")
self.search_all_check.connect("toggled", self._on_search_all_toggled)
toolbar.pack_start(self.search_all_check, False, False, 0)
outer.pack_start(toolbar, False, False, 0)
def build_window(categories):
win = Gtk.Window(type=Gtk.WindowType.TOPLEVEL)
win.set_title("Bernina Cheat Sheet")
win.get_style_context().add_class("cheatsheet-overlay")
win.set_decorated(False)
win.set_position(Gtk.WindowPosition.CENTER)
win.set_keep_above(True)
win.set_skip_taskbar_hint(True)
win.set_skip_pager_hint(True)
win.set_type_hint(Gdk.WindowTypeHint.DIALOG)
self.scroller = Gtk.ScrolledWindow()
self.scroller.set_policy(Gtk.PolicyType.NEVER, Gtk.PolicyType.AUTOMATIC)
outer.pack_start(self.scroller, True, True, 0)
screen = win.get_screen()
visual = screen.get_rgba_visual()
if visual and screen.is_composited():
win.set_visual(visual)
hint = Gtk.Label(
label="Esc or Super+F1 again to close · Ctrl+F to search",
xalign=0,
)
hint.get_style_context().add_class("cs-hint")
outer.pack_start(hint, False, False, 0)
outer = Gtk.Box(orientation=Gtk.Orientation.VERTICAL)
outer.set_border_width(18)
outer.pack_start(title_bar(win), False, False, 0)
self.win.add(outer)
columns = [
Gtk.Box(orientation=Gtk.Orientation.VERTICAL, spacing=6)
for _ in range(MAX_COLUMNS)
]
entries = []
for i, category in enumerate(categories):
box, rows = category_box(category)
columns[i % MAX_COLUMNS].pack_start(box, False, False, 0)
entries.append((box, category["name"].lower(), rows))
geo = self.win.get_screen().get_monitor_geometry(
self.win.get_screen().get_primary_monitor()
)
self.win.set_default_size(
min(1100, int(geo.width * 0.8)), min(800, int(geo.height * 0.8))
)
entry = search_bar(entries)
outer.pack_start(entry, False, False, 0)
self.win.connect("key-press-event", self._on_key_press)
self.win.connect("destroy", lambda *_: Gtk.main_quit())
columns_row = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, spacing=28)
for col in columns:
columns_row.pack_start(col, False, False, 0)
def _title_bar(self):
"""No window decorations are used (they'd break the floating-overlay
look), so dragging and closing are reimplemented by hand here --
click-drag anywhere on the bar moves the window, the button on the
right closes it."""
bar = Gtk.EventBox()
bar.get_style_context().add_class("cs-titlebar")
scroller = Gtk.ScrolledWindow()
scroller.set_policy(Gtk.PolicyType.NEVER, Gtk.PolicyType.AUTOMATIC)
scroller.add(columns_row)
outer.pack_start(scroller, True, True, 0)
row = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL)
self.title_label = Gtk.Label(label=ROOT_TITLE, xalign=0)
self.title_label.get_style_context().add_class("cs-title")
row.pack_start(self.title_label, True, True, 0)
hint = Gtk.Label(
label="Esc or Super+F1 again to close · Ctrl+F to search", xalign=0
)
hint.get_style_context().add_class("cs-hint")
outer.pack_start(hint, False, False, 0)
close_btn = Gtk.Button(label="✕")
close_btn.get_style_context().add_class("cs-close-btn")
close_btn.set_relief(Gtk.ReliefStyle.NONE)
close_btn.connect("clicked", lambda *_: Gtk.main_quit())
row.pack_start(close_btn, False, False, 0)
win.add(outer)
bar.add(row)
bar.connect(
"button-press-event",
lambda widget, event: self.win.begin_move_drag(
event.button, int(event.x_root), int(event.y_root), event.time
)
if event.button == 1
else False,
)
return bar
geo = win.get_screen().get_monitor_geometry(
win.get_screen().get_primary_monitor()
)
win.set_default_size(min(1100, int(geo.width * 0.8)), min(800, int(geo.height * 0.8)))
win.connect("key-press-event", lambda w, e: _on_key_press(w, e, entry))
win.connect("destroy", lambda *_: Gtk.main_quit())
return win, entry
def _on_key_press(widget, event, search_entry):
ctrl = event.state & Gdk.ModifierType.CONTROL_MASK
if ctrl and event.keyval in (Gdk.KEY_f, Gdk.KEY_F):
search_entry.grab_focus()
search_entry.select_region(0, -1)
return True
if event.keyval == Gdk.KEY_Escape:
# First Escape just clears an active search (typing Ctrl+F, then
# Escape to see everything again shouldn't also close the whole
# overlay) -- only close once there's no search text left to clear.
if search_entry.get_text():
search_entry.set_text("")
def _on_key_press(self, _widget, event):
ctrl = event.state & Gdk.ModifierType.CONTROL_MASK
if ctrl and event.keyval in (Gdk.KEY_f, Gdk.KEY_F):
self.search_entry.grab_focus()
self.search_entry.select_region(0, -1)
return True
Gtk.main_quit()
return False
if event.keyval == Gdk.KEY_Escape:
# First Escape just clears an active search (typing Ctrl+F, then
# Escape to see everything again shouldn't also close the whole
# overlay) -- only close once there's no search text left to
# clear.
if self.search_entry.get_text():
self.search_entry.set_text("")
return True
Gtk.main_quit()
return False
def _on_search_all_toggled(self, check):
self.search_all = check.get_active()
self._render()
def navigate(self, target, label):
base_dir = os.path.dirname(self.current[0])
path = os.path.normpath(os.path.join(base_dir, target))
# A link clicked from within a combined "search all" view still
# means "go look at that one sheet" -- drop out of that mode first.
if self.search_all:
self.search_all = False
self.search_all_check.set_active(False) # fires _on_search_all_toggled itself
self.history.append(self.current)
self.current = (path, label)
self._render()
def go_back(self):
if not self.history:
return
self.current = self.history.pop()
if self.search_all:
self.search_all = False
self.search_all_check.set_active(False)
self._render()
def _render(self):
"""Rebuilds just the content area (and title/back-button state)
for whatever self.current / self.search_all currently say -- the
window chrome built in build_chrome() is untouched."""
if self.search_all:
# Always the full reachable set from the true root, regardless
# of which sheet is "current" -- "all sheets" should mean all,
# not just what's reachable from wherever you happen to be.
sheets = discover_sheets(MD_PATH, ROOT_TITLE)
categories = []
for path, label, sheet_categories in sheets:
is_root = path == os.path.normpath(MD_PATH)
for category in sheet_categories:
name = category["name"] if is_root else f"{label} — {category['name']}"
categories.append({"name": name, "shortcuts": category["shortcuts"]})
self.title_label.set_label(f"{ROOT_TITLE} — all sheets")
else:
try:
categories = load_categories(self.current[0])
except (subprocess.CalledProcessError, OSError, json.JSONDecodeError):
categories = []
if self.current[0] == os.path.normpath(MD_PATH):
self.title_label.set_label(ROOT_TITLE)
else:
self.title_label.set_label(f"{ROOT_TITLE} › {self.current[1]}")
self.back_btn.set_visible(bool(self.history) and not self.search_all)
columns = [
Gtk.Box(orientation=Gtk.Orientation.VERTICAL, spacing=6)
for _ in range(MAX_COLUMNS)
]
entries = []
for i, category in enumerate(categories):
box, rows = category_box(category, self.navigate)
columns[i % MAX_COLUMNS].pack_start(box, False, False, 0)
entries.append((box, category["name"].lower(), rows))
self.entries = entries
columns_row = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, spacing=28)
for col in columns:
columns_row.pack_start(col, False, False, 0)
old_child = self.scroller.get_child()
if old_child:
self.scroller.remove(old_child)
self.scroller.add(columns_row)
columns_row.show_all()
_apply_filter(self.search_entry.get_text(), self.entries)
def show(self):
self.build_chrome()
self._render()
self.win.show_all()
self.back_btn.set_visible(False)
self.search_entry.grab_focus()
def wait_for_source(timeout=10):
@@ -342,8 +526,6 @@ def main():
signal.signal(signal.SIGTERM, lambda *_: GLib.idle_add(cleanup))
categories = load_categories()
provider = Gtk.CssProvider()
provider.load_from_data(CSS)
Gtk.StyleContext.add_provider_for_screen(
@@ -352,9 +534,8 @@ def main():
Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION,
)
win, search_entry = build_window(categories)
win.show_all()
search_entry.grab_focus()
overlay = Overlay()
overlay.show()
Gtk.main()
try:
os.unlink(PID_FILE)
+27 -9
View File
@@ -1,7 +1,11 @@
#!/usr/bin/env python3
"""Convert cheatsheet.md into the JSON format the "Shortcuts" gnome-shell
extension (Shortcuts@kyle.aims.ac.za) expects for its `shortcuts-file`
setting: a list of {"name": <category>, "shortcuts": [{"key", "description"}, ...]}.
"""Convert a cheatsheet .md file (cheatsheet.md, or a linked sub-sheet
alongside it) into the JSON format cheatsheet_overlay renders: a list of
{"name": <category>, "shortcuts": [{"key", "description"[, "link"]}, ...]}.
(Originally written to feed the "Shortcuts" gnome-shell extension's
shortcuts-file setting -- that extension is no longer installed, see
startup_bernina_terminal's "Defensive cleanup" comment -- cheatsheet_overlay
is now this JSON's only consumer, so its shape is free to extend.)
Usage: cheatsheet_to_shortcuts_json <input.md> <output.json>
@@ -12,12 +16,20 @@ since they aren't keyboard shortcuts. The category name is always the
*nearest* preceding heading, so a "##" section containing "###" subsections
each with their own table (Compose key) yields one category per "###", not
one lumped-together "##" category.
A first-column cell written as a markdown link, e.g.
`[Admin & Account Setup](cheatsheet_admin.md)` in a Command/Shortcut/Sheet
table, becomes a navigable entry instead of a plain shortcut: cheatsheet_overlay
shows it as a clickable link and, on click, loads and displays *that* file
in place of the current one (path resolved relative to the linking file's
own directory), rather than treating ".md" as a literal key combo.
"""
import json
import re
import sys
CELL_STRIP = re.compile(r"`|\*\*")
MD_LINK = re.compile(r"^\[([^\]]+)\]\(([^)]+\.md)\)$")
def clean(text):
@@ -97,12 +109,18 @@ def build_shortcuts(header, rows):
# Shortcut | Action [| Runs] (app shortcuts, gTile, primary-controls)
# Command | Description (the bin/ script index)
if ncols >= 2 and header[0].lower().startswith(("shortcut", "command")):
return [
{"key": row[0], "description": row[1]}
for row in rows
if row[0]
]
# Sheet | Description (links to other cheat sheets)
if ncols >= 2 and header[0].lower().startswith(("shortcut", "command", "sheet")):
out = []
for row in rows:
if not row[0]:
continue
m = MD_LINK.match(row[0])
if m:
out.append({"key": m.group(1), "description": row[1], "link": m.group(2)})
else:
out.append({"key": row[0], "description": row[1]})
return out
return []
+1 -1
View File
@@ -54,7 +54,7 @@ END_MARKER = "<!-- END SCRIPT INDEX -->"
# this generator's own sibling infra (already covered in its own section
# above in cheatsheet.md).
EXCLUDE = {
"cheatsheet.md", "anaconda_env.bak", "bpy-select_bak",
"cheatsheet.md", "cheatsheet_admin.md", "anaconda_env.bak", "bpy-select_bak",
"jungfrau_console_nox~", "me", "mosaic01.vlm",
"bs_pvs_SLAAR21-CVME-LAS6991", "create_personal_dir.md", "gopass.md",
"migrate_to_network_drive.md", "list_bin_commands",