puml_canvas 0.13.0
puml_canvas: ^0.13.0 copied to clipboard
A native PlantUML-compatible diagram renderer for Flutter. Parses PUML in Dart and paints directly onto a Canvas — no server, no WebView.
Changelog #
0.13.0 #
Added #
- New opt-in Sugiyama (hierarchical) layout for state diagrams, enabled
via
useSugiyamaForStatesonPumlView/AutoLayout(default off; the existing state layout is unchanged when the flag is off). It lays composite states out recursively, honors PlantUML arrow direction hints (->horizontal,-->vertical,-up->/-down->/-left->/-right->), treats horizontal arrows as same-rank so a shared successor centers between them, renders self-transitions as loop-backs, separates parallel transitions and de-overlaps their labels, scopes[H]/[H*]history pseudo-states inside their owning composite, and nudges edge labels clear of nodes and one another. - State parser support for dotted-name composite nesting:
state A.Xdeclares stateXinside compositeA(andA.B.Cnests deeper), with repeated prefixes merging into one composite. - State transitions now capture their arrow direction, and qualified
history targets such as
X --> State3[H*]preserve the owning composite. - The example app now shows the official plantuml.com rendering alongside the puml_canvas output for side-by-side comparison.
Changed #
- State names resolve globally regardless of declaration order: a state referenced inside a composite (or before its declaration) that is actually defined / used at an outer scope no longer produces a duplicate nested stub.
Fixed #
- Numerous example sample sources that were invalid PlantUML (and failed to render on plantuml.com) were corrected across state, sequence, class, activity, component, deployment, gantt, mindmap, object, WBS, and JSON diagrams.
0.12.1 #
Added #
- State diagram golden coverage was expanded for state descriptions, history pseudo-states, stereotype pseudo-states, SDL receive-style states, concurrent-region separators, cross-container transitions, and collision-avoidance labels.
- Class diagram golden coverage now includes PlantUML-style visibility icons for class members.
Changed #
- Class member visibility markers now render as PlantUML-style icons instead of plain text symbols: private square, protected diamond, package triangle, and public circle, with filled variants for methods and hollow variants for fields.
- State diagram layout was refined for composite states, concurrent regions, pseudo-state shapes, state descriptions, transition routing, and label collision avoidance.
Fixed #
- State transitions that cross container boundaries no longer create duplicate or misplaced shapes in the rendered scene.
- State diagram concurrent regions now distinguish horizontal
||region layout from vertical--region layout.
0.12.0 #
Added #
- Sequence diagrams now support
hide footboxandskinparam actorStyle awesome; actor symbols can render the awesome actor variant, and foot participant boxes can be suppressed while preserving lifeline length. - Sequence separators and notes were refined: title separators now render
as a PlantUML-style double-line divider with clearer spacing, inline
note left/note rightafter a message anchors near that message, and multi-line... label ...delay blocks are accepted. - Activity diagrams now preserve action stereotypes, parse
split/split again/end split, tolerate SDL / UML signal-object stereotypes on actions, and accept Salt-style procedure-call activity nodes and multi-line marker bodies. - Timing diagrams now accept richer time anchors (
@lane,@+N,@-N,@H:M:S, date anchors, arithmetic anchors), analog and rectangle lane kinds, hidden-state shorthand, compact/style metadata, cross-lane annotation arrows, and extended clock / state forms. - Gantt diagrams now accept natural project dates,
projectscale/printscale/zoomdirectives, date-range coloring, raw dependency arrows, aliases,requiressyntax, resource assignments, relative starts / ends, explicit end dates, and chainedthentasks. - Component / deployment parsing now accepts additional PlantUML forms:
multi-line bracketed descriptions, sprites and skinparam blocks as
no-op metadata, component/deployment inline styles, nested component
containers, ports (
port,portin,portout), lollipop/interface arrow variants, direction-hint arrows, and broad allowmixing matrices. - State, mindmap, WBS, YAML, network, and ArchiMate parsers gained broader PlantUML compatibility coverage, including style/highlight metadata, history pseudo-states, direction directives, boxless markers, and ArchiMate include/macro-style sources.
- Inline markup now accepts space-delimited
<color ...>tags and emits deterministic[img]placeholders for PlantUML image tags. - The named color table now includes additional CSS colors such as
cadetblue,steelblue,royalblue,dodgerblue,skyblue,turquoise,chocolate,crimson,tomato,coral,wheat, andorchid. - Golden and parser coverage was expanded for the new activity, sequence, class, component/deployment, state, timing, Gantt, mindmap, WBS, ArchiMate, YAML, network, and inline-markup cases.
Changed #
- Class diagrams now render kind badges in the title bar for supported declaration kinds and draw an explicit divider between header and member sections for crisper output.
- The example app's sub-sample cards now use a taller preview area and scrollable preview panes instead of a fixed interactive viewer, making large sample diagrams easier to inspect.
Fixed #
- The lexer now treats bare semicolons as benign statement terminators,
supports escaped
\ntokens in labels, accepts multi-line bracketed description blocks, keeps semicolons inside<code>bodies from ending marker labels, and recognizes additional timing / state shorthand forms. - The preprocessor now tolerates
!unquoted/!finalprocedure and function blocks, bare-identifier procedure names, and!endfunctionclosures without aborting parsing. - Component, deployment, activity, timing, Gantt, state, mindmap, WBS, and network regression cases now parse instead of throwing on common PlantUML syntax that is currently rendered approximately or consumed as metadata.
0.11.0 #
Added #
- Sequence diagrams now support
hide unlinked,mainframe <label>, nested participant boxes, inline actor declarations, participant stereotypes,alt/elsetab and branch body colors, and PlantUML-style found / lost message endpoints (?->,[->,->?,->]). - Sequence arrow support was expanded for all PlantUML head / tail
decoration combinations, including leading
o/xtail markers, bidirectional decorated arrows, edge-found / edge-lost variants, and transmission duration annotations such asA ->(10) Bwith&-synchronized messages. - Use case diagrams now support colon-wrapped actors, parenthesized
use cases, package / rectangle grouping, direction-hint arrows,
generalization arrows, attached and free-standing notes, dotted note
connectors, multi-line use-case labels with
--,==, and..Title..separators, node stereotypes, and inline relation styling (#color,line.bold,line.dashed,line.dotted,text:color). - JSON diagrams now accept
<style> ... </style>blocks and#highlightdirectives as no-op styling metadata. Inlinejson ... { ... }blocks inside@startumlare recognized as JSON diagrams so mixed sources can parse instead of failing. - Network diagrams now accept
nwdiag { ... }wrappers, nestedgroupblocks, semicolon-separated statements, comments, segment properties, anonymous top-level groups, and shared node names across networks. - The example app now uses a structured sample catalog with sub-samples for sequence, use case, class, activity, component, state, object, deployment, timing, regex, network, wireframe, Archimate, Gantt, mindmap, WBS, EBNF, JSON, and YAML diagrams.
- Golden and parser coverage was expanded for the new sequence, use case, JSON, nwdiag, class-regression, and inline-markup cases.
Changed #
- The example app now shows selected diagram families as a scrollable list of editable sub-sample cards, each with its own live preview, instead of loading only one sample source at a time.
Fixed #
- Class diagram parsing now tolerates additional PlantUML forms reported
in regression cases: colored / stereotyped package blocks, dotted
package names,
scale ... width,set separator, lollipop interface relations, direction-hint arrows, and association-class connectors. - Sequence layout now excludes anonymous found / lost endpoints from the
participant order, filters emptied boxes when
hide unlinkedis used, and keeps synchronized duration arrows from over-expanding or overlapping later events.
0.10.0 #
Added #
- Sequence diagrams now carry explicit note background colors through to
layout, including
note ... #colorforms. - Sequence activation bars now support
activate X #color, preserving nested activation colors in the rendered bars. - Sequence parsing now accepts additional note variants and endings such
as
hnote,rnote,endnote,endrnote, andendhnote. - Sequence diagrams now support delay separators written as
|||and labeled skip separators such as... Some delay .... - Sequence parsing now handles
return ...as a dashed reply from the most recent forward message and consumesautoactivatedirectives so diagrams using PlantUML auto-activation syntax continue to render. - Inline markup support was expanded with Creole / PlantUML-style
monospace (
""text""),--strike--, colored underline / strike / wavy underline tags, text backgrounds,<font ...>color / size attributes, and deterministic image placeholders. - Sequence labels and notes now expand
<U+HHHH>unicode escapes and%autonumber%placeholders. - Sequence messages now accept a per-message
#colorafter the target, in addition to arrow-embedded color syntax. - Golden coverage was expanded for autoactivate / return, colored activations, delay separators, Creole markup, and advanced inline markup cases.
Changed #
- Autonumber labels now close any still-open inline markup tags before appending message text, preventing the autonumber format styling from leaking into the rest of the label.
- The example app editor now debounces preview rendering, preserves the cursor when loading samples / files, supports select-all shortcuts, and suppresses a known macOS keyboard state assertion.
Fixed #
- Sequence notes and labels that extend left of the first lifeline now shift the diagram right instead of being clipped off-canvas.
- Note body lexing now preserves inline separator / markup text inside labeled skip separators instead of re-tokenizing it.
0.9.0 #
Added #
- Class diagrams now use the shared
graph_layoutlayered layout and orthogonal edge router. Directed relationships assign classes to layers, sibling ordering uses barycenter-style crossing reduction, offset edges route through dogleg segments, same-row edges can detour around intervening boxes, and parallel / reverse relationships are separated into lanes. - Sequence diagrams now support
group/partitionblocks, richer participant declarations (#color,order N, and PlantUML-style multi-line[ ... ]labels with title / separator / code sections), quoted inline participants with"Display" as Alias, andnote left/note rightforms without an explicitof Xtarget. - Sequence
autonumberhandling now covers rest-of-line formats, PlantUML0/#placeholders,stop/resumesemantics, multi-level counters such as1.1.1, andinc <level>updates. - Sequence arrow parsing and rendering now covers additional PlantUML variants, including half arrows, circle / cross heads, bidirectional forms, and colored arrows.
- Class diagrams now accept implicit class declarations from
relationships, additional declaration kinds (
circle,diamond,dataclass,metaclass,protocol,stereotype,struct), the()/<>shorthand forms, and extended relationship head markers (#,x,},+,^/v). - The example app now includes a sample picker for multiple diagram types, an "Open PUML" file action, and a zoomable / pannable preview.
- Golden coverage was expanded for the new sequence, class, activity, state, and topology rendering cases.
Changed #
- The release workflow now runs
flutter test --exclude-tags goldenbecause golden output is platform-font dependent. - Golden test helpers now set the requested surface size explicitly so large diagram goldens render at their intended dimensions.
Fixed #
- Sequence diagrams that use
partitiongroups no longer get misrouted to the activity parser when sequence participant markers are present. - Sequence group frames now span the actual rendered leftmost and rightmost lifelines even when participant ordering is changed.
- Self messages now reserve space for multi-line labels and can render backward self-message loops on the left side of the lifeline.
- Notes without an explicit target now anchor to the nearest suitable
participant instead of requiring
note left/right of X.
0.8.0 #
Added #
- EBNF diagrams now render as PlantUML-style railroad tracks: each
rule becomes a labeled track with entry/exit dots, sequences are
connected horizontally, alternations branch with rejoin points, and
repetitions draw a U-loop back to the start. Previously EBNF bodies
rendered as raw text dumps. New
EbnfParser(recursive-descent tokenizer + parser) backs the AST, exposed viaEbnfRuleand a sealedEbnfExprhierarchy. - Component / deployment parser now honors the
left to right directionandtop to bottom directiondirectives (default remainstop to bottom).
Changed #
- Component / deployment layout: top-level containers and free nodes
are now placed in BFS-layered order driven by their relations
(default top-to-bottom stacks each rank as a row; with
left to right directioneach rank becomes a column). Sibling containers inside a parent container (e.g. multiple subnets inside a VPC) lay out as a row by default so peer groupings render side-by-side; leaf node children of a container continue to stack vertically. Previously every top-level container went into a single horizontal row regardless of flow, and nested children always stacked vertically. - Mindmap: a child without an explicit
+/-side marker now defaults to the right side (matching PlantUML's default behavior). Previously auto-side children alternated left/right, which split simple roadmaps across both sides of the root.
Fixed #
- State diagram: transitions whose endpoint is the
[*]pseudo-state (initial or final) are now drawn. Previously the emit loop looked up the raw[*]key in the node table, which the layout had already split into distinct[*]:initial/[*]:finalentries, so the arrow was silently dropped and the start/end dots floated disconnected. - State diagram: a bidirectional pair of transitions between the same
two states (e.g.
A --> B : submit/B --> A : request changes) now renders as two parallel arrows offset perpendicular to the edge axis, so both labels remain readable. Previously both transitions drew along the same center-to-center axis and stacked their labels on top of each other.
0.7.9 #
Fixed #
- Preprocessor:
!theme NAMEis silently consumed (no actual theme loading) so sources that start with!theme spacelabno longer fall through as an unrecognized line. - Preprocessor:
!$var = valueassignment-style syntax stores the value in the macro table under the$-prefixed key, so later references like$var(in content lines and!ifexpressions) anddefined($var)resolve correctly. The trailing value's surrounding double quotes, if present, are stripped. - Preprocessor:
!procedure $NAME($a, $b, ...)…!endprocedurecaptures the body as a multi-line template with positional parameters and stores it in a separate procedure table. A content line that starts with$NAME(args)invocation is expanded in place: arguments substitute$a,$b, … throughout the body (quoted-string args are unquoted before substitution) and the resulting body lines are themselves macro-expanded. - Preprocessor: unknown
!directivelines (anything not in the recognized set) are silently consumed instead of leaking through to the lexer. - Parser (component):
component "Name" as Alias #Colornow accepts and skips the trailing#colortoken, so procedure expansions likecomponent "Gateway" as Gateway #LightBlueparse cleanly.
0.7.8 #
Changed #
- JSON / YAML data diagrams now render in PlantUML's canonical
"linked tables" style: every
DataObjectandDataArraybecomes its own standalone two-column table laid out left-to-right by depth. Where a parent's value is a nested object/array, the parent's value cell shows a small connector dot and a dashed line links it to the top of the child table. Previously every nested value rendered as a recursively indented sub-table inside the parent's value cell, which made deep documents balloon both horizontally and vertically. Existingjson_diagram.pngandyaml_diagram.pnggoldens are regenerated.
0.7.7 #
Fixed #
- Gantt diagram date axis labels no longer overlap. The tick step now
enforces a minimum 78px gap between labels so date strings like
2026-05-25(about 70px wide at fontSize 10) have room to render. Previously short timelines (≤14 days) emitted a label every day at 14px spacing, producing illegible smudge text.
0.7.6 #
Fixed #
- Lexer:
!-prefixed directives at the start of a line (e.g.!pragma teoz true,!theme spacelab,!if,!else,!endif,!$var = value) are now silently consumed instead of raisingLexerException("Unexpected '!'"). The full body between!procedure ... !endprocedure(and!function/!definelong) is also skipped, so procedure definitions no longer pollute the token stream. - Lexer: lines starting with
$(procedure-call invocations such as$service("Gateway", #LightBlue)) are silently skipped at line start, matching the lenient handling of!directives. - Lexer:
&at the start of a line (PlantUML teoz "in parallel with previous" continuation) is consumed silently so the rest of the line parses as a normal sequence message. - Lexer: bidirectional arrows
<->,<-->, etc. are now recognized asarrowtokens. - Lexer: new
@startebnf/@endebnfand@startregex/@endregexdiagram boundaries. The body is captured as raw text and rendered as a monospace code listing. - Parser (timing): added
binarylane kind, rendered as a two-state robust lane.highlight ...andhide ...lines are silently skipped. - Parser (state):
hide/showdirectives are silently consumed in both top-level and nested state bodies.state H <<history>>declarations now parse — the trailing stereotype is accepted after the state name. - Parser (gantt):
title ...is accepted as a no-op decoration.<weekday> are closedand[Task] requires N peoplelines are silently skipped. New compound forms parse:[Task] lasts N days and starts at [Other]'s endandthen [Task] lasts N days(chains to the previous task's end). - Parser (json):
#highlight/#-prefixed directive lines in the JSON body are stripped beforejsonDecode, so the highlight annotation no longer breaks the parse. - Parser (yaml):
#highlightlines are stripped. YAML anchors (key: &name value), references (key: *name), and merge keys (<<: *name) are now supported. Anchored values are captured and inlined when referenced; merge keys expand the referenced object's entries into the current mapping. - Parser (sequence):
return ...,break ..., and teoz timing markers like{name}at the start of a line (including the bidirectional{start} <-> {end}SLA-window form) are silently consumed so the surrounding diagram still parses. - Parser (component): top-level
note <pos> of X ... end noteblocks andhide/showdirectives are silently skipped so deployment-style diagrams with annotation notes parse cleanly. - AST: new
EbnfDiagramwith atextfield; rendered by the newEbnfLayoutas a bordered monospace code block.TimingLaneKindgains abinaryvariant. - Colors: expanded the named-color table with
lightyellow,lightpink,lightcyan,salmon,gold,silver,cyan,magenta, and other CSS standard names so#LightYellow,#Salmon,#Gold, etc. parse without "Unknown color" errors.
0.7.5 #
Fixed #
- Lexer: a
-inside identifier-like words (e.g.Multi-region,omni-viewer.app,us-east-1) no longer raisesLexerException("Unexpected '-'"). Identifier scanning now greedily consumes-when it sits between two letter/digit/underscore characters, so identifiers may contain internal hyphens. Arrow scanning (->,-->,-[#color]->,<-, etc.) is unaffected because arrows always start at a position that is not inside an identifier. - Lexer: backslash escape sequences inside
"..."string literals are now interpreted.\nbecomes an actual newline,\"becomes a literal double quote, and\\becomes a single backslash. This matches PlantUML's behaviour and makes labels like"CDN Edge\n{global}"render as two lines. - Parser: use-case diagram dispatch (
usecase/rectangle) now requires the keyword to appear at the start of a line, soskinparam componentStyle rectangleno longer accidentally routes the diagram to the use-case parser. - Component / deployment diagrams: added a new
storagenode keyword.storage "Object Store" as S3parses as aComponentNodewithComponentNodeKind.storageand renders as a<<storage>>-stereotyped box;storage "Bucket" { ... }parses as aComponentContainerwithContainerKind.storage(and nests inside other containers likenode). - Component / deployment diagrams: nested-container parsing now
also accepts
database/queue/storagecontainer forms inside another container body, so deeply nested deployment topologies likeframe { node { node { node { ... } } } }parse without throwing.
0.7.4 #
Fixed #
- Component diagrams:
database "X" as DBandqueue "Q" as QQstandalone node declarations now render as cylinder / queue-pipe shapes viaSceneSymbolinstead of being miscategorized as generic<<component>>boxes. Two newComponentNodeKind.databaseandComponentNodeKind.queuevalues are emitted by the parser. The container forms (database X { ... }/queue X { ... }) still parse as containers via lookahead for{. - Component diagrams: relations whose endpoint is the alias of a
container (e.g.
cloud "Payment Gateway" as PGfollowed by[Payment Adapter] --> PG) now resolve to the container's rect, so the arrow is actually emitted instead of being silently dropped.ComponentContainer.aliasis now persisted on the AST. - Component diagrams: relation arrows now route as three-segment
Manhattan paths instead of straight diagonals, and detour
sideways when the straight path would pass through another
node's rect. This fixes the case where an arrow between two
nodes in the same container visually cut through a third
intervening node (e.g.
Order Service --> Inventory Servicepassing throughPayment Adapter).
0.7.3 #
Added #
- Class diagram header stereotype:
class Foo <<Aggregate>>andinterface Repository<T>style declarations now parse and render with the stereotype text shown in a small italic font above the class name (the same area used by the synthetic<<interface>>/<<enum>>etc. labels). A newString? stereotypefield is available onClassDecl. - Generic type parameters on class / interface / record headers:
class AggregateRoot<ID>and nested forms such asinterface Repository<T extends AggregateRoot<ID>, ID>are accepted; the generics text is appended to the displayed header name asName<...>and stored on a newString? genericsfield. Generics on relationship endpoints (e.g.Repository<T> <|.. R) are accepted and dropped. recordclass kind.record Money { amount: BigDecimal }parses as aClassDeclwithClassKind.record_and renders with a<<record>>stereotype label.- Free-floating notes in class diagrams:
note "text" as N1declares aFreeNoteattached to aliasN1; subsequentN1 .. SomeClasslines connect the note to the class with a dashed line. Multi-linenote <pos> of Class ... end noteblocks now also work inside class diagrams and are stored asFreeNoteentries withattachedToset. Notes render as yellowSceneNoteshapes placed below the class grid. package "label" <<Stereotype>> { ... }wrapper blocks are accepted at the top level of a class diagram; the wrapper is unmodeled and its body classes / relationships are flattened into the surrounding diagram.hide empty members/hide circle/hide ...directives at the top of a class diagram are silently consumed.
Fixed #
- Lexer no longer throws
Unexpected '<'for the angle bracket forms used in class diagrams.<<...>>(followed by anything other than-) is now aTokenType.stereotypetoken and a single<...>(with balanced nested angle brackets) is aTokenType.genericstoken. The existing arrow forms (<-,<--,<<-,<<--,<|--,<|..) are preserved.
0.7.2 #
Fixed #
- Activity diagram now accepts
detach,break, andkillterminator keywords (previously the parser rejected them asUnexpected token in activity diagram). - Activity diagram
whileandrepeat whileloops now accept the PlantUMLis (label)(yes-edge) andnot (label)(no-edge / repeat exit) modifiers, e.g.repeat while (cond) is (yes) not (no). Labels render as small italic text next to the corresponding loop arrows.
0.7.1 #
Fixed #
- Activity diagram tail arrows no longer cross through other branches' content boxes. The Manhattan tail's horizontal segment now sits just above the merge diamond (below all branches' content) instead of at the source-to-merge midpoint, which previously caused short branches to draw their tail through deeper sibling branches.
- Class / object / ER diagram BFS levelling now counts every directed relationship (composition, aggregation, association arrows, dependency, realization) toward a class's indegree, not just inheritance. Diagrams that use only associations (no inheritance) now lay out top-down by relationship direction instead of collapsing every class into a single row.
0.7.0 #
Changed #
- Activity diagram
if/elseif/elseandforkblocks now route their branches side-by-side instead of stacking them vertically on the spine. Each branch occupies its own column laid out horizontally (column width derived recursively from a_measureSubtreewalk so nested decisions expand their enclosing column), with three-segment Manhattan connector arrows from the decision diamond (or top fork bar) down into each column and matching tail arrows up into the merge diamond (or bottom fork bar) below. Theyes/no/ user-supplied condition labels render next to the horizontal segment of each connector.whileandrepeatblocks keep their existing vertical layout.
0.6.0 #
Added #
- Universal directive support. The six top-of-diagram directives
title,header,footer,caption,legend, andskinparamare now accepted by every keyword-dispatched diagram type (sequence, class, use case, activity, state, component, timing) — not just sequence diagrams. Previously the non-sequence parsers threwParserExceptionwhen a source started withtitle Foo, which blocked the common PlantUML convention of "first line is the diagram title." Decorations are stored on a newDiagramDecorationsholder accessible viadiagram.decorationson everyDiagramsubclass; rendering uses a newwrapWithDecorationshelper so every layout draws the header/title above and legend/caption/footer below its inner content. - Use-case-diagram
left to right directionandtop to bottom directionlayout-orientation hints are now parsed.left to right directionsetsUseCaseDiagram.leftToRightDirectiontotrue;top to bottom directionis parsed and ignored (the existing layout already places actors on the left and use cases on the right). Unknown variants are not consumed. - Component diagrams now recognize the
databasenode keyword (as a synonym forcomponent) so deployment-style sources that declaredatabase "Orders DB" as ODBparse without throwing.
Changed #
SequenceDiagramno longer exposes the individualtitle,caption,header,footer,legend, andskinconstructor parameters and fields. They live on the newdecorationsfield (aDiagramDecorationsinstance) instead. Callers constructingSequenceDiagraminstances directly should migrate fromSequenceDiagram(title: 'X', ...)toSequenceDiagram(decorations: DiagramDecorations(title: 'X'), ...).
0.5.0 #
Added #
- PlantUML preprocessor support. A new pure-Dart
Preprocessorruns as a string-to-string transformation BEFORE the existingLexer→Parserpipeline, so the diagram parser never sees preprocessor directives. Supported directives:!define MACRO value(simple text substitution);!define MACRO(a,b) body(function-like macro with positional substitution);!undef MACRO(remove a macro);!if expr/!elseif expr/!else/!endif(conditional inclusion with arbitrary nesting);!include path(inline another file's content, recursively preprocessed in the same context);!startsub id/!endsub(capture a named subsection of a file);!includesub path!sub_id(also!include path!sub_id) — include only a named subsection;!pragma key value(parsed and ignored, reserved for engine settings). Macro substitution scans content lines for known macro names and replaces them, but skips text inside double-quoted string literals ("...") so quoted labels are never munged.!function/!procedure/!return/!include_manyare reserved but skipped in v1. The!ifexpression language supports identifier lookup (a macro name evaluates to its body, or empty string if undefined), integer and double-quoted string literals, comparison operators==/!=/</>/<=/>=(numeric when both sides are integers, lexicographic otherwise), logical&&/||/!, parenthesized sub-expressions, and a built-indefined(NAME)predicate. Bare expressions are truthy when non-zero / non-empty. Adds aFileLoadertypedef (String Function(String path)) for resolving!includepaths to text;!includeraisesPreprocessorExceptionwhen the loader is null, when the loader throws, or when a circular include chain is detected. Other failure modes (unterminated!if,!endifwithout a matching!if,!elseifafter!else, unterminated!startsub, unknown!includesubid, malformed expression) also raisePreprocessorExceptioncarrying the offending line number. PumlView.fileLoaderparameter that plumbs aFileLoaderthrough to the preprocessor so widget callers can opt in to!include/!includesubsupport without bundlingdart:io(the default is null, which leaves!includeunsupported but is fine for the common case of inline-only sources). The widget'sbuildnow callsPreprocessor(fileLoader: fileLoader).preprocess(source)before the lexer; sources with no!directives pass through verbatim so existing diagrams are byte-identical.
0.4.0 #
Added #
- Network (nwdiag) diagrams. Network diagrams use a dedicated
@startnwdiag/@endnwdiagboundary and describe a set of horizontal network segments with attached nodes. Adds two new lexer tokens (startNwdiag/endNwdiag); the body is captured via the existing raw-lineinDataBodymode so each user line is preserved verbatim as atexttoken (the parser does all of the heavy lifting on the captured strings, so PlantUML tokens like[,],{,}, and=inside an nwdiag line are not mistaken for arrows / class dividers / string literals by the shared lexer). Adds aNetworkDiagramAST subclass with aList<NetworkSegment> networksfield; eachNetworkSegmentcarries a name, an optional segment-level address, and a list ofNetworkNode(name plus optional address). The parser routes@startnwdiagto_parseNetworkDiagram, which walks the captured lines and dispatches each through a small set of regexes —network NAME {,address = "...",nodeName [attr = "value"], and a barenodeNameform — opening a new segment onnetwork NAME {, closing it on}, and collecting node lines into the currently-open segment. A newNetworkLayoutrenders each segment as a horizontal blueSceneBoxbus bar with the network name (and optional address in a smaller gray line below) printed in a left-hand label column, distributes the segment's nodes evenly along the bus width as small whiteSceneBoxrectangles, prints each node's name centered inside (and the node address in a smaller line below if present), and joins each node to the bus with a verticalSceneLine. Multiple segments stack vertically with a fixed gap between rows. For v1 simplicity, a node that appears in multiple networks is rendered once per segment as an independent node (it appears duplicated rather than as a single shared node vertically spanning all of its networks); "shared node spanning" is a v2 enhancement. The embedded@startuml+nwdiag { ... }form that PlantUML also accepts is not supported in v1 — use the dedicated@startnwdiag/@endnwdiagboundary instead. - Gantt diagrams. Gantt uses a dedicated
@startgantt/@endganttboundary and describes a project schedule as a sequence of dated tasks, point-in-time milestones, and section dividers. Adds two new lexer tokens (startGantt/endGantt); the body is captured via the existing raw-lineinDataBodymode so each user line is preserved verbatim as atexttoken (the parser does all of the heavy lifting on the captured strings, so PlantUML tokens like[,],--, and'sinside a Gantt line are not mistaken for arrows / class dividers / string literals by the shared lexer). Adds aGanttDiagramAST subclass withprojectStart: DateTimeand a sealedGanttItemhierarchy (GanttTaskcarrying name + start + duration + optional color,GanttMilestonecarrying name + date,GanttSectioncarrying a title). The parser routes@startganttto_parseGanttDiagram, which dispatches each captured line through a small set of regexes —Project starts YYYY-MM-DD,[Name] lasts N day|days|week| weeks|month|months,[Name] starts YYYY-MM-DD,[Name] starts at [Other]'s end|start,[Name] happens at [Other]'s end|start | YYYY-MM-DD, and-- Title --— and builds an intermediate task / milestone / section list. A second walk resolves each task's absolute start by following itsstarts at [X]'s end|startchain back to either an explicit ISO date or the project start (with avisitingset to detect circular references); milestones are then resolved against the already-resolved task starts.weeksare stored asN * 7days andmonthsasN * 30days. A newGanttLayoutcomputes the overall date range (min start to max end), maps days to X with a fixed 14 px-per-day scale, stacks one row per item vertically with task / milestone / section names in a left-hand label column, and emits each task as a blueSceneBoxbar with a darker blue stroke, each milestone as a small amberSceneDiamond, each section as a bold-titledSceneLineacross the full plot width, and a thin top axis with date-labeled ticks (one per day / week / month depending on span). Color modifiers ([Name] is colored in red) are accepted by the parser and applied to the task fill; dependency arrows between tasks, pauses, and weekends-off scheduling are not yet supported. - Salt wireframe diagrams. Salt uses a dedicated
@startsalt/@endsaltboundary and describes a UI mockup as a grid of widgets wrapped in{}; each newline is a row and|separates cells within a row. Adds two new lexer tokensstartSalt/endSalt; the body is captured via the existing raw-lineinDataBodymode so each user line is preserved verbatim as atexttoken (the parser splits cells itself, so PlantUML tokens like[,(, and--inside a cell are not mistaken for arrows or class dividers). The parser routes@startsaltto_parseSaltDiagram, strips the opening{and closing}lines, and parses each remaining row: a line of--becomes a dividerSaltRow; otherwise the line is split on|and each cell is classified with a small regex / prefix-match heuristic into one ofSaltLabel,SaltButton([Label]),SaltTextField("text"),SaltRadio((X) Label/( ) Label), orSaltCheckbox([X] Label/[ ] Label). Cell detection is whitespace-tolerant. A newSaltLayoutsizes the grid as a table — columnjwidth is the max measured cell width in columnjacross all rows, rowiheight is the max measured cell height in rowi— and emits each cell as the appropriate scene shape inside an outerSceneBoxwith padding: buttons render as a graySceneRoundedBox, text fields as a whiteSceneRoundedBoxwith italicSceneText, radios as a filled-or-ringSceneCircleplus label, checkboxes as a smallSceneBox(with a two-segment check-markSceneLinepair when checked) plus label, and dividers as a full-widthSceneLineacross the inner content area. Tabs, dropdowns, trees, and advanced widgets are not yet supported. - JSON and YAML data diagrams. JSON diagrams use a dedicated
@startjson/@endjsonboundary; YAML diagrams use@startyaml/@endyaml. Adds four new lexer tokens (startJson/endJson/startYaml/endYaml) and a newinDataBodyraw-line capture mode in the lexer that preserves each body line verbatim (including leading whitespace, which YAML parsing depends on) and emits it as atexttoken until the matching end directive. Adds aDataDiagramAST subclass with aDataNode root(sealed:DataObject,DataArray,DataScalar) and aformat: DataFormat.{json, yaml}field;DataObjectpreserves insertion order by usingList<MapEntry<String, DataNode>>rather than a regularMap. The parser routes@startjsonto_parseJsonDiagram(which concatenates the body text tokens and feeds them todart:convert'sjsonDecode, then walks the resultingMap/List/ primitives into theDataNodetree;Mapis aLinkedHashMapso key order is preserved) and@startyamlto_parseYamlDiagram. YAML uses a small built-in subset parser (mappings, block sequences, and scalars only — no anchors, flow style, multi-line strings, or explicit tags) so the package adds no new pub.dev dependencies. Malformed input on either path raisesParserExceptioncarrying the original line / column. A newDataLayoutrenders each object / array as a verticalSceneBoxtable: the left column holds the key (or array index suffixed with:) on a light gray background and the right column holds the value. Nested objects and arrays render as sub-tables placed inside the value cell so the layout nests recursively. Scalar values render asSceneTextwith type-based coloring (strings green, numbers blue, booleans purple,nullitalic gray); string values are rendered in double quotes for unambiguity. Row dividers are drawn withSceneLine. - WBS (work breakdown structure) diagrams. Uses a dedicated
@startwbs/@endwbsboundary and reuses the mindmap's indented-tree syntax (one*per depth level) but renders as a top-down hierarchical tree instead of a horizontal radial mindmap. Adds two new lexer tokensstartWbs/endWbs; the existinginMindmapBodyraw-line capture was generalized toinIndentedTreeBodyand parameterized by an end keyword so both@endmindmapand@endwbsreuse the same scanner. The parser routes@startwbsto_parseWbsDiagramwhich delegates to a shared_parseIndentedTreehelper (factored out of the existing mindmap path); both diagrams reuseMindmapNodesince the tree data is identical. Adds aWbsDiagramAST subclass with an optionalMindmapNode root. A newWbsLayoutwalks the tree and computes each subtree width asmax(own node width, sum of children's subtree widths + horizontalGap × gaps), then places the root at the top with horizontal center equal to its subtree's center; each child level is offset down by the parent's height plus a vertical gap, and each child is placed inside its allocated subtree band so its center sits above its own children. Nodes render asSceneRoundedBox(root yellow, leaves white) and parent-to-child connectors render asSceneLinesegments: a single vertical line when the child is directly below the parent, or a three-segment manhattan path (down, across, down) when their X coordinates differ. - Mindmap diagrams. Mindmaps use a dedicated
@startmindmap/@endmindmapboundary (distinct from the shared@startuml/@endumlused by every other diagram kind) and describe a tree by indenting each node with leading*characters (one per depth level). Adds two new lexer tokensstartMindmap/endMindmap(per-kind boundary tokens rather than a generalizeddirectiveStart/directiveEndpair, to keep the lexer simple and avoid touching the ~50startUml/endUmlreferences in existing code paths; future per-kind boundaries should follow the same pattern). A new lexerinMindmapBodymode (similar to the existing multi-line note / legend / class body modes) captures every line between@startmindmapand@endmindmapas a single rawtexttoken so the parser can split the line itself without the*characters being mistaken for arrows or stars. The parser routes to_parseMindmapDiagramwhenever the first directive is@startmindmap; this dispatch runs before the existing@startumlbody auto-detection and does not interact with it. Adds aMindmapDiagramAST subclass with an optionalMindmapNode rootand aMindmapNode(text,depth,side: MindmapSide .{auto, left, right}, optionalcolor, and achildrenlist). Each input line is parsed as[+|-]\**+ [[#color]] text: the leading+forces the node to the right side,-forces it left, the run of*characters sets the tree depth, and an optional[#color]modifier (named or hex, same set as arrow[#color]) fills the node's box. Tree assembly uses a stack-of-ancestors algorithm so a deeper line attaches to the most recent shallower line; depth jumps and multiple root nodes raiseParserException. A newMindmapLayoutwalks the tree and produces a horizontal radial layout: the root sits in the middle as a yellowSceneRoundedBox, top-level children with no explicit side prefix are auto-balanced by alternating right/left (first auto child goes right, second left, third right, …) while explicit+/-prefixes pin the child to that side; each descendant inherits its top-level ancestor's side. On each side the layout reserves a slot per depth (depth × horizontalGapfrom the root) and vertically stacks subtrees so siblings never overlap, centering each subtree on its allocated band. Child nodes render as whiteSceneRoundedBoxshapes (or the requested[#color]fill); each parent-to-child connector is a straightSceneLinefrom the parent's outer edge to the child's inner edge, drawn in gray. The multi-line text box form (**: text;) is not yet supported. - ER (entity-relationship) diagrams. Implemented as a thin extension of
the class diagram infrastructure rather than a new
Diagramsubclass: adds anentity_variant toClassKind, arequiredflag and astereotypefield onField, and aCrowFootenum (one,zeroOrOne,zeroOrMany,oneOrMany) plusfromCrowFoot/toCrowFootfields onRelationship. The parser recognizesentity Name { ... }headers (theentitykeyword routes to the class diagram only when followed by a{body so the existing sequenceentityparticipant keyword still works), parses field lines with a leading*as required and a trailing<<PK>>/<<FK>>form as the field's stereotype, and decodes crow's foot relationship arrows whose endpoints are||/o|/o{/|{on the right side and their mirrored forms||/|o/}o/}|on the left side, with either--(solid) or..(dashed) bodies. A new_scanCrowFootArrowpre-pass runs from the lexer's|and}entry points before the existingdoublePipe/rightBracehandlers so crow's foot arrows lex as a singlearrowtoken while the||50||sequence separator and standalone braces continue to lex unchanged.ClassLayoutrenders entity headers with an<<entity>>stereotype label and, when a relationship carriesfromCrowFoot/toCrowFoot, omits the regular arrow head and emits a newSceneCrowFootscene shape at each marked endpoint (position, angle along the line, and kind); the renderer paints the crow's foot as a perpendicular tick for "one", a small white circle for the "zero" part, and a three-pronged crow for the "many" part. - Timing diagrams. The parser dispatches to a
TimingDiagramwhen it sees therobust/concise/clocklane keywords or an@<number>time cursor at the start of a line. The discriminator runs ahead of activity so timing wins when these markers are present. Adds aTimingDiagramAST subclass withTimingLane(alias,label,kind: TimingLaneKind.{robust, concise, clock}, optionalclockPeriod) and a sealedTimingEventhierarchy withStateChange(time,lane,state) andTimingArrow(time,from,to, optionallabel). Supported syntax:robust "Label" as Alias/concise "Label"/clock "Label" with period Nlane declarations,@<integer>time-cursor markers that set the parser's current time,<alias> is <StateName>state assignments (states persist until changed), and<alias> -> <alias> : labelarrow annotations between lanes at the current time. A newatTimelexer token recognizes@followed by digits and emits the numeric lexeme;@startuml/@endumlcontinue to lex as before because the digit-prefix check fires first. A newTimingLayoutrenders a horizontal time axis with tick marks at every used time across the top, stacks lanes vertically below, and maps time to X proportionally (smallest time pinned to the plot's left edge, largest to the right, intermediates by linear interpolation; each adjacent pair gets at least a 60 px gap). Robust lanes draw each state as a horizontalSceneLinesegment whose Y position is chosen from the alphabetically-sorted set of states seen on the lane, with a verticalSceneLineedge at each transition and the state name printed above each segment. Concise lanes draw a single horizontal line with the state name above each segment and a small vertical tick at each transition. Arrows render as a verticalSceneLinewith a filled arrow head at the target lane. Clock lanes parse and reserve space but render as an empty labeled band in v1; highlighted time ranges are not yet supported. - Deployment diagrams. Implemented as a thin extension of component
diagrams rather than a new
Diagramsubclass:_looksLikeComponentDiagramnow also recognizes theartifactkeyword at the start of a line so a source that only usesartifactandnodestill routes to the component parser. Adds anartifactvariant toComponentNodeKind(now{component, interface, artifact}) and an_parseArtifactDeclthat accepts the sameartifact Nameandartifact "Display" as Aliasforms ascomponent, both at the top level and inside container bodies.ComponentLayoutrenders artifact nodes as a small whiteSceneNote(~80×40, with the document-style folded top-right corner), distinct from the light-blue component rectangles. - Component diagrams. The parser dispatches to a
ComponentDiagramwhen it sees thecomponentkeyword, a container keyword (package/node/cloud/frame), a bracketed[Name]shorthand, or the()interface shorthand at the start of a line. The discriminator runs between state and class so the dispatch order is activity > use case > state > component > class > sequence (component wins over class becauseinterfaceis valid in both, but component-specific markers must be present for component to fire). Adds aComponentDiagramAST subclass withComponentNode(alias,label,kind: ComponentNodeKind.{component, interface}),ComponentContainer(optionallabel,kind: ContainerKind.{package, node, cloud, frame},nodeAliases, andnestedContainersfor arbitrarily nested containers), andComponentRelation(reuses the use-case-styleLineStyle/ArrowHead/MessageDirectionarrow encoding). Supported syntax:component Name/component "Display" as Aliasdeclarations, the bracket shorthand[Name]and[Name] as Alias(which supports multi-word names by joining all tokens up to the closing]),interface Name/interface "Display" as Aliasdeclarations, the lollipop shorthand() "Name" as Alias,package/node/cloud/framecontainers (with an optional quoted label, optionalas Alias, and a{ ... }body that may hold component / interface declarations, bracket and paren shorthands, and arbitrarily nested containers), and relationships using the standard arrow forms (->,-->,..>,--,..) with optional: labeland endpoints that can be aliases or bracketed shorthands. A newComponentLayoutlays out top-level containers left-to-right in a single row, then stacks any free-standing nodes below; inside each container child nodes and nested containers are stacked vertically. Components render as light-blueSceneBoxrectangles with the<<component>>stereotype above the name; interfaces render as a smallSceneCirclelollipop with the label below. Package containers draw a labeled tab in the top-left corner; node containers add two smallSceneLineshading strokes plus a top edge to suggest a 3D box; cloud containers use aSceneRoundedBox; frame containers draw a labeled notch in the top-left corner. Relationship arrows render asSceneLinebetween the rectangle edges (or the circle perimeter for interface endpoints) with an open-V arrow head at the target end. - State diagrams. The parser dispatches to a
StateDiagramwhen it sees thestatekeyword or the[*]pseudo-state literal anywhere in the body. The discriminator runs between use case and class, so the dispatch order is activity > use case > state > class > sequence (state wins over class because both can have{ ... }bodies). Adds aStateDiagramAST subclass withStateDecl(name, optionaldisplayName,nestedStates,nestedTransitions, andconcurrentRegions: List<List<StateDecl>>— emptynestedStatesand emptyconcurrentRegionsindicates a leaf state) andStateTransition(from,to, optionallabel); pseudo-states are encoded as the literal'[*]'string in transition endpoints. Supported syntax:[*] --> Xinitial transitions,X --> [*]final transitions, bareX --> Y : labeltransitions,state Namedeclarations,state "Display" as Aliasalias form,state Outer { ... }composite states with nested states and transitions, and concurrent regions inside a composite body separated by a--on its own line (which the parser special-cases as a region divider). Adds new lexer tokensleftBracket([) andrightBracket(]); a standalone*immediately after a[is emitted as an identifier so[*]lexes asleftBracket, identifier*,rightBracketand the parser folds the three tokens back into the pseudo-state literal. A newStateLayoutlays out sibling states using the same grid + BFS layered scheme asClassLayout; leaf states render asSceneRoundedBox(yellow fill, rounded corners). Composite states render as aSceneRoundedBoxwith a header band, a horizontal divider line, and the nested sub-layout emitted inside the body region (child shapes are translated into the outer state's coordinate space). Concurrent regions inside a composite are stacked vertically and separated by a dashedSceneLine. The[*]pseudo-state renders as aSceneCircle: filled when it appears as the source of a transition (initial) and ringed when it appears as the target (final). Transitions render asSceneLinewith an open-V arrow head at the target end. - Activity diagrams (new syntax). The parser dispatches to an
ActivityDiagramwhen it sees activity markers at the start of a line:start/stop,if (/while (headers,repeat/fork/partitionkeywords, or a:Action;line. The discriminator runs before the use case and class checks so activity wins when these markers are present. Adds anActivityDiagramAST subclass with a sealedActivityNodehierarchy:StartNode,StopNode,EndNode,Action(rounded action box with optional inline note),IfBlock(one or moreIfBranch { condition, thenLabel, body }entries plus an optionalelseBody/elseLabel;elseifis modeled as additionalIfBranchentries),WhileBlock(condition,isLabel,endLabel,body),RepeatBlock(body,whileCondition),ForkBlock(branches: List<List<ActivityNode>>), andPartition(name,body). Inline action text is captured by stripping the trailing;from the rest-of-line text token the colon handler already emits. New lexer tokensleftParen/rightParenfor(/); when the lexer sees a(it emits the open paren, captures the content up to the matching)as a single trimmedtexttoken, then emits the close paren — this lets condition / label expressions contain arbitrary characters (e.g.if (in stock?)). A newActivityLayoutlays out nodes top-to-bottom on a single vertical spine. Start / stop / end render asSceneCircle(filled or ringed); actions render asSceneRoundedBox; decisions render asSceneDiamond; fork synchronization points render as thickSceneBoxbars; partitions render as a thin labeled box around their body. For v1,if/elseif/elsebranches andforkbranches are stacked vertically rather than laid out side-by-side — dense diagrams will be taller than the reference PlantUML output. Adds three new scene shapes (SceneDiamond,SceneCircle,SceneRoundedBox) plumbed through the renderer. - Use case diagrams. The parser dispatches to a
UseCaseDiagramwhen it seesusecaseorrectanglekeywords (checked before the class-diagram discriminator so use case wins over class). Adds aUseCaseDiagramAST subclass withUseCaseNode(actor or use case),UseCaseRelation(reusingLineStyle,ArrowHead, andMessageDirection), andUseCaseBoundary(a rectangle wrapper with optional label and a list of contained aliases). Supported syntax:actor Name/actor "Display" as Alias,usecase Name/usecase "Display" as Alias,rectangle "Label" { ... }(label optional) for system-boundary rectangles around contained use cases, and relationship lines that reuse the sequence-style arrow forms (->,-->,..>,--,..) plus an optional:label (commonly<<include>>or<<extend>>stereotypes). A newUseCaseLayoutarranges actors vertically along the left edge, places use cases inside their boundary rectangles in a grid in the middle, and stacks any free-standing use cases below. Adds a newSceneEllipseshape (the renderer draws it viacanvas.drawOvalfor both fill and stroke), so use cases render as oval shapes with their label centered inside; actors reuse the existingSceneSymbolactor glyph. - Class diagrams. The parser now dispatches between sequence and class
diagrams based on body content: sources containing
class,interface,enum,abstract,annotation, orexceptionkeywords (or arrows like<|--,*--,..>) are parsed as a class diagram; everything else falls through to the existing sequence diagram path unchanged. Adds aClassDiagramAST subclass alongsideSequenceDiagram, withClassDecl,ClassMember(sealed:Field,Method,EnumValue,MemberDivider),Relationship, and supporting enums (ClassKind,Visibility,DividerKind,RelationshipKind). - Type declarations:
class Foo,abstract class Foo(alsoabstract Foo),interface Foo,enum Foo,annotation Foo,exception Foo. Each optionally takes a{ ... }body. Inside the body, lines are interpreted as members:+name: Typefield,+method()/+method(): Typemethod, visibility chars+-#~for public / private / protected / package-private (rendered in green / red / orange / purple),{static}/{abstract}modifiers (underline / italic),--/../==section dividers, and bare identifiers for enum values. - Eight relationship kinds with the standard PlantUML arrows: inheritance
(
<|--/--|>), realization (<|../..|>), composition (*--/--*), aggregation (o--/--o), directed association (-->/<--), association (--), dependency (..>/<..), and link (..). Reversed forms swap the AST endpoints so layout always renders the head on the same side. Relationships accept optional multiplicities (A "1" *-- "*" B) and a colon-prefixed label (: has). ClassLayoutimplementing a simple grid + BFS layered layout: each class becomes a yellow box with a header band (name + optional stereotype like<<interface>>) above a member list; classes are placed in rows by BFS level starting from roots with no incoming inheritance edges; rows are centered horizontally. Relationships render as straight lines between box edges with kind-appropriate heads. Documented limitation: edges may cross for dense graphs since no edge routing is performed.- Three new
ArrowHeadvariants on the scene shape:triangle(hollow triangle, used for inheritance / realization),filledDiamond, andhollowDiamond(composition / aggregation). The renderer draws each with a fill + stroke pair so heads remain visible on any background. - Lexer support for class diagram arrow forms (
<|--,<|..,--|>,..|>,*--,--*,o--,--o,..>,<..,.., plus reversed and bracketed-modifier variants) and a class-body mode that captures member lines astexttokens between{and}. Sequence diagram arrows (->,->o,->x,-->, etc.) are unchanged. - Object diagrams via the same
ClassDiagramAST. Newobjectandmapheader keywords reuse the class-diagram dispatcher andClassLayout. Anobjectbody holds attribute assignments (name = value); amapbody holds key/value pairs (key => value). AddsClassKind.object_,ClassKind.map_, a newAttributeClassMembersubclass (name,value,isMap), and aClassDecl.instanceOffield for typed instances (object alice : Person). Object / map headers render with an underlined name per UML instance convention;mapadds a<<map>>stereotype label above the name. Relationships between objects reuse the existing class relationship arrows. Surrounding double quotes around an attribute value are stripped at parse time. AddsTokenType.equals(=) andTokenType.mapArrow(=>) for future use; current body parsing reads whole lines astexttokens (consistent with class bodies). The==token continues to lex asdoubleEqualsvia longest-match.
0.3.0 #
Added #
-
Basic
skinparamsupport for customizing diagram visuals. Both the inline form (skinparam backgroundColor #White) and the block form (skinparam sequence { ArrowColor #Red ... }) are accepted; in the block form the optional prefix is concatenated with each inner key before matching. Keys are case-insensitive and unknown keys are silently ignored. Supported keys:backgroundColor,defaultFontSize,sequenceArrowColor,sequenceLifeLineBackgroundColor,participantBackgroundColor,participantBorderColor,noteBackgroundColor,noteBorderColor. Adds aSkinParamsAST class andSequenceDiagram.skinfield; layout reads the skin to override the corresponding default colors and to scale the label / note / header / footer / caption / legend font size. The diagram background is plumbed through a newScene.backgroundfield that the renderer fills before painting any shape. Adds newleftBrace/rightBracetoken types for{and}. -
Multi-line comments
/' ... '/. Anything between the opening/'and the closing'/is skipped by the lexer, including newlines. The existing single-line'comment behavior is unchanged. An unterminated/'(no closing'/before EOF) raisesLexerExceptionpointing at the opening position. -
Inline HTML / Markdown formatting in label text. The renderer and text measurer now parse a small markup subset before painting or measuring:
<b>/**bold**,<i>///italic//,<u>/__under__,<s>/~~strike~~,<color:name>and<color:#RRGGBB>(named or hex, same set as arrow[#color]modifiers),<size:N>, and<br>/\nfor line breaks. Markup nests; unknown tags pass through as literal text so pre-existing label strings render unchanged. Applies to message labels, note bodies, participant display names, group/box labels, and the title / caption / header / footer / legend regions. Addslib/src/text/inline_markup.dart(parseInlineMarkup) and extracts the shared color parser intolib/src/text/colors.dart(tryParseColor,namedColors); both are re-exported from the package barrel. -
newpagedirective for splitting a single sequence into multiple logical pages within one source. Each page shares participants and diagram-level decorations (header / footer / legend / title / caption). An optional per-page title may follow the keyword (newpage Page Two Title). Rendered as a thick horizontal divider line across the diagram width with the optional title centered above it; lifelines and activation stacks continue uninterrupted across the divider (a deliberate simplification of PlantUML's paginated PDF output). Adds aNewPagesequence-event subclass. -
legend…endlegend(alsoend legend) directive that draws a small bordered box of multi-line text below the diagram body and above any caption or footer. An optional alignment modifier (left/right/center, defaultleft) positions the box horizontally within the diagram width; body text is left-aligned inside the box. DuplicatelegendthrowsParserException. Adds aLegendAST class andSequenceDiagram.legendfield. The lexer captures legend body lines as rawtexttokens, mirroring multi-line note handling, so the body may contain punctuation freely. -
title,header,footer, andcaptiondirectives that decorate a sequence diagram with surrounding text regions. Each supports a single-line form (title My Title) and a multi-line form terminated withend title/end header/end footer/end caption.headerandfooteraccept an optional alignment modifier (center/left/right, defaultcenter). Title renders centered above the diagram in bold; header and footer render small and gray at the very top and bottom with the chosen alignment; caption renders centered below the diagram in italic. Duplicate declarations throwParserException. AddsSequenceDiagram.title,SequenceDiagram.caption,SequenceDiagram.header,SequenceDiagram.footerfields and a newHeaderFooterAST class. -
autonumberdirective for sequence diagrams. Prepends a running sequence number to every subsequentMessagelabel. Supports the variantsautonumber,autonumber <start>,autonumber <start> <increment>, and an optional trailing format string (e.g.autonumber 10 5 "[%03d]").autonumber stoppauses numbering;autonumber resume [n]resumes from the remembered (or explicitly given) value. Format placeholders supported are%dand%0NdforNin 1–9; a format string with no%d-like marker is used as a literal prefix with the number appended after a space. Numbering is applied at parse time by rewritingMessage.label; no AST or layout changes are needed. -
Sequence-diagram separator lines:
== Title ==draws a solid horizontal rule with the title centered in a rounded grey label box that interrupts the line.||n||(digits between two||markers) reservesnpixels of vertical space (clamped to 20–200) and draws a small two-bar zigzag mark on each lifeline....draws a centered...skip indicator.--on its own line draws a dashed horizontal rule across all lifelines. The deactivate-source suffix--on messages (B --> A --) is unaffected — separators only fire when--is the leading token on a line. Adds aSeparatorAST type andSeparatorKindenum.
-
New lexer tokens
doubleEquals(==),doublePipe(||), anddotDotDot(...). The==and||…||scanners also emit the in-between label (text) / digit (text) as a normaltexttoken so the parser can pick it up. -
box "Label" [#color]…end boxgroups participants visually inside a tinted, labeled rectangle around their top actor boxes. Multiple boxes are allowed and appear side-by-side; participants declared at top level (outside any box) remain unboxed. Nested boxes and events inside a box are rejected with aParserException. Adds aParticipantBoxAST type, aSequenceDiagram.boxesfield, and aSequenceDiagram.boxOf(alias)helper. Inner participants are also appended toSequenceDiagram.participantsso existing code paths that scan participants continue to see them. -
New lexer
TokenType.hashColorfor standalone#colorname/#RRGGBBmodifiers (e.g. the optional color on aboxdeclaration). Arrow modifiers continue to embed their color inside the arrow lexeme as before. -
Multi-line notes:
note left of A/note right of A/note over A(andnote over A, B) followed by any number of body lines and terminated byend note. Each body line is trimmed and joined with\nto become the note's text. The single-linenote … : textform is unchanged. -
ref over A : text(andref over A, B, … : text) reference box, rendered as a rectangle spanning the named participants with a smallreftab at the top-left. Adds aRefBoxsequence-event subclass. -
Standalone
createanddestroykeyword statements:create Aemits aCreateevent for an existing/implicit alias.create participant "Name" as A(or any actor kind:actor,boundary,control,entity,database,collections,queue) declares the participant and emits aCreateevent in one statement.destroy Aemits aDestroyevent terminating the lifeline with an X.
-
Inline lifecycle / activation suffixes on messages:
A -> B ++activates the target.B --> A --deactivates the source.A -> C **creates the target lifeline at the message Y (top actor box drops down rather than being pinned to the diagram top).C -> A !!destroys the target — its lifeline ends with an X mark and its bottom actor box is omitted.
-
New
ActivationSuffixenum onMessageand newCreate/Destroysequence-event subclasses; the parser decomposes a suffixed message into aMessageplus the appropriate follow-up event. -
New lexer tokens
plusPlus(++),minusMinus(--),starStar(**), andbangBang(!!). The arrow scanner runs first so dashed arrows (-->,--[#color]->,<--) continue to lex as a single arrow lexeme; a standalone--is only emitted when no arrow form matches.
0.2.0 #
Added #
- Full PlantUML arrow-variant grammar:
->,-->,->>,-->>,->o,-->o,->x,-->x, plus reversed forms<-,<--,<<-,<<--. Each form chooses an independent (line style, arrow head, direction). - New
ArrowHeadenum (filled,open,openCircle,cross),LineStyleenum (solid,dashed), andMessageDirectionenum (forward,backward) onMessage. - Arrow modifiers
-[hidden]->(reserves layout space but draws nothing) and-[#color]->(named or hex stroke color). Compose with every existing arrow head/style/direction. AddsMessage.hidden: boolandMessage.color: Color?fields.
Changed #
Message.style: MessageStylewas split intoMessage.lineStyle: LineStyle,Message.head: ArrowHead, andMessage.direction: MessageDirection.SceneLine.arrowHead: boolis nowSceneLine.head: ArrowHead?(null = no head) with aheadAtFrom: boolflag indicating which end carries it.- The default head for
->is now a filled triangle (matching PlantUML). The previous open-V shape is selected with->>/-->>. - Lexer now emits a single
TokenType.arrowfor every arrow form; the parser inspects the lexeme to decode (lineStyle,head,direction).TokenType.dashedArrowwas removed.
0.1.0 #
Initial unreleased snapshot. Sequence diagrams render natively without a PlantUML server.
Added #
PumlViewwidget that lexes, parses, lays out, and paints a PlantUML source string in pure Dart.- Sequence diagram support:
- Solid (
->) and dashed (-->) messages with optional labels. - Self-messages (
A -> A) rendered as a stepped loop. participantdeclarations with quoted display names and aliases.note left of/note right of/note over(single- and multi-participant), drawn as folded-corner yellow boxes.activate/deactivaterendered as stacked activation bars on lifelines.alt/else/opt/loop/pargroup blocks with nesting, transparent outer frame, label tab, and dashedelsedividers.
- Solid (
- Pluggable
TextMeasurerfor headless layout testing. - Golden-test infrastructure (
test/golden/, macOS-generated baselines). - Example app with a live editor and
InteractiveViewerpreview.