Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3ed1966b82
|
||
|
|
55333bbe56
|
||
|
|
48458b054d
|
||
|
|
e45144c0e8
|
||
|
|
fe66e5a72a | ||
|
|
01d930bfd5 | ||
|
|
f33fe8f932
|
||
|
|
7da39889d4
|
||
|
|
a46bb8534b
|
||
|
|
00d52fe83f
|
||
|
|
47e9f42d5f
|
||
|
|
a815037f24
|
||
|
|
fab45bd8ab
|
||
|
|
4231233f76
|
||
|
|
34ec00768f
|
||
|
|
a7db89b214 | ||
|
|
511368d405
|
||
|
|
3a7e0a8176
|
||
|
|
03c0f1cc7e
|
||
|
|
df785be454
|
||
|
|
692a4570ff
|
||
|
|
53adb58525
|
||
|
|
771bfdc0ea
|
||
|
|
1000a3a19a | ||
|
|
f3763cb1f7
|
||
|
|
c19d507486
|
||
|
|
fe01e63dd0
|
||
|
|
d6c390f3c5
|
||
|
|
bbc8bb0339
|
||
|
|
f39e14654a
|
||
|
|
6bf98ebcb8 |
@@ -14,7 +14,7 @@ jobs:
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Install tytanic
|
||||
run: cargo binstall tytanic@0.2.2
|
||||
run: cargo binstall tytanic@0.3.3
|
||||
|
||||
- name: Run test suite
|
||||
run: tt run
|
||||
|
||||
@@ -15,7 +15,7 @@ This package lets you render sequence diagrams directly in Typst. The following
|
||||
<td>
|
||||
|
||||
```typst
|
||||
#import "@preview/chronos:0.2.2"
|
||||
#import "@preview/chronos:0.3.0"
|
||||
#chronos.diagram({
|
||||
import chronos: *
|
||||
_par("Alice")
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
/// Manually adds an event to the given participant
|
||||
/// - participant (str): The participant concerned by the event
|
||||
/// - event (str): The event type (see @@EVENTS for ccepted values)
|
||||
#let _evt(participant, event) = {}
|
||||
/// - lifeline-style (auto, dict): See @@_seq()
|
||||
#let _evt(participant, event, lifeline-style: auto) = {}
|
||||
|
||||
/// Creates a sequence / message between two participants
|
||||
/// - p1 (str): Start participant
|
||||
@@ -21,6 +22,7 @@
|
||||
/// - destroy-src (bool): If true, destroy the source lifeline and participant
|
||||
/// - lifeline-style (auto, dict): Optional styling options for lifeline rectangles (see CeTZ documentation for more information on all possible values)
|
||||
/// - slant (none, int): Optional slant of the arrow
|
||||
/// - outer-lifeline-connect (bool): If true, enables legacy anchoring, making sequences connect to the leftmost lifeline when arriving from the left side. If false, all connections are made with the latest/rightmost lifeline
|
||||
/// -> array
|
||||
#let _seq(
|
||||
p1,
|
||||
@@ -39,7 +41,8 @@
|
||||
disable-src: false,
|
||||
destroy-src: false,
|
||||
lifeline-style: auto,
|
||||
slant: none
|
||||
slant: none,
|
||||
outer-lifeline-connect: false
|
||||
) = {}
|
||||
|
||||
/// Creates a return sequence
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
#chronos.diagram({
|
||||
import chronos: *
|
||||
_seq("User", "A", comment: "DoWork", enable-dst: true)
|
||||
_seq("A", "B", comment: [#sym.quote.angle.l createRequest #sym.quote.angle.r], enable-dst: true)
|
||||
_seq("A", "B", comment: [#sym.quote.chevron.l createRequest #sym.quote.chevron.r], enable-dst: true)
|
||||
_seq("B", "C", comment: "DoWork", enable-dst: true)
|
||||
_seq("C", "B", comment: "WorkDone", destroy-src: true, disable-src: true, dashed: true)
|
||||
_seq("B", "A", comment: "RequestCreated", disable-src: true, dashed: true)
|
||||
@@ -15,7 +15,7 @@
|
||||
import chronos: *
|
||||
_seq("User", "A", comment: "DoWork", enable-dst: true, lifeline-style: (fill: rgb("#FFBBBB")))
|
||||
_seq("A", "A", comment: "Internal call", enable-dst: true, lifeline-style: (fill: rgb("#E9967A")))
|
||||
_seq("A", "B", comment: [#sym.quote.angle.l createRequest #sym.quote.angle.r], enable-dst: true)
|
||||
_seq("A", "B", comment: [#sym.quote.chevron.l createRequest #sym.quote.chevron.r], enable-dst: true)
|
||||
_seq("B", "A", comment: "RequestCreated", disable-src: true, disable-dst: true, dashed: true)
|
||||
_seq("A", "User", comment: "Done", disable-src: true)
|
||||
})
|
||||
|
||||
|
Before Width: | Height: | Size: 88 KiB After Width: | Height: | Size: 88 KiB |
|
Before Width: | Height: | Size: 22 KiB After Width: | Height: | Size: 22 KiB |
@@ -4,6 +4,13 @@
|
||||
gallery_dir := "./gallery"
|
||||
set shell := ["bash", "-uc"]
|
||||
|
||||
@version:
|
||||
echo $'\e[1mTypst:\e[0m'
|
||||
typst --version
|
||||
echo
|
||||
echo $'\e[1mTytanic:\e[0m'
|
||||
tt util about
|
||||
|
||||
manual:
|
||||
typst c manual.typ manual.pdf
|
||||
|
||||
|
||||
@@ -1 +1 @@
|
||||
#import "@preview/cetz:0.4.0": *
|
||||
#import "@preview/cetz:0.4.2": *
|
||||
@@ -3,6 +3,9 @@
|
||||
#import "/src/consts.typ": *
|
||||
#import "/src/core/utils.typ": get-ctx, set-ctx, expand-parent-group
|
||||
|
||||
#let display-name(name) = text(name, weight: "bold")
|
||||
#let display-desc(desc) = text([\[#desc\]], weight: "bold", size: .8em)
|
||||
|
||||
#let render-start(grp) = get-ctx(ctx => {
|
||||
let grp = grp
|
||||
ctx.y -= Y-SPACE
|
||||
@@ -44,8 +47,8 @@
|
||||
|
||||
|
||||
#let draw-group(x0, x1, y0, y1, group) = {
|
||||
let name = text(group.name, weight: "bold")
|
||||
let m = measure(box(name))
|
||||
let name = display-name(group.name)
|
||||
let m = measure(name)
|
||||
let w = m.width / 1pt + 15
|
||||
let h = m.height / 1pt + 6
|
||||
draw.rect(
|
||||
@@ -71,7 +74,7 @@
|
||||
if group.desc != none {
|
||||
draw.content(
|
||||
(x0 + w, y0),
|
||||
text([\[#group.desc\]], weight: "bold", size: .8em),
|
||||
display-desc(group.desc),
|
||||
anchor: "north-west",
|
||||
padding: 3pt
|
||||
)
|
||||
@@ -86,7 +89,7 @@
|
||||
)
|
||||
draw.content(
|
||||
(x0, y),
|
||||
text([\[#elmt.desc\]], weight: "bold", size: .8em),
|
||||
display-desc(elmt.desc),
|
||||
anchor: "north-west",
|
||||
padding: 3pt
|
||||
)
|
||||
@@ -105,6 +108,22 @@
|
||||
let x0 = min-x - 10
|
||||
let x1 = max-x + 10
|
||||
|
||||
// Fit name and descriptions
|
||||
let name-m = measure(display-name(group.name))
|
||||
let width = name-m.width / 1pt + 15
|
||||
if group.desc != none {
|
||||
let desc-m = measure(display-desc(group.desc))
|
||||
width += desc-m.width / 1pt + 6
|
||||
}
|
||||
if group.grp-type == "alt" {
|
||||
width = calc.max(width, ..group.elses.map(e => {
|
||||
let elmt = e.at(1)
|
||||
let desc-m = measure(display-desc(elmt.desc))
|
||||
return desc-m.width / 1pt + 6
|
||||
}))
|
||||
}
|
||||
x1 = calc.max(x1, x0 + width + 3)
|
||||
|
||||
draw-group(x0, x1, start-y, ctx.y, group)
|
||||
|
||||
if group.grp-type == "alt" {
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
#import "/src/cetz.typ": draw, vector
|
||||
#import "/src/cetz.typ": coordinate, draw, vector
|
||||
|
||||
#import "note.typ"
|
||||
#import "/src/consts.typ": *
|
||||
#import "/src/core/utils.typ": get-ctx, set-ctx
|
||||
#import "/src/core/utils.typ": expand-parent-group, get-ctx, set-ctx
|
||||
|
||||
#let get-arrow-marks(sym, color) = {
|
||||
if sym == none {
|
||||
@@ -13,12 +13,23 @@
|
||||
}
|
||||
(
|
||||
"": none,
|
||||
">": (symbol: ">", fill: color),
|
||||
">>": (symbol: "straight"),
|
||||
"\\": (symbol: ">", fill: color, harpoon: true),
|
||||
"\\\\": (symbol: "straight", harpoon: true),
|
||||
"/": (symbol: ">", fill: color, harpoon: true, flip: true),
|
||||
"//": (symbol: "straight", harpoon: true, flip: true),
|
||||
">": (symbol: ">", fill: color, stroke: (dash: "solid")),
|
||||
">>": (symbol: "straight", stroke: (dash: "solid")),
|
||||
"\\": (symbol: ">", fill: color, harpoon: true, stroke: (dash: "solid")),
|
||||
"\\\\": (symbol: "straight", harpoon: true, stroke: (dash: "solid")),
|
||||
"/": (
|
||||
symbol: ">",
|
||||
fill: color,
|
||||
harpoon: true,
|
||||
flip: true,
|
||||
stroke: (dash: "solid"),
|
||||
),
|
||||
"//": (
|
||||
symbol: "straight",
|
||||
harpoon: true,
|
||||
flip: true,
|
||||
stroke: (dash: "solid"),
|
||||
),
|
||||
"x": none,
|
||||
"o": none,
|
||||
).at(sym)
|
||||
@@ -56,11 +67,11 @@
|
||||
let width = calc.abs(ctx.x-pos.at(i1) - ctx.x-pos.at(i2))
|
||||
|
||||
let h = 0
|
||||
let comment = if seq.comment == none {none} else {
|
||||
let comment = if seq.comment == none { none } else {
|
||||
let w = calc.min(width * 1pt, measure(seq.comment).width)
|
||||
box(
|
||||
width: if i1 == i2 {auto} else {w},
|
||||
seq.comment
|
||||
width: if i1 == i2 { auto } else { w },
|
||||
seq.comment,
|
||||
)
|
||||
}
|
||||
// Reserve space for comment
|
||||
@@ -71,7 +82,7 @@
|
||||
h,
|
||||
..seq.linked-notes.map(n => {
|
||||
note.get-size(n).height / 2
|
||||
})
|
||||
}),
|
||||
)
|
||||
ctx.y -= h
|
||||
|
||||
@@ -79,13 +90,13 @@
|
||||
i: i1,
|
||||
x: ctx.x-pos.at(i1),
|
||||
y: ctx.y,
|
||||
ll-lvl: ctx.lifelines.at(i1).level * LIFELINE-W / 2
|
||||
ll-lvl: ctx.lifelines.at(i1).level * LIFELINE-W / 2,
|
||||
)
|
||||
let end-info = (
|
||||
i: i2,
|
||||
x: ctx.x-pos.at(i2),
|
||||
y: ctx.y,
|
||||
ll-lvl: ctx.lifelines.at(i2).level * LIFELINE-W / 2
|
||||
ll-lvl: ctx.lifelines.at(i2).level * LIFELINE-W / 2,
|
||||
)
|
||||
let slant = if seq.slant == auto {
|
||||
DEFAULT-SLANT
|
||||
@@ -129,21 +140,27 @@
|
||||
if seq.create-dst {
|
||||
let par = ctx.participants.at(i2)
|
||||
let m = measure(box(par.display-name))
|
||||
let f = if i1 > i2 {-1} else {1}
|
||||
let f = if i1 > i2 { -1 } else { 1 }
|
||||
end-info.x -= (m.width + PAR-PAD.last() * 2) / 2pt * f
|
||||
(par.draw)(par, y: end-info.y)
|
||||
(par.draw)(par, y: end-info.y - m.height / 1pt)
|
||||
}
|
||||
|
||||
end-info.ll-lvl = ctx.lifelines.at(i2).level * LIFELINE-W / 2
|
||||
|
||||
// Compute left/right position at start/end
|
||||
start-info.insert("lx", start-info.x)
|
||||
if start-info.ll-lvl != 0 { start-info.lx -= LIFELINE-W / 2 }
|
||||
end-info.insert("lx", end-info.x)
|
||||
if end-info.ll-lvl != 0 { end-info.lx -= LIFELINE-W / 2 }
|
||||
|
||||
start-info.insert("rx", start-info.x + start-info.ll-lvl)
|
||||
end-info.insert("rx", end-info.x + end-info.ll-lvl)
|
||||
let start-lx = start-info.x
|
||||
let end-lx = end-info.x
|
||||
if seq.outer-lifeline-connect {
|
||||
if start-info.ll-lvl != 0 { start-lx -= LIFELINE-W / 2 }
|
||||
if end-info.ll-lvl != 0 { end-lx -= LIFELINE-W / 2 }
|
||||
} else {
|
||||
if start-info.ll-lvl != 0 { start-lx = start-info.rx - LIFELINE-W }
|
||||
if end-info.ll-lvl != 0 { end-lx = end-info.rx - LIFELINE-W }
|
||||
}
|
||||
start-info.insert("lx", start-lx)
|
||||
end-info.insert("lx", end-lx)
|
||||
|
||||
// Choose correct points to link
|
||||
let x1 = start-info.rx
|
||||
@@ -158,13 +175,13 @@
|
||||
mark: (
|
||||
start: get-arrow-marks(seq.start-tip, seq.color),
|
||||
end: get-arrow-marks(seq.end-tip, seq.color),
|
||||
scale: 1.2
|
||||
scale: 1.2,
|
||||
),
|
||||
stroke: (
|
||||
dash: if seq.dashed {(2pt,2pt)} else {"solid"},
|
||||
dash: if seq.dashed { (2pt, 2pt) } else { "solid" },
|
||||
paint: seq.color,
|
||||
thickness: .5pt
|
||||
)
|
||||
thickness: .5pt,
|
||||
),
|
||||
)
|
||||
|
||||
let y0 = start-info.y
|
||||
@@ -202,13 +219,13 @@
|
||||
(x1, start-info.y),
|
||||
(x-mid, start-info.y),
|
||||
(x-mid, end-info.y),
|
||||
(x2, end-info.y)
|
||||
(x2, end-info.y),
|
||||
)
|
||||
|
||||
if comment != none {
|
||||
comment-anchor = (
|
||||
start: if x-mid < x1 {"south-east"} else {"south-west"},
|
||||
end: if x-mid < x1 {"south-west"} else {"south-east"},
|
||||
start: if x-mid < x1 { "south-east" } else { "south-west" },
|
||||
end: if x-mid < x1 { "south-west" } else { "south-east" },
|
||||
left: "south-west",
|
||||
right: "south-east",
|
||||
center: "south",
|
||||
@@ -217,16 +234,20 @@
|
||||
comment-pt = (
|
||||
start: pts.first(),
|
||||
end: pts.at(1),
|
||||
left: if x-mid < x1 {pts.at(1)} else {pts.first()},
|
||||
right: if x-mid < x1 {pts.first()} else {pts.at(1)},
|
||||
center: (pts.first(), 50%, pts.at(1))
|
||||
left: if x-mid < x1 { pts.at(1) } else { pts.first() },
|
||||
right: if x-mid < x1 { pts.first() } else { pts.at(1) },
|
||||
center: (pts.first(), 50%, pts.at(1)),
|
||||
).at(seq.comment-align)
|
||||
}
|
||||
|
||||
expand-parent-group(
|
||||
calc.min(x1, x2, x-mid),
|
||||
calc.max(x1, x2, x-mid),
|
||||
)
|
||||
} else {
|
||||
pts = (
|
||||
(x1, start-info.y),
|
||||
(x2, end-info.y)
|
||||
(x2, end-info.y),
|
||||
)
|
||||
|
||||
if comment != none {
|
||||
@@ -242,14 +263,14 @@
|
||||
comment-pt = (
|
||||
start: start-pt,
|
||||
end: end-pt,
|
||||
left: if x2 < x1 {end-pt} else {start-pt},
|
||||
right: if x2 < x1 {start-pt} else {end-pt},
|
||||
center: (start-pt, 50%, end-pt)
|
||||
left: if x2 < x1 { end-pt } else { start-pt },
|
||||
right: if x2 < x1 { start-pt } else { end-pt },
|
||||
center: (start-pt, 50%, end-pt),
|
||||
).at(seq.comment-align)
|
||||
|
||||
comment-anchor = (
|
||||
start: if x2 < x1 {"south-east"} else {"south-west"},
|
||||
end: if x2 < x1 {"south-west"} else {"south-east"},
|
||||
start: if x2 < x1 { "south-east" } else { "south-west" },
|
||||
end: if x2 < x1 { "south-west" } else { "south-east" },
|
||||
left: "south-west",
|
||||
right: "south-east",
|
||||
center: "south",
|
||||
@@ -261,6 +282,11 @@
|
||||
(p1, p2) = (p2, p1)
|
||||
}
|
||||
comment-angle = vector.angle2(p1, p2)
|
||||
|
||||
expand-parent-group(
|
||||
calc.min(x1, x2),
|
||||
calc.max(x1, x2),
|
||||
)
|
||||
}
|
||||
|
||||
// Start circle tip
|
||||
@@ -270,27 +296,27 @@
|
||||
radius: CIRCLE-TIP-RADIUS,
|
||||
stroke: none,
|
||||
fill: seq.color,
|
||||
name: "_circle-start-tip"
|
||||
name: "_circle-start-tip",
|
||||
)
|
||||
pts.at(0) = "_circle-start-tip"
|
||||
|
||||
// Start cross tip
|
||||
|
||||
// Start cross tip
|
||||
} else if is-cross-tip(seq.start-tip) {
|
||||
let size = CROSS-TIP-SIZE
|
||||
let cross-pt = (
|
||||
pts.first(),
|
||||
size * 2,
|
||||
pts.at(1)
|
||||
pts.at(1),
|
||||
)
|
||||
draw.line(
|
||||
(rel: (-size, -size), to: cross-pt),
|
||||
(rel: (size, size), to: cross-pt),
|
||||
stroke: seq.color + 1.5pt
|
||||
stroke: seq.color + 1.5pt,
|
||||
)
|
||||
draw.line(
|
||||
(rel: (-size, size), to: cross-pt),
|
||||
(rel: (size, -size), to: cross-pt),
|
||||
stroke: seq.color + 1.5pt
|
||||
stroke: seq.color + 1.5pt,
|
||||
)
|
||||
pts.at(0) = cross-pt
|
||||
}
|
||||
@@ -302,27 +328,27 @@
|
||||
radius: 3,
|
||||
stroke: none,
|
||||
fill: seq.color,
|
||||
name: "_circle-end-tip"
|
||||
name: "_circle-end-tip",
|
||||
)
|
||||
pts.at(pts.len() - 1) = "_circle-end-tip"
|
||||
|
||||
// End cross tip
|
||||
|
||||
// End cross tip
|
||||
} else if is-cross-tip(seq.end-tip) {
|
||||
let size = CROSS-TIP-SIZE
|
||||
let cross-pt = (
|
||||
pts.last(),
|
||||
size * 2,
|
||||
pts.at(pts.len() - 2)
|
||||
pts.at(pts.len() - 2),
|
||||
)
|
||||
draw.line(
|
||||
(rel: (-size, -size), to: cross-pt),
|
||||
(rel: (size, size), to: cross-pt),
|
||||
stroke: seq.color + 1.5pt
|
||||
stroke: seq.color + 1.5pt,
|
||||
)
|
||||
draw.line(
|
||||
(rel: (-size, size), to: cross-pt),
|
||||
(rel: (size, -size), to: cross-pt),
|
||||
stroke: seq.color + 1.5pt
|
||||
stroke: seq.color + 1.5pt,
|
||||
)
|
||||
pts.at(pts.len() - 1) = cross-pt
|
||||
}
|
||||
@@ -335,8 +361,22 @@
|
||||
comment,
|
||||
anchor: comment-anchor,
|
||||
angle: comment-angle,
|
||||
padding: 3pt
|
||||
padding: 3pt,
|
||||
name: "comment",
|
||||
)
|
||||
|
||||
// TODO: Improve this
|
||||
draw.get-ctx(c => {
|
||||
let (_, left, right) = coordinate.resolve(
|
||||
c,
|
||||
"comment.west",
|
||||
"comment.east",
|
||||
)
|
||||
expand-parent-group(
|
||||
left.at(0),
|
||||
right.at(0),
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
if seq.create-dst {
|
||||
@@ -353,16 +393,22 @@
|
||||
if seq.linked-notes.len() != 0 {
|
||||
end-info.y = calc.min(
|
||||
end-info.y,
|
||||
y0 - calc.max(..seq.linked-notes.map(n => {
|
||||
let m = note.get-size(n)
|
||||
return m.height / 2
|
||||
}))
|
||||
y0
|
||||
- calc.max(..seq.linked-notes.map(n => {
|
||||
let m = note.get-size(n)
|
||||
return m.height / 2
|
||||
})),
|
||||
)
|
||||
}
|
||||
|
||||
set-ctx(c => {
|
||||
c.y = end-info.y
|
||||
c.lifelines = ctx.lifelines
|
||||
c.last-drawn = (
|
||||
type: "seq",
|
||||
start-info: start-info,
|
||||
end-info: end-info,
|
||||
)
|
||||
return c
|
||||
})
|
||||
})
|
||||
|
||||
@@ -1,32 +1,66 @@
|
||||
#import "/src/core/utils.typ": get-ctx, is-elmt, set-ctx
|
||||
#import "/src/cetz.typ": draw
|
||||
|
||||
#let render(sync) = get-ctx(ctx => {
|
||||
set-ctx(c => {
|
||||
c.sync-ys = ()
|
||||
c.sync = (
|
||||
ctx: ctx,
|
||||
bottoms: (),
|
||||
starts: (),
|
||||
start-y: ctx.y,
|
||||
align-y: ctx.y
|
||||
)
|
||||
c.in-sync = true
|
||||
return c
|
||||
})
|
||||
})
|
||||
|
||||
#let in-sync-render(elmt) = {
|
||||
set-ctx(c => {
|
||||
c.y = c.sync.start-y
|
||||
return c
|
||||
})
|
||||
draw.hide({
|
||||
(elmt.draw)(elmt)
|
||||
})
|
||||
set-ctx(c => {
|
||||
c.sync.starts.push(c.last-drawn.start-info.y)
|
||||
c.sync.bottoms.push(c.y)
|
||||
return c
|
||||
})
|
||||
}
|
||||
|
||||
#let render-end(sync) = get-ctx(ctx => {
|
||||
for e in sync.elmts {
|
||||
assert(is-elmt(e), message: "Sync element can only contain chronos elements, found " + repr(e))
|
||||
assert(
|
||||
e.type == "seq",
|
||||
message: "Sync element can only contain sequences, found '" + e.type + "'"
|
||||
)
|
||||
|
||||
set-ctx(c => {
|
||||
c.y = ctx.y
|
||||
return c
|
||||
})
|
||||
(e.draw)(e)
|
||||
set-ctx(c => {
|
||||
c.sync-ys.push(c.y)
|
||||
return c
|
||||
})
|
||||
}
|
||||
|
||||
set-ctx(c => {
|
||||
c.y = calc.min(..c.sync-ys)
|
||||
c.remove("sync-ys")
|
||||
let new-sync = c.sync
|
||||
if new-sync.starts.len() != 0 {
|
||||
new-sync.align-y = calc.min(..new-sync.starts)
|
||||
}
|
||||
new-sync.remove("ctx")
|
||||
return c.sync.ctx + (sync: new-sync)
|
||||
})
|
||||
|
||||
for (i, e) in sync.elmts.enumerate() {
|
||||
set-ctx(c => {
|
||||
let dy = c.sync.starts.at(i) - c.sync.start-y
|
||||
c.y = c.sync.align-y - dy
|
||||
return c
|
||||
})
|
||||
(e.draw)(e)
|
||||
}
|
||||
|
||||
set-ctx(c => {
|
||||
let heights = c.sync.starts.zip(c.sync.bottoms).map(((s, b)) => b - s)
|
||||
c.y = c.sync.align-y + calc.min(..heights)
|
||||
c.remove("sync")
|
||||
return c
|
||||
})
|
||||
})
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
#import "draw/note.typ": get-box as get-note-box, get-size as get-note-size
|
||||
#import "draw/participant.typ"
|
||||
#import "draw/sync.typ": in-sync-render
|
||||
#import "utils.typ": *
|
||||
#import "/src/consts.typ": *
|
||||
|
||||
@@ -15,22 +16,6 @@
|
||||
})
|
||||
}
|
||||
|
||||
#let unwrap-syncs(elements) = {
|
||||
let i = 0
|
||||
while i < elements.len() {
|
||||
let elmt = elements.at(i)
|
||||
if elmt.type == "sync" {
|
||||
elements = (
|
||||
elements.slice(0, i + 1) +
|
||||
elmt.elmts +
|
||||
elements.slice(i + 1)
|
||||
)
|
||||
}
|
||||
i += 1
|
||||
}
|
||||
return elements
|
||||
}
|
||||
|
||||
#let seq-update-lifelines(participants, pars-i, seq) = {
|
||||
let participants = participants
|
||||
let com = if seq.comment == none {""} else {seq.comment}
|
||||
@@ -308,7 +293,6 @@
|
||||
|
||||
#let compute-columns-width(participants, elements, pars-i) = {
|
||||
elements = elements.filter(is-elmt)
|
||||
elements = unwrap-syncs(elements)
|
||||
|
||||
let cells
|
||||
(participants, elements, cells) = compute-max-lifeline-levels(participants, elements, pars-i)
|
||||
@@ -334,7 +318,8 @@
|
||||
lifelines: participants.map(_ => (
|
||||
level: 0,
|
||||
lines: ()
|
||||
))
|
||||
)),
|
||||
in-sync: false
|
||||
)
|
||||
chronos-ctx.insert(
|
||||
"widths",
|
||||
@@ -393,7 +378,13 @@
|
||||
if not is-elmt(elmt) {
|
||||
(elmt,)
|
||||
} else if "draw" in elmt and elmt.type != "par" {
|
||||
(elmt.draw)(elmt)
|
||||
get-ctx(ctx => {
|
||||
if ctx.in-sync and elmt.type != "sync-end" {
|
||||
in-sync-render(elmt)
|
||||
} else {
|
||||
(elmt.draw)(elmt)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
#import "draw/group.typ": render-end as grp-render-end
|
||||
#import "draw/sync.typ": render-end as sync-render-end
|
||||
#import "utils.typ": get-group-span, is-elmt
|
||||
#import "/src/participant.typ": _exists as par-exists, _par
|
||||
#import "/src/sequence.typ": _seq
|
||||
@@ -18,6 +19,24 @@
|
||||
)
|
||||
}
|
||||
|
||||
#let flatten-sync(elmts, i) = {
|
||||
let sync = elmts.at(i)
|
||||
elmts.at(i) = sync
|
||||
let start = sync
|
||||
start.remove("elmts")
|
||||
return (
|
||||
elmts.slice(0, i) +
|
||||
(start,) +
|
||||
sync.elmts +
|
||||
((
|
||||
type: "sync-end",
|
||||
draw: sync-render-end,
|
||||
elmts: sync.elmts
|
||||
),) +
|
||||
elmts.slice(i + 1)
|
||||
)
|
||||
}
|
||||
|
||||
#let update-group-children(elmts, i) = {
|
||||
let elmts = elmts
|
||||
let group-end = elmts.at(i)
|
||||
@@ -38,7 +57,8 @@
|
||||
seq.p2, seq.p1,
|
||||
comment: ret.comment,
|
||||
disable-src: true,
|
||||
dashed: true
|
||||
dashed: true,
|
||||
end-tip: ret.end-tip,
|
||||
).first()
|
||||
return (elmts, activation-history)
|
||||
}
|
||||
@@ -58,6 +78,9 @@
|
||||
|
||||
if elmt.type == "grp" {
|
||||
elmts = flatten-group(elmts, i)
|
||||
|
||||
} else if elmt.type == "sync" {
|
||||
elmts = flatten-sync(elmts, i)
|
||||
|
||||
} else if elmt.type == "seq" {
|
||||
if elmt.enable-dst {
|
||||
|
||||
@@ -42,7 +42,7 @@
|
||||
let (i0, i1) = get-group-span(participants, elmt)
|
||||
min-i = calc.min(min-i, i0)
|
||||
max-i = calc.max(max-i, i1)
|
||||
} else if elmt.type == "sync" {
|
||||
} else if elmt.type == "sync-end" {
|
||||
let (i0, i1) = get-group-span(participants, elmt)
|
||||
min-i = calc.min(min-i, i0)
|
||||
max-i = calc.max(max-i, i1)
|
||||
|
||||
@@ -39,5 +39,5 @@
|
||||
}
|
||||
_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 _opt(desc, elmts) = _grp("opt", desc: desc, type: "opt", elmts)
|
||||
#let _break(desc, elmts) = _grp("break", desc: desc, type: "break", elmts)
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#let version = version(0, 2, 2)
|
||||
#let version = version(0, 3, 0)
|
||||
#import "diagram.typ": diagram, from-plantuml
|
||||
|
||||
#import "sequence.typ": _seq, _ret
|
||||
|
||||
@@ -42,13 +42,13 @@
|
||||
),)
|
||||
}
|
||||
|
||||
#let _evt(participant, event) = {
|
||||
#let _evt(participant, event, lifeline-style: auto) = {
|
||||
return ((
|
||||
type: "evt",
|
||||
draw: evt-render,
|
||||
participant: participant,
|
||||
event: event,
|
||||
lifeline-style: auto
|
||||
lifeline-style: lifeline-style
|
||||
),)
|
||||
}
|
||||
|
||||
|
||||
@@ -5,9 +5,9 @@
|
||||
p2,
|
||||
comment: none,
|
||||
comment-align: "left",
|
||||
dashed: false,
|
||||
dashed: none,
|
||||
start-tip: "",
|
||||
end-tip: ">",
|
||||
end-tip: none,
|
||||
color: black,
|
||||
flip: false,
|
||||
enable-dst: false,
|
||||
@@ -17,8 +17,23 @@
|
||||
disable-src: false,
|
||||
destroy-src: false,
|
||||
lifeline-style: auto,
|
||||
slant: none
|
||||
slant: none,
|
||||
outer-lifeline-connect: false
|
||||
) = {
|
||||
dashed = if dashed == none {
|
||||
create-dst
|
||||
} else {
|
||||
dashed
|
||||
}
|
||||
end-tip = if end-tip == none {
|
||||
if create-dst {
|
||||
">>"
|
||||
} else {
|
||||
">"
|
||||
}
|
||||
} else {
|
||||
end-tip
|
||||
}
|
||||
return ((
|
||||
type: "seq",
|
||||
draw: sequence.render,
|
||||
@@ -39,13 +54,15 @@
|
||||
destroy-src: destroy-src,
|
||||
lifeline-style: lifeline-style,
|
||||
slant: slant,
|
||||
outer-lifeline-connect: outer-lifeline-connect,
|
||||
linked-notes: ()
|
||||
),)
|
||||
}
|
||||
|
||||
#let _ret(comment: none) = {
|
||||
#let _ret(comment: none, end-tip: ">") = {
|
||||
return ((
|
||||
type: "ret",
|
||||
comment: comment
|
||||
comment: comment,
|
||||
end-tip: end-tip
|
||||
),)
|
||||
}
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
# generated by tytanic, do not edit
|
||||
|
||||
diff/**
|
||||
out/**
|
||||
|
After Width: | Height: | Size: 8.3 KiB |
|
After Width: | Height: | Size: 8.2 KiB |
@@ -0,0 +1,32 @@
|
||||
#set page(width: auto, height: auto)
|
||||
#import "/src/lib.typ": *
|
||||
|
||||
#diagram({
|
||||
_par("a", display-name: "Alice")
|
||||
_par("b", display-name: "Bob")
|
||||
|
||||
// Left to right
|
||||
_seq("a", "b", create-dst: true)
|
||||
_seq("a", "b", enable-dst: true)
|
||||
_seq("a", "b", enable-dst: true)
|
||||
_gap()
|
||||
_seq("a", "b", destroy-dst: true)
|
||||
_gap()
|
||||
_seq("a", "b", destroy-dst: true)
|
||||
})
|
||||
|
||||
#pagebreak()
|
||||
|
||||
#diagram({
|
||||
_par("a", display-name: "Alice")
|
||||
_par("b", display-name: "Bob")
|
||||
|
||||
// Right to left
|
||||
_seq("b", "a", create-dst: true)
|
||||
_seq("b", "a", enable-dst: true)
|
||||
_seq("b", "a", enable-dst: true)
|
||||
_gap()
|
||||
_seq("b", "a", destroy-dst: true)
|
||||
_gap()
|
||||
_seq("b", "a", destroy-dst: true)
|
||||
})
|
||||
@@ -0,0 +1,4 @@
|
||||
# generated by tytanic, do not edit
|
||||
|
||||
diff/**
|
||||
out/**
|
||||
|
After Width: | Height: | Size: 7.2 KiB |
|
After Width: | Height: | Size: 7.2 KiB |
|
After Width: | Height: | Size: 9.2 KiB |
|
After Width: | Height: | Size: 9.5 KiB |
|
After Width: | Height: | Size: 7.7 KiB |
|
After Width: | Height: | Size: 7.6 KiB |
@@ -0,0 +1,110 @@
|
||||
#set page(width: auto, height: auto)
|
||||
#import "/src/lib.typ": *
|
||||
|
||||
#diagram({
|
||||
_par("a", display-name: "Alice")
|
||||
_par("b", display-name: "Bob")
|
||||
|
||||
// Left to right
|
||||
_seq("a", "b")
|
||||
_seq("a", "b", enable-dst: true)
|
||||
_seq("a", "b")
|
||||
_seq("a", "b", enable-dst: true)
|
||||
_seq("a", "b")
|
||||
_seq("a", "b", disable-dst: true)
|
||||
_seq("a", "b")
|
||||
_seq("a", "b", disable-dst: true)
|
||||
_seq("a", "b")
|
||||
})
|
||||
|
||||
#pagebreak()
|
||||
|
||||
#diagram({
|
||||
_par("a", display-name: "Alice")
|
||||
_par("b", display-name: "Bob")
|
||||
|
||||
// Right to left
|
||||
_seq("b", "a")
|
||||
_seq("b", "a", enable-dst: true)
|
||||
_seq("b", "a")
|
||||
_seq("b", "a", enable-dst: true)
|
||||
_seq("b", "a")
|
||||
_seq("b", "a", disable-dst: true)
|
||||
_seq("b", "a")
|
||||
_seq("b", "a", disable-dst: true)
|
||||
_seq("b", "a")
|
||||
})
|
||||
|
||||
#pagebreak()
|
||||
|
||||
#diagram({
|
||||
_par("a", display-name: "Alice")
|
||||
_par("b", display-name: "Bob")
|
||||
|
||||
// Self right
|
||||
_seq("a", "a")
|
||||
_seq("a", "a", enable-dst: true)
|
||||
_seq("a", "a")
|
||||
_seq("a", "a", enable-dst: true)
|
||||
_seq("a", "a")
|
||||
_seq("a", "a", disable-dst: true)
|
||||
_seq("a", "a")
|
||||
_seq("a", "a", disable-dst: true)
|
||||
_seq("a", "a")
|
||||
})
|
||||
|
||||
#pagebreak()
|
||||
|
||||
#diagram({
|
||||
_par("a", display-name: "Alice")
|
||||
_par("b", display-name: "Bob")
|
||||
|
||||
let _seq = _seq.with(flip: true)
|
||||
|
||||
// Self left
|
||||
_seq("b", "b")
|
||||
_seq("b", "b", enable-dst: true)
|
||||
_seq("b", "b")
|
||||
_seq("b", "b", enable-dst: true)
|
||||
_seq("b", "b")
|
||||
_seq("b", "b", disable-dst: true)
|
||||
_seq("b", "b")
|
||||
_seq("b", "b", disable-dst: true)
|
||||
_seq("b", "b")
|
||||
})
|
||||
|
||||
#pagebreak()
|
||||
|
||||
#diagram({
|
||||
_par("a", display-name: "Alice")
|
||||
_par("b", display-name: "Bob")
|
||||
|
||||
// Disable src (rtl)
|
||||
_seq("a", "b")
|
||||
_seq("a", "b", enable-dst: true)
|
||||
_seq("a", "b")
|
||||
_seq("a", "b", enable-dst: true)
|
||||
_seq("a", "b")
|
||||
_seq("b", "a", disable-src: true)
|
||||
_seq("a", "b")
|
||||
_seq("b", "a", disable-src: true)
|
||||
_seq("a", "b")
|
||||
})
|
||||
|
||||
#pagebreak()
|
||||
|
||||
#diagram({
|
||||
_par("a", display-name: "Alice")
|
||||
_par("b", display-name: "Bob")
|
||||
|
||||
// Disable src (ltr)
|
||||
_seq("b", "a")
|
||||
_seq("b", "a", enable-dst: true)
|
||||
_seq("b", "a")
|
||||
_seq("b", "a", enable-dst: true)
|
||||
_seq("b", "a")
|
||||
_seq("a", "b", disable-src: true)
|
||||
_seq("b", "a")
|
||||
_seq("a", "b", disable-src: true)
|
||||
_seq("b", "a")
|
||||
})
|
||||
@@ -0,0 +1,4 @@
|
||||
# generated by tytanic, do not edit
|
||||
|
||||
diff/**
|
||||
out/**
|
||||
|
After Width: | Height: | Size: 7.5 KiB |
|
After Width: | Height: | Size: 10 KiB |
|
After Width: | Height: | Size: 8.9 KiB |
@@ -0,0 +1,75 @@
|
||||
#set page(width: auto, height: auto)
|
||||
#import "/src/lib.typ": *
|
||||
|
||||
#diagram({
|
||||
_par("a", display-name: "Alice")
|
||||
_par("b", display-name: "Bob")
|
||||
|
||||
_evt("a", "enable")
|
||||
_gap()
|
||||
_seq("a", "b")
|
||||
_evt("a", "disable")
|
||||
_gap()
|
||||
_evt("a", "enable")
|
||||
_evt("b", "enable")
|
||||
_seq("a", "b")
|
||||
_evt("a", "enable")
|
||||
_evt("b", "enable")
|
||||
_gap()
|
||||
_seq("a", "b")
|
||||
_evt("a", "disable")
|
||||
_evt("b", "disable")
|
||||
_gap()
|
||||
_evt("a", "disable")
|
||||
_evt("b", "disable")
|
||||
})
|
||||
|
||||
#pagebreak()
|
||||
|
||||
#diagram({
|
||||
_par("a", display-name: "Alice")
|
||||
_par("b", display-name: "Bob")
|
||||
_par("c", display-name: "Charlie")
|
||||
|
||||
_seq("a", "b")
|
||||
_gap()
|
||||
_seq("a", "b", enable-dst: true)
|
||||
_evt("c", "create")
|
||||
_seq("c", "a")
|
||||
_evt("b", "destroy")
|
||||
})
|
||||
|
||||
#pagebreak()
|
||||
|
||||
#diagram({
|
||||
_par("a", display-name: "Alice")
|
||||
_par("b", display-name: "Bob")
|
||||
|
||||
_seq("a", "b")
|
||||
_evt("b", "enable")
|
||||
_seq("a", "b")
|
||||
_evt("b", "enable", lifeline-style: (fill: red))
|
||||
_gap()
|
||||
_seq("b", "a")
|
||||
_evt("b", "disable")
|
||||
_seq("a", "b")
|
||||
_evt("b", "enable", lifeline-style: (
|
||||
stroke: (
|
||||
paint: green,
|
||||
dash: "dashed",
|
||||
thickness: 2pt
|
||||
)
|
||||
))
|
||||
_gap()
|
||||
_seq("b", "a")
|
||||
_evt("b", "disable")
|
||||
_seq("b", "a")
|
||||
_evt("b", "disable")
|
||||
_seq("a", "b")
|
||||
_evt("b", "enable", lifeline-style: (
|
||||
radius: 4pt
|
||||
))
|
||||
_gap()
|
||||
_seq("b", "a")
|
||||
_evt("b", "disable")
|
||||
})
|
||||
@@ -0,0 +1,4 @@
|
||||
# generated by tytanic, do not edit
|
||||
|
||||
diff/**
|
||||
out/**
|
||||
|
After Width: | Height: | Size: 9.0 KiB |
@@ -0,0 +1,27 @@
|
||||
#set page(width: auto, height: auto)
|
||||
#import "/src/lib.typ": *
|
||||
|
||||
#diagram({
|
||||
_par("a", display-name: "Alice")
|
||||
_par("b", display-name: "Bob")
|
||||
|
||||
_seq("a", "b", enable-dst: true)
|
||||
_seq("a", "b", enable-dst: true, lifeline-style: (fill: red))
|
||||
_gap()
|
||||
_seq("b", "a", disable-src: true)
|
||||
_seq("a", "b", enable-dst: true, lifeline-style: (
|
||||
stroke: (
|
||||
paint: green,
|
||||
dash: "dashed",
|
||||
thickness: 2pt
|
||||
)
|
||||
))
|
||||
_gap()
|
||||
_seq("b", "a", disable-src: true)
|
||||
_seq("b", "a", disable-src: true)
|
||||
_seq("a", "b", enable-dst: true, lifeline-style: (
|
||||
radius: 4pt
|
||||
))
|
||||
_gap()
|
||||
_seq("b", "a", disable-src: true)
|
||||
})
|
||||
|
Before Width: | Height: | Size: 33 KiB After Width: | Height: | Size: 33 KiB |
|
Before Width: | Height: | Size: 23 KiB After Width: | Height: | Size: 23 KiB |
|
Before Width: | Height: | Size: 25 KiB After Width: | Height: | Size: 26 KiB |
|
Before Width: | Height: | Size: 50 KiB After Width: | Height: | Size: 51 KiB |
@@ -0,0 +1,4 @@
|
||||
# generated by tytanic, do not edit
|
||||
|
||||
diff/**
|
||||
out/**
|
||||
|
After Width: | Height: | Size: 7.4 KiB |
|
After Width: | Height: | Size: 7.4 KiB |
@@ -0,0 +1,29 @@
|
||||
#set page(width: auto, height: auto)
|
||||
#import "/src/lib.typ": *
|
||||
|
||||
#let make-diagram(_seq) = {
|
||||
diagram({
|
||||
_par("a")
|
||||
_par("b")
|
||||
_par("c")
|
||||
_seq("a", "b")
|
||||
_seq("c", "b")
|
||||
_seq("a", "b", enable-dst: true)
|
||||
_seq("a", "b")
|
||||
_seq("c", "b")
|
||||
_seq("a", "b", enable-dst: true)
|
||||
_seq("a", "b")
|
||||
_seq("c", "b")
|
||||
_seq("a", "b", enable-dst: true)
|
||||
_seq("a", "b")
|
||||
_seq("c", "b")
|
||||
|
||||
_evt("b", "disable")
|
||||
_evt("b", "disable")
|
||||
_evt("b", "disable")
|
||||
})
|
||||
}
|
||||
|
||||
#make-diagram(_seq)
|
||||
#pagebreak()
|
||||
#make-diagram(_seq.with(outer-lifeline-connect: true))
|
||||
|
Before Width: | Height: | Size: 29 KiB After Width: | Height: | Size: 29 KiB |
@@ -0,0 +1,4 @@
|
||||
# generated by tytanic, do not edit
|
||||
|
||||
diff/**
|
||||
out/**
|
||||
|
After Width: | Height: | Size: 15 KiB |
|
After Width: | Height: | Size: 8.4 KiB |
@@ -0,0 +1,47 @@
|
||||
#set page(width: auto, height: auto)
|
||||
#import "/src/lib.typ": *
|
||||
|
||||
#diagram({
|
||||
_par("a")
|
||||
_par("b")
|
||||
_par("c")
|
||||
_sync({
|
||||
_seq("b", "a")
|
||||
_seq("b", "c")
|
||||
})
|
||||
_gap()
|
||||
_sync({
|
||||
_seq("b", "a", comment: [Comment])
|
||||
_seq("b", "c")
|
||||
})
|
||||
_gap()
|
||||
_sync({
|
||||
_seq("b", "a")
|
||||
_seq("b", "c", comment: [Comment])
|
||||
})
|
||||
_gap()
|
||||
_sync({
|
||||
_seq("b", "a", comment: [Two\ lines])
|
||||
_seq("b", "c", comment: [Comment])
|
||||
})
|
||||
|
||||
_sync({
|
||||
_seq("b", "a")
|
||||
_seq("b", "c", slant: 10)
|
||||
})
|
||||
|
||||
_sync({
|
||||
_seq("b", "a")
|
||||
_seq("b", "b")
|
||||
})
|
||||
})
|
||||
|
||||
#pagebreak()
|
||||
|
||||
#diagram({
|
||||
_sync({
|
||||
_seq("a", "b", comment: [Abcdefgh])
|
||||
_seq("b", "c", comment: [Foo\ bar], slant: 10)
|
||||
_seq("c", "c", slant: 20)
|
||||
})
|
||||
})
|
||||
@@ -0,0 +1,4 @@
|
||||
# generated by tytanic, do not edit
|
||||
|
||||
diff/**
|
||||
out/**
|
||||
|
After Width: | Height: | Size: 12 KiB |
|
After Width: | Height: | Size: 11 KiB |
|
After Width: | Height: | Size: 17 KiB |
|
After Width: | Height: | Size: 8.3 KiB |
|
After Width: | Height: | Size: 8.3 KiB |
@@ -0,0 +1,71 @@
|
||||
#set page(width: auto, height: auto)
|
||||
#import "/src/lib.typ": *
|
||||
|
||||
#let preamble = {
|
||||
_par("a", display-name: [Alice])
|
||||
_par("b", display-name: [Bob])
|
||||
_col("a", "b", width: 2cm)
|
||||
}
|
||||
|
||||
#diagram({
|
||||
preamble
|
||||
_grp("Group 1", {
|
||||
_seq("a", "b")
|
||||
})
|
||||
_grp("Group 2", desc: [Description], {
|
||||
_seq("a", "b")
|
||||
})
|
||||
})
|
||||
|
||||
#pagebreak()
|
||||
|
||||
#diagram({
|
||||
preamble
|
||||
_alt(
|
||||
"case 1", {
|
||||
_seq("a", "b")
|
||||
},
|
||||
"case 2", {
|
||||
_seq("a", "b")
|
||||
},
|
||||
"case 3", {
|
||||
_seq("a", "b")
|
||||
}
|
||||
)
|
||||
})
|
||||
|
||||
#pagebreak()
|
||||
|
||||
#diagram({
|
||||
preamble
|
||||
_loop("loop 1", {
|
||||
_seq("a", "b")
|
||||
})
|
||||
_loop("loop 2", min: 1, {
|
||||
_seq("a", "b")
|
||||
})
|
||||
_loop("loop 3", max: 10, {
|
||||
_seq("a", "b")
|
||||
})
|
||||
_loop("loop 3", min: 1, max: 10, {
|
||||
_seq("a", "b")
|
||||
})
|
||||
})
|
||||
|
||||
#pagebreak()
|
||||
|
||||
#diagram({
|
||||
preamble
|
||||
_opt("Optional", {
|
||||
_seq("a", "b")
|
||||
})
|
||||
})
|
||||
|
||||
#pagebreak()
|
||||
|
||||
#diagram({
|
||||
preamble
|
||||
_break("Break", {
|
||||
_seq("a", "b")
|
||||
})
|
||||
})
|
||||
@@ -1,7 +1,7 @@
|
||||
[package]
|
||||
name = "chronos"
|
||||
version = "0.2.2"
|
||||
compiler = "0.13.1"
|
||||
version = "0.3.0"
|
||||
compiler = "0.14.2"
|
||||
repository = "https://git.kb28.ch/HEL/chronos"
|
||||
entrypoint = "src/lib.typ"
|
||||
authors = [
|
||||
|
||||