Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
53 commits
Select commit Hold shift + click to select a range
347fdfa
Migrate to React
celonymire Dec 10, 2025
bbbecca
Migrate to legend-state observer framework
celonymire Dec 10, 2025
ca4b817
Remove leftover reference of external
celonymire Dec 10, 2025
67e932f
Update instructions to mention React + @legendapp/state
celonymire Dec 12, 2025
b4975f4
Make Rspack alias React and define NODE_ENV to fix React ownership is…
celonymire Dec 12, 2025
0200323
Update instructions to remove TailwindCSS
celonymire Dec 12, 2025
325ff39
Final architecture updates to stylesheets
celonymire Dec 13, 2025
a4dc50a
Ensure TextHandler invariants are maintained in both strings
celonymire Dec 13, 2025
a072b6b
Set acceptedStdout for webview when trigger editing
celonymire Dec 13, 2025
4a1ddfd
Remove duplicate types.ts
celonymire Dec 13, 2025
87b5d14
Initial implementation of new Testcases UI
celonymire Dec 13, 2025
05429e7
Added a view for state of no opened files
celonymire Dec 13, 2025
a83ac19
Update instructions
celonymire Dec 13, 2025
31add23
Initial revamp of Stress Tester UI and added expanding text
celonymire Dec 13, 2025
52089e2
Add comment explaining why we force write newline on accepted stdout
celonymire Dec 13, 2025
b127828
Save the external runtime error from running the command
celonymire Dec 13, 2025
811bb38
Restrict accept icon further
celonymire Dec 13, 2025
9746438
Refactor out chunk callback into another method
celonymire Dec 13, 2025
d083763
Make the textarea stderr variant for certain states in stress tester
celonymire Dec 13, 2025
315fe9d
Add icons for commands that affect all testcases in judge title bar
celonymire Dec 13, 2025
a7fe300
Dual-weird div and textarea implementation to avoid empty trailing ne…
celonymire Dec 13, 2025
4686f6b
Remove unused divider class
celonymire Dec 13, 2025
e604326
Fixed alignment of Next Testcase button
celonymire Dec 13, 2025
028b7fc
Adjust margin of new testcase button icon
celonymire Dec 13, 2025
76e1a35
Implemented visibility change
celonymire Dec 13, 2025
7ab536c
Add back skip and toggle functionality
celonymire Dec 13, 2025
7436999
Allow scrollbar for long horizontal content
celonymire Dec 13, 2025
2c32b1b
Fix condition for accept answer icon
celonymire Dec 13, 2025
1afaa87
Make skipping apply visible opacity effect
celonymire Dec 13, 2025
69bac7e
Add styling to COMPILING status
celonymire Dec 13, 2025
ce538c9
Slightly reduce text size
celonymire Dec 13, 2025
b2e66d6
Refactor terminal handling to ensure readiness before writing output
celonymire Dec 13, 2025
92860a3
Re-implement problem settings (time limit)
celonymire Dec 13, 2025
e1ffa33
Updated view of compile error to be more distinctive
celonymire Dec 13, 2025
1d8c14f
Save compile error state
celonymire Dec 13, 2025
e2ad3e5
Fix linter errors
celonymire Dec 13, 2025
cccc739
Remove leftover debug code
celonymire Dec 13, 2025
30e9b05
Use ===
celonymire Dec 13, 2025
dc21deb
Removed unnecessary from judge view IO clearing upon save
celonymire Dec 13, 2025
9843012
Switch back to testcases view after saving
celonymire Dec 13, 2025
9caa990
Enhance the settings save button in judge settings
celonymire Dec 13, 2025
3b1617b
Add info on 0 value for time limit
celonymire Dec 13, 2025
2945ec0
Merge remote-tracking branch 'origin/ui-revamp' into ui-revamp
celonymire Dec 13, 2025
9d546d3
Don't need to handle enter key for save setting now that we have a bu…
celonymire Dec 13, 2025
e0bf1ad
Increment newline count in TextHandler
celonymire Dec 13, 2025
6c0049d
Remove extra space in class names
celonymire Dec 13, 2025
a121074
Update src/webview/judge/Testcase.tsx
celonymire Dec 13, 2025
8d85e5a
Update src/extension/utils/vscode.ts
celonymire Dec 13, 2025
d378515
Avoid redundant truthiness bypass
celonymire Dec 13, 2025
9ee6026
Make useLayoutEffect depend on value
celonymire Dec 13, 2025
15faac6
Calrify comment about TextHandler even more
celonymire Dec 13, 2025
02eac73
Update to use legend state's For
celonymire Dec 13, 2025
c765b8e
Update documentation to reflect Valibot schema integration and clarif…
celonymire Dec 13, 2025
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
11 changes: 6 additions & 5 deletions .github/copilot-instructions.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,20 +3,21 @@
This repository contains a VS Code extension that provides two webview-based tools for competitive programming: **Judge** and **Stress**.

- 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.
- 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`.
- 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).
- Webview frontend code lives under `src/webview/**` and is built with React + `@legendapp/state` for reactive state management. It talks to the extension only through typed messages defined in `src/shared/*-messages.ts`.
- Shared enums, message contracts, and Valibot schemas live under `src/shared/**` and define the protocol between extension and webviews (including the `Status` lifecycle in `enums.ts` and testcase structures in `schemas.ts`).

Build and tooling:

- Use `bun install` to install dependencies.
- Use `bun run watch` during development and `bun run prod` for production builds. The build is two-stage: Tailwind CLI compiles `src/styles/global.css` to `dist/styles.css`, then Rspack bundles the extension and webviews into `dist/`.
- Run `bun run lint` and `bun run format` to apply ESLint (TypeScript + Preact) and Prettier rules.
- Use `bun run watch` during development and `bun run prod` for production builds. Rspack bundles the extension and webviews into `dist/`. Each webview has its own `index.css` stylesheet that is bundled alongside its JavaScript.
- Run `bun run lint` and `bun run format` to apply ESLint (TypeScript + React) and Prettier rules.

Design and implementation guidelines:

- 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.
- All extension ↔ webview communication must use the discriminated unions and Valibot schemas in `src/shared/*-messages.ts`. Append to enums instead of reordering to keep numeric values and stored data stable.
- 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.
- Use `TextHandler` for streamed output; always call `.reset()` for a fresh run and `.write(data, last)` for updates.
- Use `@legendapp/state` for webview state: wrap components with `observer()`, access values via `.get()`, mutate via `.set()`, and use `<For>` for reactive list rendering.
- Keep changes minimal and consistent with existing patterns. Prefer reusing the Judge/Stress provider and webview patterns over introducing new architectures.

Additional path-specific details are defined in `.github/instructions/*.instructions.md`, which Copilot uses when working in matching files.
16 changes: 7 additions & 9 deletions .github/instructions/build-and-config.instructions.md
Original file line number Diff line number Diff line change
@@ -1,17 +1,15 @@
---
applyTo: "package.json,rspack.config.ts,eslint.config.ts,tailwind.config.ts,tsconfig*.json"
applyTo: "package.json,rspack.config.ts,eslint.config.ts,tsconfig*.json"
---

This repository uses Bun, Rspack, Tailwind CSS, TypeScript, and ESLint to build and lint the Fast Olympic Coding VS Code extension and its webviews.
This repository uses Bun, Rspack, TypeScript, and ESLint to build and lint the Fast Olympic Coding VS Code extension and its webviews.

When working on the build, config, or tooling files matched by this pattern:

- Use `bun install` to install dependencies. Prefer Bun scripts in `package.json` over ad-hoc commands.
- During development, run `bun run watch` to start Rspack and the Tailwind CLI in watch mode. For production builds, use `bun run prod` to generate minified, no-sourcemap bundles.
- The build is two-stage:
- `build:css`: Tailwind CLI reads from `src/styles/global.css` and writes `dist/styles.css`.
- `build:js`: Rspack bundles the extension backend and webview frontends into `dist/`.
- The Rspack configuration (`rspack.config.ts`) exports two configs: one targeting Node.js/CommonJS for the extension, and one targeting the web/ES modules for the webviews (TypeScript/TSX with Preact). Keep this separation intact when modifying the config.
- During development, run `bun run watch` to start Rspack in watch mode. For production builds, use `bun run prod` to generate minified, no-sourcemap bundles.
- Rspack bundles the extension backend and webview frontends into `dist/`. Each webview has its own `index.css` stylesheet that is bundled alongside its JavaScript.
- The Rspack configuration (`rspack.config.ts`) exports two configs: one targeting Node.js/CommonJS for the extension, and one targeting the web/ES modules for the webviews (TypeScript/TSX with React). Keep this separation intact when modifying the config.
- Type-checking is handled by ForkTsCheckerWebpackPlugin, using `tsconfig.node.json` for the extension and `tsconfig.app.json` for the webviews. Keep these project files aligned with the respective code trees.
- For quality gates, use `bun run lint` (ESLint with TypeScript + Preact rules) and `bun run format` (Prettier). Avoid adding overlapping or conflicting linters/formatters.
- Prefer minimal, focused config changes. Avoid introducing large new toolchains or build systems; extend the existing Rspack + Tailwind + Bun setup instead.
- For quality gates, use `bun run lint` (ESLint with TypeScript + React rules) and `bun run format` (Prettier). Avoid adding overlapping or conflicting linters/formatters.
- Prefer minimal, focused config changes. Avoid introducing large new toolchains or build systems; extend the existing Rspack + Bun setup instead.
9 changes: 5 additions & 4 deletions .github/instructions/extension-backend.instructions.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,12 @@ This repository is a VS Code extension called "Fast Olympic Coding." The `src/ex

When changing files under `src/extension/**`:

- Treat `JudgeViewProvider` and `StressViewProvider` as the main controllers for their respective webviews. They extend `BaseViewProvider`, which encapsulates webview setup, CSP nonce generation, message posting, and workspaceState access keyed by active file path.
- All extension ⇄ webview communication must go through the discriminated unions and enums in `src/shared/*-messages.ts`. Do not introduce ad-hoc string message types; instead, extend the shared enums and message unions.
- The `Status` enum in `src/shared/types.ts` represents the lifecycle: COMPILING → RUNNING → (AC | WA | RE | TL | CE | NA | EDITING). Preserve existing numeric values and append new states only at the end.
- Treat `JudgeViewProvider` and `StressViewProvider` as the main controllers for their respective webviews. They extend `BaseViewProvider`, which encapsulates webview setup, CSP nonce generation, message posting via Valibot-validated schemas, and workspaceState access keyed by active file path.
- Webviews rely on Codicons for icons; `BaseViewProvider` already whitelists `@vscode/codicons/dist/codicon.css` in local resource roots and injects the stylesheet. Preserve that setup (CSP, resource roots, and link tag) whenever adjusting webview HTML or resource handling so icons keep rendering.
- All extension ⇄ webview communication must go through the discriminated unions and Valibot schemas in `src/shared/*-messages.ts`. Do not introduce ad-hoc string message types; instead, extend the shared enums and message unions.
- The `Status` enum in `src/shared/enums.ts` represents the lifecycle: COMPILING → RUNNING → (AC | WA | RE | TL | CE | NA | EDITING). Preserve existing numeric values and append new states only at the end.
- Persisted testcases and limits are stored in `workspaceState`, with a top-level key per view ("judge" / "stress") and an inner key per absolute file path. Treat the "default" state (no testcases and timeLimit = 0) as "no data" and delete storage entries rather than persisting defaults indefinitely.
- Use `TextHandler` (from the extension utilities) for all streamed output shown in the webviews. Always call `.reset()` before a fresh run and `.write(data, last)` to update output so truncation, batching, and whitespace handling remain correct.
- Use `TextHandler` (from the extension utilities) for all streamed output shown in the webviews. It must keep the full data for comparisons while truncating display output, normalizes CRLF to LF, and ensures a trailing newline on final writes. Always call `.reset()` before a fresh run and `.write(data, last)` to update output so truncation, batching, and whitespace handling remain correct.
- For compilation and execution, use the helpers in `src/extension/utils/runtime.ts`. Specifically, use `compile()` (which caches builds by md5 of the full command) and `Runnable` (which wraps child processes with timing, timeout via `AbortSignal.timeout`, and exit/timeout information) instead of spawning processes manually.
- In the Stress view logic, keep the sequential generator pattern that feeds testcases to the solution and reference solution, and ensure the loop respects both per-test (`stressTestcaseTimeLimit`) and global (`stressTimeLimit`) limits while exiting early on the first mismatch or failure for speed.
- Always resolve command variables via `resolveVariables` / `resolveCommand` from `src/extension/utils/vscode.ts` before spawning external processes. Use built-in variables like `${exeExtname}`, `${path:...}`, and `${fileDirnameBasename}` for cross-platform-safe paths.
Expand Down
14 changes: 7 additions & 7 deletions .github/instructions/shared-contracts.instructions.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,20 +2,20 @@
applyTo: "src/shared/**/*.ts"
---

The `src/shared/**` directory contains enums, message contracts, schemas, and shared types used by both the extension backend (`src/extension/**`) and the webview frontend (`src/webview/**`). These files define the public protocol between the two halves of the extension.
The `src/shared/**` directory contains enums, Valibot schemas, message contracts, and shared types used by both the extension backend (`src/extension/**`) and the webview frontend (`src/webview/**`). These files define the public protocol between the two halves of the extension.

When changing files under `src/shared/**`:

- Treat the message and enum definitions here as the single source of truth for extension ↔ webview communication. All messages should be discriminated unions with clear `type` or `kind` fields, and both sides should switch on these discriminants.
- Treat the message and enum definitions here as the single source of truth for extension ↔ webview communication. All messages use Valibot schemas (e.g., `v.object()`, `v.literal()`, `v.enum()`) with discriminated unions via `v.union([...])` and `type` fields, and both sides should switch on these discriminants.
- When you add new message types or enum members, append them to the existing enums instead of reordering or renaming values. This preserves numeric enum identifiers and avoids breaking persisted data (for example, stored `Status` values).
- Keep message payloads minimal but explicit. Prefer well-typed fields over loosely structured objects to make it clear what each side should expect.
- Keep message payloads minimal but explicit. Prefer well-typed Valibot schemas over loosely structured objects to make it clear what each side should expect.
- If you change a shared type, update both the extension providers (under `src/extension/providers/**`) and the corresponding webview handlers (under `src/webview/**`) in the same change to avoid protocol drift.
- The `Status` enum in `types.ts` models the run lifecycle: COMPILING → RUNNING → (AC | WA | RE | TL | CE | NA | EDITING). Preserve these semantics when adding new statuses and ensure the UI and backend continue to interpret them consistently.
- Schemas and validation helpers here should remain lightweight and focused on the Judge/Stress workflows. Avoid introducing heavy validation frameworks unless absolutely required.
- The `Status` enum in `enums.ts` models the run lifecycle: COMPILING → RUNNING → (AC | WA | RE | TL | CE | NA | EDITING). Preserve these semantics when adding new statuses and ensure the UI and backend continue to interpret them consistently.
- Use Valibot (`import * as v from "valibot"`) for all schemas. Define individual message schemas, then combine them into a union schema and export an inferred type (e.g., `type WebviewMessage = v.InferOutput<typeof WebviewMessageSchema>`).
- Because these contracts are central to the extension's behavior, keep changes focused and backwards-compatible wherever possible.

When adding a new feature that requires extension ↔ webview communication:

- First, define or extend the shared contract in `src/shared/` (add a new enum member, interface, and union entry as needed). Append to existing enums rather than reordering to keep numeric values stable.
- First, define or extend the shared contract in `src/shared/` (add a new enum member, Valibot schema, and union entry). Append to existing enums rather than reordering to keep numeric values stable.
- Then update the relevant Provider class under `src/extension/providers/` to mutate its internal state, call `_postMessage` with the new message type, and persist state via `writeStorage()` only after all mutations are complete.
- Finally, implement handling for the new message type on the webview side under `src/webview/**`, updating the relevant `App.tsx` and components to react to the new messages. Do not rely on message ordering beyond the established initial `INITIAL_STATE` / `SHOW` messages.
- Finally, implement handling for the new message type on the webview side under `src/webview/**`, adding a case to the `window.addEventListener("message", ...)` handler in `App.tsx`. Do not rely on message ordering beyond the established initial `INITIAL_STATE` / `SHOW` messages.
21 changes: 15 additions & 6 deletions .github/instructions/webview-frontend.instructions.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,24 @@
applyTo: "src/webview/**/*.ts,src/webview/**/*.tsx"
---

The `src/webview/**` tree contains the Preact-based frontend code for the Judge and Stress webviews. These run in an isolated browser-like environment, not in the VS Code extension host.
The `src/webview/**` tree contains the React-based frontend code for the Judge and Stress webviews. These run in an isolated browser-like environment, not in the VS Code extension host.

When changing files under `src/webview/**`:

- Do not import the `vscode` module here; webview code should communicate with the extension only via the typed message contracts defined in `src/shared/*-messages.ts`.
- 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.
- 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.
- 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.
- 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.
- Do not import the `vscode` module here; webview code should communicate with the extension only via `postProviderMessage()` from each view's `message.ts` file, which wraps `vscode.postMessage()` with typed contracts from `src/shared/*-messages.ts`.
- 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 via `window.addEventListener("message", ...)`.
- Codicons are the icon set used across the webviews. The backend already exposes `@vscode/codicons/dist/codicon.css`; prefer the existing `codicon-` classes instead of adding new icon libraries or custom SVG sprite sheets unless strictly necessary.
- When you need new messages or actions from the webview to the extension, first extend the shared enums and Valibot schemas 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.
- Each webview has its own `index.css` stylesheet (e.g., `src/webview/judge/index.css`, `src/webview/stress/index.css`). Import it in the webview's entry file (`index.tsx`). The CSS is bundled by Rspack alongside the webview JavaScript.
- Use `@legendapp/state` for reactive state management:
- Wrap components with `observer()` from `@legendapp/state/react` for automatic re-rendering.
- Access observable values with `.get()` and mutate with `.set(value)` or `.set(prev => newValue)`.
- Use `<For each={obs$}>` for reactive list rendering; it efficiently handles additions/removals without re-rendering the entire list.
- Use `useObservable(value)` for component-local observable state.
- Collections like `Map` and `Set` have fine-grained reactivity; use `state$.map.get(key)` to get an observable for a specific entry.
- Avoid introducing additional state libraries; follow the patterns in the Judge and Stress apps.
- Shared webview utilities live in `src/webview/utils.ts` (e.g., `getStatusColor`).
- 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.
- Maintain consistency with existing components such as `AutoresizeTextarea`, `Testcase`, and `State` in terms of props, message handling, and minimal DOM manipulation.
- Keep the file layout lean (e.g., flat component files per view) and avoid introducing extra nested directories unless there's a clear benefit; mirror the existing Judge/Stress structure when adding new pieces.
- Keep changes surgical: avoid large-scale refactors or stylistic rewrites unless they are necessary for a specific task.
5 changes: 3 additions & 2 deletions .vscodeignore
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
!LICENSE
!media/icon.png
!dist/judge/index.js
!dist/judge/index.css
!dist/stress/index.js
!dist/extension.js
!dist/styles.css
!dist/stress/index.css
!dist/extension.js
Loading