Repository navigation
Add Mermaid-aware source syntax highlighting - #105
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
📝 WalkthroughWalkthroughThe change adds a bounded Mermaid tokenizer and CodeMirror language extension. The session editor uses Mermaid highlighting instead of Markdown highlighting. Theme variables support light, dark, and forced-colors modes. Tests cover parsing, accessibility, editing, and Yjs synchronization. ChangesMermaid source highlighting
Estimated code review effort: 4 (Complex) | ~45 minutes Sequence Diagram(s)sequenceDiagram
participant User
participant SessionWorkspace
participant mermaidSourceLanguage
participant CodeMirror
participant YjsSession
User->>SessionWorkspace: Open Mermaid source editor
SessionWorkspace->>mermaidSourceLanguage: Configure language extension
mermaidSourceLanguage->>CodeMirror: Tokenize and highlight source
User->>CodeMirror: Edit source incrementally
CodeMirror->>YjsSession: Synchronize source update
YjsSession-->>CodeMirror: Preserve collaborative document state
Possibly related PRs
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@e2e-workspace-ux-validate.ts`:
- Around line 3543-3544: Update the keyboard input in the Mermaid editor test to
include the two-space indentation after the newline, either by typing the
indented text directly or by pressing Enter separately before typing B-->C, so
it matches the expected value.
🪄 Autofix
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro Plus
Run ID: cbb7ebf4-6cd6-4513-9e2a-e69f25813f32
⛔ Files ignored due to path filters (1)
pnpm-lock.yamlis excluded by!**/pnpm-lock.yaml
📒 Files selected for processing (8)
apps/web/package.jsonapps/web/src/app/globals.cssapps/web/src/app/globals.test.tsapps/web/src/components/session-workspace.tsxapps/web/src/lib/mermaid-language.test.tsapps/web/src/lib/mermaid-language.tsdocs/context-map.mde2e-workspace-ux-validate.ts
| await page.keyboard.type('\nB-->C'); | ||
| const expected = `${MERMAID_HIGHLIGHT_BROWSER_FIXTURE}\n B-->C`; |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟠 Major | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
set -eu
printf '%s\n' '--- target lines ---'
sed -n '3515,3565p' e2e-workspace-ux-validate.ts
printf '%s\n' '--- related fixture and editor setup ---'
rg -n -C 8 'MERMAID_HIGHLIGHT_BROWSER_FIXTURE|page\.keyboard\.type|B-->C|contenteditable|Monaco|CodeMirror|textarea' e2e-workspace-ux-validate.ts
printf '%s\n' '--- candidate editor handling ---'
rg -n -S -g '*.{ts,tsx,js,jsx}' 'insertText|beforeinput|keydown|Enter|indent|auto.?indent|mermaid' . | head -n 240Repository: donovan-yohan/arielcharts
Length of output: 46354
🏁 Script executed:
#!/bin/bash
set -eu
sed -n '3515,3565p' e2e-workspace-ux-validate.ts
rg -n -C 8 'MERMAID_HIGHLIGHT_BROWSER_FIXTURE|page\.keyboard\.type|B-->C' e2e-workspace-ux-validate.tsRepository: donovan-yohan/arielcharts
Length of output: 16155
🏁 Script executed:
#!/bin/bash
set -eu
printf '%s\n' '--- Playwright declarations and version ---'
rg -n -S 'playwright|`@playwright/test`' package.json package-lock.json pnpm-lock.yaml yarn.lock bun.lockb 2>/dev/null || true
printf '%s\n' '--- editor implementation and newline-related handlers ---'
rg -n -S -g '*.{ts,tsx,js,jsx}' 'y-codemirror|CodeMirror|EditorView|indentOnInput|insertNewline|newline|indent' apps packages e2e | head -n 260
printf '%s\n' '--- nearby input helpers ---'
rg -n -C 12 'async function (replaceSource|waitForSource|ensureSourceFlyoutOpen)' e2e-workspace-ux-validate.tsRepository: donovan-yohan/arielcharts
Length of output: 50381
🌐 Web query:
Playwright Keyboard.type newline \n behavior documentation source
💡 Result:
In Playwright, the keyboard.type() method (and related locator-based typing methods) interprets the newline character \n as an Enter key press [1][2][3]. When you provide a string containing \n to keyboard.type() or pressSequentially(), Playwright treats the newline character as a command to generate an Enter keystroke [1][3]. This behavior is designed to simulate how a real keyboard interacts with elements like textareas or input fields [1]. Key Technical Details: - Behavior: The \n character triggers a keydown, keypress, and keyup sequence for the Enter key [4][1]. - Alternatives: - If your goal is to set the value of an element without simulating keystrokes, use locator.fill(), which does not trigger Enter key events and is generally recommended for performance and reliability [4][2][5]. - If you need to type the literal characters \n without triggering an Enter press, you may need to escape the character (e.g., using \\n) or utilize keyboard.insertText() to inject the text directly into the focused element without generating individual key events [4][3]. Note that keyboard.type() is intended for situations requiring special keyboard handling; for standard text input, locator.fill() remains the official, preferred approach [4][5].
Citations:
- 1: https://github.com/microsoft/playwright/blob/d3d436d3/tests/page/page-keyboard.spec.ts
- 2: [BUG] Typing newline breaks script microsoft/playwright#27174
- 3: https://stackoverflow.com/questions/74134037/how-to-ensure-page-type-uses-a-newline-character-n-instead-of-triggering-an-e
- 4: https://playwright.dev/docs/api/class-keyboard
- 5: https://playwright.dev/docs/input
🏁 Script executed:
#!/bin/bash
set -eu
printf '%s\n' '--- session workspace editor configuration ---'
sed -n '1,35p' apps/web/src/components/session-workspace.tsx
sed -n '1300,1415p' apps/web/src/components/session-workspace.tsx
printf '%s\n' '--- source replacement helper ---'
sed -n '55,115p' e2e/support/workspace.ts
printf '%s\n' '--- all direct editor key handling in the workspace component ---'
rg -n -C 6 'keymap|indent|Enter|insertText|yCollab|EditorView\.updateListener|new EditorView|basicSetup|defaultKeymap' apps/web/src/components/session-workspace.tsxRepository: donovan-yohan/arielcharts
Length of output: 10615
🌐 Web query:
Playwright 1.59.1 keyboard.type newline source keyboardKeyForString Enter
💡 Result:
In Playwright, keyboard.type is intended for typing characters rather than triggering special key actions like a newline or Enter [1][2]. Including a newline character (\n) in a string passed to keyboard.type does not reliably trigger an Enter key press and can cause unexpected behavior; the Playwright team explicitly recommends against using keyboard.type for standard text entry in favor of locator.fill [3][1][2]. If you need to press the Enter key, you should use the dedicated locator.press or keyboard.press methods [1][4][2]. There is no internal method named keyboardKeyForString; the logic for handling keys is managed internally by Playwright's keyboard input handler, which maps strings to key codes [5]. Recommended patterns: 1. For submitting a form or pressing Enter: Use locator.press('Enter') [4][2]. await page.locator('#your-input').press('Enter'); 2. For typing characters one-by-one (if special keyboard handling is required): Use locator.pressSequentially [4][2]. await page.locator('#your-input').pressSequentially('your text'); await page.locator('#your-input').press('Enter'); 3. For general text input: Use locator.fill, which is the most stable and recommended approach [3][1][2]. await page.locator('#your-input').fill('your text'); The keyboard.type method is considered a legacy or low-level API and should generally be avoided for modern Playwright automation [1][6][2].
Citations:
- 1: https://playwright.dev/docs/api/class-keyboard
- 2: https://runebook.dev/en/docs/playwright/api/class-keyboard/keyboard-type
- 3: [BUG] Typing newline breaks script microsoft/playwright#27174
- 4: https://playwright.dev/docs/input
- 5: https://github.com/microsoft/playwright/blob/main/packages/playwright-core/src/server/input.ts
- 6: https://playwright.dev/python/docs/api/class-keyboard
🏁 Script executed:
#!/bin/bash
set -eu
printf '%s\n' '--- Playwright 1.59.1 keyboard implementation ---'
curl -fsSL https://raw.githubusercontent.com/microsoft/playwright/v1.59.1/packages/playwright-core/src/server/input.ts \
| rg -n -C 12 'type\(text|insertText|press\(key|keyboardKey'
printf '%s\n' '--- local Mermaid language configuration ---'
rg -n -C 20 'mermaidSourceLanguage|indentService|indentNodeProp|foldNodeProp|languageData' apps/web/src/components/session-workspace.tsx apps/web/srcRepository: donovan-yohan/arielcharts
Length of output: 24373
🌐 Web query:
site:github.com/microsoft/playwright v1.59.1 keyboard.ts type(text) newline
💡 Result:
In Playwright (including version 1.59.1), the keyboard.type(text) method is designed to send keydown, keypress, and keyup events for each character in the provided string [1][2]. Regarding the handling of newline characters (e.g., '\n'): 1. Behavior: When you include a newline character in the string passed to keyboard.type(text), Playwright processes it as part of the text input [3]. If the target element (like a <textarea>) supports newlines, the newline character will typically result in a new line being inserted [3]. 2. Limitations: The keyboard.type method is intended for typing visible text characters [1]. For special keys, including 'Enter', Playwright documentation explicitly recommends using the keyboard.press method instead [1]. 3. Recommended Approach: If you need to trigger an 'Enter' keypress to submit a form or explicitly move to a new line in a way that triggers keyboard events for the Enter key, you should use keyboard.press('Enter') [1]. If you need to insert multiple lines of text that include newlines, you can use keyboard.type(text) containing '\n' characters, but be aware that it simulates typing each character individually, and if you need the specific 'Enter' key behavior (which may differ from simply inserting a character), keyboard.press('Enter') is the preferred and more robust API for that specific action [1][3]. In the internal implementation, keyboard.type iterates through the string and calls insertText for characters not found in the standard US keyboard layout map, while using press for those that are [2][4]. The logic for handling input is contained within the packages/playwright-core/src/server/input.ts file [2][4].
Citations:
- 1: https://github.com/microsoft/playwright/blob/v1.60.0/docs/src/api/class-keyboard.md
- 2: https://github.com/microsoft/playwright/blob/d3d436d3/packages/playwright-core/src/server/input.ts
- 3: https://github.com/microsoft/playwright/blob/d3d436d3/tests/page/page-keyboard.spec.ts
- 4: https://github.com/microsoft/playwright/blob/main/packages/playwright-core/src/server/input.ts
🏁 Script executed:
#!/bin/bash
set -eu
python3 - <<'PY'
import re
import urllib.request
url = "https://raw.githubusercontent.com/microsoft/playwright/v1.59.1/packages/playwright-core/src/server/input.ts"
src = urllib.request.urlopen(url, timeout=15).read().decode()
type_body = re.search(r"async type\(progress: Progress, text: string, options\?: \{ delay\?: number \}\) \{(.*?)\n \}", src, re.S)
assert type_body, "Playwright type() implementation not found"
body = type_body.group(1)
print("type() uses press for layout characters:", "usKeyboardLayout.has(char)" in body)
print("type() uses insertText for non-layout characters:", "this._insertText(progress, char)" in body)
print("newline is explicitly mapped in type():", bool(re.search(r"\\n", body)))
print("newline code point:", repr("\n"))
PY
printf '%s\n' '--- Mermaid language indentation declarations ---'
sed -n '1,180p' apps/web/src/lib/mermaid-language.ts | rg -n -C 3 'StreamLanguage|indent|indentNodeProp|indentService|languageData'
printf '%s\n' '--- codemirror package versions ---'
rg -n -A 3 -B 2 '^ codemirror@|^ "`@codemirror/`(state|view|language)@' pnpm-lock.yamlRepository: donovan-yohan/arielcharts
Length of output: 2449
🌐 Web query:
CodeMirror 6 insertText newline indentation indentOnInput input handler
💡 Result:
In CodeMirror 6, managing text insertion, newlines, and indentation is handled through a combination of core state transactions, command extensions, and language-specific features [1][2]. For inserting text with proper indentation, the recommended approach depends on whether you are reacting to user input or performing a programmatic update. Newline and Indentation Commands To handle the Enter key with automatic indentation, CodeMirror 6 provides built-in commands in the @codemirror/commands package [3]: - insertNewlineAndIndent: Standard behavior for the Enter key, which calculates indentation based on the language's syntax tree [1][3]. - insertNewlineKeepIndent: A simpler alternative that preserves the indentation of the previous line without invoking complex syntax-based re-indentation [3]. You can configure these in your keymap: keymap.of([{ key: "Enter", run: insertNewlineAndIndent }]) [4]. Automatic Re-indentation (indentOnInput) The indentOnInput extension automatically re-indents the current line when a user types specific characters (e.g., closing braces) [5][1]. It relies on language data defined in your language extension [5][2]: 1. Enable it by adding the indentOnInput extension to your EditorView [5][6]. 2. Configure your language data to include an indentOnInput field, which must be a Regular Expression [5][1]. 3. When the text from the start of the line to the cursor matches this expression, CodeMirror will trigger a re-indentation of that line [5][1]. Programmatic Text Insertion When inserting text programmatically (e.g., via a custom button or API), use the view.dispatch method [7]. To ensure correct multi-cursor behavior, use the state.changeByRange helper, which allows you to define changes relative to each selection range independently [7][8]. For example: view.dispatch(view.state.changeByRange(range => ({ changes: { from: range.from, insert: "your text" }, range: EditorSelection.cursor(range.from + "your text".length) }))) [7][3]. If you need to calculate indentation for inserted text programmatically, you can use the getIndentation function (from @codemirror/language) to retrieve the correct indentation level for a specific position [5][1]. Top Results: [5], [1], [3], [6]
Citations:
- 1: https://deepwiki.com/codemirror/language/4.3-indentation
- 2: https://codemirror.net/docs/extensions/
- 3: https://github.com/codemirror/commands/blob/main/src/commands.ts
- 4: https://discuss.codemirror.net/t/v6-enter-key-should-run-insertnewline/7773
- 5: https://github.com/codemirror/language/blob/8e970001/src/indent.ts
- 6: https://github.com/codemirror/basic-setup/blob/main/src/codemirror.ts
- 7: https://codemirror.net/examples/change/
- 8: https://discuss.codemirror.net/t/updating-multiple-selections-individually-with-a-transaction/5077
Insert the expected indentation explicitly.
page.keyboard.type('\nB-->C') inserts the newline without CodeMirror’s Enter indentation. The resulting source lacks the two spaces required by expected. Type '\n B-->C', or press Enter separately before typing B-->C.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@e2e-workspace-ux-validate.ts` around lines 3543 - 3544, Update the keyboard
input in the Mermaid editor test to include the two-space indentation after the
newline, either by typing the indented text directly or by pressing Enter
separately before typing B-->C, so it matches the expected value.
Summary
Review
One broad adversarial review found compact-connector, catalog-keyword, and browser-evidence gaps. They were batched into one fix pass. Independent narrow reruns then corrected two E2E contract errors (CodeMirror auto-indent and MCP catalog-vs-read projection). Final review approved exact head with no remaining P0/P1/P2.
Exact-head evidence
Base:
47ef53374af744edd0a2d1527481097e36494516Head:
bb097fcda4b595c493c0f3a54f543f4155d19a82Tree:
0fe8d95bf82c16b35bc71539d2cb0cc0ef135490Closes #100
Summary by CodeRabbit
New Features
Bug Fixes