Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ mojoh2
mojoh2tls
mojoget
mojo_http_server
snapshot/snapshot
screen/screen
# editor/OS
.DS_Store
__pycache__/
Expand Down
4 changes: 4 additions & 0 deletions CHAT_UI_TODO.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ else. Not started; this captures the plan + the verified pieces it builds on.
| `rusqlite` conversations + messages | **MOJO-libs `sqlite/`** — write + read + SELECT, verified vs real `sqlite3` (`integrity_check: ok`) | HAVE |
| `serde_json` | **MOJO-libs `json/`** | HAVE |
| `reqwest` → LLM (streaming) | **MOJO-libs `http/client.mojo`** — DNS, chunked, gzip/deflate, **https/TLS**, redirects | HAVE (SSE token-stream parse = small add) |
| clipboard copy/paste | **MOJO-libs `clipboard/`** — Wayland/X11 text clipboard + explicit OSC52 fallback | HAVE (Linux text clipboard; xsel round-trip verified) |
| LLM backend | see "LLM endpoint" below | DECISION |

## Architecture
Expand All @@ -21,6 +22,9 @@ state via `store_user_state`/`retrieve_user_state`):
- **left panel** — conversation list (from `sqlite`: `conversations` table).
- **center** — scrollable message history (`scroll_area` over `messages`) + a
`text_area` input + Send button.
- **clipboard** — copy message text / generated paths via `clipboard.write_text`;
paste external prompt text via `clipboard.read_text` where the UI exposes a
paste action.
- **on Send** — append user msg → `sqlite`; POST to the LLM endpoint via
`http.client` (json body); stream/collect the reply; append assistant msg →
`sqlite`; re-render.
Expand Down
42 changes: 30 additions & 12 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,16 +6,19 @@ TLS + WebSockets, JSON (with a high-performance tape parser), an async executor,
(PNG/JPEG/WebP decode+encode, resize/filters, 16-bit/ICC/EXIF/CMYK), fast memory
allocators (arena/pool/slab/ring), a SQLite-format database engine (read + SELECT +
write, no FFI), and a full PDF 1.7 writer + reader
(embedded/subset fonts, encryption, digital signatures) — built from the ground up
on libc/OpenSSL/nghttp2/zlib/brotli via FFI.

Mojo's standard library has no sockets, TLS, HTTP, JSON, or PDF. These libraries
fill that gap. The guiding principle is **"Mojo for everything; C only for the gaps
Mojo genuinely can't reach"** — and those gaps are small (C-ABI callbacks for
nghttp2 and OpenSSL ALPN; zlib's `z_stream`). Everything else — the event loop,
sockets, the HTTP/1.1 and WebSocket protocols, the JSON parser and validator, the
DEFLATE codec (both directions), and the PDF crypto stack (**MD5, SHA-1/256/384/512,
RC4, AES, RSA, ECDSA, big-integer math** — all pure Mojo) — is implemented here.
(embedded/subset fonts, encryption, digital signatures), plus Linux desktop
clipboard integration for Mojo apps — built from the ground up on
libc/OpenSSL/nghttp2/zlib/brotli via FFI.

Mojo's standard library has no sockets, TLS, HTTP, JSON, PDF, or desktop
clipboard API. These libraries fill that gap. The guiding principle is **"Mojo
for everything; C only for the gaps Mojo genuinely can't reach"** — and those
gaps are small (C-ABI callbacks for nghttp2 and OpenSSL ALPN; zlib's `z_stream`;
desktop clipboard ownership delegated to the user's Wayland/X11 provider). Everything
else — the event loop, sockets, the HTTP/1.1 and WebSocket protocols, the JSON
parser and validator, the DEFLATE codec (both directions), and the PDF crypto
stack (**MD5, SHA-1/256/384/512, RC4, AES, RSA, ECDSA, big-integer math** — all
pure Mojo) — is implemented here.

Toolchain: **Mojo 1.0.0b1 / MAX 26.3** (via [pixi](https://pixi.sh)).

Expand Down Expand Up @@ -148,6 +151,17 @@ frame sequence (+ audio) into an mp4 — e.g. generated frames + generated audio
(LTX2/NAVA). Verified: an mp3 decodes to samples and a frames+wav mux produces a
valid **h264+aac** mp4 (independent `ffprobe` oracle). Requires `ffmpeg` on PATH.

### [`clipboard/`](clipboard/) — desktop clipboard for Mojo apps
Linux desktop clipboard helpers for app workflows like copying generated image
paths, prompts, logs, and user-selected text. Runtime provider detection covers
Wayland `wl-copy`/`wl-paste`, X11 `xclip`, and X11 `xsel`; OSC52 terminal
clipboard writes are available only when explicitly requested. Payload bytes
travel over provider stdin/stdout, not through shell-interpolated command strings.
The public API is intentionally small (`write_text`, `read_text`, `clear`,
`detect_backend`, `availability_report`) so apps can import one stable module
while backend support grows. Compile-safe tests always run; real clipboard
round-trip is opt-in because it mutates the user's clipboard.

### [`svg/`](svg/) — pure-Mojo SVG icon loader (subset → raster)
Parse an **SVG icon** and rasterize it to a `graphics.Canvas` (RGBA, transparent
bg) → PNG or GPU texture. Pure Mojo on top of the `graphics` vector engine: full
Expand Down Expand Up @@ -207,8 +221,9 @@ timeout, write backpressure, **streamed responses**, **prefork multi-core**, and

## Building

Everything builds from the repo root with `-I .` so the packages (`json`, `net`,
`http`, `async`) resolve. C shims compile to `.o` and link via `-Xlinker`.
Everything builds from the repo root with `-I .` so top-level packages (`json`,
`net`, `http`, `async`, `clipboard`, etc.) resolve. C shims compile to `.o` and
link via `-Xlinker`.

```bash
# pure-Mojo libs need nothing extra:
Expand Down Expand Up @@ -255,6 +270,9 @@ live local TLS server. A sampling of what is *measured*:
confirming TOML-invalid input + non-ASCII strings are handled correctly.
- **mem**: arena/pool/slab/ring allocators, 170 assertions, with microbenchmarks
(pool 2.9×, slab 2.5×, arena bump+reset ~5.3× vs raw `alloc`/`free`).
- **clipboard**: compile-safe helper tests cover provider detection/reporting,
OSC52 sequence generation, and Base64 vectors; real Wayland/X11 round-trip is
opt-in with `CLIPBOARD_TEST_REAL=1` because it changes the user's clipboard.

Known limits are documented per-lib and are version/scope choices, not design
walls — e.g. the JSON codec's per-field *value* binding is one line per field
Expand Down
104 changes: 104 additions & 0 deletions clipboard/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
# clipboard

Desktop clipboard helpers for Mojo apps.

The module is Linux-first and dependency-light: it links only libc from Mojo and
uses the desktop provider already present at runtime:

- Wayland: `wl-copy` and `wl-paste` from `wl-clipboard`
- X11: `xclip` or `xsel`
- Terminal fallback: OSC52 write sequence, explicit only

Payload text is sent over provider stdin/stdout. It is not interpolated into a
shell command, so paths, prompts, and generated text do not become shell input.

## Modules

| Module | What it is |
|---|---|
| `clipboard.mojo` | Public text clipboard API: `write_text`, `read_text`, `clear`, `detect_backend`, `backend_available`, `availability_report`, `osc52_sequence`, and `write_text_osc52`. Uses libc `popen`/`fread`/`fwrite` to stream payload bytes to trusted provider commands. |
| `tests/clipboard_test.mojo` | Compile-safe checks for backend names, selection names, provider reporting, Base64 vectors, and OSC52 sequences. With `CLIPBOARD_TEST_REAL=1`, runs a real Wayland/X11 round-trip and restores prior non-empty clipboard text. |

## API

```mojo
from clipboard.clipboard import (
read_text, write_text, clear, detect_backend, availability_report,
SELECTION_CLIPBOARD, SELECTION_PRIMARY,
)

def main() raises:
print(availability_report())
write_text(String("/tmp/generated/image.png"))
var pasted = read_text()
print("clipboard:", pasted)

write_text(String("primary selection"), SELECTION_PRIMARY)
```

Backends are selected automatically by `detect_backend()`:

1. Wayland when `WAYLAND_DISPLAY` is set and `wl-copy`/`wl-paste` exist.
2. X11 `xclip` when `DISPLAY` is set and `xclip` exists.
3. X11 `xsel` when `DISPLAY` is set and `xsel` exists.

Explicit backends are available through `BACKEND_WAYLAND`, `BACKEND_XCLIP`,
`BACKEND_XSEL`, and `BACKEND_OSC52`.

## Backend Behavior

| Backend | Read | Write | Selection support | Runtime requirement |
|---|---:|---:|---|---|
| Wayland | yes | yes | clipboard + primary | `WAYLAND_DISPLAY`, `wl-copy`, `wl-paste` |
| X11 `xclip` | yes | yes | clipboard + primary | `DISPLAY`, `xclip` |
| X11 `xsel` | yes | yes | clipboard + primary | `DISPLAY`, `xsel` |
| OSC52 | no | yes | clipboard + primary target codes | terminal that accepts OSC52 |

`BACKEND_AUTO` chooses the first full read/write provider in that order. It does
not auto-select OSC52 because OSC52 is write-only and visibly emits terminal
escape sequences.

## OSC52

OSC52 is write-only and terminal-dependent, so it is never selected
automatically:

```mojo
from clipboard.clipboard import write_text_osc52

def main() raises:
write_text_osc52(String("copied through the terminal"))
```

Use it only for terminal apps where emitting an escape sequence to stdout or a
terminal writer is expected behavior. `write_text_osc52()` prints a convenience
sequence to stdout; use `osc52_sequence()` when your app needs exact byte control.

## Limits

- Text API only. UTF-8 is preserved byte-for-byte through the provider pipe.
- Clipboard persistence is owned by the provider. On some X11 setups, the
provider process may need a running X server until ownership is transferred.
- `read_text(max_bytes=...)` defaults to 64 MiB to protect apps from accidental
unbounded reads.
- No macOS/Windows backend yet. Add native providers behind the same public API
rather than changing app code.

## Tests

Compile-safe tests:

```bash
pixi run mojo run -I . clipboard/tests/clipboard_test.mojo
```

Real clipboard round-trip is opt-in because it mutates the user's clipboard:

```bash
CLIPBOARD_TEST_REAL=1 pixi run mojo run -I . clipboard/tests/clipboard_test.mojo
```

Observed validation on the development machine:

- `pixi run --manifest-path /home/alex/mojodiffusion/pixi.toml mojo run -I . -I /home/alex/MOJO-libs /home/alex/MOJO-libs/clipboard/tests/clipboard_test.mojo` → `14 passed, 0 failed`.
- `CLIPBOARD_TEST_REAL=1 pixi run --manifest-path /home/alex/mojodiffusion/pixi.toml mojo run -I . -I /home/alex/MOJO-libs /home/alex/MOJO-libs/clipboard/tests/clipboard_test.mojo` → `xsel`, `16 passed, 0 failed`.
11 changes: 11 additions & 0 deletions clipboard/__init__.mojo
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# clipboard - desktop clipboard helpers for Mojo apps.
#
# Public surface:
# from clipboard.clipboard import (
# BACKEND_AUTO, BACKEND_WAYLAND, BACKEND_XCLIP, BACKEND_XSEL,
# BACKEND_OSC52, SELECTION_CLIPBOARD, SELECTION_PRIMARY,
# detect_backend, backend_available, backend_name, availability_report,
# read_text, write_text, clear, osc52_sequence, write_text_osc52,
# )
#
# See clipboard/README.md for backend requirements and limits.
Loading