diff --git a/gallery/example1.pdf b/gallery/example1.pdf index de434a8..a3f8e8f 100644 Binary files a/gallery/example1.pdf and b/gallery/example1.pdf differ diff --git a/gallery/example1.typ b/gallery/example1.typ index 48be250..28d10de 100644 --- a/gallery/example1.typ +++ b/gallery/example1.typ @@ -33,15 +33,38 @@ Alice <-- Bob: Another authentication Response #chronos.diagram({ import chronos: * _seq("Alice", "Bob", comment: "Authentication Request") - _seq("Bob", "Alice", comment: "Authentication Failure") - _grp("My own label", desc: "My own label2", { - _seq("Alice", "Log", comment: "Log attack start") - _grp("loop", desc: "1000 times", { - _seq("Alice", "Bob", comment: "DNS Attack") - }) - _seq("Alice", "Bob", comment: "Log attack end") + _alt( + "successful case", { + _seq("Bob", "Alice", comment: "Authentication Accepted") + }, + "some kind of failure", { + _seq("Bob", "Alice", comment: "Authentication Failure") + + _grp("My own label", desc: "My own label2", { + _seq("Alice", "Log", comment: "Log attack start") + _loop("1000 times", { + _seq("Alice", "Bob", comment: "DNS Attack") + }) + _seq("Alice", "Log", comment: "Log attack end") + }) + }, + "Another type of failure", { + _seq("Bob", "Alice", comment: "Please repeat") + } + ) +}) + +#chronos.diagram({ + import chronos: * + _par("a", display-name: box(width: 1.5em, height: .5em), show-bottom: false) + _par("b", display-name: box(width: 1.5em, height: .5em), show-bottom: false) + _col("a", "b", width: 2cm) + _loop("a<1", min: 1, { + _seq("a", "b", end-tip: ">>") + _seq("b", "a", end-tip: ">>") }) + _seq("a", "b", end-tip: ">>") }) #chronos.diagram({ diff --git a/src/diagram.typ b/src/diagram.typ index b70eef5..8412d60 100644 --- a/src/diagram.typ +++ b/src/diagram.typ @@ -185,7 +185,7 @@ // Compute groups spans (horizontal) for (i, elmt) in elmts.enumerate() { - if elmt.type == "grp" { + if elmt.type == "grp" or elmt.type == "alt" { let (min-i, max-i) = get-group-span(participants, elmt) elmts.at(i).insert("min-i", min-i) elmts.at(i).insert("max-i", max-i) diff --git a/src/group.typ b/src/group.typ index 78e00c7..4d3cb3c 100644 --- a/src/group.typ +++ b/src/group.typ @@ -11,6 +11,36 @@ ),) } +#let _alt(desc, elmts, ..args) = { + let all-elmts = () + all-elmts += elmts + let args = args.pos() + for i in range(0, args.len(), step: 2) { + let else-desc = args.at(i) + let else-elmts = args.at(i + 1, default: ()) + all-elmts.push(( + type: "else", + desc: else-desc + )) + all-elmts += else-elmts + } + + return _grp("alt", desc: desc, type: "alt", all-elmts) +} + +#let _loop(desc, min: none, max: auto, elmts) = { + let name = "loop" + if min != none { + if max == auto { + max = "*" + } + name += "(" + str(min) + "," + str(max) + ")" + } + _grp(name, desc: desc, type: "loop", elmts) +} +#let _opt(desc, elmts) = grp("opt", desc: desc, type: "opt", elmts) +#let _break(desc, elmts) = grp("break", desc: desc, type: "break", elmts) + #let render(x0, x1, y0, y1, group) = { let shapes = () let name = text(group.name, weight: "bold") @@ -50,5 +80,20 @@ ) } + return shapes +} + +#let render-else(x0, x1, y, elmt) = { + let shapes = draw.line( + (x0, y), + (x1, y), + stroke: (dash: (2pt, 1pt), thickness: .5pt) + ) + shapes += draw.content( + (x0, y), + text([\[#elmt.desc\]], weight: "bold", size: .8em), + anchor: "north-west", + padding: 3pt + ) return shapes } \ No newline at end of file diff --git a/src/lib.typ b/src/lib.typ index 6afc60f..2d96474 100644 --- a/src/lib.typ +++ b/src/lib.typ @@ -2,7 +2,7 @@ #import "diagram.typ": diagram, from-plantuml, _gap, _evt, _col #import "sequence.typ": _seq -#import "group.typ": _grp +#import "group.typ": _grp, _loop, _alt, _opt, _break #import "participant.typ": _par #import "separator.typ": _sep #import "note.typ": _note diff --git a/src/renderer.typ b/src/renderer.typ index a772654..4d9c46c 100644 --- a/src/renderer.typ +++ b/src/renderer.typ @@ -242,6 +242,7 @@ let draw-seq = sequence.render.with(pars-i, x-pos, participants) let draw-group = group.render.with() + let draw-else = group.render-else.with() let draw-sep = separator.render.with(x-pos) let draw-par = participant.render.with(x-pos) let draw-note = note.render.with(pars-i, x-pos) @@ -283,6 +284,9 @@ if g.at(1).max-i == elmt.max-i { g.at(3) += 1 } g }) + if elmt.grp-type == "alt" { + elmt.insert("elses", ()) + } groups.push((y, elmt, 0, 0)) y -= m.height / 1pt @@ -294,6 +298,21 @@ let x1 = x-pos.at(group.max-i) + end-lvl * 10 + 20 shapes += draw-group(x0, x1, start-y, y, group) + if group.grp-type == "alt" { + for (else-y, else-elmt) in group.elses { + shapes += draw-else(x0, x1, else-y, else-elmt) + } + } + + // Alt's elses -> reserve space for label + store position + } else if elmt.type == "else" { + y -= Y-SPACE + let m = measure(text([\[#elmt.desc\]], weight: "bold", size: .8em)) + groups.last().at(1).elses.push(( + y, elmt + )) + y -= m.height / 1pt + // Separator } else if elmt.type == "sep" { let shps