-
Notifications
You must be signed in to change notification settings - Fork 0
Phase 30 intuition plan
Part of the Amiga port design log.
amiga.intuition C sub-module exposing intuition.library's
EasyRequest family. Three entry points:
from amiga import intuition
idx = intuition.easy_request("Title", "Body line one.\nBody line two.",
["Yes", "No", "Cancel"])
ok = intuition.auto_request("Replace existing file?", yes="Yes", no="No")
intuition.message("Done.", button="OK")easy_request returns the 0-based leftmost index of the
clicked button, so the call above gives 0 for Yes, 1 for
No, 2 for Cancel. (auto_request and message translate
that back into bool / None for the common cases.)
The module is shared across all four variants — intuition.library
ships with every AmigaOS install, there's no external SDK, and the
size cost is small (~1.5 KB text).
-
easy_request(title, body, buttons)→ int (0-based button index; rightmost button is always the "cancel" / 0 convention) -
auto_request(body, yes="Yes", no="No")→ bool, two-button wrapper -
message(body, button="OK")→ None, single-button notice - printf-escape safety (raw user strings are passed as
%sargs, not as the format string) - Latin-1 codec for the title/body so non-ASCII text renders cleanly under AmigaOS Topaz/CP-1252 displays
- Arbitrary window/widget surfaces — see "Non-goals"
- Custom gadgets, file/font/screen pickers (Phase 31 handles file)
- Non-blocking / async requesters — modal only
-
intuition.libraryopened lazily on first call (cached base) - Uses Phase 17's library-calling infrastructure as fallback if preferred over explicit C, but a direct C module is probably simpler given how concentrated the API surface is
Three Python entry points, all backed by a single EasyRequestArgs
call through intuition.library v36+:
| Function | Returns |
|---|---|
intuition.easy_request(title, body, buttons) |
int — 0-based leftmost button index |
intuition.auto_request(body, yes="Yes", no="No") |
bool — True iff Yes clicked |
intuition.message(body, button="OK") |
None |
Translation: AmigaOS conventionally numbers buttons rightmost-is-0
(EasyRequest returns 0 for the right gadget, 1 for the next, …,
N-1 for the leftmost). The module flips that to Python's natural
0-based-leftmost so buttons[easy_request(...)] does the right thing.
es_TextFormat is hard-coded to "%s" and the body is passed as the
single varargs arg, so a % in the body is rendered literally rather
than interpreted as a printf directive.
Vamos has a no-op EasyRequest stub — useful for confirming the call
threads through cleanly but not for end-to-end visual checks. Those
need Amiberry or real hardware. Verified working under Amiberry
2026-05-31; intuition.library opens its own screen if no public
screen is currently up, so the requester appears regardless of
whether Workbench is loaded.
This section is the step-by-step ship plan — how to chunk the work into landable PRs. The design block above answers what and why.
Phase 30 lands a small C module that wraps intuition.library's
EasyRequestArgs() family, exposing the three Python entry points
shown at the top of this page.
Step 1: C module skeleton + easy_request → Step 2: auto_request + message
↓
Step 3: docs + smoke
| # | Step | Output | On-target smoke |
|---|---|---|---|
| 1 |
modintuition.c opens intuition.library lazily, exposes easy_request(title, body, buttons). Latin-1 codec on the three strings; printf-safety via es_TextFormat = "%s" + body as the single arg. Returns 0-based leftmost int. |
New _intuition C module wired into the build, registered with MP_REGISTER_MODULE(MP_QSTR__intuition, ...). |
A 3-button easy_request under Amiberry — click each button, confirm right return value. |
| 2 |
auto_request(body, yes="Yes", no="No") and message(body, button="OK") wrappers (both still in C — they're tiny and avoid the Python round-trip). auto_request returns bool; message returns None. |
Same C file extended; amiga.py adds import _intuition as intuition so from amiga import intuition and amiga.intuition.message(...) both work. |
A 2-button auto_request and a 1-button message under Amiberry. |
| 3 | Docs flip, manifest verification, no-arg & arg-shape tests. |
docs/amiga.md Phase 30 → ✅, docs/amiga-testing.md gains a short Intuition subsection ("interactive — needs visual check under Amiberry"). |
Tests against argument validation (empty buttons list, non-string, etc.) — pure-Python, runnable under vamos. |
Each step is small (50–100 LOC of C plus a Python alias). Step 3 is purely paperwork.
-
ports/amiga/modintuition.c— new C source. - Lazy
IntuitionBase = OpenLibrary("intuition.library", 36)cached in a static; opened on first call. No close on exit needed (the library is system-wide; AmigaOS reaps it when the process dies). Optionally wireamiga_intuition_close()intomain.c's shutdown for symmetry — cheap. -
ports/amiga/Makefileaddsmodintuition.ctoSRC_Cand toSRC_QSTR(the new function names are qstrs). - The C entry:
static mp_obj_t mod_intuition_easy_request( mp_obj_t title_in, mp_obj_t body_in, mp_obj_t buttons_in);
- Decode all three strings as Latin-1 (use
mp_obj_str_get_datafor the raw bytes; on AmigaOS the console + Topaz font is CP1252-ish, so Latin-1 is the safe middle ground). bytes-typed args pass through untouched. -
buttons_inis iterable; collect labels into a singleAllocVec'd buffer joined by|. Empty list →TypeError. - Populate a stack
struct EasyStruct:struct EasyStruct es = { sizeof(struct EasyStruct), 0, title_buf, // es_Title (CONST_STRPTR)"%s", // printf-safe body gadget_buf, // joined labels };
- Call
EasyRequestArgs(NULL, &es, NULL, &body_arg)wherebody_argis(STRPTR)body_buf— a single-element args block matching the%s. - Translate AmigaOS rightmost-is-0 to 0-based-leftmost:
(r == 0) ? (N - 1) : (r - 1)where N is the button count. - Free the joined-labels buffer; return the int.
- Decode all three strings as Latin-1 (use
EasyRequest's varargs pull va_arg from va_list, which is
caller-frame-dependent on m68k cdecl. We'd need to build the
arg block by hand anyway. EasyRequestArgs documents the args
pointer explicitly, which is what we already have to do.
Visual check under Amiberry from the interactive REPL:
>>> from amiga import intuition
>>> intuition.easy_request("Title", "Pick one.", ["Apple", "Banana", "Cancel"])→ requester pops on the Workbench screen.
- Click Apple →
0 - Click Banana →
1 - Click Cancel (or close-window equivalent) →
2
Repeat with a single-button list ["OK"] — returns 0 either way
since rightmost == leftmost when N=1.
| Failure | Behaviour |
|---|---|
intuition.library won't open (impossible on stock AmigaOS, but...) |
OSError(MP_ENOENT) from easy_request first call |
Empty buttons list |
TypeError("at least one button required") |
Non-string / non-bytes in buttons / title / body
|
mp_obj_str_get_data raises TypeError automatically |
Label or title contains \0
|
Truncated at the embedded NUL (AmigaOS C-string limit). Document; don't pre-validate. |
Label contains \n
|
Pass through. EasyRequest lays gadgets out by ` |
Body contains \n
|
Renders as a line break (intentional — Intuition splits the body on \n). |
Body contains %
|
Safe — es_TextFormat = "%s" makes the body a literal arg, not a format string. |
- Both live in the same
modintuition.cas Step 1 — implemented as thin wrappers around the sameeasy_request_implstatic function so the title/format/gadget-join logic is shared. -
auto_request(body, yes="Yes", no="No"):- Title defaults to empty string (just the body shown).
- Labels:
[yes, no].EasyRequestreturns 1 if Yes clicked, 0 if No clicked → our translation gives0/1. - Return
Trueif the Yes button was picked,Falseotherwise.
-
message(body, button="OK"):- Title empty.
- One label.
- Return
None. Don't bother propagating the return code.
-
ports/amiga/modules/amiga.pygains:Nowimport _intuition as intuition # exposes amiga.intuition.*
from amiga import intuitionandamiga.intuition.message(...)both work.
>>> intuition.auto_request("Replace existing file?")
True # user clicked Yes
False # user clicked No
>>> intuition.message("Job done.")
# requester pops, user clicks OK, returns None- Three-arg shape used by
easy_requestdoesn't translate cleanly intoMP_DEFINE_CONST_FUN_OBJ_3if we want kwargs; useMP_DEFINE_CONST_FUN_OBJ_KWwith amp_arg_ttable soeasy_request(title, body, buttons)positional + future kwargs (e.g.idcmp=...) work without breaking the API.
-
docs/amiga.mdPhase 30 status → ✅; the section gains a short "Status — done" block listing the three functions and noting the AmigaOS rightmost-is-0 → 0-based-leftmost translation. -
docs/amiga-testing.mdgains an Intuition subsection under Amiberry runner: "Interactive only — needs visual click-through to verify return values." - A tiny
tests/ports/amiga/test_intuition_argshape.pythat exercises the argument validation without actually opening a requester (mock out_intuition.easy_requestand check the wrappers pass the right labels). Runs under vamos.
All four variants ship the module — intuition.library is part
of every AmigaOS install and there's no external SDK to fetch.
Size cost: ~1.5 KB text.
-
Modal blocking.
EasyRequestArgsis fully blocking — the Python call doesn't return until the user clicks a button. This matches the design intent ("modal only"). If a future caller wants non-blocking, that needsBuildEasyRequestArgs+SysReqHandler— separate phase. -
Screen independence.
intuition.libraryrenders on the default public screen if one is up, and opens its own if not — so the requester appears regardless of whether Workbench is loaded.OSError(EIO)only fires ifEasyRequestArgsitself returns-1(genuine intuition-side failure, very rare). -
Latin-1 codec choice. AmigaOS's stock Topaz font and the
console driver are largely CP1252-compatible for the printable
range; treating Python strings as Latin-1 covers
é/ñ/ü/£/€-ishcharacters that scripts are likely to want. UTF-8 input bytes go through a.decode("utf-8")→.encode("latin-1", "replace")pipeline so non-Latin-1 codepoints render as?rather than corrupt bytes. -
\nin body. Intuition'sEasyRequestbody honours\nas a line break — useful for multi-line prompts. Document. Title and gadget labels don't honour\n(\nin a label gets truncated at the line break by AmigaOS rendering). - Title length. Long titles get clipped by the window's title bar. Don't pre-validate length; let AmigaOS handle.
- Arbitrary windows / widgets / event loops —
easy_requestis the only blocking-modal Intuition surface we need. - Custom gadgets, font requesters, screen pickers, palette requesters — separate APIs, separate phases.
- File requester — that's
asl.library, Phase 31. - Non-blocking / async requesters — needs
BuildEasyRequest+SysReqHandler, deferred. - Hooking the IDCMP signal to get richer button events — the
return value from
EasyRequestArgsis enough for our use case.
ports/amiga/modintuition.c — C module (~180 LOC)
ports/amiga/Makefile — adds modintuition.c to SRC_C / SRC_QSTR
ports/amiga/modules/amiga.py — adds `import _intuition as intuition`
tests/ports/amiga/test_intuition_argshape.py — vamos arg-shape smoke test
docs/amiga.md — Phase 30 status flip + done block
docs/amiga-testing.md — Intuition subsection
Variants: all four. ~1.5 KB text per variant, no network/SSL deps.