Compare commits

...

2 Commits

10 changed files with 178 additions and 13 deletions

View File

@ -63,6 +63,45 @@ _grp("Group 1", desc: "Description", {
})
```)
#let alt = example(```
_par("a", display-name: "Alice")
_par("b", display-name: "Bob")
_alt(
"first encounter", {
_seq("a", "b", comment: "Who are you ?")
_seq("b", "a", comment: "I'm Bob")
},
"know eachother", {
_seq("a", "b", comment: "Hello Bob")
_seq("b", "a", comment: "Hello Alice")
},
"best friends", {
_seq("a", "b", comment: "Hi !")
_seq("b", "a", comment: "Hi !")
}
)
```)
#let loop = example(```
_par("a", display-name: "Alice")
_par("b", display-name: "Bob")
_loop("default loop", {
_seq("a", "b", comment: "Are you here ?")
})
_gap()
_loop("min loop", min: 1, {
_seq("a", "b", comment: "Are you here ?")
})
_gap()
_loop("min-max loop", min: 1, max: 5, {
_seq("a", "b", comment: "Are you still here ?")
})
```)
#let sync = example(```
_par("alice", display-name: "Alice")
_par("bob", display-name: "Bob")

View File

@ -2,7 +2,7 @@
/// #examples.grp
/// - name (content): The group's name
/// - desc (none, content): Optional description
/// - type (str): The groups's type (unused for the moment)
/// - type (str): The groups's type (should only be set through other functions like @@_alt() or @@_loop() )
/// - elmts (array): Elements inside the group (can be sequences, other groups, notes, etc.)
#let _grp(
name,
@ -11,9 +11,48 @@
elmts
) = {}
/// Synchronizes multiple sequences
/// Creates an alt-else group of sequences
///
/// It contains at least one section but can have as many as needed
/// #examples.alt
/// - desc (content): The alt's label
/// - elmts (array): Elements inside the alt's first section
/// - ..args (content, array): Complementary "else" sections.\ You can add as many else sections as you need by passing a content (else section label) followed by an array of elements (see example)
#let _alt(
desc,
elmts,
..args
)
/// Creates a looped group of sequences
/// #examples.loop
/// - desc (content): Loop description
/// - min (none, number): Optional lower bound of the loop
/// - max (auto, number): Upper bound of the loop. If left as `auto` and `min` is set, it will be infinity (`'*'`)
/// - elmts (array): Elements inside the group
#let _loop(
desc,
min: none,
max: auto,
elmts
) = {}
/// Synchronizes multiple sequences\
/// All elements inside a synchronized group will start at the same time
/// #examples.sync
/// - elmts (array): Synchronized elements (generally sequences or notes)
#let _sync(
elmts
)
/// Creates an optional group\
/// This is a simple wrapper around @@_grp()
/// - desc (content): Group description
/// - elmts (array): Elements inside the group
#let _opt(desc, elmts) = {}
/// Creates a break group\
/// This is a simple wrapper around @@_grp()
/// - desc (content): Group description
/// - elmts (array): Elements inside the group
#let _break(desc, elmts) = {}

Binary file not shown.

View File

@ -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({

Binary file not shown.

View File

@ -183,7 +183,7 @@ chronos.diagram({
examples: examples
)
)
#tidy.show-module(grp-docs, show-outline: false)
#tidy.show-module(grp-docs, show-outline: false, sort-functions: none)
#pagebreak(weak: true)

View File

@ -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)

View File

@ -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")
@ -52,3 +82,18 @@
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
}

View File

@ -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

View File

@ -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