diff options
| author | blasty <peter@haxx.in> | 2026-08-21 12:08:42 +0200 |
|---|---|---|
| committer | blasty <peter@haxx.in> | 2026-08-21 12:08:42 +0200 |
| commit | 7a3b198a904da186cc2860df059b063db24282ea (patch) | |
| tree | fd5a754169522c0ccd8b7e0d70b2238395d81b09 /experiments | |
| parent | docs: be honest that the triskel fork is unpublished (diff) | |
| download | ida-tui-7a3b198a904da186cc2860df059b063db24282ea.tar.gz ida-tui-7a3b198a904da186cc2860df059b063db24282ea.tar.xz ida-tui-7a3b198a904da186cc2860df059b063db24282ea.zip | |
splash: give the logo a placement id so re-anchoring replaces, not stacks
A kitty placement is identified by (image id, placement id); an a=p with no
p= key is anonymous and every one stacks another copy. The splash re-anchors
on every progress note (~5/s), so a 60s load ended with ~300 placements of an
RGBA logo alpha-compositing over each other -- soft edges creeping to solid,
and the terminal re-rendering all of them per frame.
Same pair every time (LOGO_PLACEMENT) = the terminal REPLACES the placement,
so re-anchoring is free and atomic. That is also why on_resize no longer
clear()s first (that showed a hole for a frame), and why a shrunk-to-nothing
region now drops the placement instead of leaving a stale one anchored.
tests/test_kittygfx.py pins the escapes (pure, stdlib);
experiments/splash_place_count.py counts what a real splash sends.
Diffstat (limited to 'experiments')
| -rw-r--r-- | experiments/splash_place_count.py | 97 |
1 files changed, 97 insertions, 0 deletions
diff --git a/experiments/splash_place_count.py b/experiments/splash_place_count.py new file mode 100644 index 0000000..6d8322a --- /dev/null +++ b/experiments/splash_place_count.py @@ -0,0 +1,97 @@ +#!/usr/bin/env python +"""Count what the splash actually SENDS to the terminal. + +Pushes a real LoadingScreen onto a bare Textual app with kitty graphics forced +on and kittygfx._write captured, then drives it the way the app does (a status +write per progress tick) and tallies the escapes. + + PYTHONPATH=. ~/ida-venv/bin/python experiments/splash_place_count.py +""" +from __future__ import annotations + +import asyncio +import os +import re +import sys + +os.environ["IDATUI_KITTY"] = "1" + +from textual.app import App, ComposeResult # noqa: E402 +from textual.widgets import Static # noqa: E402 + +from idatui import kittygfx # noqa: E402 + +SENT: list[str] = [] + + +def _fake_write(data: str) -> bool: + SENT.append(data) + return True + + +kittygfx._write = _fake_write # type: ignore[assignment] +kittygfx._cell = (9, 22) + +from idatui.app import LoadingScreen # noqa: E402 + + +def tally() -> dict[str, int]: + blob = "".join(SENT) + return { + "uploads (a=t)": len(re.findall(r"\x1b_G[^;]*a=t", blob)), + "placements (a=p)": len(re.findall(r"\x1b_G[^;]*a=p", blob)), + "deletes (a=d)": len(re.findall(r"\x1b_G[^;]*a=d", blob)), + "bytes": len(blob), + } + + +class Host(App): + CSS = "#loading-box { width: 70; height: auto; }" + + def compose(self) -> ComposeResult: + yield Static("host") + + +async def main() -> None: + ticks = int(sys.argv[1]) if len(sys.argv) > 1 else 40 + app = Host() + async with app.run_test(size=(100, 45)) as pilot: + screen = LoadingScreen("target") + app.push_screen(screen) + await pilot.pause() + await pilot.pause() + print(f"image mode: {screen._image}") + after_mount = tally() + print("after mount:", after_mount) + + # what the app does: _status() -> loading_screen.update_note(), once + # per progress write. Spread over ~4s of wall clock like a real load. + for i in range(ticks): + screen.update_note(f"analyzing… {i}") + await asyncio.sleep(0.1) + await pilot.pause() + print(f"after {ticks} progress notes:", tally()) + + screen.dismiss() + await pilot.pause() + print("after dismiss:", tally()) + + d = tally() + blob = "".join(SENT) + cmds = re.findall(r"\x1b_G([^;\x1b]*)", blob) + ids = {dict(kv.split("=", 1) for kv in c.split(",") if "=" in kv).get("p") + for c in cmds if "a=p" in c.split(",")} + onscreen = "unbounded (anonymous)" if None in ids else len(ids) + print() + print(f"=> {d['placements (a=p)']} place escapes sent, " + f"{d['deletes (a=d)']} deletes") + print(f" images actually on screen: {onscreen}") + print(" A placement is identified by (image id, placement id). An a=p with") + print(" no p= key is ANONYMOUS and stacks a fresh copy every time; with a") + print(" p= key the terminal replaces the previous one. logo.png is RGBA, so") + print(" stacking also composites its soft edges towards solid.") + m = re.search(r"\x1b_G(a=p[^;\x1b]*)", blob) + print(" placement escape:", m.group(1) if m else "(none)") + + +asyncio.run(main()) |
