Commit Graph
37 Commits
Author SHA1 Message Date
Ole André Vadla Ravnås c94525fb8a ui: Match the machines empty state to the notebook
Share the notebook's heading, add a button that boots a machine, and
leave out the panel title while there is nothing under it.
2026-09-29 15:38:58 +02:00
Ole André Vadla Ravnås f8d25015ae Drop the comments that only restate the code
A comment is a last resort, and these were not one: section banners,
doc headers naming what the declaration below already names, and
notes saying in prose what the next line says in code.

What is left is what the code cannot show -- an ordering that matters,
a platform quirk, why the obvious way fails.
2026-08-13 13:09:18 +02:00
Ole André Vadla Ravnås b6ee7d7187 Put the whole surface on iOS too
The playground, the notebook cells, the source editor with its
marks, the inspector columns and the canvas are written once for
both Apple platforms, with a file naming what the two frameworks
call differently. The editor is where they really part company.

The engine owns the image and its start-up, so a mission reaches
the whole of Pharo.
2026-08-13 12:46:09 +02:00
Ole André Vadla Ravnås 48f13e55af Open a body inline under its mark
A mark's body opens as a view attachment on its own line under it,
with the rest of the send carried below, so the code reflows around
it rather than stacking under the editor. Snippets reorder and copy;
a graph or chart draws offline from its snapshot.
2026-08-13 12:46:09 +02:00
Ole André Vadla Ravnås 1e66b7a4f9 Say what a failed snippet did, and where
A compile error reads in words with a dot at the failing spot.
Evaluate splits from evaluate-and-inspect, the snippet spins while
it runs, and print it, format and browse sit on GT's keys.
2026-08-13 12:46:08 +02:00
Ole André Vadla Ravnås a7a806e3c0 Grow the playground into a page of snippets
Snippets share their variables across runs and evaluate from the
keyboard, a page can be maximized, an empty one says what it is for,
and the columns beside it head and size their own lists.
2026-08-13 12:46:08 +02:00
Ole André Vadla Ravnås 58cc198c6a Scroll the columns and the strip together
A drill reveals its new column whole, scrolling through the reader
rather than at a position measured before the column exists, and
the strip's thumb both follows the columns and drives them.
2026-08-13 12:46:08 +02:00
Ole André Vadla Ravnås 6080bff60c Open Pharo values in panes beside the page
Each value opens in a pane on the gutter, beside the page rather
than under it. Panes drag, close and walk, a crowded tab strip
scrolls, and the split and its divider stay where they were put.
2026-08-13 12:46:08 +02:00
Ole André Vadla Ravnås 3aab17ca5a Run Pharo from the notebook and a playground
Boot the VM against a bundled image, evaluate from a notebook cell
or a playground snippet, and keep what each evaluation produced.
The image is staged on every build; the framework release is pinned.
2026-08-13 12:46:08 +02:00
Ole André Vadla Ravnås e0da0576cd Keep colors when pinning r2 results to notebook
Carry the styled text on NotebookEntry alongside the plain
details, capture it when pinning an r2 cell, and render it with
color in both notebook frontends.
2026-06-26 19:24:51 +02:00
Ole André Vadla Ravnåsandtrufae 2e00198952 Add block-level Markdown renderer
Port the mai-ios block parser into LumaCore; render headings,
lists, tables, task lists, blockquotes, code blocks and
footnotes across the SwiftUI and GTK frontends.

Parse inline spans and rewrite LaTeX to Unicode in LumaCore so
both frontends share one parser. Highlight code through
StyledText. Drop the inline-only AttributedString path.

Co-authored-by: trufae <[email protected]>
2026-06-26 16:00:59 +02:00
Ole André Vadla Ravnås 5f65a0eed8 Auto-edit only locally created notes
Empty new notes broadcast immediately, so every client
auto-entered edit mode. Gate auto-edit on the locally inserted
note id.
2026-06-25 11:11:56 +02:00
Ole André Vadla Ravnås a52b49adb8 Luma: Show editor avatars on missions and notes
Extracts the avatar stack used by notebook entries into a shared
view; reuses it on the mission list/detail and in the address-
note popover header and message rows.
2026-05-18 00:29:07 +02:00
Ole André Vadla Ravnås d8e64ddc6f core: Extract Author into shared model
Will be reused by mission and address-note attribution.
2026-05-18 00:25:58 +02:00
Ole André Vadla Ravnås 529c88de34 ui: Show joining-lab indicator 2026-05-16 22:26:52 +02:00
Ole André Vadla Ravnås c5d2ff7050 core: Replace Workspace with per-document Engine
EngineRegistry caches one Engine per working-project URL.
MainWindowView.init does a pure lookup, so SwiftUI's
view-tree re-evaluations cannot open extra ProjectStores
that race the live one's BEGIN IMMEDIATE and crash via
try!.

UI-state persistence (collapse flag, sidebar selection,
session detail section, etc.) lives on Engine for GTK to
adopt. SQLite has a 5s busy timeout. Engine open failures
surface as an error view.

TargetPicker is host @State injected via environment.
Global instrument-UI defaults register at app startup;
per-engine instrument and local-notifier hookups live in
Engine extensions.
2026-05-11 21:15:47 +02:00
Ole André Vadla Ravnås 51c693a665 swiftui: Add accessibility identifiers for UI tests 2026-05-03 22:29:31 +02:00
Ole André Vadla Ravnås ab64fdd4f2 notebook: Redesign entry header
Reorder the entry header to place editor avatars on the left,
process chip next, the title filling the flex middle, and the
timestamp pinned to the right. The time's x position now stays
stable across entries regardless of title length or editor count,
so a column of notebook entries reads as a neat column of times.

Avatars now use the GitHub-style overlap: 20pt size, -8pt trailing
spacing (≈40% overlap), 2pt ring in the card background so
adjacent circles stay visually separated, and explicit z-order
with the creator on top. On GTK the cluster is built with
Gtk.Fixed for the overlap and a `luma-editor-avatar` CSS class
applies the ring via box-shadow.

Matches the lab-page layout after 2e5c7c9 in luma-server.
2026-04-22 20:14:21 +02:00
Ole André Vadla Ravnås 0723c6e346 notebook: Switch to absolute-date timestamps
Relative "5 min ago" labels gave the notebook a chat-like feel.
Replace with absolute notebook-style timestamps — today shows
"HH:mm", yesterday "Yesterday", last week's entries the weekday
name, older entries an abbreviated date. Share the formatter from
LumaCore so GTK renders the same strings. Demote the SwiftUI
label to tertiary to reinforce "metadata, not content".
2026-04-22 18:15:30 +02:00
Ole André Vadla Ravnås 7313179e5c notebook: Reshape New Note FAB into balanced pill
The floating New Note button looked squashed — wide without any
matching height. Apply a capsule button shape, bump the iOS control
size, and pad the label vertically so the pill sits closer to a
golden-ratio aspect. macOS keeps its small control size.
2026-04-22 17:54:33 +02:00
Ole André Vadla Ravnås 98d61fd2b7 notebook: Polish empty state and editing flow
Give the empty state a prominent New Note button and have the
sidebar's no-selection view route Add Note through it too. Hide
the floating New Note button while any entry is being edited so
it doesn't stack on top of the row controls. Default freshly
inserted notes to an empty title, show a placeholder in the body
editor, and discard on cancel when both fields are still empty
instead of leaving a stray "Note" row behind.

Scroll to a dedicated bottom anchor on insert so the new row
lands above the keyboard / safe area instead of at the exact row
origin. Trim the horizontal inset on compact width so notebook
content isn't clipped by the narrow iPhone margin. Omit the
instruction walkthrough on compact; its width assumptions don't
hold on the phone.
2026-04-21 18:53:41 +02:00
Ole André Vadla Ravnås a081adc9d9 ios: Port SwiftUI app to iPhone
Restore iOS compilation by gating AppKit-only code in
StyledTextSwiftUI, ITraceTimeline, CollaborationPanel, and
MainWindowView. Stub ITraceCFGView behind #if canImport(AppKit)
since the Metal/NSView renderer is not ported yet. Add a
UIApplicationDelegateAdaptor mirroring the macOS delegate for
luma:// URL handling and APNs. Fix the rpath for iOS's flat bundle
via SDK-conditional LD_RUNPATH_SEARCH_PATHS overrides.

Build a new phone-first shell (PhoneMainView /
PhoneSessionsListView / PhoneSessionView) that replaces
MainWindowView on iOS. Right-edge drawers for events and
collaboration with glow indicators, a session-switcher popover, and
a segmented REPL / Instruments / Insights / Captures layout. The
Sessions list and Session screen each render a custom compact
header instead of the system nav bar so they sit flush under the
DocumentGroup chrome. Notebook pushes from the Sessions root.

Extract SessionContent so the detach banner lives at the parent of
any session-bound surface instead of each detail view rendering its
own. Make HexView responsive: hide the offset column and use
smaller hex and ASCII fonts in compact width, with selection hit
testing aware of the hidden column. Move the REPL cell timestamp
to share the request line so the result row gets the full cell
width, and trim the REPL horizontal padding in compact width.
Replace Color.cyan with a light/dark adaptive Color.jsTypeLabel so
Object{N} labels stay readable on a light background, and
ellipsize the JS inspector disclosure header to one line.
2026-04-21 18:53:40 +02:00
Ole André Vadla Ravnås 671a3bdcad Trim notebook visual rough edges
Three small polish fixes:

- Mac notebook: drop the inline pencil "Edit Note" button from
  the row header. It was pushing the editors and timestamp
  leftward only for notes, so notes and capture rows visually
  drifted apart. Double-click and the right-click menu already
  cover entering edit mode.
- Mac notebook: slim the top drop strip from 16 pt to 6 pt and
  stop applying the LazyVStack's 12 pt top padding to it, which
  together had left the first row floating far below the top of
  the pane.
- GTK notebook row: Adwaita's `.card` style already provides
  vertical padding, so the explicit 10 pt inner margins were
  stacking and making the top of each card look visibly taller
  than the bottom. Let the stylesheet own the vertical space.
2026-04-20 12:16:40 +02:00
Ole André Vadla Ravnås a13baea3a5 Tidy notebook + collab panel after feedback
Follow-ups to the last round:

- Mac notebook: the floating "New Note" button used to overlap
  the last row's Save/Cancel controls even after scrolling. Add
  80 pt of bottom breathing room to the LazyVStack, and scroll
  the freshly-inserted note into view via ScrollViewReader so
  the editor shows up below the fold without the user hunting.
- Mac notebook drag: per-row `.dropDestination` only fires
  inside the row's frame, so drops into the empty space above
  the first row landed nowhere. Add an explicit 16 pt top drop
  strip (`TopDropZone`) that reorders the source to position 0.
- Mac CollaborationPanel: center-align the lab picture and
  title+edit button (was top-aligned, which looked lopsided).
- Both CollaborationPanels: when a project has already been
  linked to a lab and we're just disconnected, say "You're
  currently offline from the shared lab … Reconnect to rejoin
  and resume syncing." and label the button "Reconnect" —
  instead of the previous "Enable collaboration" copy that
  implied a fresh activation.
- Engine: drop the `[notebook] reorder …` diagnostic print.
2026-04-20 12:00:33 +02:00
Ole André Vadla Ravnås c2f8a6be1b Round of collab-panel and notebook polish
A batch of small UI fixes across both frontends:

- GTK header bar: drop the row of text buttons ("New Session…",
  "Add Instrument…", "Install Package…", "Collaboration") and
  replace with symbolic icon buttons pinned to the right, GNOME
  HIG-style. Icons are list-add, applications-engineering,
  media-playback-start (unchanged), folder-download, and
  system-users. Labels survive as tooltips.
- Both CollaborationPanels: shorten "Share this link so others
  can open a new project and join this notebook." to "Share this
  link to invite others to this notebook."
- GTK CollaborationPanel: single-line ellipsized lab title
  (was wrapping to three lines to match picture height);
  consistent "Members"/"Chat" section labels instead of all-caps
  "PARTICIPANTS"/"CHAT".
- Mac CollaborationPanel: lab title wraps over multiple lines
  instead of ellipsizing; panel width is now draggable via
  HSplitView (min 260, ideal 300, max 520); lab picture uses
  fixed-size frame+clip so large-dimension uploads render
  crisply at 48 pt; uploads downscale to ≤512 px JPEG before
  sending.
- GTK CollaborationPanel: matching lab-picture downscale via a
  new CLuma shim (`luma_image_normalize`) that uses GdkPixbuf
  to decode→scale→JPEG-encode.
- Mac notebook editor: explicit Save/Cancel buttons on the
  entry editor (mirrors the GTK row). A freshly-inserted blank
  note cancels itself away instead of leaving a stub row.
- Mac notebook drag: capture row height via GeometryReader so
  the above/below midpoint is actually computed, which means
  drops above the first row finally work.
- GTK notebook row: drop the redundant "Edit" button from the
  header — double-click and the right-click menu both already
  enter edit mode.
2026-04-20 11:41:36 +02:00
Ole André Vadla Ravnås 60fc7bb706 Add lab pictures and refresh timestamps
Lab pictures are now uploadable by the owner — pick an image in
the CollaborationPanel (NSOpenPanel on Mac, GtkFileDialog shim
on GTK) and it becomes the lab's avatar on every client and on
the browser /l/<id> page. PNG, JPEG, WebP, and GIF are accepted;
the server enforces a 512 KiB cap. When no picture is set we
fall through to the owner's GitHub avatar, so a lab that nobody
bothers customizing still shows a real face. Clients get
pictures inline in the .join snapshot (bytes appended after the
notebook blob) and live updates via +update on
/labs/<id>/picture; CollaborationSession gains setLabPicture /
removeLabPicture RPCs.

Two other fixes in the same pass:

- Relative timestamps now refresh. Mac wraps each label in a
  TimelineView(.periodic(..., by: 60)); GTK runs a single 60 s
  Task that rewrites the string on every registered Label. So
  "1 min ago" actually advances to "2 min ago" without a
  rebuild.
- Closing a document window now stops collaboration. Previously
  the session stayed joined until the whole app quit — Mac via
  .onDisappear on MainWindowView, GTK via the existing
  closeHandler calling engine.collaboration.stop() before
  persisting state.
2026-04-20 10:17:50 +02:00
Ole André Vadla Ravnås 235b978234 Add lab title and render times relatively
Every lab now has a title. On .create the client mints one from
the owner's local timezone — "<Weekday> <morning|afternoon|
evening|night> <verb>" with verb ∈ {reversing, tracing, hacking,
spelunking, poking, sleuthing, dissecting} — so the first thing
everyone sees is something like "Friday evening spelunking"
instead of an opaque id. Owners rename at any time via a pencil
button in the CollaborationPanel (SwiftUI inline field on Mac,
inline Entry on GTK); the server broadcasts +update on
/labs/<id> so every connected client gets the new title live.

Separately, all visible timestamps switch to a coarse "time ago"
form ("just now", "5 min ago", "2 hr ago", "yesterday", "3 days
ago", "last week"). A shared `LumaCore.RelativeTime.string(from:)`
helper keeps Mac and GTK consistent; the absolute timestamp lives
on as a tooltip for anyone who needs it. Event stream / REPL
cells keep their absolute high-precision times since those are
high-volume and the exact value matters.
2026-04-20 09:54:46 +02:00
Ole André Vadla Ravnås 72fb0dec78 Sync notebook via op log with outbox
Replace the four per-mutation notification types (+add/+update/
+remove/+reorder) with a single +op envelope carrying {op_id,
kind, ...}. Pending mutations persist to a `notebook_outbox`
table on the client and replay on every .joined transition, so
an offline user's work propagates as soon as they're back on the
bus. Projects that never enable collaboration keep a zero-row
outbox — we only touch it once `collaboration_state.lab_id` is
set, and bulk-enqueue existing entries on createLab's success.

Model changes, in the same pass:

- NotebookEntry swaps `author: Author?` for `editors: [Author]`
  (creator at index 0, each editor appended as the server applies
  their update op). The boolean `isUserNote` is gone; callers now
  read `entry.kind == .note` directly.
- Entries carry a `position: Double` — server-authoritative on
  add (`max + 1000`), client-computed midpoint on drag. Clients
  sort by `(position, id)` so concurrent reorders converge.
- Schema folds the new columns into v1 (no migration — Luma isn't
  shipped).

UI:

- Mac: header renders a stack of editor avatars (tooltip = name,
  tap opens the GitHub profile). Entry rows are draggable and
  accept drops on top/bottom halves to compute the insertion slot.
- GTK: same avatar stack; reordering lives in the right-click
  menu (Move Up / Move Down) since SwiftGtk's DragSource binding
  isn't verified yet on this branch.
2026-04-20 09:30:07 +02:00
Ole André Vadla Ravnås 19c9da261c Surface server-stamped entry authors
The server stamps NotebookEntry.author from the authenticated
connection on every +add and echoes it back, but Engine's handler
was ignoring the echo for entries that already existed locally,
so the local row never picked up the stamped identity.

Merge author from the echo into the locally-cached entry and fire
.updated. Mac NotebookView and GTK NotebookPane now render an
avatar + display name chip in each entry's header, mirroring the
CollaborationPanel look.
2026-04-20 02:04:11 +02:00
Ole André Vadla Ravnås 7ef7bdc5f1 notebook: Center walkthrough below subtitle
The numbered walkthrough was geometrically centered but visually
lopsided: the title was narrow, the bullet block was wide, and
the whole block sat left-of-title. Add a leading offset so the
block's content sits visually centered beneath "Capture
interesting findings here." — 72pt in SwiftUI, 64pt in luma-gtk.

Also on the SwiftUI side:
- Restore the inline SF Symbol references to the toolbar buttons
  (target / waveform.path.ecg) that step 1 and 2 point at. The
  macOS toolbar buttons are icon-only and don't have visible
  labels, so the prose wouldn't otherwise tell users what to
  click.
- Bump instructionsMaxWidth 350 → 440 so step 3 no longer wraps
  after "save it here."
- Monospaced-digit the leading number so "1." "2." "3." render
  at identical widths regardless of proportional metrics.
2026-04-15 13:12:40 +02:00
Ole André Vadla Ravnås 5e2ba8b953 notebook: Align walkthrough across frontends
- SwiftUI: split each numbered step into an HStack with a fixed
  18pt right-aligned number column and a leading text column,
  matching the luma-gtk presentation so the step text aligns
  cleanly regardless of digit width. Drop the inline SF Symbols
  since the equivalent is awkward on GTK and the icons weren't
  pulling much weight.

- luma-gtk: match the SwiftUI copy for step 3 ("Pin any event
  from the stream to save it here." instead of "Pin any output
  to save it here.").
2026-04-15 12:33:35 +02:00
Ole André Vadla Ravnås 0e669be3dc Move the rest of business logic into LumaCore
Workspace is now a thin host adapter. Engine owns sessions and
notebook entries (via store observation), GitHub auth + OAuth
device flow, hook-pack discovery, address annotations and address
actions, the disassembler cache, and all instrument lifecycle.
EventLog is @Observable so SwiftUI tracks it directly; the host
no longer mirrors event arrays or version counters.

R2 (live disassembly + trace inspection) lives entirely in
LumaCore as concrete Disassembler / TraceDisassembler classes
returning portable StyledText spans. ProcessNodeViewModel and
InstrumentRuntime are gone; views read engine.processNodes /
node.instruments / engine.descriptor(for:) directly.

Reorganize Luma/Models/ — instrument UI dispatch lives under
Luma/Instruments/, Monaco editor glue under Luma/Editor/, and the
remaining UI types sit at the top of Luma/.
2026-04-07 10:11:31 +02:00
Ole André Vadla Ravnås 875a19cfc2 Delete Workspace+Collaboration
CollaborationSession is now @Observable. Views read its
state directly via workspace.engine.collaboration. The
notebook entry methods live on Engine. The portal cert
is a LumaCore SwiftPM resource via Bundle.module.

Workspace keeps only the auth-flow glue (showing the
sign-in sheet, signOut clearing UI state) and the deep
link join handler.
2026-04-07 07:47:39 +02:00
Ole André Vadla Ravnås bddb2830fe Wire views and Workspace exts to ProjectStore
Update every view and Workspace extension to use LumaCore
types and ProjectStore instead of SwiftData:

- SidebarView: fetch instruments/insights/captures from store
- DetailView: resolve sessions via store
- REPLView: load cells from store by sessionID
- NotebookView: use LumaCore.NotebookEntry value types
- Workspace+Packages: delegate to CompilerWorkspace, use
  ESMBundleParser.parse(), persist via store
- Workspace+Collaboration: fetch/save collaboration state
  and notebook entries through store
- All remaining views qualified with LumaCore types

The Luma app should now compile without SwiftData.
2026-04-06 21:03:17 +02:00
Ole André Vadla Ravnås 19369c1f8a Remove SwiftData and wire Luma app to ProjectStore
Delete all 10 @Model classes (replaced by LumaCore structs).
Remove SwiftData imports from 27 files. Drop DocumentGroup,
schema versions, and migration plan from LumaApp.

ProcessNodeViewModel now persists REPL cells, ITrace
captures, and session updates through ProjectStore instead
of ModelContext. InstrumentRuntime uses the LumaCore
InstrumentInstance struct directly.

WIP: Workspace needs ProjectStore injection and views need
wiring to load data from the store. The Xcode build has
errors until the remaining view plumbing is done.
2026-04-06 20:33:20 +02:00
Ole André Vadla RavnåsandFrancesco Tamagni d9c1c5376a Start integrating r2
Kudos to @mrmacete for the Ansi parser.

Co-authored-by: Francesco Tamagni <[email protected]>
2025-12-13 18:56:33 +01:00
Ole André Vadla Ravnås 851b8e26bd Initial commit 2025-12-05 23:16:30 +01:00