iris is the framework alone; the app is one crate in app-rust/
Iris: "the organization of the rust rewrite is a mess right now... there shouldn't be anything related to the app inside of iris. Iris is supposed to be the UI framework alone." And, on the crate count: "I'm confused why the app only code needs more than one crate though." Nine cargo workspaces become three, and the port's project code -- which sat in five places, four of them inside the framework -- becomes one crate, `ai-app`, in `app-rust/`: client-core -> app-rust/src/client iris/transcript-ui -> app-rust/src/ui iris/transcript-fixture -> app-rust/src/ui/fixture.rs + tests/ + touch/ iris/desktop-app -> app-rust/src/desktop + src/bin_desktop.rs iris/android-app -> app-rust/src/android + android-project/ android-shell -> app-rust/src/shell iris/ keeps core, macro, the iris crate, tabs-ui and rig-input, and now mentions no session, transcript, setup or server anywhere. Only two of the old splits had a reason that survived reading. event-model stays a crate at the repo root because server/ depends on it too, so a crate is what makes the backend and the app agree by construction. The two Android .so names looked like a hard constraint -- a package produces one library artifact -- until P2 turned out to already plan merging those two Android apps into one; both faces now come out of libai_app.so, picked apart by features so `--no-default-features --features shell` keeps wgpu, parley and iris out of the Compose app's APK. docs/RUST.md's "One app crate" has the rest, including what each remaining feature is for. DECISIONS.md and SUBAGENTS.md move into docs/ with everything else. Verified: ./run-tests.sh and `cd iris && cargo test` green, clippy and fmt clean in all five workspaces, `cargo ndk -t x86_64` links libai_app.so, build-apk.sh produces an APK that installs and launches on this checkout's emulator (Gl ... virgl, as expected), and the phone-sized headless screenshot renders the transcript unchanged. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
1 parent
7b54aaf3c4
commit
a9312e9431
113 files changed
+23221
-2992
No files matched your search
Executable
+96
@@ -0,0 +1,96 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Turns `iris::input` debug lines -- from a phone's diagnostics report, or
|
||||
from a report the layer-1 harness produced with tracing on
|
||||
(`iris::diagnostics::set_trace(true)`) -- back into a `TouchScript` file
|
||||
`iris::harness::Harness::replay` can play back at layer 1.
|
||||
|
||||
Why this exists: `docs/RUST.md`'s "Three test layers" box says the cheapest
|
||||
layer that can answer a question wins, and a gesture that misbehaves on
|
||||
Iris's phone is otherwise only describable in words. `iris::sense::
|
||||
log_input_event`'s one line per platform event (Android's on_touch_event
|
||||
once per `MotionEvent`, with historical samples inline; winit's once per
|
||||
pointer `WindowEvent`; the harness's `touch`, once per script line) already
|
||||
carries everything a `.touch` file's `t_ms action x y` needs -- this just
|
||||
reads it back out and reconstructs the samples in order, expanding each
|
||||
event's inline historical samples into their own `move` lines first (they
|
||||
are always intermediate positions of a move, and Android documents them as
|
||||
oldest first, which is also the order they appear in the line).
|
||||
|
||||
Usage:
|
||||
report_to_touch.py < report.txt > replay.touch
|
||||
report_to_touch.py report.txt > replay.touch
|
||||
|
||||
Only lines containing "iris input: action=..." are read; everything else in
|
||||
the report (insets, frame timings, drag-release summaries) is ignored, so
|
||||
this can be pointed at Copy report's whole clipboard text directly.
|
||||
"""
|
||||
|
||||
import re
|
||||
import sys
|
||||
|
||||
# The message half of `sense::log_input_event`'s format string, prefix-
|
||||
# agnostic: a real report line also carries the ring's own
|
||||
# `HH:MM:SS.mmm LEVEL target:` header (`LogLine::format`) or, forwarded
|
||||
# through `ai_server::client_log`, a `[<source> <clock> #<seq>]` tag ahead
|
||||
# of that -- neither of which this needs to understand, since `search`
|
||||
# (not `match`) finds the marker wherever it starts.
|
||||
LINE_RE = re.compile(
|
||||
r"iris input: action=(?P<action>\w+) x=(?P<x>-?[0-9.]+) y=(?P<y>-?[0-9.]+) "
|
||||
r"t=(?P<t>[0-9]+)ms history=(?P<hist>[0-9]+)(?P<rest>.*)$"
|
||||
)
|
||||
# One historical sample inside `rest`: `t:x,y`, space-separated, oldest first
|
||||
# -- see `log_input_event`'s own doc for why order matters.
|
||||
HIST_RE = re.compile(r"(?P<t>[0-9]+):(?P<x>-?[0-9.]+),(?P<y>-?[0-9.]+)")
|
||||
|
||||
|
||||
def _fmt(value: float) -> str:
|
||||
"""The number as `TouchScript::parse`'s own `f32::parse` would round-trip
|
||||
it -- an integer without a trailing `.0` where the source was one
|
||||
(every coordinate here is a physical pixel), `{:g}` otherwise so a
|
||||
fractional value from a real device is not silently truncated."""
|
||||
if value == int(value):
|
||||
return str(int(value))
|
||||
return f"{value:g}"
|
||||
|
||||
|
||||
def convert(lines):
|
||||
"""Every `iris::input` line, oldest first, expanded to one `(t_ms,
|
||||
action, x, y)` tuple per touch sample -- a historical sample is always
|
||||
an intermediate `move`, and the event's own sample keeps its real
|
||||
action (`down`/`move`/`up`/`cancel`)."""
|
||||
rows = []
|
||||
for line in lines:
|
||||
m = LINE_RE.search(line)
|
||||
if not m:
|
||||
continue
|
||||
hist_count = int(m.group("hist"))
|
||||
hist_matches = list(HIST_RE.finditer(m.group("rest")))
|
||||
if len(hist_matches) != hist_count:
|
||||
print(
|
||||
f"report_to_touch: {line.strip()!r} says history={hist_count} but "
|
||||
f"holds {len(hist_matches)} samples -- skipped",
|
||||
file=sys.stderr,
|
||||
)
|
||||
continue
|
||||
for hm in hist_matches:
|
||||
rows.append(
|
||||
(int(hm.group("t")), "move", float(hm.group("x")), float(hm.group("y")))
|
||||
)
|
||||
rows.append(
|
||||
(int(m.group("t")), m.group("action"), float(m.group("x")), float(m.group("y")))
|
||||
)
|
||||
return rows
|
||||
|
||||
|
||||
def main():
|
||||
if len(sys.argv) > 2:
|
||||
print("usage: report_to_touch.py [report.txt] < report.txt", file=sys.stderr)
|
||||
return 2
|
||||
text = open(sys.argv[1]) if len(sys.argv) == 2 else sys.stdin
|
||||
for t_ms, action, x, y in convert(text):
|
||||
print(f"{t_ms} {action} {_fmt(x)} {_fmt(y)}")
|
||||
return 0
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
sys.exit(main())
|
||||
Reference in new issue
Block a user