diff --git a/gallery/example1.pdf b/gallery/example1.pdf index a1d2b15..1042c9a 100644 Binary files a/gallery/example1.pdf and b/gallery/example1.pdf differ diff --git a/gallery/example2.pdf b/gallery/example2.pdf index 174b24b..69a5943 100644 Binary files a/gallery/example2.pdf and b/gallery/example2.pdf differ diff --git a/gallery/example2.typ b/gallery/example2.typ index 2b50105..ca2903e 100644 --- a/gallery/example2.typ +++ b/gallery/example2.typ @@ -39,3 +39,13 @@ _seq("charlie", "alice", comment: "ok", dashed: true, disable-src: true) }) +#chronos.diagram({ + import chronos: * + _seq("?", "Alice", comment: [?->\ *short* to actor1]) + _seq("[", "Alice", comment: [\[->\ *from start* to actor1]) + _seq("[", "Bob", comment: [\[->\ *from start* to actor2]) + _seq("?", "Bob", comment: [?->\ *short* to actor2]) + _seq("Alice", "]", comment: [->\]\ from actor1 *to end*]) + _seq("Alice", "?", comment: [->?\ *short* from actor1]) + _seq("Alice", "Bob", comment: [->\ from actor1 to actor2]) +}) \ No newline at end of file diff --git a/src/diagram.typ b/src/diagram.typ index 916b5c7..26866e1 100644 --- a/src/diagram.typ +++ b/src/diagram.typ @@ -1,6 +1,6 @@ #import "utils.typ": get-group-span #import "renderer.typ": render -#import "participant.typ" as participant: _par +#import "participant.typ" as participant: _par, PAR-SPECIALS #let _gap(size: 20) = { return (( @@ -45,6 +45,22 @@ } } + let pars = participants + participants = () + participants.push(_par("[", invisible: true).first()) + for (i, p) in pars.enumerate() { + let before = _par("?" + p.name, invisible: true).first() + let after = _par(p.name + "?", invisible: true).first() + if i == 0 { + participants.push(before) + } else { + participants.insert(-1, before) + } + participants.push(p) + participants.push(after) + } + participants.push(_par("]", invisible: true).first()) + // Add index to participant for (i, p) in participants.enumerate() { p.insert("i", i) @@ -57,6 +73,12 @@ 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) + } else if elmt.type == "seq" { + if elmt.p1 == "?" { + elmts.at(i).p1 = "?" + elmt.p2 + } else if elmt.p2 == "?" { + elmts.at(i).p2 = elmt.p1 + "?" + } } } diff --git a/src/participant.typ b/src/participant.typ index 4ff6761..f661d4c 100644 --- a/src/participant.typ +++ b/src/participant.typ @@ -1,16 +1,23 @@ #import "@preview/cetz:0.2.2": draw #import "consts.typ": * -#let _par(name, display-name: auto, from-start: true) = { +#let PAR-SPECIALS = "?[]" + +#let _par(name, display-name: auto, from-start: true, invisible: false) = { return (( type: "par", name: name, display-name: if display-name == auto {name} else {display-name}, - from-start: from-start + from-start: from-start, + invisible: invisible ),) } #let _exists(participants, name) = { + if name == "?" or name == "[" or name == "]" { + return true + } + for p in participants { if name == p.name { return true diff --git a/src/renderer.typ b/src/renderer.typ index 531fc37..d8b1504 100644 --- a/src/renderer.typ +++ b/src/renderer.typ @@ -2,10 +2,12 @@ #import "utils.typ": get-participants-i, get-style #import "group.typ" #import "participant.typ" +#import participant: PAR-SPECIALS #import "sequence.typ" #import "separator.typ" #import "consts.typ": * +#let DEBUG-INVISIBLE = false #let get-columns-width(participants, elements) = { participants = participants.map(p => { @@ -56,8 +58,10 @@ for i in range(participants.len() - 1) { let p1 = participants.at(i) let p2 = participants.at(i + 1) - let w1 = measure(box(p1.display-name)).width + PAR-PAD.last() * 2 - let w2 = measure(box(p2.display-name)).width + PAR-PAD.last() * 2 + let w1 = if p1.invisible {0pt} else {measure(box(p1.display-name)).width} + let w2 = if p2.invisible {0pt} else {measure(box(p2.display-name)).width} + w1 += PAR-PAD.last() * 2 + w2 += PAR-PAD.last() * 2 widths.push(w1 / 2pt + w2 / 2pt + PAR-SPACE) } @@ -79,7 +83,7 @@ let m = measure(cell.cell) widths.at(cell.i2 - 1) = calc.max( widths.at(cell.i2 - 1), - m.width / 1pt - widths.slice(0, cell.i2 - 1).sum() + m.width / 1pt - widths.slice(cell.i1, cell.i2 - 1).sum() ) } @@ -115,7 +119,7 @@ // Draw participants (start) for p in participants { - if p.from-start { + if p.from-start and not p.invisible { shapes += draw-par(p) } } @@ -174,8 +178,26 @@ // Draw vertical lines + lifelines + end participants shapes += draw.on-layer(-1, { - for (i, p) in participants.enumerate() { - let x = x-pos.at(i) + if DEBUG-INVISIBLE { + for p in participants.filter(p => p.invisible) { + let color = if p.name.starts-with("?") {green} else if p.name.ends-with("?") {red} else {blue} + let x = x-pos.at(p.i) + draw.line( + (x, 0), + (x, y), + stroke: (paint: color, dash: "dotted") + ) + draw.content( + (x, 0), + p.display-name, + anchor: "west", + angle: 90deg + ) + } + } + + for p in participants.filter(p => not p.invisible) { + let x = x-pos.at(p.i) // Draw vertical line let last-y = 0 @@ -185,7 +207,7 @@ let lines = () // Compute lifeline rectangles + destruction positions - for line in lifelines.at(i).lines { + for line in lifelines.at(p.i).lines { let event = line.first() if event == "create" { last-y = line.at(1)