Task 17 implements control-flow blocks (loop, alt, opt, par) for sequence diagrams in Ferrite's native Mermaid renderer.
Repeating sequence of messages.
sequenceDiagram
participant A
participant B
loop Retry up to 3 times
A->>B: Request
B-->>A: Response
end
Alternative paths with conditions. Supports multiple else branches.
sequenceDiagram
participant A
participant B
alt Success
A->>B: Normal flow
else Error
A->>B: Error handling
else Timeout
A->>B: Timeout handling
end
Optional sequence that may or may not occur.
sequenceDiagram
participant A
participant B
opt Has notification
A->>B: Send notification
end
Parallel execution paths. Supports multiple and branches.
sequenceDiagram
participant A
participant B
participant C
par Fetch from B
A->>B: Request B
B-->>A: Response B
and Fetch from C
A->>C: Request C
C-->>A: Response C
end
/// Type of control-flow block
pub enum SeqBlockKind {
Loop,
Alt,
Opt,
Par,
}
/// A segment within a block (for alt/par branches)
pub struct SeqBlockSegment {
pub segment_label: Option<String>,
pub statements: Vec<SeqStatement>,
}
/// A control-flow block
pub struct SeqBlock {
pub kind: SeqBlockKind,
pub label: String,
pub segments: Vec<SeqBlockSegment>,
}
/// Statement in a sequence diagram
pub enum SeqStatement {
Message(Message),
Block(SeqBlock),
}The parser uses a block stack to handle nesting:
- Block openers (
loop,alt,opt,par): Push newSeqBlockBuilderonto stack - Branch keywords (
else,and): Start new segment in current block (validates block kind) - Block closer (
end): Pop and finalize block, add to parent or top-level - Messages: Add to current block or top-level
Error handling:
- Unmatched
endwithout opener elseoutsidealtblockandoutsideparblock- Unclosed block at end of diagram
Blocks are rendered as labeled rectangles:
- Background: Semi-transparent fill color per block type
- Header label: Block kind + label in top-left corner (e.g., "loop [Retry]")
- Segment separators: Dashed lines between alt/par branches with labels
- Nesting: Inner blocks are inset from outer blocks
Block colors (with transparency for layering):
- Loop: Green tint
- Alt: Orange/amber tint
- Opt: Blue tint
- Par: Purple tint
The renderer calculates block dimensions by:
- Counting message slots in all segments recursively
- Adding header height (20px)
- Adding separator heights for multi-segment blocks
- Adding padding (8px)
Horizontal span: From leftmost to rightmost participant, with padding.
src/markdown/mermaid.rs:- Lines ~1143-1205: New AST types (
SeqBlockKind,SeqBlockSegment,SeqBlock,SeqStatement) - Lines ~1207-1280:
SeqBlockBuilderhelper struct - Lines ~1282-1405: Updated
parse_sequence_diagram()with block parsing - Lines ~1445-1970: Updated renderer with block drawing functions
- Lines ~1143-1205: New AST types (
Visual test file: docs/test-sequence-blocks.md
Test cases:
- Simple blocks (loop, alt, opt, par)
- Multi-branch blocks (alt with multiple else, par with multiple and)
- Nested blocks (blocks inside blocks)
- Mixed content (messages and blocks interleaved)
- Empty blocks
- Blocks without labels
Parser error cases:
- Unmatched
end elseoutsidealtandoutsidepar- Unclosed blocks
- No cross-block spanning: Blocks cannot span across participants that don't have messages inside them
- Fixed colors: Block colors are hardcoded, not themeable via Mermaid directives
- No critical blocks:
criticalblock type is not supported - No break keyword:
breakinside loops is not supported
- Add
critical,breakblock support - Themeable block colors via Mermaid directives
- Activation boxes (Task 19)
- Notes (Task 19)