Conversation
- Add renderMermaid() in src/render.ts to wrap raw content in a mermaid div - Add isMermaidFile() in src/view.ts using MarkEdit.getFileInfo() - Route .mmd files to renderMermaid() in getRenderedHtml() (__FULL_BUILD__ only) - Add tests for renderMermaid() function Co-authored-by: cyanzhong <6745066+cyanzhong@users.noreply.github.com>
src/view.ts
Outdated
| } | ||
|
|
||
| const info = await MarkEdit.getFileInfo(); | ||
| return info?.filePath?.endsWith('.mmd') ?? false; |
There was a problem hiding this comment.
Good catch — fixed in 3939e04 by using .toLowerCase().endsWith('.mmd') so it matches .MMD, .Mmd, etc.
Co-authored-by: cyanzhong <6745066+cyanzhong@users.noreply.github.com>
|
@copilot After careful consideration, I think we might want a new option (default true), because it seems multi-markdown also uses "mmd". Or do you have a better way to recognize mermaid diagrams? Also, we want to support filename extension |
Co-authored-by: cyanzhong <6745066+cyanzhong@users.noreply.github.com>
Added a |
There was a problem hiding this comment.
Pull request overview
Enables standalone Mermaid rendering when opening .mmd / .mermaid files in MarkEdit Preview (instead of treating them as Markdown), controlled by a new renderMermaidDiagram user setting.
Changes:
- Added
renderMermaid()helper to wrap raw Mermaid content in a<div class="mermaid">…</div>with HTML escaping. - Added
renderMermaidDiagramsetting (defaulttrue) to allow opting out (e.g., for MultiMarkdown.mmdusage). - Updated preview rendering flow to detect Mermaid files via
MarkEdit.getFileInfo()and route them throughrenderMermaid(). - Added unit tests for
renderMermaid()behavior (wrapping/escaping/trimming).
Reviewed changes
Copilot reviewed 4 out of 4 changed files in this pull request and generated 2 comments.
| File | Description |
|---|---|
src/render.ts |
Adds standalone Mermaid HTML renderer utility. |
src/settings.ts |
Introduces renderMermaidDiagram toggle to gate .mmd behavior. |
src/view.ts |
Detects Mermaid file extensions and switches rendering path in full builds. |
tests/render.test.ts |
Adds test coverage for standalone Mermaid rendering and escaping. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
You can also share your feedback on Copilot code review. Take the survey.
|
@copilot comment #81 (comment) reads reasonable, but it doesn't look complete, work on this. |
Co-authored-by: cyanzhong <6745066+cyanzhong@users.noreply.github.com>
Fixed in |
src/render.ts
Outdated
| export function renderMermaid(content: string, lineInfo = false) { | ||
| const trimmed = content.trim(); | ||
| const escaped = mdit.utils.escapeHtml(trimmed); | ||
| const lineAttrs = lineInfo ? ` data-line-from="0" data-line-to="${Math.max(0, trimmed.split('\n').length - 1)}"` : ''; |
There was a problem hiding this comment.
@copilot This isn't always correct. Use state.lineBreak from codemirror or its built-in way to get max lines.
There was a problem hiding this comment.
Fixed in 2cdc887. renderMermaid() now accepts an optional lastLine number instead of computing it from the content. The call site in view.ts uses MarkEdit.editorView.state.doc.lines - 1 for the correct line count.
Co-authored-by: cyanzhong <6745066+cyanzhong@users.noreply.github.com>
src/view.ts
Outdated
| } | ||
|
|
||
| async function isMermaidFile() { | ||
| if (!renderFileAsMermaid || typeof MarkEdit.getFileInfo !== 'function') { |
There was a problem hiding this comment.
@copilot This is bad. How can a user config affects the result of isMermaidFile? Is this your design principles?
There was a problem hiding this comment.
Moved the renderFileAsMermaid check out of isMermaidFile() into the call site in 986c6dc. isMermaidFile() now purely detects file type by extension.
Co-authored-by: cyanzhong <6745066+cyanzhong@users.noreply.github.com>
|
@copilot We need to do two things because I've changed my mind:
Try your best. |
Co-authored-by: cyanzhong <6745066+cyanzhong@users.noreply.github.com>
Done in
Warning Firewall rules blocked me from connecting to one or more addresses (expand for details)I tried to connect to the following addresses, but was blocked by firewall rules:
If you need me to access, download, or install something from one of these locations, you can either:
|
src/render.ts
Outdated
| if (lineInfo) { | ||
| const lastLine = MarkEdit.editorView.state.doc.lines - 1; |
There was a problem hiding this comment.
@copilot So many duplicate code between renderKatex and renderMermaid, try better.
There was a problem hiding this comment.
Extracted a shared renderStandaloneBlock(className, innerHtml, lineInfo) helper in 68753db — handles pluginsReady, lineInfo attributes, and div wrapping. renderMermaid and renderKatex are now thin wrappers that just prepare their inner HTML.
…plication Co-authored-by: cyanzhong <6745066+cyanzhong@users.noreply.github.com>
src/render.ts
Outdated
|
|
||
| async function renderStandaloneBlock(className: string, innerHtml: string, lineInfo: boolean) { | ||
| await pluginsReady; | ||
| const lineAttrs = lineInfo |
There was a problem hiding this comment.
@copilot prefer one-liner as long as not absurdly long.
There was a problem hiding this comment.
Inlined the lineAttrs ternary into the return statement in 57c75e2.
src/view.ts
Outdated
| } | ||
|
|
||
| async function isMermaidFile() { | ||
| const ext = await getFileExtension(); |
There was a problem hiding this comment.
Renamed to extension in 57c75e2.
src/render.ts
Outdated
| return renderStandaloneBlock('katex-block', rendered, lineInfo); | ||
| } | ||
|
|
||
| async function renderStandaloneBlock(className: string, innerHtml: string, lineInfo: boolean) { |
There was a problem hiding this comment.
@copilot Why "block" when you render the entire file as something? Also, why mermaid vs katex-block?
There was a problem hiding this comment.
Renamed to renderStandalone and changed katex-block → katex for consistency with mermaid in 57c75e2.
… class, inline lineAttrs, expand ext to extension Co-authored-by: cyanzhong <6745066+cyanzhong@users.noreply.github.com>
There was a problem hiding this comment.
Pull request overview
Adds “standalone file rendering” paths so MarkEdit preview treats Mermaid diagram files and LaTeX files as their native formats (instead of Markdown), while keeping existing Markdown rendering behavior intact and gating the feature behind __FULL_BUILD__.
Changes:
- Add
renderMermaid()andrenderKatex()to render raw.mmd/.mermaidand.texfiles as standalone outputs. - Route rendering in
getRenderedHtml()based on file extension (viaMarkEdit.getFileInfo()), falling back to Markdown rendering when unavailable. - Add Vitest coverage for standalone Mermaid/KaTeX rendering and scroll-sync line attributes.
Reviewed changes
Copilot reviewed 4 out of 4 changed files in this pull request and generated 2 comments.
| File | Description |
|---|---|
src/render.ts |
Introduces standalone Mermaid/KaTeX rendering helpers and shared wrapper for optional scroll-sync attributes. |
src/view.ts |
Adds extension-based routing to choose Mermaid/KaTeX standalone rendering vs Markdown. |
src/utils.ts |
Adds a file-extension helper used by view.ts for routing. |
tests/render.test.ts |
Adds tests for standalone Mermaid/KaTeX rendering, escaping, trimming, and line attribute behavior. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| export async function getFileExtension(filePath?: string) { | ||
| const index = filePath?.lastIndexOf('.'); | ||
| return index === -1 ? '' : filePath?.slice(index).toLowerCase(); |
There was a problem hiding this comment.
getFileExtension() is declared async but doesn't await, and it can return undefined when filePath is missing (because index becomes undefined and the ternary falls through to filePath?.slice(...)). This makes the helper's contract unclear and can lead to subtle misuse (e.g., callers forgetting to await). Consider making it a synchronous function that always returns a string (e.g., '' when filePath is falsy or has no dot).
| export async function getFileExtension(filePath?: string) { | |
| const index = filePath?.lastIndexOf('.'); | |
| return index === -1 ? '' : filePath?.slice(index).toLowerCase(); | |
| export function getFileExtension(filePath?: string): string { | |
| if (!filePath) { | |
| return ''; | |
| } | |
| const index = filePath.lastIndexOf('.'); | |
| if (index < 0 || index === filePath.length - 1) { | |
| return ''; | |
| } | |
| return filePath.slice(index).toLowerCase(); |
| const lineTo = MarkEdit.editorView.state.doc.lines - 1; | ||
| const lineAttrs = lineInfo ? ` data-line-from="0" data-line-to="${lineTo}"` : ''; |
There was a problem hiding this comment.
renderStandalone() reads MarkEdit.editorView.state.doc.lines unconditionally, even when lineInfo is false. This makes renderMermaid()/renderKatex() depend on editorView being available even for copy/export and unit tests where line info is intentionally omitted. Consider only computing lineTo when lineInfo is true (and/or gracefully handling a missing editorView by skipping line attributes).
| const lineTo = MarkEdit.editorView.state.doc.lines - 1; | |
| const lineAttrs = lineInfo ? ` data-line-from="0" data-line-to="${lineTo}"` : ''; | |
| let lineAttrs = ''; | |
| if (lineInfo && MarkEdit.editorView) { | |
| const lineTo = MarkEdit.editorView.state.doc.lines - 1; | |
| lineAttrs = ` data-line-from="0" data-line-to="${lineTo}"`; | |
| } |
.mmdand.mermaidfiles opened in MarkEdit render as standalone Mermaid diagrams, and.texfiles render as standalone KaTeX math — rather than treating them as Markdown. Standalone file rendering works automatically with no user option required, gated behind__FULL_BUILD__.Changes
src/render.ts— Add asyncrenderMermaid(content, lineInfo)that wraps raw content in<div class="mermaid">with HTML escaping, bypassing the markdown-it pipeline. Add asyncrenderKatex(content, lineInfo)that renders raw LaTeX content viakatex.renderToString()withdisplayMode: trueandthrowOnError: false, wrapping the output in<div class="katex">. Both delegate to a shared privaterenderStandalone(className, innerHtml, lineInfo)helper that awaitspluginsReadyand handles div wrapping with optionaldata-line-from/data-line-toattributes for scroll sync. WhenlineInfois enabled, the line count is read internally from CodeMirror'sMarkEdit.editorView.state.doc.lines.src/view.ts— Add a sharedgetFileExtension()helper usingMarkEdit.getFileInfo()for case-insensitive extension extraction. AddisMermaidFile()to detect.mmdand.mermaid, andisKatexFile()to detect.tex. Route these files torenderMermaid()orrenderKatex()respectively ingetRenderedHtml(), gated behind__FULL_BUILD__. PasslineInfothrough for scroll sync support.README.md— Removed the previously addedrenderFileAsMermaidsetting (standalone rendering is now automatic).tests/render.test.ts— Tests forrenderMermaid(wrapping, escaping, trimming, line info attributes) andrenderKatex(wrapping, KaTeX output, error handling, trimming, line info attributes, markdown compatibility). Tests usevi.mock('markedit-api')to properly mock the module foreditorViewline counting.The rendered mermaid div is picked up by the existing
handlePostRender()→mermaid.run()pipeline, and KaTeX output is already rendered HTML fromkatex.renderToString(), so preview, copy, and export all work consistently. Scroll sync works in preview mode via thedata-line-from/data-line-toattributes on the wrapper divs (line count derived internally from CodeMirror's editor state), while copy/export omit them. Falls back to normal Markdown rendering ifgetFileInfois unavailable or the file extension doesn't match.Original prompt
💬 Send tasks to Copilot coding agent from Slack and Teams to turn conversations into code. Copilot posts an update in your thread when it's finished.