Skip to content

CopperlineOS/arexx-next

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

5 Commits
 
 
 
 
 
 
 
 

arexx-next

Rexx-inspired scripting & shell for CopperlineOS.
arexx-next is a tiny, embeddable scripting language and command-line tool for automating CopperlineOS via message ports. It revives the classic ARexx idea—every app has a port; everything is scriptable—with modern touches: JSON helpers, event subscriptions, and first-class Unix socket IPC.

TL;DR: write small scripts that talk directly to copperd, compositord, blitterd, and audiomixerd, orchestrating frame-accurate visuals and audio.


Status

  • Phase-0 MVP: interpreter + standard library for ports/JSON/env/files.
  • Targets Linux-hosted CopperlineOS services (JSON protocol v0).
  • License: MIT OR Apache-2.0.

Why it exists

CopperlineOS is about deterministic media and scriptable everything. You shouldn’t need Rust or C to:

  • create a layer, bind an image, and animate it;
  • build a quick audio graph; or
  • connect multiple services into a scene.

ARexx on the Amiga did this brilliantly. arexx-next brings that spirit back, tuned for modern IPC.


Layout

arexx-next/
├─ src/                 # interpreter & stdlib
├─ stdlib/              # reusable scripts/macros
├─ examples/            # runnable demos
├─ docs/                # language reference
└─ arx                  # CLI entrypoint (symlink or bin name)

The CLI binary is referred to as arx in examples below.


Language at a glance

  • Rexx-like syntax: dynamic variables, SAY for print, CALL for functions, PROCEDURE for local scope.
  • Comments: /* block comment */ (Rexx-style).
  • Strings: "double-quoted"; concatenation via ||.
  • Numbers: arbitrary precision integers; decimal floats.
  • Errors: non‑zero RC (return code) and exceptions abort script unless trapped.

Example: hello world

SAY "Hello, Copperline!"

Example: variables & procedures

name = ARG(1)
IF name = "" THEN name = "world"
CALL greet name
EXIT 0

greet: PROCEDURE
  PARSE ARG who
  SAY "Hello," who || "!"
RETURN

Run: arx examples/hello.rexx Darren


Standard library (Phase-0)

  • PORTSEND(sock, json) → string response (or empty for event streams).
  • PORTSUB(sock, filter_json) → stream handle id (read via PORTREAD(id)).
  • JSON(obj_or_text) → canonical JSON string; JSONGET(text, key) → value (simple paths).
  • ENV(name) → environment var; SLEEP(ms) → sleep milliseconds.
  • FSREAD(path) / FSWRITE(path, text).
  • TIMEUS() → microseconds since epoch (monotonic on supported hosts).

Note: JSON helpers are intentionally small—use tools like jq for heavy manipulation if needed.


Ports discovery

By default, arexx-next maps well-known service names to sockets (override with env vars):

Name Socket Env override
copperd /run/copperline/copperd.sock COPPERD_SOCKET
compositord /run/copperline/compositord.sock COMPOSITORD_SOCKET
blitterd /run/copperline/blitterd.sock BLITTERD_SOCKET
audiomixerd /run/copperline/audiomixerd.sock AUDIOMIXERD_SOCKET

Helper: ADDRESS pseudo-statement addresses a port by name.

ADDRESS copperd '{ "cmd":"ping" }'

Equivalent to: CALL PORTSEND "/run/copperline/copperd.sock", '{ "cmd":"ping" }'


Example: animate a layer over a Vulkan scene

This mirrors the SDK examples using copperd + compositord.

/* demo.rexx — move a sprite 4 px per frame */

compos = "/run/copperline/compositord.sock"
copper = "/run/copperline/copperd.sock"

/* 1) Create a layer and bind an image */
CALL PORTSEND compos, '{"cmd":"create_layer"}'
CALL PORTSEND compos, '{"cmd":"bind_image","id":1,"path":"/tmp/sprite.rgba","w":128,"h":128,"format":"RGBA8"}'
CALL PORTSEND compos, '{"cmd":"set","id":1,"x":100,"y":360,"alpha":1.0,"z":10,"visible":true}'

/* 2) Load a tiny Copper program */
prog = '{ "version":1, "program":[' ||
  '{ "op":"MOVE","reg":"layer[1].x","value":100 },' ||
  '{ "op":"MOVE","reg":"layer[1].y","value":360 },' ||
  '{ "op":"LOOP","count":-1,"label":"loop" },' ||
  '{ "label":"loop" },' ||
  '{ "op":"WAIT","vsync":true },' ||
  '{ "op":"ADD","reg":"layer[1].x","delta":4 },' ||
  '{ "op":"IRQ","tag":"tick" },' ||
  '{ "op":"JUMP","label":"loop" }] }'

resp = PORTSEND(copper, '{ "cmd":"load","program":' || prog || ' }')
id = JSONGET(resp, "id")
CALL PORTSEND copper, '{ "cmd":"start","id":' || id || ' }'

SAY "Animating layer 1; press Ctrl+C to stop."

Run: arx demo.rexx


Example: reactive scripts (subscriptions)

Listen to vsync and log frame times:

sock = "/run/copperline/compositord.sock"
sub = PORTSUB(sock, '{"cmd":"subscribe","events":["vsync"]}')
DO FOREVER
  line = PORTREAD(sub)
  IF line = "" THEN LEAVE
  usec = JSONGET(line, "usec")
  frame = JSONGET(line, "frame")
  SAY "vsync: frame=" frame " usec=" usec
END

CLI usage

arx FILE [args...]            # run a script
arx -e 'SAY "hi"'             # eval one-liner
arx -i                        # interactive REPL
arx --std path                # add search path to stdlib
arx --trace                   # trace statements
arx --version

Scripts receive positional parameters via ARG(n). RC holds last return code.


Embedding

The interpreter is a small C/Rust library (libarexx_next) you can link into apps/services to expose custom functions (e.g., to drive your own port).

  • Register native functions (rex_native("PORTSEND", c_fn_portsend) etc.).
  • Expose key-value environment/state to scripts.
  • Bind to your service’s port for in-process automation.

(Embedding API stabilises after Phase-0.)


Error handling & determinism

  • By default, an unhandled error aborts the script with non-zero exit code.
  • Use SIGNAL ON ERROR and CALL ON ERROR (planned) to trap/handle errors.
  • PORTSEND/PORTSUB return errors in RC and may set a global LASTERROR string.

Best practice: keep scripts idempotent and small; offload heavy loops to services via Copper programs or audio graphs.


Security

  • Scripts are local automation. There is no network transport in Phase-0.
  • File access is unrestricted by default; for sandboxed setups, run arx under a restricted user or sandbox (bubblewrap, flatpak, systemd-run).
  • Services may require capability tokens; pass them via script variables or env (e.g., caps field in requests).

Roadmap

  • v0.1: ports/JSON stdlib, basic language, REPL, examples.
  • v0.2: pattern-matching PARSE helpers, better JSON path (JSONPATH), timers (EVERY ms DO ... END).
  • v0.3: module system, package manager for stdlib macros.
  • v0.4: debugger hooks (breakpoints, step), profiling for long scripts.

RFCs tracked in CopperlineOS/rfcs.


Contributing

  • Keep examples tiny and runnable on a stock Linux host with the Phase-0 services.
  • Language changes require tests in tests/ and a short design note in docs/.
  • Please format code and scripts; see CONTRIBUTING.md and CODE_OF_CONDUCT.md.

License

Dual-licensed under Apache-2.0 OR MIT.


See also

About

scripting language + shell

Resources

License

Unknown and 2 other licenses found

Licenses found

Unknown
LICENSE
Apache-2.0
LICENSE-APACHE
MIT
LICENSE-MIT

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published