Skip to content

✨ feat(playground): show execution time in footer#1284

Merged
harehare merged 1 commit intomainfrom
feat/playground-execution-time
Feb 16, 2026
Merged

✨ feat(playground): show execution time in footer#1284
harehare merged 1 commit intomainfrom
feat/playground-execution-time

Conversation

@harehare
Copy link
Copy Markdown
Owner

No description provided.

…ion time in the footer after running or generating AST\n- Style execution time for better visibility\n\nCloses #XXX (replace with actual issue if applicable)
Copilot AI review requested due to automatic review settings February 16, 2026 13:31
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds execution timing feedback to the mq-playground UI so users can see how long a run (and currently AST generation) takes.

Changes:

  • Add executionTime state and measure duration around mq.run(...) and mq.toAst(...).
  • Render an execution-time badge in the playground footer.
  • Add CSS styling for the new footer badge.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 3 comments.

File Description
packages/mq-playground/src/index.css Adds .execution-time styling for the new footer badge.
packages/mq-playground/src/Playground.tsx Captures execution timing and renders it in the footer; also changes AST tab behavior to trigger AST generation on tab click.
Comments suppressed due to low confidence (1)

packages/mq-playground/src/Playground.tsx:312

  • handleRun reads isFirstRun inside a useCallback, but isFirstRun is not included in the dependency array. This callback will keep the initial value (likely always true), so the UI may keep showing "Initializing..." even on subsequent runs. Include isFirstRun in the deps or switch to a useRef/functional pattern to track first-run without stale closure issues.
  const handleRun = useCallback(async () => {
    setIsFirstRun(false);

    if (!code || !markdown) {
      return;
    }
    setResult(isFirstRun ? "Initializing..." : "Running...");
    setAstResult("");
    setExecutionTime(null);

    const startTime = performance.now();

    try {
      setResult(
        await mq.run(code, markdown, {
          isUpdate,
          inputFormat,
          listStyle,
          linkTitleStyle,
          linkUrlStyle,
        }),
      );
    } catch (e) {
      setResult((e as Error).toString());
    } finally {
      const endTime = performance.now();
      setExecutionTime(endTime - startTime);
    }
  }, [
    code,
    markdown,
    inputFormat,
    isUpdate,
    listStyle,
    linkUrlStyle,
    linkTitleStyle,
  ]);

Comment on lines +1609 to +1615
{executionTime && (
<div className="footer-right">
<div className="execution-time">
{executionTime.toFixed(2)} ms
</div>
</div>
)}
Copy link

Copilot AI Feb 16, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The conditional render uses {executionTime && (...)}. Since executionTime is a number | null, a measured value of 0 will be treated as falsy and the footer badge will not render. Prefer an explicit null check (e.g. executionTime !== null) so 0 ms still displays.

Copilot uses AI. Check for mistakes.
Comment on lines 1439 to +1443
className={`tab ${activeTab === "ast" ? "active" : ""}`}
onClick={() => setActiveTab("ast")}
onClick={() => {
handleGenerateAst();
setActiveTab("ast");
}}
Copy link

Copilot AI Feb 16, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Clicking the "AST" tab now triggers handleGenerateAst() automatically, while there is still a separate "Generate AST" button shown when the AST tab is active. This is a behavioral change unrelated to the PR title and creates two different entry points (and repeated re-generation on repeated tab clicks). Consider either reverting to just tab switching, or removing the extra button / gating auto-generation (e.g. only generate if astResult is empty or code changed).

Copilot uses AI. Check for mistakes.
Comment on lines +319 to +330
setExecutionTime(null);

const startTime = performance.now();

try {
const ast = await mq.toAst(code);
setAstResult(JSON.stringify(JSON.parse(ast), null, " "));
} catch (e) {
setAstResult((e as Error).toString());
} finally {
const endTime = performance.now();
setExecutionTime(endTime - startTime);
Copy link

Copilot AI Feb 16, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

executionTime is updated by both handleRun and handleGenerateAst, but the footer just renders a generic "ms" value. After generating an AST (or if operations overlap), the footer can show the AST timing while the Output tab/result is shown, which makes the value misleading. Consider tracking separate timings (e.g., runExecutionTime vs astExecutionTime) or storing { kind, ms } and only displaying the timing relevant to the active tab/last completed action.

Suggested change
setExecutionTime(null);
const startTime = performance.now();
try {
const ast = await mq.toAst(code);
setAstResult(JSON.stringify(JSON.parse(ast), null, " "));
} catch (e) {
setAstResult((e as Error).toString());
} finally {
const endTime = performance.now();
setExecutionTime(endTime - startTime);
try {
const ast = await mq.toAst(code);
setAstResult(JSON.stringify(JSON.parse(ast), null, " "));
} catch (e) {
setAstResult((e as Error).toString());

Copilot uses AI. Check for mistakes.
@harehare harehare merged commit 1fc7ae2 into main Feb 16, 2026
12 checks passed
@harehare harehare deleted the feat/playground-execution-time branch February 16, 2026 13:52
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants