feat: shared pseudoscript-lsp-core — stdio + LSP-over-wasm, one API#12
Conversation
A partial identifier under the caret ends at the offset, so the `<= offset` trigger scan selected it instead of the `.`/`::`/`:`/`#[` before it, falling through to general items. Skip the boundary identifier; its predecessor governs context. Adds with-prefix tests per context. refs #10 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Native LSP (complete.rs) and the web IDE's context-free JS provider are unsynchronised; wasm exports no completion. Notes the surface to edit per request and the unify-via-wasm direction. refs #10 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The web IDE completed from a context-free JS provider (every keyword + every symbol, always), while the LSP's context-aware engine was unreachable from wasm (tower-lsp/tokio won't build to wasm32). Extract the completion engine into pseudoscript-model::complete with a neutral CompletionItem/CompletionKind over byte offsets, carrying the governing_trigger scope fix. pseudoscript-lsp and pseudoscript-wasm become thin adapters: the LSP maps to lsp_types, wasm serialises to JSON via a new completion(modules, fqn, offset) export. The web IDE calls it and replaces only the trailing identifier segment, so members complete after '.', a module's symbols after '::', macros after '#[', types in type position — identical to native editors. Regenerated pds-wasm bundle. refs #10 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Deploying pseudoscript-landing with
|
| Latest commit: |
bb85516
|
| Status: | ✅ Deploy successful! |
| Preview URL: | https://d7709d93.pseudoscript-landing.pages.dev |
| Branch Preview URL: | https://feat-ide-lsp-completion.pseudoscript-landing.pages.dev |
Deploying pseudoscript-ide with
|
| Latest commit: |
bb85516
|
| Status: | ✅ Deploy successful! |
| Preview URL: | https://77b430c1.pseudoscript-ide.pages.dev |
| Branch Preview URL: | https://feat-ide-lsp-completion.pseudoscript-ide.pages.dev |
|
Browser acceptance — verified in the live dev IDE (ACME Tickets sample,
Engine + wasm + IDE wiring all exercised. The "not yet verified" caveat in the description is now closed. |
Broader LSP alignment (the web IDE should source language intelligence from the compiler, not reimplement it in JS): - Semantic highlighting: extract the AST-aware token engine into pseudoscript-model::semantic (neutral SemKind/SemToken over byte offsets); pseudoscript-lsp delta-encodes to lsp_types, pseudoscript-wasm exports semantic_tokens(). The IDE now decorates these tokens (data-sem marks) and the hand-written StreamLanguage tokenizer + JS keyword lists are gone — no more drift from the lexer. - Folding: extract fold ranges into pseudoscript-model::fold; wasm folding_ranges(); the IDE folds AST-accurate ranges and blocks.js (brace-scan) is removed. Testing suite (data-testid throughout, no brittle selectors): - Vitest + Testing Library: unit tests for offset conversion, component test for FileTree's data-testid contract. - Playwright e2e: headless tests for highlighting roles, completion scoping + the prefix-narrowing scope fix, and compiler-driven folding. - Storybook (@storybook/sveltekit) with FileTree stories. - data-testid added to file rows, editor host, and sample cards. refs #10 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
refs #13 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
refs #13 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
One LSP API, two transports. The handler logic (analysis, complete, convert, infer, refs, semantic, symbols) moves into a new pseudoscript-lsp-core crate that depends on pseudoscript-model + standalone lsp-types =0.94.1 (the version tower-lsp 0.20 re-exports, WASM-safe), NOT tower-lsp. - pseudoscript-lsp keeps only the stdio transport (server.rs + the disk-walking workspace.rs) over lsp-core. - pseudoscript-wasm's language exports (completion, hover, semantic_tokens, folding_ranges) now call the same lsp-core handlers and serialise their lsp_types results to JSON, so the wasm API is byte-for-byte the LSP API. Hover drops the SVG (now a plain lsp_types::Hover); the diagram stays on symbol_scene/symbol_svg. - The web IDE is now an LSP client: decodes delta-encoded SemanticTokens, integer CompletionItemKind, line-based FoldingRange, Markdown Hover. definition/references stay fqn-ergonomic (LSP Location is URL-centric; the browser has no file URLs) but share model::resolve, so no fork. refs #13 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Architecture follow-up: one LSP API, two transportsPer review, the wasm API now mirrors the LSP API exactly via a shared core, instead of parallel adapters that could drift. New crate
Verified: |
decl.span reaches back over leading `///` doc comments and blank lines,
so folding it swallowed the gaps between declarations — the rendered
code lost its newlines (`{…}…}…}`). Fold from the declaration's name
through its end instead, and fold only brace-delimited records (a
brace-less `data = | …` union is not a block fold). Regression tests
in model and e2e.
refs #13
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The fold close landed at the start of the closing line, so an indented `}` left its leading whitespace between the `…` placeholder and the brace. Close at the brace itself (past the indent) so the indentation folds away too. refs #13 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The Topbar and footer brand showed both a plain accent dot and the nested-squares Mark. Keep the Mark; remove the dot. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
`identity::sessions.` only tried the bare name `sessions` in the current module, so cross-module member completion never resolved. Resolve the qualifier path to the owning module (public, per §8.2). refs #13 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…ndo-on-switch - Nav history records the pre-jump caret as the origin, so Back works from the first go-to-definition (was: only the destination recorded). - Editor exposes location(); the shell records it before each jump. - Theme selector in the toolbar cycles system/light/dark. - Syntax highlight colours move to theme-aware --hl-* tokens (dark + darker, higher-contrast light variants), so light mode is legible. - A file switch resets the editor undo history, so Ctrl+Z no longer undoes across the boundary into the previous file (Format stays undoable on the same file). refs #13 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Only `#[` + the name were decorator; `#[onevent(catalog::EventCancelled)]` left its args as namespace/type and the brackets uncoloured, reading as fragments. Colour the whole `#[…]` span as a decorator (subsuming name and args), matching the prior tokenizer. refs #13 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…als clicks - Doc preview embeds the whole built site in a host page and swaps pages in an iframe on internal-link clicks (assets inlined), so navigation stays in the preview instead of breaking on relative .html links. - The hover card's transparent bridge is pointer-transparent, so clicks and double-clicks land on the editor text, not the tooltip; the card itself stays interactive. refs #13 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Open-folder, import and recents were three mismatched affordances stacked together. Recast them as one row language under Start (open folder / import) and Recent, with a consistent glyph + meta + chevron, matching the example cards' rigor. data-testid on the action rows. refs #13 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…nter byte mapping - An opened example persists nowhere, so it is no longer recorded in recents (legacy sample entries are filtered out); it re-opens from the examples catalogue. - Seed the session baseline from the example so edits register; the save indicator now reads 'session · N unsaved' once a session is edited. - Restore the byteToChar import in pseudoscript-language.js — the linter needs it to map diagnostic byte spans; its removal during the semantic highlighting change broke all diagnostics. Add an e2e guard. refs #13 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The doc site drew sequences with a dagre node-graph; the web IDE draws a
lifeline/message UML diagram positioned by pseudoscript-layout. Unify
them: embed the positioned Layout in the Sequence figure props (Rust),
vendor the IDE's FlowTimeline + Sequence{Lifeline,Messages,Fragment}
components into the doc bundle (dropping the IDE-only theme store), and
pass the layout through. Regenerated client.js/ssr.js/style.css and the
wasm bundle.
Verified: a module page embeds the layout and the client bundle renders
the lifelines.
refs #13
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Convert both Svelte apps from JS to TypeScript: every lib .js → .ts and every component to <script lang="ts">, with typed $props/$state and typed function signatures. Configs/tests to .ts too (svelte.config.js stays .js per SvelteKit). tsconfig strict; @types/node + vite-env shims. svelte-check passes with 0 errors on both apps; wired `npm run check` into CI (web job + a new landing job). Build, vitest (9/9) and the Playwright e2e (5/5) are green — types only, no runtime change. refs #13 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
General/reference-position completion only offered keywords + this module's symbols, so a cross-module reference (e.g. context::AcmeTickets) couldn't be started from autocomplete. Add the workspace's other modules (the names before ::) to the general set; pick one, then :: drills in. refs #13 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Audit of the completion engine surfaced several gaps: - Members of a local binding (a = Repo.fetch(id); a.) gave nothing — the receiver's inferred type was unused. Move infer into the model (it depends only on model) and resolve the binding's type to its node. - Type position offered Result but not Option (both built-in generics). - A macro argument (#[onevent(Event)]) got the general keyword set instead of types; route it to type completion. infer.rs moves from pseudoscript-lsp-core to pseudoscript-model; lsp-core re-points to pseudoscript_model::infer. Tests for each gap. refs #13 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Apply rustfmt and satisfy clippy::semicolon_if_nothing_returned in the call-member check added in the previous commit — the CI `cargo fmt --all --check` and `clippy --all-targets -D warnings` gates. No behavior change. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Two IDE correctness bugs:
1. The new-project (`starterModule`) and new-file (`pdsSkeleton`)
templates emitted generic brace-nested pseudocode — `#` comments,
`system X { container Y { fn z() } }`, none of which is PseudoScript.
Replace with a minimal valid model: `//!` header, `///` docs, a
`public system`, a `public container … for …`, and a void callable.
Verified to check clean and project a diagram.
2. Go-to-definition reported PDS-GOTO-003 (resolved symbol not in the
navigator) for every cross-module target. `nodeIndex` was keyed by
single-file `outline`, which derives the module FQN from the `//!`
header, while `definition`/`hover`/`references` qualify by the file's
path FQN. When the two differ (`messaging` header vs `messagingcore`
path) the index missed. Key `nodeIndex` off the workspace outline
(`outlineModules`, path FQNs, cross-file parents resolved), grouping
each node to its file by longest module-FQN prefix.
Pin the resolver contract with a wasm test: `definition` qualifies by the
workspace module FQN, not the `//!` header. JS-only IDE change otherwise —
no wasm rebuild needed for the fix itself.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The empty-template e2e asserted the old starter's hardcoded `Platform` system. The starter now names the system after the project, so assert the stable `public container Api` the template always emits, and check the external-reload test against that token. Full e2e suite (10) + storybook build pass locally. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…e 0) Begin the Phase-1 logic lift: add src/lib/core/types.ts holding the shapes the view and the (coming) pure core modules both need — StructureNode, Symbol, Problem, OpenFile, WorkspaceModel, Loc, Canvas, doc/dialog/note types — plus the WasmApi injection interface (the subset of pds.ts the core will take as a dependency rather than import, keeping core unit-testable). +page.svelte now imports these (WorkspaceModel aliased to its historical PageWorkspace name); only the view-specific MountInput stays local. Pure type re-home, no behaviour change. check + vitest green. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…core (Wave 1a) Lift three independent concerns out of +page.svelte into pure, unit-tested core modules; the page now delegates via thin wrappers (behaviour identical): - core/navigation.ts — history reducer (record/collapse/cap/step), originLoc, samePosition. The impure applyLocation/editorApi stay in the page. - core/diagnostics.ts — computeDiagnostics: checkModules → problems/errorCount/ errorPaths, with the throw-degrades-to-empty behaviour preserved (WASM injected). - core/workspace-ops.ts — pdsSkeleton/pascalName/normalizePdsPath/slugify/withBase/ docPathSet and the new-file/new-doc/rename validators + danglingImporters, now taking the file set / base / doc paths as args instead of reading globals. 20 new vitest cases pin these (incl. the valid-starter-template and GOTO-adjacent invariants). Full suite: 32 vitest + 10 e2e green, svelte-check 0 errors. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Complete Wave 1 — the remaining independent pure concerns lift out of +page.svelte; the page delegates via thin wrappers (behaviour identical): - core/dirty.ts — keyOf, computeDirty (live buffers vs baseline), dirtyPaths, seedBaseline (pure, returns a new map), and classifyReload (skip/reload/ conflict). The debounce/FS/timer half stays in the page (→ save store later). - core/share.ts — snapshotWorkspace, mountedSources, parseHashPayload around the already-pure codec; the impure mountWorkspace/encode/decode stay in the page. - core/docs.ts — manifestHasDeps, resolveDocPath (./.. normalise), findDocByPath, buildDocConfig, sampleDocPages. The async readDocPages/load-race guard stays. 15 more vitest cases. Full suite: 47 vitest + 10 e2e green, build clean, svelte-check 0 errors. Wave 1 done: 6 core modules, page steadily shrinking. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Lift the structural heart out of +page.svelte: - core/model.ts — buildModelIndex(nodes, moduleFqns) computes the node index, per-file grouping (longest-prefix, the cross-module GOTO fix), flows, type map, and collapse info in one pass; plus pure resolvers resolveNodeFqn (collapsed member → real node), ownerNodeOf (field → owner, PDS-GOTO-002), ancestry (cycle-guarded), nodeTitle, singleLifelineScene, nodeByteOffset. - core/canvas.ts — projectCanvas: symbolScene vs context, collapseSequence, the empty/throw → lifeline fallback, layout; errors reported via an injected callback (wired to reportError) so it stays side-effect-free. canvasHint. The page now derives a single `index` and exposes its fields via aliases, and the canvas is one projectCanvas call. Dropped the now-dead charToByte/collapseSequence/ Info/PdsScene imports. 15 new vitest cases (incl. the GOTO + fallback invariants). Full suite: 62 vitest + 10 e2e green, svelte-check 0 errors. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Begin moving reactive $state off +page.svelte into thin Svelte-5 rune stores (state ownership only — all logic already lives in core/*): - stores/notifications.svelte.ts — owns the toast stack, flash message, and their timers; notify/dismiss/flash. - stores/wasm.svelte.ts — owns ready/error/version + the initWasm lifecycle. The page reads via aliases (`const ready = $derived(wasm.ready)`, etc.) and thin delegating wrappers, so every call site is unchanged; it no longer declares those state vars or imports initWasm/version. Behaviour identical: 62 vitest + 10 e2e green, svelte-check 0 errors. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Move the history trail off +page.svelte into stores/navigation.svelte.ts — it owns history/index over the pure core/navigation reducer and exposes canBack/ canForward/record/recordIfMoved/back/forward/reset. The view keeps the impure application (applyLocation: open file, jump editor) and calls back()/forward(), applying the returned Loc. Call sites unchanged via thin aliases. Behaviour identical — e2e exercises go-to-definition + Back/Forward: 62 vitest + 10 e2e green, svelte-check 0 errors. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…drop corner ticks Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Move the canonical workspace and selection state off +page.svelte: - stores/workspace.svelte.ts (wsStore) — workspace, openFile, moduleSources, manifestSource/Error, docGroups/Sources/Meta. - stores/selection.svelte.ts (selection) — view, seqDepth, selected, pendingGoto. Technique (svelte-check-guarded, zero behaviour change): replace each `let X = $state(...)` with a read-only `const X = $derived(store.X)` so every read site is untouched; the checker then flags each write (assign-to-derived) and those route to `store.X = …`. The derived/aria-selected reads stay intact (guarded the substitution so `aria-selected` wasn't mangled). The page keeps all orchestration (selectNode, mutations, the pendingGoto effect). 62 vitest + 10 e2e green, svelte-check 0 errors. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- stores/save.svelte.ts (saveStore) — owns persisted baseline + saveState cue; the debounce/FS methods stay in the view. Writes routed via the checker-guided derived-alias technique. - stores/diagnostics.svelte.ts (diagnostics) — a derived-only store: re-runs the static check over wsStore + WASM checkModules via core/diagnostics, exposing problems/errorCount/errorPaths. Added wsStore.allModules getter so the page and this store share one module list. Dropped the now-dead computeDiagnostics/checkModules page imports. 62 vitest + 10 e2e green, svelte-check 0 errors. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The last of the canonical state moves off +page.svelte: - stores/ui.svelte.ts (ui) — panel/modal flags, the persisted doc reading width, recents, canvas popovers, and the prompt/confirm dialogs (handlers stay in the view). - stores/share.svelte.ts (shareStore) — the share-encode busy flag. Same checker-guided derived-alias + write-reroute technique; no attribute names collided. With this, all ~30 canonical $state vars now live in 8 focused rune stores (wasm, notifications, navigation, workspace, selection, save, diagnostics, ui, share); +page.svelte holds orchestration + template, all logic in core/*. Full gate: 62 vitest + 10 e2e green, build + storybook ok, svelte-check 0 errors. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…kens
Phase 2 foundation: bring shadcn-svelte in and map its theme onto the existing
design tokens — keep the colours and fonts, let shapes follow shadcn.
- Tailwind v4 via @tailwindcss/vite (vite.config); deps: tailwindcss,
tw-animate-css, clsx, tailwind-merge, tailwind-variants, bits-ui.
- app.css: `@import "tailwindcss"` + a `@theme inline` block mapping shadcn's
semantic tokens to our vars — brand `--accent` → `primary`, surfaces/lines →
card/secondary/muted/border, `--err` → destructive, `--radius` → the radius
scale. Fonts already share Tailwind's `--font-sans`/`--font-mono` names, so
they map for free. `dark:` keys off the existing `data-theme`. Tailwind's
layers sit below the unlayered hand-written CSS, so the current UI is untouched
— only shadcn components draw from Tailwind (verified: compiled
`.bg-primary{background-color:var(--accent)}`).
- components.json + src/lib/utils.ts (cn) so `shadcn-svelte add` works.
- Button component (shadcn) + a Storybook showcase; themed Storybook preview
(app.css + data-theme) so components render on the IDE palette.
No regression: 62 vitest + 10 e2e green, build + storybook ok, svelte-check 0
errors. Existing components unchanged — migration to shadcn comes next, per panel.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Pull the genuine registry components (via `npx shadcn-svelte@latest add`) the panel redesign will use: tooltip, separator, dropdown-menu, scroll-area, tabs — joining button. Each is the official component built on Bits UI headless primitives (DropdownMenuPrimitive, TooltipPrimitive, …) + tailwind-variants, not hand-rolled, and inherits the brand theme via the tokens mapped in app.css. Unused until the migration, so the build tree-shakes them; verified they compile: 62 vitest + 10 e2e green, build clean, svelte-check 0 errors. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Restructure +page.svelte into a Fleet-style island shell built from shadcn-svelte primitives, on the brand theme (compact "mira" density): - ActivityBar (left, VS-Code rail): Explorer / Canvas activities + Settings anchored bottom-left; shadcn Tooltip labels. - FileMenu (top-left, shadcn DropdownMenu): Open project, New file/doc, Save, Save all, Share/Export/Import, Build docs. TopBar adds theme/Format/save cue + the download-skill link (e2e testid kept). - StructurePanel (right, collapsible): the workspace symbol/outline tree, lifted out of FileTree into SymbolTree.svelte. FileTree drops its Symbols section. - ProblemsBadge (top-right, shadcn Popover): error/warning count → ProblemsPane, replacing the Problems view tab (Fleet floating icon). - Canvas is its own activity that replaces the editor in the centre; Explorer restores it. StatusBar extracted, compact. View model: selection.view "problems" dropped (→ code|canvas); ui.structureOpen (default on) + ui.problemsOpen added; added saveAll. New shell grid CSS; old .app/.workspace/.tree-pane/.view-toggle/.statusbar styles + Toolbar.svelte removed. Behaviour preserved — verified by the full e2e oracle (10) which exercises the new shell (create project, editor, file rows, canvas, diagnostics): 62 vitest + 10 e2e green, build + storybook ok, svelte-check 0 errors. Screenshotted dark: the activity rail, file tree, editor/canvas centre, and structure panel render on the brand palette. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- shadcn ContextMenu on file-tree rows (Open / Rename… / New file… / Delete) and on Structure-panel symbols (Go to definition / Reveal on canvas). Left-click and the data-testid="file-*" rows still work (e2e green). - Island look: a shared `.island` treatment (rounded, hairline-framed) on the activity rail, explorer, centre, and structure; the `.body` grid gains a gutter + padding on the app backdrop, so the panels read as separated Fleet islands. Top/status bars stay flush full-width. Collapsing structure now drops its column (no trailing gap). - vitest.config: add the `$lib` alias so deep shadcn-svelte imports resolve in component tests as they do in the app (FileTree.test was failing to load). 62 vitest + 10 e2e green, build clean, svelte-check 0 errors. Screenshotted: the rounded islands float on the dark backdrop; right-click opens the themed menu. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Add a shadcn Command palette (CommandPalette.svelte) opened with Cmd/Ctrl-K: a centred dialog that searches the workspace's files and symbols (kind-badged, fqn-qualified) and jumps to the pick — selectFile for a file, go-to-definition for a symbol. Wired via ui.commandOpen + a window keydown. 62 vitest + 10 e2e green, build clean, svelte-check 0 errors. Screenshotted: typing "order" filters to the orders module + its Order/OrderStatus/… symbols. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- TopBar gains a VS-Code-style centre search pill (workspace name + ⌘/Ctrl-K badge) that opens the command palette — discoverable + a tidy focal point. - FileMenu: "Go to file or symbol…" item (⌘K) and a Save shortcut hint (⌘S), platform-correct modifier glyph; "Open project…" relabelled. 62 vitest + 10 e2e green, build clean, svelte-check 0 errors. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…skill→settings Per product direction, rebalance the shell chrome: - StatusBar (footer) now hosts the save indicator and the Problems badge/popover (moved off the header). - TopBar (header) gains Back/Forward; drops save + problems. - Settings becomes a proper panel: an Appearance theme switcher (system/light/dark) and the authoring-skill download moved out of the header. e2e opens Settings via the activity-bar gear to reach the skill download. - StructurePanel gains a filter input (search symbols by name/fqn, ancestors kept so the tree still nests). - Command palette widened (≈56rem). 62 vitest + 10 e2e green, build clean, svelte-check 0 errors. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Squash of the day's IDE work into one commit. Highlights: - Shell: Fleet/VS-Code island layout, activity bar, tool-window panels with drag-resizable + persisted widths, relocated chrome, unified bottom-right toast notifications. - Files & editor: FS-backed file manager, unified file tree (symbol/text search), multi-file tabs as standalone pills with per-file state preserved, non-PDS files surfaced and editable with highlighting, TOML highlighting. - Launcher: IntelliJ-style Search Everywhere command palette, separate New-project dialog (mandatory name, target-folder-before-template). - Canvas: right-click context menus, Customise modal (layout algorithms + floating edge styles), layout presets, and PNG/SVG diagram export. - Language intelligence: LSP symbol rename across the project with a selectable preview. - CLI: `pds lang` and `pds skill` for offline language discovery. - Polish: PWA/address-bar colour + header sizing, opaque editor gutter, themed active-tab border. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
e9a567b to
4802ae5
Compare
The header's go-to/search button sat ~4px closer to the right edge than the right-rail nav button under it. Make the topbar's right zone a rail-width (--right-rail-w) box ending the same --island-gap from the edge as the rail column, with the icon centred — so both centre at the same distance from the edge. Apply the same gap in the PWA window-controls-overlay inset. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The header back/forward/search buttons were 1.7rem with 15px glyphs, smaller than the 2rem/18px act-btns in the left activity bar and right rail. Bump them to the same 2rem box and 18px (1.75 stroke) glyph so the search button matches the rail button it sits above; centre alignment is unchanged. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The header was 38px (--bar-h, shared with the content/tab/dock bars) while the left activity bar and right rail are 42px wide. Give the header its own height by reviving the unused --topbar-h (now 42px) and wiring the .ide grid row and TopBar to it — so the header matches the rail width and the rails start flush with its bottom edge. The compact --bar-h chrome is unchanged. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Mirror the C4 graph: lifelines, message labels, and signature type tokens open a right-click menu (Go to definition / Find usages) instead of the hold-hover info card and Cmd-click. Extract the shared menu chrome into CanvasMenu, driven by a declarative section model both diagrams build; hoist the menu/target types into core/types. Remove the now-dead hover-info popover path. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
web-landing: collapse onto one theme (model-driven development + pseudo-programming). - Hero: 'Model the intent. Implement the detail.', single primary CTA (Web IDE), benefit-led copy, Wikipedia links to MDE/pseudocode. - Reframe Workflow/agent copy; cut Convergence, Packages, IdeShowcase, Proof. - Scroll-link the Refine/Generate animations (scrub with scroll position). - Refine example now uses verbatim 'pds eval' diagnostics. - Match light theme to the web-ide; de-card the install band; align hero gutter. pds: add 'eval' subcommand — read a model from stdin, report diagnostics, exit non-zero on error (lets an agent check a snippet without a file). Factor the shared 'report_source' helper out of 'check'; add integration tests. docs: refresh CLAUDE.md (toolchain is implemented; list crates + commands incl. eval); add a root README with a hero + repository signposting. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
web-landing SEO pass: - index.html: aligned description, canonical, robots, theme-color, keywords; Open Graph + Twitter summary_large_image cards; JSON-LD (WebSite + SoftwareApplication); svg icon + apple-touch-icon; a <noscript> fallback with the h1, pitch, and primary links (the app is client-rendered). - public/: robots.txt + sitemap.xml (https://pdscript.dev/), and a real 1200x630 og.png social preview. - Hero: mark the decorative C4 diagram aria-hidden so the a11y tree reflects only meaningful content. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Closes #10. Closes #13. Single MR.
The web IDE now sources all language intelligence from the shared compiler core (via wasm), instead of reimplementing pieces in JavaScript. Plus an automated test suite.
1. Completion (was: context-free JS provider)
governing_trigger): a partial identifier under the caret no longer hijacks the trigger, so./::/:/#[contexts stay scoped.pseudoscript-model::complete(neutral types, byte offsets);pseudoscript-lspandpseudoscript-wasmare thin adapters. IDE calls the wasmcompletionexport.2. Semantic highlighting (was: hand-written StreamLanguage tokenizer)
pseudoscript-model::semantic(SemKind/SemToken, byte offsets).pseudoscript-lspdelta-encodes tolsp_types;pseudoscript-wasmexportssemantic_tokens.data-semmarks). The JS keyword lists, regex token rules, andHighlightStyleare deleted — no more drift from the compiler's lexer. StreamLanguage is kept only for comment-toggle.3. Folding (was:
blocks.jsbrace-scan)pseudoscript-model::fold;pseudoscript-wasmexportsfolding_ranges. The IDE folds AST-accurate ranges;blocks.jsremoved.Formatting, diagnostics, hover, definition, references, and outline were already wasm-backed (audit in #13). Highlight colours stay client-side (presentation). Rename/inlay/doc-highlight are absent features, not reimplementations — out of scope.
4. Test suite (data-testid throughout, no brittle selectors)
data-testidcontract.data-testid/data-sem.@storybook/sveltekit): FileTree stories.data-testidadded to file rows, editor host, sample cards.testworkflow runs Rust (fmt/clippy/test) + web-ide (vitest, build, e2e, storybook) on every PR.Verification
cargo fmt --check,cargo clippy --workspace --all-targets -- -D warnings,cargo test --workspace— all green (19 suites).web-ide:vitest run9/9,playwright test4/4,vite build+storybook buildsucceed.shared::→ only moduleshared's symbols;shared::User→ 1, no keyword leak.