Screenshot feature (text + PNG) and keybind editor tab in settings

- New screenshot action (default alt+p, bindable like any action):
  renders the current workspace to a buffer and saves it as plain text
  and/or PNG (screenshot_format = text|png|both, screenshot_dir
  configurable, default skärmbilder/ under the config dir). The PNG is
  rasterized cell by cell with an embedded DejaVu Sans Mono font
  (vendored, ~340 kB); glyphs missing from the font (color emoji)
  render as filled boxes. A popup confirms the saved paths
- Settings dialog gains a 'Tangenter' row: lists all keybinds with
  label and scope, Enter captures the next keypress as the new chord
  (persisted by rewriting [[keybind]] via toml_edit), Delete removes
  a binding — changes take effect immediately
- Integration suite: 48/48 (screenshot files + validity, keybind list,
  live rebind ctrl+space→alt+z)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
2026-07-16 00:30:56 +02:00
parent 3db0c82e03
commit 9d637a9378
14 changed files with 625 additions and 14 deletions

View File

@@ -461,6 +461,53 @@ def main():
disp.send(key_event(code="Esc"))
time.sleep(0.3)
# ── 4k. Skärmbild via alt+p ──────────────────────────────────────
disp.send(key_event(ch="p", modifiers="ALT"))
text = disp.frame_text(timeout=8.0, contains="Skärmbild sparad")
check("alt+p tar skärmbild och visar bekräftelse", "Skärmbild sparad" in text)
disp.send(key_event(code="Enter")) # stäng popupen
time.sleep(0.3)
shots = sorted(os.listdir(os.path.join(cfgdir, "skärmbilder")))
txts = [s for s in shots if s.endswith(".txt")]
pngs = [s for s in shots if s.endswith(".png")]
check("skärmbild sparar .txt och .png", bool(txts) and bool(pngs),
f"filer: {shots}")
if txts:
t = open(os.path.join(cfgdir, "skärmbilder", txts[0])).read()
check("textskärmbilden innehåller panelen", "TUI-WM" in t)
if pngs:
magic = open(os.path.join(cfgdir, "skärmbilder", pngs[0]), "rb").read(8)
check("PNG-skärmbilden har giltig header",
magic == b"\x89PNG\r\n\x1a\n", f"magic: {magic!r}")
# ── 4l. Tangent-fliken i inställningarna ─────────────────────────
disp.send(mouse_event({"Down": "Left"}, gx, 0))
disp.send(mouse_event({"Up": "Left"}, gx, 0))
disp.frame_text(timeout=5.0, contains="Tangenter")
for _ in range(6):
disp.send(key_event(code="Down"))
disp.send(key_event(code="Enter"))
text = disp.frame_text(timeout=5.0, contains="Fönsterväxlare")
check("tangentvyn listar keybinds",
"alt+w" in text and "Fönsterväxlare" in text)
# byt tangent på första raden (ctrl+space → alt+z)
disp.send(key_event(code="Enter"))
disp.frame_text(timeout=5.0, contains="tryck ny tangent")
disp.send(key_event(ch="z", modifiers="ALT"))
time.sleep(0.5)
cfg_now = open(os.path.join(cfgdir, "config.toml")).read()
check("ombindning skrivs till config.toml", '"alt+z"' in cfg_now,
f"keybind-rader: {[l for l in cfg_now.splitlines() if 'alt+z' in l]!r}")
disp.send(key_event(code="Esc"))
disp.send(key_event(code="Esc"))
time.sleep(0.3)
# alt+z ska nu öppna kommandodialogen (var ctrl+space)
disp.send(key_event(ch="z", modifiers="ALT"))
text = disp.frame_text(timeout=5.0, contains="Tui-run")
check("den nya bindningen fungerar direkt", "Tui-run" in text)
disp.send(key_event(code="Esc"))
time.sleep(0.3)
# ── 5. Popup + popup_result via Enter ───────────────────────────
app.send({
"type": "spawn_popup", "message": "Integrationstest?",