mirror of
https://github.com/anomalyco/opencode.git
synced 2026-08-21 14:13:35 +00:00
fix(tui): optimize Mermaid terminal rendering (#42595)
This commit is contained in:
parent
f7d21babb6
commit
1cf97fac5c
4 changed files with 60 additions and 2 deletions
|
|
@ -44,6 +44,7 @@ interface PreparedDiagram {
|
|||
}
|
||||
|
||||
export interface MermaidMarkdownRendererOptions {
|
||||
/** Use terminal-optimized diagram spacing. Defaults to true. */
|
||||
compact?: boolean
|
||||
/** Fold horizontal flowcharts that exceed this width. Defaults to 120 columns. */
|
||||
layoutMaxWidth?: number
|
||||
|
|
@ -118,10 +119,11 @@ function prepareDiagram(
|
|||
layoutMaxWidth: number,
|
||||
): PreparedDiagram {
|
||||
const colors = options.colors ?? {}
|
||||
const compact = options.compact ?? true
|
||||
switch (kind) {
|
||||
case "flowchart": {
|
||||
const grid = drawFlowchartDiagramGrid(parseMermaidFlowchartDiagram(source), {
|
||||
compact: options.compact,
|
||||
compact,
|
||||
layoutMaxWidth,
|
||||
})
|
||||
const size = grid.getTextSize({ trimTop: true, trimBottom: true })
|
||||
|
|
@ -161,7 +163,7 @@ function prepareDiagram(
|
|||
}
|
||||
}
|
||||
case "sequence": {
|
||||
const grid = drawSequenceDiagramGrid(parseMermaidSequenceDiagram(source), { compact: options.compact })
|
||||
const grid = drawSequenceDiagramGrid(parseMermaidSequenceDiagram(source), { compact })
|
||||
const size = grid.getTextSize()
|
||||
return {
|
||||
kind,
|
||||
|
|
|
|||
|
|
@ -243,6 +243,28 @@ describe("createStateTransitionRenderPlans", () => {
|
|||
).toBe(false)
|
||||
}
|
||||
})
|
||||
|
||||
test("keeps routes to offset end markers continuous", () => {
|
||||
const diagram = prepareVisibleStateDiagram(
|
||||
parseMermaidStateDiagram(`stateDiagram-v2
|
||||
[*] --> Pending
|
||||
Pending --> Running
|
||||
Running --> Idle
|
||||
Running --> Interrupted
|
||||
Interrupted --> [*]`),
|
||||
)
|
||||
const layout = createStateDiagramLayout(diagram, { minStateGap: 12 })
|
||||
const plan = createStateTransitionRenderPlans(diagram, layout.bounds, 30).find(
|
||||
(plan) => plan.route.transition.to === "__end",
|
||||
)!
|
||||
|
||||
expect(
|
||||
plan.path.slice(1).every(([x, y], index) => {
|
||||
const previous = plan.path[index]!
|
||||
return Math.abs(x - previous[0]) + Math.abs(y - previous[1]) === 1
|
||||
}),
|
||||
).toBe(true)
|
||||
})
|
||||
})
|
||||
|
||||
describe("createStateTransitionJunctionPlans", () => {
|
||||
|
|
|
|||
|
|
@ -216,6 +216,11 @@ function verticalCorridorCrossesUnrelatedState(
|
|||
})
|
||||
}
|
||||
|
||||
function hasVerticalCorridor(from: BoxBounds, to: BoxBounds): boolean {
|
||||
if (from.centerY < to.centerY) return from.top + from.height <= to.top - 1
|
||||
return from.top - 1 >= to.top + to.height
|
||||
}
|
||||
|
||||
function horizontalCorridorCrossesUnrelatedState(
|
||||
diagram: StateVisibleDiagram,
|
||||
transition: StateVisibleTransition,
|
||||
|
|
@ -388,6 +393,9 @@ export function createStateTransitionRoutePlans(
|
|||
}
|
||||
return [{ ...base, kind: "horizontal-forward", leftToRight: from.centerX <= to.centerX }]
|
||||
}
|
||||
if (!hasVerticalCorridor(from, to)) {
|
||||
return [{ ...base, kind: "side-parallel", railX: allocateSideRail(transition.label) }]
|
||||
}
|
||||
if (from.centerX !== to.centerX) {
|
||||
return [{ ...base, kind: "vertical-elbow", hasReverse: false, offsetConnector: false }]
|
||||
}
|
||||
|
|
@ -395,6 +403,9 @@ export function createStateTransitionRoutePlans(
|
|||
}
|
||||
|
||||
if (from.centerY !== to.centerY) {
|
||||
if (!hasVerticalCorridor(from, to)) {
|
||||
return [{ ...base, kind: "side-parallel", railX: allocateSideRail(transition.label) }]
|
||||
}
|
||||
if (from.centerY > to.centerY && feedback)
|
||||
return [
|
||||
{
|
||||
|
|
|
|||
|
|
@ -78,6 +78,29 @@ flowchart LR
|
|||
expect(markdown.getChildren()[0]?.marginTop).toBe(1)
|
||||
})
|
||||
|
||||
test("uses compact terminal spacing for Mermaid diagrams by default", async () => {
|
||||
const testRenderer = await createTestRenderer({ width: 80, height: 40 })
|
||||
renderer = testRenderer.renderer
|
||||
const markdown = new MarkdownRenderable(renderer, {
|
||||
id: "markdown-compact-mermaid",
|
||||
content: `\`\`\`mermaid
|
||||
flowchart TD
|
||||
repo[Organization profile repo] --> build[Build]
|
||||
build --> worker[Isolated organization Worker]
|
||||
worker --> sessions[SessionDOs]
|
||||
sessions --> opencode[OpenCode + native plugins]
|
||||
opencode --> modal[Modal workspaces]
|
||||
\`\`\``,
|
||||
syntaxStyle,
|
||||
renderNode: createMermaidMarkdownRenderer(renderer),
|
||||
})
|
||||
|
||||
renderer.root.add(markdown)
|
||||
await renderMarkdown(markdown, testRenderer.renderOnce)
|
||||
|
||||
expect(markdown.getChildren()[0]?.height).toBe(28)
|
||||
})
|
||||
|
||||
test("recognizes normalized Mermaid fence info strings", async () => {
|
||||
const testRenderer = await createTestRenderer({ width: 80, height: 14 })
|
||||
renderer = testRenderer.renderer
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue