Skip to content

Commit bbbecca

Browse files
committed
Migrate to legend-state observer framework
1 parent 347fdfa commit bbbecca

File tree

13 files changed

+230
-361
lines changed

13 files changed

+230
-361
lines changed

.github/copilot-instructions.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
This repository contains a VS Code extension that provides two webview-based tools for competitive programming: **Judge** and **Stress**.
44

55
- Extension backend code lives under `src/extension/**` and uses the VS Code API. `JudgeViewProvider` and `StressViewProvider` extend `BaseViewProvider`, which handles webview setup, CSP nonce generation, workspaceState storage, and message dispatch.
6-
- Webview frontend code lives under `src/webview/**` and is built with Preact. It talks to the extension only through typed messages defined in `src/shared/*-messages.ts`.
6+
- Webview frontend code lives under `src/webview/**` and is built with Preact + `@legendapp/state` for reactive state management. It talks to the extension only through typed messages defined in `src/shared/*-messages.ts`.
77
- Shared enums, message contracts, and types live under `src/shared/**` and define the protocol between extension and webviews (including the `Status` lifecycle and testcase structures).
88

99
Build and tooling:
@@ -17,6 +17,7 @@ Design and implementation guidelines:
1717
- All extension ↔ webview communication must use the discriminated unions and enums in `src/shared/*-messages.ts`. Append to enums instead of reordering to keep numeric values and stored data stable.
1818
- Use `compile()` and `Runnable` from `src/extension/utils/runtime.ts` for running code, and `resolveVariables` / `resolveCommand` from `src/extension/utils/vscode.ts` for safe, cross-platform commands.
1919
- Use `TextHandler` for streamed output; always call `.reset()` for a fresh run and `.write(data, last)` for updates.
20+
- Use `@legendapp/state` for webview state: wrap components with `observer()`, access values via `.get()`, mutate via `.set()`, and use `<Memo>{() => obs$.get()}</Memo>` for direct DOM updates (e.g., streaming text).
2021
- Keep changes minimal and consistent with existing patterns. Prefer reusing the Judge/Stress provider and webview patterns over introducing new architectures.
2122

2223
Additional path-specific details are defined in `.github/instructions/*.instructions.md`, which Copilot uses when working in matching files.

.github/instructions/webview-frontend.instructions.md

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,13 @@ When changing files under `src/webview/**`:
1010
- Treat the `App.tsx` components under `src/webview/judge/` and `src/webview/stress/` as entry points for each view. They receive initial state and subsequent updates exclusively through message types defined in the shared message unions.
1111
- When you need new messages or actions from the webview to the extension, first extend the shared enums and message interfaces in `src/shared/*-messages.ts`, then update both the extension providers and the webview components to handle the new types. Avoid magic string message names.
1212
- Assume styles are provided by an external CSS file built from `src/styles/global.css` into `dist/styles.css` via Tailwind CLI. Do not import CSS directly into TypeScript/TSX; the extension side (`BaseViewProvider`) injects the stylesheet as a `<link>` in the webview HTML.
13-
- Prefer the existing lightweight stack (Preact + signals) for state management. Avoid introducing heavier frontend state libraries; instead, follow the current patterns used in the Judge and Stress apps.
13+
- Use `@legendapp/state` for reactive state management:
14+
- Wrap components with `observer()` from `@legendapp/state/react` for automatic re-rendering.
15+
- Access observable values with `.get()` and mutate with `.set(value)` or `.set(prev => newValue)`.
16+
- Use `<Memo>{() => obs$.get()}</Memo>` for direct DOM updates that bypass VDOM diffing (ideal for streaming stdout/stderr).
17+
- Use `useObservable(value)` for component-local observable state.
18+
- Collections like `Map` and `Set` have fine-grained reactivity; use `state$.map.get(key)` to get an observable for a specific entry.
19+
- Avoid introducing additional state libraries; follow the patterns in the Judge and Stress apps.
1420
- Keep UI logic decoupled from process execution details. The webview should focus on rendering state and sending/receiving typed messages, not on spawning processes or resolving filesystem paths.
1521
- Maintain consistency with existing components such as `AutoresizeTextarea`, `Testcase`, and `State` in terms of props, message handling, and minimal DOM manipulation.
1622
- Keep changes surgical: avoid large-scale refactors or stylistic rewrites unless they are necessary for a specific task.

bun.lock

Lines changed: 3 additions & 8 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

eslint.config.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ import * as globals from "globals";
99
export default [
1010
js.configs.recommended,
1111
{
12-
ignores: ["dist/**", "node_modules/**", "src/external/**"],
12+
ignores: ["dist/**", "node_modules/**"],
1313
},
1414
{
1515
files: ["src/**/*.ts", "src/**/*.tsx"],

package.json

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -317,8 +317,8 @@
317317
"@rspack/cli": "^1.6.7",
318318
"@tailwindcss/postcss": "^4.1.17",
319319
"@types/node": "^22.19.2",
320-
"@types/react": "^19.1.6",
321-
"@types/react-dom": "^19.1.5",
320+
"@types/react": "^19.2.7",
321+
"@types/react-dom": "^19.2.3",
322322
"@types/vscode": "^1.106.1",
323323
"@types/vscode-webview": "^1.57.5",
324324
"@typescript-eslint/eslint-plugin": "^8.49.0",
@@ -337,10 +337,9 @@
337337
"typescript": "^5.9.3"
338338
},
339339
"dependencies": {
340-
"@preact/signals-react": "^3.6.1",
341-
"nu-observables": "^0.0.7",
342-
"react": "^19.1.0",
343-
"react-dom": "^19.1.0",
340+
"@legendapp/state": "3.0.0-beta.42",
341+
"react": "^19.2.1",
342+
"react-dom": "^19.2.1",
344343
"valibot": "^1.2.0"
345344
}
346345
}

src/external/observable.ts

Lines changed: 0 additions & 147 deletions
This file was deleted.

0 commit comments

Comments
 (0)