Compare commits
	
		
			12 Commits
		
	
	
		
			v0.1.0
			...
			feat/parse
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| f369fc6e43 | |||
| 0bfe68b429 | |||
| eb09a23fc1 | |||
| c4f09a0a3e | |||
| 9275169e8c | |||
| a198708743 | |||
| b66634d44f | |||
| 3bc103b9d7 | |||
| feff030510 | |||
| 56cc1b11c0 | |||
| 647d50e125 | |||
| 522cd1537a | 
							
								
								
									
										3
									
								
								TODO.md
									
									
									
									
									
								
							
							
						
						
									
										3
									
								
								TODO.md
									
									
									
									
									
								
							| @@ -22,6 +22,7 @@ | |||||||
| - [ ] Add args verification to catch user errors + pretty error messages | - [ ] Add args verification to catch user errors + pretty error messages | ||||||
| - [ ] PlantUML parser | - [ ] PlantUML parser | ||||||
| - [ ] (Message numbering) | - [ ] (Message numbering) | ||||||
| - [ ] Different types of groups (alt/loop/etc.) | - [ ] Mainframes | ||||||
|  | - [x] Different types of groups (alt/loop/etc.) | ||||||
| - [ ] Delays | - [ ] Delays | ||||||
| - [ ] Auto-fit in parent | - [ ] Auto-fit in parent | ||||||
							
								
								
									
										39
									
								
								docs/example.typ
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										39
									
								
								docs/example.typ
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,39 @@ | |||||||
|  | #import "../src/lib.typ" as chronos | ||||||
|  |  | ||||||
|  | #let example-preamble = "import \"../src/lib.typ\": *;" | ||||||
|  | #let example-scope = ( | ||||||
|  |   chronos: chronos | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | #let example(src, show-src: true, vertical: false, fill: true, wrap: true) = { | ||||||
|  |   src = src.text | ||||||
|  |   let full-src = example-preamble + src | ||||||
|  |   let body = eval(full-src, scope: example-scope) | ||||||
|  |   let img = if wrap { chronos.diagram(body) } else { body } | ||||||
|  |  | ||||||
|  |   block(width: 100%, | ||||||
|  |     align(center, | ||||||
|  |       box( | ||||||
|  |         stroke: black + 1pt, | ||||||
|  |         radius: .5em, | ||||||
|  |         fill: if fill {color.white.darken(5%)} else {none}, | ||||||
|  |         if show-src { | ||||||
|  |           let src-block = align(left, raw(src, lang: "typc")) | ||||||
|  |           table( | ||||||
|  |             columns: if vertical {1} else {2}, | ||||||
|  |             inset: 1em, | ||||||
|  |             align: horizon + center, | ||||||
|  |             stroke: none, | ||||||
|  |             img, | ||||||
|  |             if vertical {table.hline()} else {table.vline()}, src-block | ||||||
|  |           ) | ||||||
|  |         } else { | ||||||
|  |           table( | ||||||
|  |             inset: 1em, | ||||||
|  |             img | ||||||
|  |           ) | ||||||
|  |         } | ||||||
|  |       ) | ||||||
|  |     ) | ||||||
|  |   ) | ||||||
|  | } | ||||||
							
								
								
									
										155
									
								
								docs/examples.typ
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										155
									
								
								docs/examples.typ
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,155 @@ | |||||||
|  | #import "example.typ": example | ||||||
|  |  | ||||||
|  | #let seq-comm-align = example(``` | ||||||
|  | _par("p1", display-name: "Start participant") | ||||||
|  | _par("p2", display-name: "End participant") | ||||||
|  | let alignments = ( | ||||||
|  |   "start", "end", | ||||||
|  |   "left", "right", | ||||||
|  |   "center" | ||||||
|  | ) | ||||||
|  | for a in alignments { | ||||||
|  |   _seq( | ||||||
|  |     "p2", "p1", | ||||||
|  |     comment: raw(a), | ||||||
|  |     comment-align: a | ||||||
|  |   ) | ||||||
|  | } | ||||||
|  | ```) | ||||||
|  |  | ||||||
|  | #let seq-tips = example(``` | ||||||
|  | let _seq = _seq.with(comment-align: "center") | ||||||
|  | _par("a", display-name: "Alice") | ||||||
|  | _par("b", display-name: "Bob") | ||||||
|  |  | ||||||
|  | _seq("a", "b", comment: "Various tips", end-tip: "") | ||||||
|  | _seq("a", "b", end-tip: ">", comment: `->`) | ||||||
|  | _seq("a", "b", end-tip: ">>", comment: `->>`) | ||||||
|  | _seq("a", "b", end-tip: "\\", comment: `-\`) | ||||||
|  | _seq("a", "b", end-tip: "\\\\", comment: `-\\`) | ||||||
|  | _seq("a", "b", end-tip: "/", comment: `-/`) | ||||||
|  | _seq("a", "b", end-tip: "//", comment: `-//`) | ||||||
|  | _seq("a", "b", end-tip: "x", comment: `->x`) | ||||||
|  | _seq("a", "b", start-tip: "x", comment: `x->`) | ||||||
|  | _seq("a", "b", start-tip: "o", comment: `o->`) | ||||||
|  | _seq("a", "b", end-tip: ("o", ">"), comment: `->o`) | ||||||
|  | _seq("a", "b", start-tip: "o", | ||||||
|  |                end-tip: ("o", ">"), comment: `o->o`) | ||||||
|  | _seq("a", "b", start-tip: ">", | ||||||
|  |                end-tip: ">", comment: `<->`) | ||||||
|  | _seq("a", "b", start-tip: ("o", ">"), | ||||||
|  |                end-tip: ("o", ">"), comment: `o<->o`) | ||||||
|  | _seq("a", "b", start-tip: "x", | ||||||
|  |                end-tip: "x", comment: `x<->x`) | ||||||
|  | _seq("a", "b", end-tip: ("o", ">>"), comment: `->>o`) | ||||||
|  | _seq("a", "b", end-tip: ("o", "\\"), comment: `-\o`) | ||||||
|  | _seq("a", "b", end-tip: ("o", "\\\\"), comment: `-\\o`) | ||||||
|  | _seq("a", "b", end-tip: ("o", "/"), comment: `-/o`) | ||||||
|  | _seq("a", "b", end-tip: ("o", "//"), comment: `-//o`) | ||||||
|  | _seq("a", "b", start-tip: "x", | ||||||
|  |                end-tip: ("o", ">"), comment: `x->o`) | ||||||
|  | ```) | ||||||
|  |  | ||||||
|  | #let grp = example(``` | ||||||
|  | _par("a", display-name: "Alice") | ||||||
|  | _par("b", display-name: "Bob") | ||||||
|  |  | ||||||
|  | _grp("Group 1", desc: "Description", { | ||||||
|  |   _seq("a", "b", comment: "Authentication") | ||||||
|  |   _grp("loop", desc: "1000 times", { | ||||||
|  |     _seq("a", "b", comment: "DoS Attack") | ||||||
|  |   }) | ||||||
|  |   _seq("a", "b", end-tip: "x") | ||||||
|  | }) | ||||||
|  | ```) | ||||||
|  |  | ||||||
|  | #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") | ||||||
|  | _par("craig", display-name: "Craig") | ||||||
|  |  | ||||||
|  | _seq("bob", "alice")  // Unsynchronized | ||||||
|  | _seq("bob", "craig")  //  " | ||||||
|  | _sync({ | ||||||
|  |   _seq("bob", "alice")  // Synchronized | ||||||
|  |   _seq("bob", "craig")  //  " | ||||||
|  | }) | ||||||
|  | _seq("alice", "bob")  // Unsynchronized | ||||||
|  | _seq("craig", "bob")  //  " | ||||||
|  | _sync({ | ||||||
|  |   _seq("alice", "bob")  // Synchronized | ||||||
|  |   _seq("craig", "bob")  //  " | ||||||
|  | }) | ||||||
|  | ```) | ||||||
|  |  | ||||||
|  | #let gaps-seps = example(``` | ||||||
|  | _par("alice", display-name: "Alice") | ||||||
|  | _par("bob", display-name: "Bob") | ||||||
|  |  | ||||||
|  | _seq("alice", "bob", comment: "Hello") | ||||||
|  | _gap(size: 10) | ||||||
|  | _seq("bob", "alice", comment: "Hi") | ||||||
|  | _sep("Another day") | ||||||
|  | _seq("alice", "bob", comment: "Hello again") | ||||||
|  | ```) | ||||||
|  |  | ||||||
|  | #let notes-shapes = example(``` | ||||||
|  | _par("alice", display-name: "Alice") | ||||||
|  | _par("bob", display-name: "Bob") | ||||||
|  | _note("over", `default`, pos: "alice") | ||||||
|  | _note("over", `rect`, pos: "bob", shape: "rect") | ||||||
|  | _note("over", `hex`, pos: ("alice", "bob"), shape: "hex") | ||||||
|  | ```) | ||||||
|  |  | ||||||
|  | #let notes-sides = example(``` | ||||||
|  | _par("alice", display-name: "Alice") | ||||||
|  | _par("bob", display-name: "Bob") | ||||||
|  | _par("charlie", display-name: "Charlie") | ||||||
|  | _note("left", [`left` of Alice], pos: "alice") | ||||||
|  | _note("right", [`right` of Charlie], pos: "charlie") | ||||||
|  | _note("over", [`over` Alice and Bob], pos: ("alice", "bob")) | ||||||
|  | _note("across", [`across` all participants]) | ||||||
|  | _seq("alice", "bob") | ||||||
|  | _note("left", [linked with sequence]) | ||||||
|  | _note("over", [A note], pos: "alice") | ||||||
|  | _note("over", [Aligned note], pos: "charlie", aligned: true) | ||||||
|  | ```, vertical: true) | ||||||
							
								
								
									
										8
									
								
								docs/gaps_seps.typ
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										8
									
								
								docs/gaps_seps.typ
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,8 @@ | |||||||
|  | /// Creates a gap before the next element | ||||||
|  | /// - size (int): Size of the gap | ||||||
|  | #let _gap(size: 20) = {} | ||||||
|  |  | ||||||
|  | /// Creates a separator before the next element | ||||||
|  | /// #examples.gaps-seps | ||||||
|  | /// - name (content): Name to display in the middle of the separator | ||||||
|  | #let _sep(name) = {} | ||||||
							
								
								
									
										58
									
								
								docs/groups.typ
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										58
									
								
								docs/groups.typ
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,58 @@ | |||||||
|  | /// Creates a group of sequences | ||||||
|  | /// #examples.grp | ||||||
|  | /// - name (content): The group's name | ||||||
|  | /// - desc (none, content): Optional description | ||||||
|  | /// - 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, | ||||||
|  |   desc: none, | ||||||
|  |   type: "default", | ||||||
|  |   elmts | ||||||
|  | ) = {} | ||||||
|  |  | ||||||
|  | /// 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) = {} | ||||||
							
								
								
									
										23
									
								
								docs/notes.typ
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										23
									
								
								docs/notes.typ
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,23 @@ | |||||||
|  | /// Creates a note | ||||||
|  | /// - side (str): The side on which to place the note (see @@SIDES for accepted values) | ||||||
|  | /// - content (content): The note's content | ||||||
|  | /// - pos (none, str, array): Optional participant(s) on which to draw next to / over. If `side` is "left" or "right", sets next to which participant the note is placed. If `side` is "over", sets over which participant(s) it is placed | ||||||
|  | /// - color (color): The note's color | ||||||
|  | /// - shape (str): The note's shape (see @@SHAPES for accepted values) | ||||||
|  | /// - aligned (bool): True if the note is aligned with another note, in which case `side` must be `"over"`, false otherwise | ||||||
|  | #let _note( | ||||||
|  |   side, | ||||||
|  |   content, | ||||||
|  |   pos: none, | ||||||
|  |   color: rgb("#FEFFDD"), | ||||||
|  |   shape: "default", | ||||||
|  |   aligned: false | ||||||
|  | ) = {} | ||||||
|  |  | ||||||
|  | /// Accepted values for `shape` argument of @@_note() | ||||||
|  | /// #examples.notes-shapes | ||||||
|  | #let SHAPES = ("default", "rect", "hex") | ||||||
|  |  | ||||||
|  | /// Accepted values for `side` argument of @@_note() | ||||||
|  | /// #examples.notes-sides | ||||||
|  | #let SIDES = ("left", "right", "over", "across") | ||||||
							
								
								
									
										67
									
								
								docs/participants.typ
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										67
									
								
								docs/participants.typ
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,67 @@ | |||||||
|  | /// Possible participant shapes | ||||||
|  | /// #box(width: 100%, align(center)[ | ||||||
|  | ///   #chronos.diagram({ | ||||||
|  | ///     import chronos: * | ||||||
|  | ///     let _par = _par.with(show-bottom: false) | ||||||
|  | ///     _par("Foo", display-name: "participant", shape: "participant") | ||||||
|  | ///     _par("Foo1", display-name: "actor", shape: "actor") | ||||||
|  | ///     _par("Foo2", display-name: "boundary", shape: "boundary") | ||||||
|  | ///     _par("Foo3", display-name: "control", shape: "control") | ||||||
|  | ///     _par("Foo4", display-name: "entity", shape: "entity") | ||||||
|  | ///     _par("Foo5", display-name: "database", shape: "database") | ||||||
|  | ///     _par("Foo6", display-name: "collections", shape: "collections") | ||||||
|  | ///     _par("Foo7", display-name: "queue", shape: "queue") | ||||||
|  | ///     _par("Foo8", display-name: "custom", shape: "custom", custom-image: TYPST) | ||||||
|  | ///     _gap() | ||||||
|  | ///   }) | ||||||
|  | /// ]) | ||||||
|  | #let SHAPES = ( | ||||||
|  |   "participant", | ||||||
|  |   "actor", | ||||||
|  |   "boundary", | ||||||
|  |   "control", | ||||||
|  |   "entity", | ||||||
|  |   "database", | ||||||
|  |   "collections", | ||||||
|  |   "queue", | ||||||
|  |   "custom" | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | /// Creates a new participant | ||||||
|  | /// - name (str): Unique participant name used as reference in other functions | ||||||
|  | /// - display-name (auto, content): Name to display in the diagram. If set to `auto`, `name` is used | ||||||
|  | /// - from-start (bool): If set to true, the participant is created at the top of the diagram. Otherwise, it is created at the first reference | ||||||
|  | /// - invisible (bool): If set to true, the participant will not be shown | ||||||
|  | /// - shape (str): The shape of the participant. Possible values in @@SHAPES | ||||||
|  | /// - color (color): The participant's color | ||||||
|  | /// - custom-image (none, image): If shape is 'custom', sets the custom image to display | ||||||
|  | /// - show-bottom (bool): Whether to display the bottom shape | ||||||
|  | /// - show-top (bool): Whether to display the top shape | ||||||
|  | /// -> array | ||||||
|  | #let _par( | ||||||
|  |   name, | ||||||
|  |   display-name: auto, | ||||||
|  |   from-start: true, | ||||||
|  |   invisible: false, | ||||||
|  |   shape: "participant", | ||||||
|  |   color: rgb("#E2E2F0"), | ||||||
|  |   custom-image: none, | ||||||
|  |   show-bottom: true, | ||||||
|  |   show-top: true, | ||||||
|  | ) = {} | ||||||
|  |  | ||||||
|  | /// Sets some options for columns between participants | ||||||
|  | /// | ||||||
|  | /// Parameters `p1` and `p2` MUST be consecutive participants (also counting found/lost messages), but they do not need to be in the left to right order | ||||||
|  | /// - p1 (str): The first neighbouring participant | ||||||
|  | /// - p2 (str): The second neighbouring participant | ||||||
|  | /// - width (auto, int, float, length): Optional fixed width of the column\ If the column's content (e.g. sequence comments) is larger, it will overflow | ||||||
|  | /// - margin (int, float, length): Additional margin to add to the column\ This margin is not included in `width` and `min-width`, but rather added separately | ||||||
|  | /// - min-width (int, float, length): Minimum width of the column\ If set to a larger value than `width`, the latter will be overriden | ||||||
|  | #let _col( | ||||||
|  |   p1, | ||||||
|  |   p2, | ||||||
|  |   width: auto, | ||||||
|  |   margin: 0, | ||||||
|  |   min-width: 0 | ||||||
|  | ) = {} | ||||||
							
								
								
									
										60
									
								
								docs/sequences.typ
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										60
									
								
								docs/sequences.typ
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,60 @@ | |||||||
|  | /// 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) = {} | ||||||
|  |  | ||||||
|  | /// Creates a sequence / message between two participants | ||||||
|  | /// - p1 (str): Start participant | ||||||
|  | /// - p2 (str): End participant | ||||||
|  | /// - comment (none, content): Optional comment to display along the arrow | ||||||
|  | /// - comment-align (str): Where to align the comment with respect to the arrow (see @@comment-align for accepted values) | ||||||
|  | /// - dashed (bool): Whether the arrow's stroke is dashed or not | ||||||
|  | /// - start-tip (str): Start arrow tip (see @@tips for accepted values) | ||||||
|  | /// - end-tip (str): End arrow tip (see @@tips for accepted values) | ||||||
|  | /// - color (color): Arrow's color | ||||||
|  | /// - flip (bool): If true, the arrow is flipped (goes from end to start). This is particularly useful for self calls, to change the side on which the arrow appears | ||||||
|  | /// - enable-dst (bool): If true, enables the destination lifeline | ||||||
|  | /// - create-dst (bool): If true, creates the destination lifeline and participant | ||||||
|  | /// - disable-dst (bool): If true, disables the destination lifeline | ||||||
|  | /// - destroy-dst (bool): If true, destroys the destination lifeline and participant | ||||||
|  | /// - disable-src (bool): If true, disables the source lifeline | ||||||
|  | /// - 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 | ||||||
|  | /// -> array | ||||||
|  | #let _seq( | ||||||
|  |   p1, | ||||||
|  |   p2, | ||||||
|  |   comment: none, | ||||||
|  |   comment-align: "left", | ||||||
|  |   dashed: false, | ||||||
|  |   start-tip: "", | ||||||
|  |   end-tip: ">", | ||||||
|  |   color: black, | ||||||
|  |   flip: false, | ||||||
|  |   enable-dst: false, | ||||||
|  |   create-dst: false, | ||||||
|  |   disable-dst: false, | ||||||
|  |   destroy-dst: false, | ||||||
|  |   disable-src: false, | ||||||
|  |   destroy-src: false, | ||||||
|  |   lifeline-style: auto, | ||||||
|  |   slant: none | ||||||
|  | ) = {} | ||||||
|  |  | ||||||
|  | /// Accepted values for `event` argument of @@_evt() | ||||||
|  | ///  | ||||||
|  | /// `EVENTS = ("create", "destroy", "enable", "disable")` | ||||||
|  | #let EVENTS = ("create", "destroy", "enable", "disable") | ||||||
|  |  | ||||||
|  | /// Accepted values for `start-tip` and `end-tip` arguments of @@_seq() | ||||||
|  | /// #examples.seq-tips | ||||||
|  | #let tips = ( | ||||||
|  |   "", ">", ">>", "\\", "\\\\", "/", "//", "x", "o", | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | /// Accepted values for `comment-align` argument of @@_seq() | ||||||
|  | /// #examples.seq-comm-align | ||||||
|  | #let comment-align = ( | ||||||
|  |   "start", "end", "left", "center", "right" | ||||||
|  | ) | ||||||
							
								
								
									
										
											BIN
										
									
								
								gallery/doc_examples.pdf
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								gallery/doc_examples.pdf
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										689
									
								
								gallery/doc_examples.typ
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										689
									
								
								gallery/doc_examples.typ
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,689 @@ | |||||||
|  | #import "../src/lib.typ": from-plantuml | ||||||
|  |  | ||||||
|  | #set page(width: auto, height: auto) | ||||||
|  |  | ||||||
|  | #let examples = ( | ||||||
|  |   ( | ||||||
|  |     [Basic Examples], | ||||||
|  |     ``` | ||||||
|  |     @startuml | ||||||
|  |     Alice -> Bob: Authentication Request | ||||||
|  |     Bob --> Alice: Authentication Response | ||||||
|  |  | ||||||
|  |     Alice -> Bob: Another authentication Request | ||||||
|  |     Alice <-- Bob: Another authentication Response | ||||||
|  |     @enduml | ||||||
|  |     ``` | ||||||
|  |   ), | ||||||
|  |   ( | ||||||
|  |     [Declaring participant], | ||||||
|  |     ``` | ||||||
|  |     @startuml | ||||||
|  |     participant Participant as Foo | ||||||
|  |     actor       Actor       as Foo1 | ||||||
|  |     boundary    Boundary    as Foo2 | ||||||
|  |     control     Control     as Foo3 | ||||||
|  |     entity      Entity      as Foo4 | ||||||
|  |     database    Database    as Foo5 | ||||||
|  |     collections Collections as Foo6 | ||||||
|  |     queue       Queue       as Foo7 | ||||||
|  |     Foo -> Foo1 : To actor  | ||||||
|  |     Foo -> Foo2 : To boundary | ||||||
|  |     Foo -> Foo3 : To control | ||||||
|  |     Foo -> Foo4 : To entity | ||||||
|  |     Foo -> Foo5 : To database | ||||||
|  |     Foo -> Foo6 : To collections | ||||||
|  |     Foo -> Foo7: To queue | ||||||
|  |     @enduml | ||||||
|  |     ``` | ||||||
|  |   ), | ||||||
|  |   ( | ||||||
|  |     [Declaring participant (2)], | ||||||
|  |     ``` | ||||||
|  |     @startuml | ||||||
|  |     actor Bob #red | ||||||
|  |     ' The only difference between actor | ||||||
|  |     'and participant is the drawing | ||||||
|  |     participant Alice | ||||||
|  |     participant "I have a really\nlong name" as L #99FF99 | ||||||
|  |     /' You can also declare: | ||||||
|  |       participant L as "I have a really\nlong name"  #99FF99 | ||||||
|  |       '/ | ||||||
|  |  | ||||||
|  |     Alice->Bob: Authentication Request | ||||||
|  |     Bob->Alice: Authentication Response | ||||||
|  |     Bob->L: Log transaction | ||||||
|  |     @enduml | ||||||
|  |     ``` | ||||||
|  |   ), | ||||||
|  |   ( | ||||||
|  |     [Use non-letters in participants], | ||||||
|  |     ``` | ||||||
|  |     @startuml | ||||||
|  |     Alice -> "Bob()" : Hello | ||||||
|  |     "Bob()" -> "This is very\nlong" as Long | ||||||
|  |     ' You can also declare: | ||||||
|  |     ' "Bob()" -> Long as "This is very\nlong" | ||||||
|  |     Long --> "Bob()" : ok | ||||||
|  |     @enduml | ||||||
|  |     ``` | ||||||
|  |   ), | ||||||
|  |   ( | ||||||
|  |     [Message to Self], | ||||||
|  |     ``` | ||||||
|  |     @startuml | ||||||
|  |     Alice -> Alice: This is a signal to self.\nIt also demonstrates\nmultiline \ntext | ||||||
|  |     @enduml | ||||||
|  |     ``` | ||||||
|  |   ), | ||||||
|  |   ( | ||||||
|  |     [Message to Self (2)], | ||||||
|  |     ``` | ||||||
|  |     @startuml | ||||||
|  |     Alice <- Alice: This is a signal to self.\nIt also demonstrates\nmultiline \ntext | ||||||
|  |     @enduml | ||||||
|  |     ``` | ||||||
|  |   ), | ||||||
|  |   ( | ||||||
|  |     [Change arrow style], | ||||||
|  |     ``` | ||||||
|  |     @startuml | ||||||
|  |     Bob ->x Alice | ||||||
|  |     Bob -> Alice | ||||||
|  |     Bob ->> Alice | ||||||
|  |     Bob -\ Alice | ||||||
|  |     Bob \\- Alice | ||||||
|  |     Bob //-- Alice | ||||||
|  |  | ||||||
|  |     Bob ->o Alice | ||||||
|  |     Bob o\\-- Alice | ||||||
|  |  | ||||||
|  |     Bob <-> Alice | ||||||
|  |     Bob <->o Alice | ||||||
|  |     @enduml | ||||||
|  |     ``` | ||||||
|  |   ), | ||||||
|  |   ( | ||||||
|  |     [Grouping message], | ||||||
|  |     ``` | ||||||
|  |     @startuml | ||||||
|  |     Alice -> Bob: Authentication Request | ||||||
|  |  | ||||||
|  |     alt successful case | ||||||
|  |  | ||||||
|  |         Bob -> Alice: Authentication Accepted | ||||||
|  |  | ||||||
|  |     else some kind of failure | ||||||
|  |  | ||||||
|  |         Bob -> Alice: Authentication Failure | ||||||
|  |         group My own label | ||||||
|  |         Alice -> Log : Log attack start | ||||||
|  |             loop 1000 times | ||||||
|  |                 Alice -> Bob: DNS Attack | ||||||
|  |             end | ||||||
|  |         Alice -> Log : Log attack end | ||||||
|  |         end | ||||||
|  |  | ||||||
|  |     else Another type of failure | ||||||
|  |  | ||||||
|  |       Bob -> Alice: Please repeat | ||||||
|  |  | ||||||
|  |     end | ||||||
|  |     @enduml | ||||||
|  |     ``` | ||||||
|  |   ), | ||||||
|  |   ( | ||||||
|  |     [Secondary group label], | ||||||
|  |     ``` | ||||||
|  |     @startuml | ||||||
|  |     Alice -> Bob: Authentication Request | ||||||
|  |     Bob -> Alice: Authentication Failure | ||||||
|  |     group My own label [My own label 2] | ||||||
|  |         Alice -> Log : Log attack start | ||||||
|  |         loop 1000 times | ||||||
|  |             Alice -> Bob: DNS Attack | ||||||
|  |         end | ||||||
|  |         Alice -> Log : Log attack end | ||||||
|  |     end | ||||||
|  |     @enduml | ||||||
|  |     ``` | ||||||
|  |   ), | ||||||
|  |   ( | ||||||
|  |     [Notes on messages], | ||||||
|  |     ``` | ||||||
|  |     @startuml | ||||||
|  |     Alice->Bob : hello | ||||||
|  |     note left: this is a first note | ||||||
|  |  | ||||||
|  |     Bob->Alice : ok | ||||||
|  |     note right: this is another note | ||||||
|  |  | ||||||
|  |     Bob->Bob : I am thinking | ||||||
|  |     note left | ||||||
|  |     a note | ||||||
|  |     can also be defined | ||||||
|  |     on several lines | ||||||
|  |     end note | ||||||
|  |     @enduml | ||||||
|  |     ``` | ||||||
|  |   ), | ||||||
|  |   ( | ||||||
|  |     [Some other notes], | ||||||
|  |     ``` | ||||||
|  |     @startuml | ||||||
|  |     participant Alice | ||||||
|  |     participant Bob | ||||||
|  |     note left of Alice #aqua | ||||||
|  |     This is displayed | ||||||
|  |     left of Alice. | ||||||
|  |     end note | ||||||
|  |  | ||||||
|  |     note right of Alice: This is displayed right of Alice. | ||||||
|  |  | ||||||
|  |     note over Alice: This is displayed over Alice. | ||||||
|  |  | ||||||
|  |     note over Alice, Bob #FFAAAA: This is displayed\n over Bob and Alice. | ||||||
|  |  | ||||||
|  |     note over Bob, Alice | ||||||
|  |     This is yet another | ||||||
|  |     example of | ||||||
|  |     a long note. | ||||||
|  |     end note | ||||||
|  |     @enduml | ||||||
|  |     ``` | ||||||
|  |   ), | ||||||
|  |   ( | ||||||
|  |     [Changing notes shape \[hnote, rnote\]], | ||||||
|  |     ``` | ||||||
|  |     @startuml | ||||||
|  |     caller -> server : conReq | ||||||
|  |     hnote over caller : idle | ||||||
|  |     caller <- server : conConf | ||||||
|  |     rnote over server | ||||||
|  |      "r" as rectangle | ||||||
|  |      "h" as hexagon | ||||||
|  |     endrnote | ||||||
|  |     rnote over server | ||||||
|  |      this is | ||||||
|  |      on several | ||||||
|  |      lines | ||||||
|  |     endrnote | ||||||
|  |     hnote over caller | ||||||
|  |      this is | ||||||
|  |      on several | ||||||
|  |      lines | ||||||
|  |     endhnote | ||||||
|  |     @enduml | ||||||
|  |     ``` | ||||||
|  |   ), | ||||||
|  |   ( | ||||||
|  |     [Note over all participants \[across\]], | ||||||
|  |     ``` | ||||||
|  |     @startuml | ||||||
|  |     Alice->Bob:m1 | ||||||
|  |     Bob->Charlie:m2 | ||||||
|  |     note over Alice, Charlie: Old method for note over all part. with:\n ""note over //FirstPart, LastPart//"". | ||||||
|  |     note across: New method with:\n""note across"" | ||||||
|  |     Bob->Alice | ||||||
|  |     hnote across:Note across all part. | ||||||
|  |     @enduml | ||||||
|  |     ``` | ||||||
|  |   ), | ||||||
|  |   ( | ||||||
|  |     [Several notes aligned at the same level \[/\]], | ||||||
|  |     ``` | ||||||
|  |     @startuml | ||||||
|  |     note over Alice : initial state of Alice | ||||||
|  |     note over Bob : initial state of Bob | ||||||
|  |     Bob -> Alice : hello | ||||||
|  |     @enduml | ||||||
|  |     ``` | ||||||
|  |   ), | ||||||
|  |   ( | ||||||
|  |     [Several notes aligned at the same level \[/\] (2)], | ||||||
|  |     ``` | ||||||
|  |     @startuml | ||||||
|  |     note over Alice : initial state of Alice | ||||||
|  |     / note over Bob : initial state of Bob | ||||||
|  |     Bob -> Alice : hello | ||||||
|  |     @enduml | ||||||
|  |     ``` | ||||||
|  |   ), | ||||||
|  |   ( | ||||||
|  |     [Divider or separator], | ||||||
|  |     ``` | ||||||
|  |     @startuml | ||||||
|  |  | ||||||
|  |     == Initialization == | ||||||
|  |  | ||||||
|  |     Alice -> Bob: Authentication Request | ||||||
|  |     Bob --> Alice: Authentication Response | ||||||
|  |  | ||||||
|  |     == Repetition == | ||||||
|  |  | ||||||
|  |     Alice -> Bob: Another authentication Request | ||||||
|  |     Alice <-- Bob: another authentication Response | ||||||
|  |  | ||||||
|  |     @enduml | ||||||
|  |     ``` | ||||||
|  |   ), | ||||||
|  |   ( | ||||||
|  |     [Delay], | ||||||
|  |     ``` | ||||||
|  |     @startuml | ||||||
|  |  | ||||||
|  |     Alice -> Bob: Authentication Request | ||||||
|  |     ... | ||||||
|  |     Bob --> Alice: Authentication Response | ||||||
|  |     ...5 minutes later... | ||||||
|  |     Bob --> Alice: Good Bye ! | ||||||
|  |  | ||||||
|  |     @enduml | ||||||
|  |     ``` | ||||||
|  |   ), | ||||||
|  |   ( | ||||||
|  |     [Space], | ||||||
|  |     ``` | ||||||
|  |     @startuml | ||||||
|  |  | ||||||
|  |     Alice -> Bob: message 1 | ||||||
|  |     Bob --> Alice: ok | ||||||
|  |     ||| | ||||||
|  |     Alice -> Bob: message 2 | ||||||
|  |     Bob --> Alice: ok | ||||||
|  |     ||45|| | ||||||
|  |     Alice -> Bob: message 3 | ||||||
|  |     Bob --> Alice: ok | ||||||
|  |  | ||||||
|  |     @enduml | ||||||
|  |     ``` | ||||||
|  |   ), | ||||||
|  |   ( | ||||||
|  |     [Lifeline Activation and Destruction], | ||||||
|  |     ``` | ||||||
|  |     @startuml | ||||||
|  |     participant User | ||||||
|  |  | ||||||
|  |     User -> A: DoWork | ||||||
|  |     activate A | ||||||
|  |  | ||||||
|  |     A -> B: << createRequest >> | ||||||
|  |     activate B | ||||||
|  |  | ||||||
|  |     B -> C: DoWork | ||||||
|  |     activate C | ||||||
|  |     C --> B: WorkDone | ||||||
|  |     destroy C | ||||||
|  |  | ||||||
|  |     B --> A: RequestCreated | ||||||
|  |     deactivate B | ||||||
|  |  | ||||||
|  |     A -> User: Done | ||||||
|  |     deactivate A | ||||||
|  |  | ||||||
|  |     @enduml | ||||||
|  |     ``` | ||||||
|  |   ), | ||||||
|  |   ( | ||||||
|  |     [Lifeline Activation and Destruction (2)], | ||||||
|  |     ``` | ||||||
|  |     @startuml | ||||||
|  |     participant User | ||||||
|  |  | ||||||
|  |     User -> A: DoWork | ||||||
|  |     activate A #FFBBBB | ||||||
|  |  | ||||||
|  |     A -> A: Internal call | ||||||
|  |     activate A #DarkSalmon | ||||||
|  |  | ||||||
|  |     A -> B: << createRequest >> | ||||||
|  |     activate B | ||||||
|  |  | ||||||
|  |     B --> A: RequestCreated | ||||||
|  |     deactivate B | ||||||
|  |     deactivate A | ||||||
|  |     A -> User: Done | ||||||
|  |     deactivate A | ||||||
|  |  | ||||||
|  |     @enduml | ||||||
|  |     ``` | ||||||
|  |   ), | ||||||
|  |   /*( | ||||||
|  |     [Lifeline Activation and Destruction (3)], | ||||||
|  |     ``` | ||||||
|  |     @startuml | ||||||
|  |     'autoactivate on | ||||||
|  |     alice -> bob : hello | ||||||
|  |     bob -> bob : self call | ||||||
|  |     bill -> bob /'#005500'/ : hello from thread 2 | ||||||
|  |     bob -> george ** : create | ||||||
|  |     return done in thread 2 | ||||||
|  |     return rc | ||||||
|  |     bob -> george !! : delete | ||||||
|  |     return success | ||||||
|  |  | ||||||
|  |     @enduml | ||||||
|  |     ``` | ||||||
|  |   ),*/ | ||||||
|  |   ( | ||||||
|  |     [Return], | ||||||
|  |     ``` | ||||||
|  |     @startuml | ||||||
|  |     Bob -> Alice : hello | ||||||
|  |     activate Alice | ||||||
|  |     Alice -> Alice : some action | ||||||
|  |     return bye | ||||||
|  |     @enduml | ||||||
|  |     ``` | ||||||
|  |   ), | ||||||
|  |   ( | ||||||
|  |     [Participant creation], | ||||||
|  |     ``` | ||||||
|  |     @startuml | ||||||
|  |     Bob -> Alice : hello | ||||||
|  |  | ||||||
|  |     create Other | ||||||
|  |     Alice -> Other : new | ||||||
|  |  | ||||||
|  |     create /'control'/ String | ||||||
|  |     Alice -> String | ||||||
|  |     note right : You can also put notes! | ||||||
|  |  | ||||||
|  |     Alice --> Bob : ok | ||||||
|  |  | ||||||
|  |     @enduml | ||||||
|  |     ``` | ||||||
|  |   ), | ||||||
|  |   ( | ||||||
|  |     [Shortcut syntax for activation, deactivation, creation], | ||||||
|  |     ``` | ||||||
|  |     @startuml | ||||||
|  |     alice -> bob ++ : hello | ||||||
|  |     bob -> bob ++ : self call | ||||||
|  |     bob -> bib ++ /' #005500'/ : hello | ||||||
|  |     bob -> george ** : create | ||||||
|  |     return done | ||||||
|  |     return rc | ||||||
|  |     bob -> george !! : delete | ||||||
|  |     return success | ||||||
|  |     @enduml | ||||||
|  |     ``` | ||||||
|  |   ), | ||||||
|  |   ( | ||||||
|  |     [Shortcut syntax for activation, deactivation, creation (2)], | ||||||
|  |     ``` | ||||||
|  |     @startuml | ||||||
|  |     alice   ->  bob     ++   : hello1 | ||||||
|  |     bob     ->  charlie --++ : hello2 | ||||||
|  |     charlie --> alice   --   : ok | ||||||
|  |     @enduml | ||||||
|  |     ``` | ||||||
|  |   ), | ||||||
|  |   ( | ||||||
|  |     [Shortcut syntax for activation, deactivation, creation (3)], | ||||||
|  |     ``` | ||||||
|  |     @startuml | ||||||
|  |     alice -> bob   ++ /'#gold'/: hello | ||||||
|  |     bob   -> alice --++ /'#gold'/: you too | ||||||
|  |     alice -> bob   --: step1 | ||||||
|  |     alice -> bob   : step2 | ||||||
|  |     @enduml | ||||||
|  |     @enduml | ||||||
|  |     ``` | ||||||
|  |   ), | ||||||
|  |   ( | ||||||
|  |     [Incoming and outgoing messages], | ||||||
|  |     ``` | ||||||
|  |     @startuml | ||||||
|  |     [-> A: DoWork | ||||||
|  |  | ||||||
|  |     activate A | ||||||
|  |  | ||||||
|  |     A -> A: Internal call | ||||||
|  |     activate A | ||||||
|  |  | ||||||
|  |     A ->] : << createRequest >> | ||||||
|  |  | ||||||
|  |     A<--] : RequestCreated | ||||||
|  |     deactivate A | ||||||
|  |     [<- A: Done | ||||||
|  |     deactivate A | ||||||
|  |     @enduml | ||||||
|  |     ``` | ||||||
|  |   ), | ||||||
|  |   ( | ||||||
|  |     [Incoming and outgoing messages (2)], | ||||||
|  |     ``` | ||||||
|  |     @startuml | ||||||
|  |     participant Alice | ||||||
|  |     participant Bob #lightblue | ||||||
|  |     Alice -> Bob | ||||||
|  |     Bob -> Carol | ||||||
|  |     ... | ||||||
|  |     [-> Bob | ||||||
|  |     [o-> Bob | ||||||
|  |     [o->o Bob | ||||||
|  |     [x-> Bob | ||||||
|  |     ... | ||||||
|  |     [<- Bob | ||||||
|  |     [x<- Bob | ||||||
|  |     ... | ||||||
|  |     Bob ->] | ||||||
|  |     Bob ->o] | ||||||
|  |     Bob o->o] | ||||||
|  |     Bob ->x] | ||||||
|  |     ... | ||||||
|  |     Bob <-] | ||||||
|  |     Bob x<-] | ||||||
|  |  | ||||||
|  |     @enduml | ||||||
|  |     ``` | ||||||
|  |   ), | ||||||
|  |   ( | ||||||
|  |     [Short arrows for incoming and outgoing messages], | ||||||
|  |     ``` | ||||||
|  |     @startuml | ||||||
|  |     ?-> Alice    : ""?->""\n**short** to actor1 | ||||||
|  |     [-> Alice    : ""[->""\n**from start** to actor1 | ||||||
|  |     [-> Bob      : ""[->""\n**from start** to actor2 | ||||||
|  |     ?-> Bob      : ""?->""\n**short** to actor2 | ||||||
|  |     Alice ->]    : ""->]""\nfrom actor1 **to end** | ||||||
|  |     Alice ->?    : ""->?""\n**short** from actor1 | ||||||
|  |     Alice -> Bob : ""->"" \nfrom actor1 to actor2 | ||||||
|  |     @enduml | ||||||
|  |     ``` | ||||||
|  |   ), | ||||||
|  |   ( | ||||||
|  |     [Normal arrow], | ||||||
|  |     ``` | ||||||
|  |     @startuml | ||||||
|  |     participant Alice as a | ||||||
|  |     participant Bob   as b | ||||||
|  |     a ->     b : ""->   "" | ||||||
|  |     a ->>    b : ""->>  "" | ||||||
|  |     a -\     b : ""-\   "" | ||||||
|  |     a -\\    b : ""-\\\\"" | ||||||
|  |     a -/     b : ""-/   "" | ||||||
|  |     a -//    b : ""-//  "" | ||||||
|  |     a ->x    b : ""->x  "" | ||||||
|  |     a x->    b : ""x->  "" | ||||||
|  |     a o->    b : ""o->  "" | ||||||
|  |     a ->o    b : ""->o  "" | ||||||
|  |     a o->o   b : ""o->o "" | ||||||
|  |     a <->    b : ""<->  "" | ||||||
|  |     a o<->o  b : ""o<->o"" | ||||||
|  |     a x<->x  b : ""x<->x"" | ||||||
|  |     a ->>o   b : ""->>o "" | ||||||
|  |     a -\o    b : ""-\o  "" | ||||||
|  |     a -\\o   b : ""-\\\\o"" | ||||||
|  |     a -/o    b : ""-/o  "" | ||||||
|  |     a -//o   b : ""-//o "" | ||||||
|  |     a x->o   b : ""x->o "" | ||||||
|  |     @enduml | ||||||
|  |     ``` | ||||||
|  |   ), | ||||||
|  |   ( | ||||||
|  |     [Itself arrow], | ||||||
|  |     ``` | ||||||
|  |     @startuml | ||||||
|  |     participant Alice as a | ||||||
|  |     participant Bob   as b | ||||||
|  |     a ->     a : ""->   "" | ||||||
|  |     a ->>    a : ""->>  "" | ||||||
|  |     a -\     a : ""-\   "" | ||||||
|  |     a -\\    a : ""-\\\\"" | ||||||
|  |     a -/     a : ""-/   "" | ||||||
|  |     a -//    a : ""-//  "" | ||||||
|  |     a ->x    a : ""->x  "" | ||||||
|  |     a x->    a : ""x->  "" | ||||||
|  |     a o->    a : ""o->  "" | ||||||
|  |     a ->o    a : ""->o  "" | ||||||
|  |     a o->o   a : ""o->o "" | ||||||
|  |     a <->    a : ""<->  "" | ||||||
|  |     a o<->o  a : ""o<->o"" | ||||||
|  |     a x<->x  a : ""x<->x"" | ||||||
|  |     a ->>o   a : ""->>o "" | ||||||
|  |     a -\o    a : ""-\o  "" | ||||||
|  |     a -\\o   a : ""-\\\\o"" | ||||||
|  |     a -/o    a : ""-/o  "" | ||||||
|  |     a -//o   a : ""-//o "" | ||||||
|  |     a x->o   a : ""x->o "" | ||||||
|  |     @enduml | ||||||
|  |     ``` | ||||||
|  |   ), | ||||||
|  |   ( | ||||||
|  |     [Incoming messages (with '|')], | ||||||
|  |     ``` | ||||||
|  |     @startuml | ||||||
|  |     participant Alice as a | ||||||
|  |     participant Bob   as b | ||||||
|  |     [->      b : ""[->   "" | ||||||
|  |     [->>     b : ""[->>  "" | ||||||
|  |     [-\      b : ""[-\   "" | ||||||
|  |     [-\\     b : ""[-\\\\"" | ||||||
|  |     [-/      b : ""[-/   "" | ||||||
|  |     [-//     b : ""[-//  "" | ||||||
|  |     [->x     b : ""[->x  "" | ||||||
|  |     [x->     b : ""[x->  "" | ||||||
|  |     [o->     b : ""[o->  "" | ||||||
|  |     [->o     b : ""[->o  "" | ||||||
|  |     [o->o    b : ""[o->o "" | ||||||
|  |     [<->     b : ""[<->  "" | ||||||
|  |     [o<->o   b : ""[o<->o"" | ||||||
|  |     [x<->x   b : ""[x<->x"" | ||||||
|  |     [->>o    b : ""[->>o "" | ||||||
|  |     [-\o     b : ""[-\o  "" | ||||||
|  |     [-\\o    b : ""[-\\\\o"" | ||||||
|  |     [-/o     b : ""[-/o  "" | ||||||
|  |     [-//o    b : ""[-//o "" | ||||||
|  |     [x->o    b : ""[x->o "" | ||||||
|  |     @enduml | ||||||
|  |     ``` | ||||||
|  |   ), | ||||||
|  |   ( | ||||||
|  |     [Outgoing messages (with '|')], | ||||||
|  |     ``` | ||||||
|  |     @startuml | ||||||
|  |     participant Alice as a | ||||||
|  |     participant Bob   as b | ||||||
|  |     a ->]      : ""->]   "" | ||||||
|  |     a ->>]     : ""->>]  "" | ||||||
|  |     a -\]      : ""-\]   "" | ||||||
|  |     a -\\]     : ""-\\\\]"" | ||||||
|  |     a -/]      : ""-/]   "" | ||||||
|  |     a -//]     : ""-//]  "" | ||||||
|  |     a ->x]     : ""->x]  "" | ||||||
|  |     a x->]     : ""x->]  "" | ||||||
|  |     a o->]     : ""o->]  "" | ||||||
|  |     a ->o]     : ""->o]  "" | ||||||
|  |     a o->o]    : ""o->o] "" | ||||||
|  |     a <->]     : ""<->]  "" | ||||||
|  |     a o<->o]   : ""o<->o]"" | ||||||
|  |     a x<->x]   : ""x<->x]"" | ||||||
|  |     a ->>o]    : ""->>o] "" | ||||||
|  |     a -\o]     : ""-\o]  "" | ||||||
|  |     a -\\o]    : ""-\\\\o]"" | ||||||
|  |     a -/o]     : ""-/o]  "" | ||||||
|  |     a -//o]    : ""-//o] "" | ||||||
|  |     a x->o]    : ""x->o] "" | ||||||
|  |     @enduml | ||||||
|  |     ``` | ||||||
|  |   ), | ||||||
|  |   ( | ||||||
|  |     [Short incoming (with '?')], | ||||||
|  |     ``` | ||||||
|  |     @startuml | ||||||
|  |     participant Alice as a | ||||||
|  |     participant Bob   as b | ||||||
|  |     a ->     b : //Long long label// | ||||||
|  |     ?->      b : ""?->   "" | ||||||
|  |     ?->>     b : ""?->>  "" | ||||||
|  |     ?-\      b : ""?-\   "" | ||||||
|  |     ?-\\     b : ""?-\\\\"" | ||||||
|  |     ?-/      b : ""?-/   "" | ||||||
|  |     ?-//     b : ""?-//  "" | ||||||
|  |     ?->x     b : ""?->x  "" | ||||||
|  |     ?x->     b : ""?x->  "" | ||||||
|  |     ?o->     b : ""?o->  "" | ||||||
|  |     ?->o     b : ""?->o  "" | ||||||
|  |     ?o->o    b : ""?o->o "" | ||||||
|  |     ?<->     b : ""?<->  "" | ||||||
|  |     ?o<->o   b : ""?o<->o"" | ||||||
|  |     ?x<->x   b : ""?x<->x"" | ||||||
|  |     ?->>o    b : ""?->>o "" | ||||||
|  |     ?-\o     b : ""?-\o  "" | ||||||
|  |     ?-\\o    b : ""?-\\\\o "" | ||||||
|  |     ?-/o     b : ""?-/o  "" | ||||||
|  |     ?-//o    b : ""?-//o "" | ||||||
|  |     ?x->o    b : ""?x->o "" | ||||||
|  |     @enduml | ||||||
|  |     ``` | ||||||
|  |   ), | ||||||
|  |   ( | ||||||
|  |     [Short outgoing (with '?')], | ||||||
|  |     ``` | ||||||
|  |     @startuml | ||||||
|  |     participant Alice as a | ||||||
|  |     participant Bob   as b | ||||||
|  |     a ->     b : //Long long label// | ||||||
|  |     a ->?      : ""->?   "" | ||||||
|  |     a ->>?     : ""->>?  "" | ||||||
|  |     a -\?      : ""-\?   "" | ||||||
|  |     a -\\?     : ""-\\\\?"" | ||||||
|  |     a -/?      : ""-/?   "" | ||||||
|  |     a -//?     : ""-//?  "" | ||||||
|  |     a ->x?     : ""->x?  "" | ||||||
|  |     a x->?     : ""x->?  "" | ||||||
|  |     a o->?     : ""o->?  "" | ||||||
|  |     a ->o?     : ""->o?  "" | ||||||
|  |     a o->o?    : ""o->o? "" | ||||||
|  |     a <->?     : ""<->?  "" | ||||||
|  |     a o<->o?   : ""o<->o?"" | ||||||
|  |     a x<->x?   : ""x<->x?"" | ||||||
|  |     a ->>o?    : ""->>o? "" | ||||||
|  |     a -\o?     : ""-\o?  "" | ||||||
|  |     a -\\o?    : ""-\\\\o?"" | ||||||
|  |     a -/o?     : ""-/o?  "" | ||||||
|  |     a -//o?    : ""-//o? "" | ||||||
|  |     a x->o?    : ""x->o? "" | ||||||
|  |     @enduml | ||||||
|  |     ``` | ||||||
|  |   ) | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | #{ | ||||||
|  |   for (title, uml) in examples { | ||||||
|  |     heading(title) | ||||||
|  |     box( | ||||||
|  |       stroke: gray, | ||||||
|  |       inset: 1em, | ||||||
|  |       stack( | ||||||
|  |         dir: ltr, | ||||||
|  |         spacing: 1em, | ||||||
|  |         raw(uml.text, block: true, lang: "plantuml"), | ||||||
|  |         from-plantuml(uml) | ||||||
|  |       ) | ||||||
|  |     ) | ||||||
|  |     pagebreak(weak: true) | ||||||
|  |   } | ||||||
|  | } | ||||||
										
											Binary file not shown.
										
									
								
							| @@ -33,15 +33,38 @@ Alice <-- Bob: Another authentication Response | |||||||
| #chronos.diagram({ | #chronos.diagram({ | ||||||
|   import chronos: * |   import chronos: * | ||||||
|   _seq("Alice", "Bob", comment: "Authentication Request") |   _seq("Alice", "Bob", comment: "Authentication Request") | ||||||
|   _seq("Bob", "Alice", comment: "Authentication Failure") |  | ||||||
|  |  | ||||||
|   _grp("My own label", desc: "My own label2", { |   _alt( | ||||||
|     _seq("Alice", "Log", comment: "Log attack start") |     "successful case", { | ||||||
|     _grp("loop", desc: "1000 times", { |       _seq("Bob", "Alice", comment: "Authentication Accepted") | ||||||
|       _seq("Alice", "Bob", comment: "DNS Attack") |     }, | ||||||
|     }) |     "some kind of failure", { | ||||||
|     _seq("Alice", "Bob", comment: "Log attack end") |       _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({ | #chronos.diagram({ | ||||||
| @@ -55,6 +78,15 @@ Alice <-- Bob: Another authentication Response | |||||||
|   _seq("Bob", "Alice", comment: "another authentication Response", dashed: true) |   _seq("Bob", "Alice", comment: "another authentication Response", dashed: true) | ||||||
| }) | }) | ||||||
|  |  | ||||||
|  | #chronos.diagram({ | ||||||
|  |   import chronos: * | ||||||
|  |   _seq("Alice", "Bob", comment: "Authentication Request") | ||||||
|  |   _delay() | ||||||
|  |   _seq("Bob", "Alice", comment: "Authentication Response") | ||||||
|  |   _delay(name: "5 minutes later") | ||||||
|  |   _seq("Bob", "Alice", comment: "Good Bye !") | ||||||
|  | }) | ||||||
|  |  | ||||||
| #chronos.diagram({ | #chronos.diagram({ | ||||||
|   import chronos: * |   import chronos: * | ||||||
|   _seq("Alice", "Bob", comment: "message 1") |   _seq("Alice", "Bob", comment: "message 1") | ||||||
|   | |||||||
										
											Binary file not shown.
										
									
								
							| @@ -144,4 +144,23 @@ chronos.diagram({ | |||||||
|   _par("d", display-name: "Danny", show-bottom: false, show-top: false) |   _par("d", display-name: "Danny", show-bottom: false, show-top: false) | ||||||
|  |  | ||||||
|   _gap() |   _gap() | ||||||
|  | }) | ||||||
|  |  | ||||||
|  | #chronos.diagram({ | ||||||
|  |   import chronos: * | ||||||
|  |  | ||||||
|  |   _par("a", display-name: "Alice") | ||||||
|  |   _par("b", display-name: "Bob") | ||||||
|  |   _par("c", display-name: "Caleb") | ||||||
|  |   _par("d", display-name: "Danny") | ||||||
|  |   _par("e", display-name: "Erika") | ||||||
|  |  | ||||||
|  |   _col("a", "b") | ||||||
|  |   _col("b", "c", width: 2cm) | ||||||
|  |   _col("c", "d", margin: .5cm) | ||||||
|  |   _col("d", "e", min-width: 2cm) | ||||||
|  |  | ||||||
|  |   //_seq("b", "c", comment: [Hello World !]) | ||||||
|  |   //_seq("c", "d", comment: [Hello World]) | ||||||
|  |   //_seq("d", "e", comment: [Hello World]) | ||||||
| }) | }) | ||||||
							
								
								
									
										
											BIN
										
									
								
								gallery/plantuml_test.pdf
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								gallery/plantuml_test.pdf
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										271
									
								
								gallery/plantuml_test.typ
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										271
									
								
								gallery/plantuml_test.typ
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,271 @@ | |||||||
|  | #import "../src/lib.typ": from-plantuml | ||||||
|  |  | ||||||
|  | #set page(width: auto, height: auto) | ||||||
|  |  | ||||||
|  | /* | ||||||
|  | #from-plantuml(``` | ||||||
|  | @startuml | ||||||
|  |  | ||||||
|  | actor User as usr | ||||||
|  | participant can_message as can | ||||||
|  | control kartculator as kc | ||||||
|  | queue XF as xf | ||||||
|  | entity Drive as drive | ||||||
|  | entity Steering as steering | ||||||
|  |  | ||||||
|  | usr -\ xf : set message "move" | ||||||
|  | xf -> can : new value on joystick | ||||||
|  |  | ||||||
|  | == If X axis change value == | ||||||
|  | can -> kc : calculate new position | ||||||
|  | kc -> can : build message | ||||||
|  | can -> steering : set new position | ||||||
|  |  | ||||||
|  | == If Y axis change value == | ||||||
|  | can -> kc : calculate new torque | ||||||
|  | kc -> can : build message | ||||||
|  | can -> xf : set message "torque" | ||||||
|  | xf -> drive : set new torque | ||||||
|  |  | ||||||
|  | @enduml | ||||||
|  | ```) | ||||||
|  |  | ||||||
|  | #pagebreak(weak: true) | ||||||
|  |  | ||||||
|  | #from-plantuml(``` | ||||||
|  | @startuml | ||||||
|  |  | ||||||
|  | actor CAN_BUS as bus | ||||||
|  | participant interrupt as ISR | ||||||
|  | queue XF as xf | ||||||
|  | participant ecan as ecan | ||||||
|  | participant canInterface as can | ||||||
|  | control canMessageController as msg | ||||||
|  |  | ||||||
|  |  | ||||||
|  | bus -\\ ISR ++  : can message | ||||||
|  | ISR -> can : newMsg | ||||||
|  | can -> ecan : read | ||||||
|  | ecan --> can : message | ||||||
|  | can -> xf : POST XF | ||||||
|  | destroy ISR | ||||||
|  |     group TICK XF | ||||||
|  | xf o-> can : receiveCan() | ||||||
|  | can -> msg : processIncoming() | ||||||
|  | msg -> can : create message | ||||||
|  | can -> xf : POST XF | ||||||
|  |     end | ||||||
|  |     group TICK XF | ||||||
|  | xf o-> can : sendCan() | ||||||
|  | can -> ecan : write | ||||||
|  | ecan -\\ bus : can message | ||||||
|  |     end | ||||||
|  |  | ||||||
|  | @enduml | ||||||
|  | ```) | ||||||
|  |  | ||||||
|  | #pagebreak(weak: true) | ||||||
|  | */ | ||||||
|  |  | ||||||
|  | /* | ||||||
|  | #from-plantuml(``` | ||||||
|  | @startuml | ||||||
|  |  | ||||||
|  | participant "Behavior::StateMachine" as sm | ||||||
|  | participant Dispatcher as d | ||||||
|  | participant TimeoutManager as tm | ||||||
|  | entity "Event::Timeout" as t | ||||||
|  | queue "TimeoutManager::timeouts_" as timeouts | ||||||
|  |  | ||||||
|  | autoactivate off | ||||||
|  | ||| | ||||||
|  | ||| | ||||||
|  | == Schedule timeout == | ||||||
|  | ||| | ||||||
|  | sm -> sm++ : scheduleTimeout | ||||||
|  | sm -> d ++: getDispatcher | ||||||
|  | d --> sm --: dispatcher | ||||||
|  | sm -> d --++ : scheduleTimeout | ||||||
|  | d -> tm ++: getTimeoutManager | ||||||
|  | tm --> d --: timeoutManager | ||||||
|  | d -> tm --++ : scheduleTimeout | ||||||
|  | tm -> t ** : new | ||||||
|  | t --> tm | ||||||
|  | tm -> timeouts --++: insert | ||||||
|  |  | ||||||
|  | ||| | ||||||
|  | ||| | ||||||
|  | == Decrement timeout (and dispatch) == | ||||||
|  | ||| | ||||||
|  | loop every tickInterval | ||||||
|  | ?->> tm ++: tick | ||||||
|  | tm -> timeouts : getFront | ||||||
|  | timeouts -> t ++ | ||||||
|  | t --> timeouts | ||||||
|  | timeouts --> tm : timeout | ||||||
|  | tm -> t  --: decrement | ||||||
|  | end | ||||||
|  | ||| | ||||||
|  | note left t | ||||||
|  | When timeout is 0, | ||||||
|  | dispatch event | ||||||
|  | end note | ||||||
|  | t -> timeouts : pop | ||||||
|  | deactivate timeouts | ||||||
|  | t ->? --: pushEvent | ||||||
|  |  | ||||||
|  | ||| | ||||||
|  | ||| | ||||||
|  | == Unschedule timeout == | ||||||
|  | ||| | ||||||
|  | sm -> sm++ : unscheduleTimeout | ||||||
|  | sm -> d ++: getDispatcher | ||||||
|  | d --> sm --: dispatcher | ||||||
|  | sm -> d --++ : unscheduleTimeout | ||||||
|  | d -> tm ++: getTimeoutManager | ||||||
|  | tm --> d --: timeoutManager | ||||||
|  | d -> tm --++ : unscheduleTimeout | ||||||
|  | tm -> timeouts --: erase | ||||||
|  | timeouts -> t !! | ||||||
|  |  | ||||||
|  | @enduml | ||||||
|  | ```) | ||||||
|  | */ | ||||||
|  |  | ||||||
|  | #pagebreak(weak: true) | ||||||
|  |  | ||||||
|  | #from-plantuml(``` | ||||||
|  | @startuml | ||||||
|  |  | ||||||
|  | participant Behavior as b | ||||||
|  | participant Dispatcher as d | ||||||
|  | entity Event as e | ||||||
|  | participant EventQueue as eq | ||||||
|  | queue "EventQueue::queue_" as q | ||||||
|  |  | ||||||
|  | == Create an Event == | ||||||
|  | ||| | ||||||
|  | ?->> b ++ : GEN | ||||||
|  | b -> e ** : new | ||||||
|  | b -> b --++ : pushEvent | ||||||
|  | e -> b : getBehavior | ||||||
|  | b --> e ++: setBehavior | ||||||
|  | e --> b -- | ||||||
|  | b -> d ++ : getDispatcher | ||||||
|  | d --> b | ||||||
|  | b -> d -- : pushEvent | ||||||
|  | d ->? -- : push | ||||||
|  |  | ||||||
|  |  | ||||||
|  | ||| | ||||||
|  | ||| | ||||||
|  | == Push Event  == | ||||||
|  | ||| | ||||||
|  | ?->> d ++: pushEvent | ||||||
|  | d -> eq--++: push | ||||||
|  | eq -> q ++ | ||||||
|  | q --> eq | ||||||
|  | eq -> q -- : pushEndQueue | ||||||
|  |  | ||||||
|  | ||| | ||||||
|  | ||| | ||||||
|  | == Dispatch == | ||||||
|  | ||| | ||||||
|  | ?->> d ++: executeOnce | ||||||
|  | d -> q : getFront | ||||||
|  | q -> e ++ | ||||||
|  | e --> q | ||||||
|  | q --> d : event | ||||||
|  | d -> q : pop | ||||||
|  | deactivate q | ||||||
|  | d -> d --++ : dispatchEvent | ||||||
|  | d -> b ++ : getBehavior | ||||||
|  | b --> d | ||||||
|  | d -> b -- : process | ||||||
|  | b -> b--: processEvent | ||||||
|  |  | ||||||
|  | destroy e | ||||||
|  |  | ||||||
|  | @enduml | ||||||
|  | ```) | ||||||
|  |  | ||||||
|  | #pagebreak(weak: true) | ||||||
|  |  | ||||||
|  | #from-plantuml(``` | ||||||
|  | @startuml | ||||||
|  | 'https://plantuml.com/sequence-diagram | ||||||
|  | actor User as usr | ||||||
|  | participant "Pb L" as pbL | ||||||
|  | participant "Pb R" as pbR | ||||||
|  | participant "LED L" as ledL | ||||||
|  | participant "LED R" as ledR | ||||||
|  |  | ||||||
|  |  | ||||||
|  | == Single click == | ||||||
|  |  | ||||||
|  | group Single click left | ||||||
|  | usr -\ pbL ++: pressButton | ||||||
|  | usr -\ pbL : releaseButton | ||||||
|  | pbL -> ledL --++ : blink | ||||||
|  | usr -\ pbL ++: pressButton | ||||||
|  | usr -\ pbL : releaseButton | ||||||
|  | pbL -> ledL -- : endBlink | ||||||
|  | deactivate ledL | ||||||
|  | end | ||||||
|  |  | ||||||
|  | group Single click right | ||||||
|  | usr -\ pbR ++: pressButton | ||||||
|  | usr -\ pbR : releaseButton | ||||||
|  | pbR -> ledR --++ : blink | ||||||
|  | usr -\ pbR ++: pressButton | ||||||
|  | usr -\ pbR : releaseButton | ||||||
|  | pbR -> ledR -- : endBlink | ||||||
|  | deactivate ledR | ||||||
|  | end | ||||||
|  |  | ||||||
|  | == Double click == | ||||||
|  |  | ||||||
|  | group Double click left | ||||||
|  | usr -\ pbL ++: pressButton | ||||||
|  | usr -\ pbL : releaseButton | ||||||
|  | usr -\ pbL : pressButton | ||||||
|  | pbL -> ledL --++ : blink | ||||||
|  | note right ledL: blink 3x | ||||||
|  | ledL ->x ledL -- : finished | ||||||
|  | end | ||||||
|  |  | ||||||
|  | group Double click right | ||||||
|  | usr -\ pbR ++: pressButton | ||||||
|  | usr -\ pbR : releaseButton | ||||||
|  | usr -\ pbR : pressButton | ||||||
|  | pbR -> ledR --++ : blink | ||||||
|  | note right ledR: blink 3x | ||||||
|  | ledR ->x ledR -- : finished | ||||||
|  | end | ||||||
|  |  | ||||||
|  | == Long click == | ||||||
|  |  | ||||||
|  | group Long click left | ||||||
|  | usr -\ pbL ++: pressButton | ||||||
|  | pbL -> ledR--: blink | ||||||
|  | activate ledL | ||||||
|  | activate ledR | ||||||
|  | usr -\ pbL ++: pressButton | ||||||
|  | pbL -> ledR -- : endBlink | ||||||
|  | deactivate ledL | ||||||
|  | deactivate ledR | ||||||
|  | end | ||||||
|  |  | ||||||
|  | group Long click right | ||||||
|  | usr -\ pbR ++: pressButton | ||||||
|  | pbR -> ledR--: blink | ||||||
|  | activate ledL | ||||||
|  | activate ledR | ||||||
|  | usr -\ pbL ++: pressButton | ||||||
|  | pbL -> ledR -- : endBlink | ||||||
|  | deactivate ledL | ||||||
|  | deactivate ledR | ||||||
|  | end | ||||||
|  |  | ||||||
|  | @enduml | ||||||
|  | ```) | ||||||
							
								
								
									
										
											BIN
										
									
								
								manual.pdf
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								manual.pdf
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										214
									
								
								manual.typ
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										214
									
								
								manual.typ
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,214 @@ | |||||||
|  | #import "@preview/tidy:0.3.0" | ||||||
|  | #import "src/lib.typ" as chronos | ||||||
|  | #import "src/participant.typ" as mod-par | ||||||
|  | #import "docs/examples.typ" | ||||||
|  | #import "docs/example.typ": example | ||||||
|  |  | ||||||
|  | #let TYPST = image("gallery/typst.png", width: 1.5cm, height: 1.5cm, fit: "contain") | ||||||
|  |  | ||||||
|  | #let doc-ref(target, full: false, var: false) = { | ||||||
|  |   let (module, func) = target.split(".") | ||||||
|  |   let label-name = module + func | ||||||
|  |   let display-name = func | ||||||
|  |   if full { | ||||||
|  |     display-name = target | ||||||
|  |   } | ||||||
|  |   if not var { | ||||||
|  |     label-name += "()" | ||||||
|  |     display-name += "()" | ||||||
|  |   } | ||||||
|  |   link(label(label-name))[#display-name] | ||||||
|  | } | ||||||
|  |  | ||||||
|  | #set heading(numbering: (..num) => if num.pos().len() < 4 { | ||||||
|  |   numbering("1.1", ..num) | ||||||
|  | }) | ||||||
|  | #{ | ||||||
|  |   outline(indent: true, depth: 3) | ||||||
|  | } | ||||||
|  | #show link: set text(fill: blue) | ||||||
|  |  | ||||||
|  | #set page(numbering: "1/1", header: align(right)[chronos #sym.dash.em v#chronos.version]) | ||||||
|  | #set page( | ||||||
|  |   header: locate(loc => align(left)[chronos #sym.dash.em v#chronos.version]), | ||||||
|  |   footer: locate(loc => align(center, counter(page).display("1/1", both: true))) | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | = Introduction | ||||||
|  |  | ||||||
|  | This package lets you create nice sequence diagrams using the CeTZ package. | ||||||
|  |  | ||||||
|  | = Usage | ||||||
|  |  | ||||||
|  | Simply import #link("https://typst.app/universe/package/chronos/")[chronos] and call the `diagram` function: | ||||||
|  | #pad(left: 1em)[```typ | ||||||
|  | #import "@preview/chronos:0.1.0" | ||||||
|  | #chronos.diagram({ | ||||||
|  |   import chronos: * | ||||||
|  |   ... | ||||||
|  | }) | ||||||
|  | ```] | ||||||
|  |  | ||||||
|  | = Examples | ||||||
|  |  | ||||||
|  | You can find the following examples and more in the #link("https://git.kb28.ch/HEL/circuiteria/src/branch/main/gallery")[gallery] directory | ||||||
|  |  | ||||||
|  | == Some groups and sequences | ||||||
|  |  | ||||||
|  | #example(``` | ||||||
|  | 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") | ||||||
|  |   }) | ||||||
|  | }) | ||||||
|  | ```, wrap: false, vertical: true) | ||||||
|  |  | ||||||
|  | #pagebreak(weak: true) | ||||||
|  |  | ||||||
|  | == Lifelines | ||||||
|  |  | ||||||
|  | #example(``` | ||||||
|  | chronos.diagram({ | ||||||
|  |   import chronos: * | ||||||
|  |   _seq("alice", "bob", comment: "hello", enable-dst: true) | ||||||
|  |   _seq("bob", "bob", comment: "self call", enable-dst: true) | ||||||
|  |   _seq( | ||||||
|  |     "bill", "bob", | ||||||
|  |     comment: "hello from thread 2", | ||||||
|  |     enable-dst: true, | ||||||
|  |     lifeline-style: (fill: rgb("#005500")) | ||||||
|  |   ) | ||||||
|  |   _seq("bob", "george", comment: "create", create-dst: true) | ||||||
|  |   _seq( | ||||||
|  |     "bob", "bill", | ||||||
|  |     comment: "done in thread 2", | ||||||
|  |     disable-src: true, | ||||||
|  |     dashed: true | ||||||
|  |   ) | ||||||
|  |   _seq("bob", "bob", comment: "rc", disable-src: true, dashed: true) | ||||||
|  |   _seq("bob", "george", comment: "delete", destroy-dst: true) | ||||||
|  |   _seq("bob", "alice", comment: "success", disable-src: true, dashed: true) | ||||||
|  | }) | ||||||
|  | ```, wrap: false, vertical: true) | ||||||
|  |  | ||||||
|  | #pagebreak(weak: true) | ||||||
|  |  | ||||||
|  | == Found and lost messages | ||||||
|  |  | ||||||
|  | #example(``` | ||||||
|  | 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]) | ||||||
|  | }) | ||||||
|  | ```, wrap: false, vertical: true) | ||||||
|  |  | ||||||
|  | #pagebreak(weak: true) | ||||||
|  |  | ||||||
|  | == Custom images | ||||||
|  |  | ||||||
|  | #example(``` | ||||||
|  | let load-img(path) = image(path, width: 1.5cm, height: 1.5cm, fit:"contain") | ||||||
|  | let TYPST = load-img("../gallery/typst.png") | ||||||
|  | let FERRIS = load-img("../gallery/ferris.png") | ||||||
|  | let ME = load-img("../gallery/me.jpg") | ||||||
|  |  | ||||||
|  | chronos.diagram({ | ||||||
|  |   import chronos: * | ||||||
|  |   _par("me", display-name: "Me", shape: "custom", custom-image: ME) | ||||||
|  |   _par("typst", display-name: "Typst", shape: "custom", custom-image: TYPST) | ||||||
|  |   _par("rust", display-name: "Rust", shape: "custom", custom-image: FERRIS) | ||||||
|  |  | ||||||
|  |   _seq("me", "typst", comment: "opens document", enable-dst: true) | ||||||
|  |   _seq("me", "typst", comment: "types document") | ||||||
|  |   _seq("typst", "rust", comment: "compiles content", enable-dst: true) | ||||||
|  |   _seq("rust", "typst", comment: "renders document", disable-src: true) | ||||||
|  |   _seq("typst", "me", comment: "displays document", disable-src: true) | ||||||
|  | }) | ||||||
|  | ```, wrap: false, vertical: true) | ||||||
|  |  | ||||||
|  | #pagebreak(weak: true) | ||||||
|  |  | ||||||
|  | = Reference | ||||||
|  |  | ||||||
|  | #let par-docs = tidy.parse-module( | ||||||
|  |   read("docs/participants.typ"), | ||||||
|  |   name: "Participants", | ||||||
|  |   require-all-parameters: true, | ||||||
|  |   scope: ( | ||||||
|  |     chronos: chronos, | ||||||
|  |     mod-par: mod-par, | ||||||
|  |     TYPST: TYPST, | ||||||
|  |     doc-ref: doc-ref | ||||||
|  |   ) | ||||||
|  | ) | ||||||
|  | #tidy.show-module(par-docs, show-outline: false, sort-functions: none) | ||||||
|  |  | ||||||
|  | #pagebreak(weak: true) | ||||||
|  |  | ||||||
|  | #let seq-docs = tidy.parse-module( | ||||||
|  |   read("docs/sequences.typ"), | ||||||
|  |   name: "Sequences", | ||||||
|  |   require-all-parameters: true, | ||||||
|  |   scope: ( | ||||||
|  |     chronos: chronos, | ||||||
|  |     doc-ref: doc-ref, | ||||||
|  |     examples: examples | ||||||
|  |   ) | ||||||
|  | ) | ||||||
|  | #tidy.show-module(seq-docs, show-outline: false, sort-functions: none) | ||||||
|  |  | ||||||
|  | #pagebreak(weak: true) | ||||||
|  |  | ||||||
|  | #let grp-docs = tidy.parse-module( | ||||||
|  |   read("docs/groups.typ"), | ||||||
|  |   name: "Groups", | ||||||
|  |   require-all-parameters: true, | ||||||
|  |   scope: ( | ||||||
|  |     chronos: chronos, | ||||||
|  |     doc-ref: doc-ref, | ||||||
|  |     examples: examples | ||||||
|  |   ) | ||||||
|  | ) | ||||||
|  | #tidy.show-module(grp-docs, show-outline: false, sort-functions: none) | ||||||
|  |  | ||||||
|  | #pagebreak(weak: true) | ||||||
|  |  | ||||||
|  | #let gap-sep-docs = tidy.parse-module( | ||||||
|  |   read("docs/gaps_seps.typ"), | ||||||
|  |   name: "Gaps and separators", | ||||||
|  |   require-all-parameters: true, | ||||||
|  |   scope: ( | ||||||
|  |     chronos: chronos, | ||||||
|  |     doc-ref: doc-ref, | ||||||
|  |     examples: examples | ||||||
|  |   ) | ||||||
|  | ) | ||||||
|  | #tidy.show-module(gap-sep-docs, show-outline: false) | ||||||
|  |  | ||||||
|  | #pagebreak(weak: true) | ||||||
|  |  | ||||||
|  | #let notes-docs = tidy.parse-module( | ||||||
|  |   read("docs/notes.typ"), | ||||||
|  |   name: "Notes", | ||||||
|  |   require-all-parameters: true, | ||||||
|  |   scope: ( | ||||||
|  |     chronos: chronos, | ||||||
|  |     doc-ref: doc-ref, | ||||||
|  |     examples: examples | ||||||
|  |   ) | ||||||
|  | ) | ||||||
|  | #tidy.show-module(notes-docs, show-outline: false) | ||||||
| @@ -1,6 +1,7 @@ | |||||||
| #import "utils.typ": get-group-span, fit-canvas | #import "utils.typ": get-group-span, fit-canvas | ||||||
| #import "renderer.typ": render | #import "renderer.typ": render | ||||||
| #import "participant.typ" as participant: _par, PAR-SPECIALS | #import "participant.typ" as participant: _par, PAR-SPECIALS | ||||||
|  | #import "sequence.typ": _seq | ||||||
|  |  | ||||||
| #let _gap(size: 20) = { | #let _gap(size: 20) = { | ||||||
|   return (( |   return (( | ||||||
| @@ -18,6 +19,17 @@ | |||||||
|   ),) |   ),) | ||||||
| } | } | ||||||
|  |  | ||||||
|  | #let _col(p1, p2, width: auto, margin: 0, min-width: 0) = { | ||||||
|  |   return (( | ||||||
|  |     type: "col", | ||||||
|  |     p1: p1, | ||||||
|  |     p2: p2, | ||||||
|  |     width: width, | ||||||
|  |     margin: margin, | ||||||
|  |     min-width: min-width | ||||||
|  |   ),) | ||||||
|  | } | ||||||
|  |  | ||||||
| #let diagram(elements, width: auto) = { | #let diagram(elements, width: auto) = { | ||||||
|   if elements == none { |   if elements == none { | ||||||
|     return |     return | ||||||
| @@ -27,7 +39,9 @@ | |||||||
|   let elmts = elements |   let elmts = elements | ||||||
|   let i = 0 |   let i = 0 | ||||||
|  |  | ||||||
|   // Flatten groups |   let activation-history = () | ||||||
|  |  | ||||||
|  |   // Flatten groups + convert returns | ||||||
|   while i < elmts.len() { |   while i < elmts.len() { | ||||||
|     let elmt = elmts.at(i) |     let elmt = elmts.at(i) | ||||||
|     if elmt.type == "grp" { |     if elmt.type == "grp" { | ||||||
| @@ -51,6 +65,30 @@ | |||||||
|         ),) + |         ),) + | ||||||
|         elmts.slice(i+1) |         elmts.slice(i+1) | ||||||
|       ) |       ) | ||||||
|  |     } else if elmt.type == "seq" { | ||||||
|  |       if elmt.enable-dst { | ||||||
|  |         activation-history.push(elmt) | ||||||
|  |       } | ||||||
|  |     } else if elmt.type == "evt" { | ||||||
|  |       if elmt.event == "enable" { | ||||||
|  |         for elmt2 in elmts.slice(0, i).rev() { | ||||||
|  |           if elmt2.type == "seq" { | ||||||
|  |             activation-history.push(elmt2) | ||||||
|  |             break | ||||||
|  |           } | ||||||
|  |         } | ||||||
|  |       } | ||||||
|  |     } else if elmt.type == "ret" { | ||||||
|  |       if activation-history.len() == 0 { | ||||||
|  |         panic("Cannot return if no lifeline is activated") | ||||||
|  |       } | ||||||
|  |       let seq = activation-history.pop() | ||||||
|  |       elmts.at(i) = _seq( | ||||||
|  |         seq.p2, seq.p1, | ||||||
|  |         comment: elmt.comment, | ||||||
|  |         disable-src: true, | ||||||
|  |         dashed: true | ||||||
|  |       ).first() | ||||||
|     } |     } | ||||||
|     i += 1 |     i += 1 | ||||||
|   } |   } | ||||||
| @@ -119,6 +157,21 @@ | |||||||
|       } else if elmt.side == "right" { |       } else if elmt.side == "right" { | ||||||
|         linked.push("]") |         linked.push("]") | ||||||
|       } |       } | ||||||
|  |  | ||||||
|  |       let pars = none | ||||||
|  |       if type(elmt.pos) == str { | ||||||
|  |         pars = (elmt.pos,) | ||||||
|  |       } else if type(elmt.pos) == array { | ||||||
|  |         pars = elmt.pos | ||||||
|  |       } | ||||||
|  |       if pars != none { | ||||||
|  |         for par in pars { | ||||||
|  |           if not participant._exists(participants, par) { | ||||||
|  |             participants.push(_par(par).first()) | ||||||
|  |           } | ||||||
|  |         } | ||||||
|  |       } | ||||||
|  |  | ||||||
|       last-note = ( |       last-note = ( | ||||||
|         elmt: elmt, |         elmt: elmt, | ||||||
|         i: i |         i: i | ||||||
| @@ -174,7 +227,7 @@ | |||||||
|  |  | ||||||
|   // Compute groups spans (horizontal) |   // Compute groups spans (horizontal) | ||||||
|   for (i, elmt) in elmts.enumerate() { |   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) |       let (min-i, max-i) = get-group-span(participants, elmt) | ||||||
|       elmts.at(i).insert("min-i", min-i) |       elmts.at(i).insert("min-i", min-i) | ||||||
|       elmts.at(i).insert("max-i", max-i) |       elmts.at(i).insert("max-i", max-i) | ||||||
| @@ -190,8 +243,4 @@ | |||||||
|   set text(font: "Source Sans 3") |   set text(font: "Source Sans 3") | ||||||
|   let canvas = render(participants, elmts) |   let canvas = render(participants, elmts) | ||||||
|   fit-canvas(canvas, width: width) |   fit-canvas(canvas, width: width) | ||||||
| } |  | ||||||
|  |  | ||||||
| #let from-plantuml(code) = { |  | ||||||
|   let code = code.text |  | ||||||
| } | } | ||||||
| @@ -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 render(x0, x1, y0, y1, group) = { | ||||||
|   let shapes = () |   let shapes = () | ||||||
|   let name = text(group.name, weight: "bold") |   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 |   return shapes | ||||||
| } | } | ||||||
							
								
								
									
										10
									
								
								src/lib.typ
									
									
									
									
									
								
							
							
						
						
									
										10
									
								
								src/lib.typ
									
									
									
									
									
								
							| @@ -1,8 +1,10 @@ | |||||||
| #import "diagram.typ": diagram, from-plantuml, _gap, _evt | #let version = version(0, 1, 1) | ||||||
|  | #import "diagram.typ": diagram, _gap, _evt, _col | ||||||
|  | #import "parser.typ": from-plantuml | ||||||
|  |  | ||||||
| #import "sequence.typ": _seq | #import "sequence.typ": _seq, _ret | ||||||
| #import "group.typ": _grp | #import "group.typ": _grp, _loop, _alt, _opt, _break | ||||||
| #import "participant.typ": _par | #import "participant.typ": _par | ||||||
| #import "separator.typ": _sep | #import "separator.typ": _sep, _delay | ||||||
| #import "note.typ": _note | #import "note.typ": _note | ||||||
| #import "sync.typ": _sync | #import "sync.typ": _sync | ||||||
| @@ -25,6 +25,9 @@ | |||||||
|       panic("Aligned notes can only be over a participant (got side '" + side + "')") |       panic("Aligned notes can only be over a participant (got side '" + side + "')") | ||||||
|     } |     } | ||||||
|   } |   } | ||||||
|  |   if color == auto { | ||||||
|  |     color = COL-NOTE | ||||||
|  |   } | ||||||
|   return (( |   return (( | ||||||
|     type: "note", |     type: "note", | ||||||
|     side: side, |     side: side, | ||||||
|   | |||||||
							
								
								
									
										1036
									
								
								src/parser.typ
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1036
									
								
								src/parser.typ
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| @@ -13,6 +13,7 @@ | |||||||
|   "queue", |   "queue", | ||||||
|   "custom" |   "custom" | ||||||
| ) | ) | ||||||
|  | #let DEFAULT-COLOR = rgb("#E2E2F0") | ||||||
|  |  | ||||||
| #let _par( | #let _par( | ||||||
|   name, |   name, | ||||||
| @@ -20,11 +21,14 @@ | |||||||
|   from-start: true, |   from-start: true, | ||||||
|   invisible: false, |   invisible: false, | ||||||
|   shape: "participant", |   shape: "participant", | ||||||
|   color: rgb("#E2E2F0"), |   color: DEFAULT-COLOR, | ||||||
|   custom-image: none, |   custom-image: none, | ||||||
|   show-bottom: true, |   show-bottom: true, | ||||||
|   show-top: true, |   show-top: true, | ||||||
| ) = { | ) = { | ||||||
|  |   if color == auto { | ||||||
|  |     color = DEFAULT-COLOR | ||||||
|  |   } | ||||||
|   return (( |   return (( | ||||||
|     type: "par", |     type: "par", | ||||||
|     name: name, |     name: name, | ||||||
|   | |||||||
| @@ -1,5 +1,5 @@ | |||||||
| #import "@preview/cetz:0.2.2": canvas, draw | #import "@preview/cetz:0.2.2": canvas, draw | ||||||
| #import "utils.typ": get-participants-i, get-style | #import "utils.typ": get-participants-i, get-style, normalize-units | ||||||
| #import "group.typ" | #import "group.typ" | ||||||
| #import "participant.typ" | #import "participant.typ" | ||||||
| #import participant: PAR-SPECIALS | #import participant: PAR-SPECIALS | ||||||
| @@ -194,6 +194,37 @@ | |||||||
|     } |     } | ||||||
|     widths.at(i) = w |     widths.at(i) = w | ||||||
|   } |   } | ||||||
|  |  | ||||||
|  |   for elmt in elements { | ||||||
|  |     if elmt.type == "col" { | ||||||
|  |       let i1 = pars-i.at(elmt.p1) | ||||||
|  |       let i2 = pars-i.at(elmt.p2) | ||||||
|  |       if calc.abs(i1 - i2) != 1 { | ||||||
|  |         let i-min = calc.min(i1, i2) | ||||||
|  |         let i-max = calc.max(i1, i2) | ||||||
|  |         let others = pars-i.pairs() | ||||||
|  |                            .sorted(key: p => p.last()) | ||||||
|  |                            .slice(i-min + 1, i-max) | ||||||
|  |                            .map(p => "'" + p.first() + "'") | ||||||
|  |                            .join(", ") | ||||||
|  |         panic( | ||||||
|  |           "Column participants must be consecutive (participants (" + | ||||||
|  |           others + | ||||||
|  |           ") are in between)" | ||||||
|  |         ) | ||||||
|  |       } | ||||||
|  |       let i = calc.min(i1, i2) | ||||||
|  |  | ||||||
|  |       if elmt.width != auto { | ||||||
|  |         widths.at(i) = normalize-units(elmt.width) | ||||||
|  |       } | ||||||
|  |       widths.at(i) = calc.max( | ||||||
|  |         widths.at(i), | ||||||
|  |         normalize-units(elmt.min-width) | ||||||
|  |       ) + normalize-units(elmt.margin) | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |  | ||||||
|   return widths |   return widths | ||||||
| } | } | ||||||
|  |  | ||||||
| @@ -211,6 +242,7 @@ | |||||||
|  |  | ||||||
|   let draw-seq = sequence.render.with(pars-i, x-pos, participants) |   let draw-seq = sequence.render.with(pars-i, x-pos, participants) | ||||||
|   let draw-group = group.render.with() |   let draw-group = group.render.with() | ||||||
|  |   let draw-else = group.render-else.with() | ||||||
|   let draw-sep = separator.render.with(x-pos) |   let draw-sep = separator.render.with(x-pos) | ||||||
|   let draw-par = participant.render.with(x-pos) |   let draw-par = participant.render.with(x-pos) | ||||||
|   let draw-note = note.render.with(pars-i, x-pos) |   let draw-note = note.render.with(pars-i, x-pos) | ||||||
| @@ -252,6 +284,9 @@ | |||||||
|         if g.at(1).max-i == elmt.max-i { g.at(3) += 1 } |         if g.at(1).max-i == elmt.max-i { g.at(3) += 1 } | ||||||
|         g |         g | ||||||
|       }) |       }) | ||||||
|  |       if elmt.grp-type == "alt" { | ||||||
|  |         elmt.insert("elses", ()) | ||||||
|  |       } | ||||||
|       groups.push((y, elmt, 0, 0)) |       groups.push((y, elmt, 0, 0)) | ||||||
|       y -= m.height / 1pt |       y -= m.height / 1pt | ||||||
|      |      | ||||||
| @@ -263,6 +298,21 @@ | |||||||
|       let x1 = x-pos.at(group.max-i) + end-lvl * 10 + 20 |       let x1 = x-pos.at(group.max-i) + end-lvl * 10 + 20 | ||||||
|       shapes += draw-group(x0, x1, start-y, y, group) |       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 |     // Separator | ||||||
|     } else if elmt.type == "sep" { |     } else if elmt.type == "sep" { | ||||||
|       let shps |       let shps | ||||||
| @@ -272,6 +322,26 @@ | |||||||
|     // Gap |     // Gap | ||||||
|     } else if elmt.type == "gap" { |     } else if elmt.type == "gap" { | ||||||
|       y -= elmt.size |       y -= elmt.size | ||||||
|  |  | ||||||
|  |     // Delay | ||||||
|  |     } else if elmt.type == "delay" { | ||||||
|  |       let y0 = y | ||||||
|  |       let y1 = y - elmt.size | ||||||
|  |       for (i, line) in lifelines.enumerate() { | ||||||
|  |         line.lines.push(("delay-start", y0)) | ||||||
|  |         line.lines.push(("delay-end", y1)) | ||||||
|  |         lifelines.at(i) = line | ||||||
|  |       } | ||||||
|  |       if elmt.name != none { | ||||||
|  |         let x0 = x-pos.first() | ||||||
|  |         let x1 = x-pos.last() | ||||||
|  |         shapes += draw.content( | ||||||
|  |           ((x0 + x1) / 2, (y0 + y1) / 2), | ||||||
|  |           anchor: "center", | ||||||
|  |           elmt.name | ||||||
|  |         ) | ||||||
|  |       } | ||||||
|  |       y = y1 | ||||||
|      |      | ||||||
|     // Event |     // Event | ||||||
|     } else if elmt.type == "evt" { |     } else if elmt.type == "evt" { | ||||||
| @@ -385,6 +455,28 @@ | |||||||
|           if event == "destroy" { |           if event == "destroy" { | ||||||
|             destructions.push((x + lvl * LIFELINE-W / 2, line.at(1))) |             destructions.push((x + lvl * LIFELINE-W / 2, line.at(1))) | ||||||
|           } |           } | ||||||
|  |         } else if event == "delay-start" { | ||||||
|  |           draw.line( | ||||||
|  |             (x, last-y), | ||||||
|  |             (x, line.at(1)), | ||||||
|  |             stroke: ( | ||||||
|  |               dash: "dashed", | ||||||
|  |               paint: gray.darken(40%), | ||||||
|  |               thickness: .5pt | ||||||
|  |             ) | ||||||
|  |           ) | ||||||
|  |           last-y = line.at(1) | ||||||
|  |         } else if event == "delay-end" { | ||||||
|  |           draw.line( | ||||||
|  |             (x, last-y), | ||||||
|  |             (x, line.at(1)), | ||||||
|  |             stroke: ( | ||||||
|  |               dash: "loosely-dotted", | ||||||
|  |               paint: gray.darken(40%), | ||||||
|  |               thickness: .8pt | ||||||
|  |             ) | ||||||
|  |           ) | ||||||
|  |           last-y = line.at(1) | ||||||
|         } |         } | ||||||
|       } |       } | ||||||
|  |  | ||||||
|   | |||||||
| @@ -8,6 +8,14 @@ | |||||||
|   ),) |   ),) | ||||||
| } | } | ||||||
|  |  | ||||||
|  | #let _delay(name: none, size: 30) = { | ||||||
|  |   return (( | ||||||
|  |     type: "delay", | ||||||
|  |     name: name, | ||||||
|  |     size: size | ||||||
|  |   ),) | ||||||
|  | } | ||||||
|  |  | ||||||
| #let render(x-pos, elmt, y) = { | #let render(x-pos, elmt, y) = { | ||||||
|   let shapes = () |   let shapes = () | ||||||
|   y -= Y-SPACE |   y -= Y-SPACE | ||||||
|   | |||||||
| @@ -4,6 +4,9 @@ | |||||||
| #import "note.typ" | #import "note.typ" | ||||||
|  |  | ||||||
| #let get-arrow-marks(sym, color) = { | #let get-arrow-marks(sym, color) = { | ||||||
|  |   if sym == none { | ||||||
|  |     return none | ||||||
|  |   } | ||||||
|   if type(sym) == array { |   if type(sym) == array { | ||||||
|     return sym.map(s => get-arrow-marks(s, color)) |     return sym.map(s => get-arrow-marks(s, color)) | ||||||
|   } |   } | ||||||
| @@ -85,6 +88,13 @@ | |||||||
|   ),) |   ),) | ||||||
| } | } | ||||||
|  |  | ||||||
|  | #let _ret(comment: none) = { | ||||||
|  |   return (( | ||||||
|  |     type: "ret", | ||||||
|  |     comment: comment | ||||||
|  |   ),) | ||||||
|  | } | ||||||
|  |  | ||||||
| #let render(pars-i, x-pos, participants, elmt, y, lifelines) = { | #let render(pars-i, x-pos, participants, elmt, y, lifelines) = { | ||||||
|   let shapes = () |   let shapes = () | ||||||
|  |  | ||||||
| @@ -294,7 +304,7 @@ | |||||||
|  |  | ||||||
|   // Start circle tip |   // Start circle tip | ||||||
|   if is-circle-tip(elmt.start-tip) { |   if is-circle-tip(elmt.start-tip) { | ||||||
|     shapes += draw.circle(pts.first(), radius: CIRCLE-TIP-RADIUS, stroke: elmt.color, fill: none, name: "_circle-start-tip") |     shapes += draw.circle(pts.first(), radius: CIRCLE-TIP-RADIUS, stroke: none, fill: elmt.color, name: "_circle-start-tip") | ||||||
|     pts.at(0) = "_circle-start-tip" |     pts.at(0) = "_circle-start-tip" | ||||||
|    |    | ||||||
|   // Start cross tip |   // Start cross tip | ||||||
| @@ -316,7 +326,7 @@ | |||||||
|  |  | ||||||
|   // End circle tip |   // End circle tip | ||||||
|   if is-circle-tip(elmt.end-tip) { |   if is-circle-tip(elmt.end-tip) { | ||||||
|     shapes += draw.circle(pts.last(), radius: 3, stroke: elmt.color, fill: none, name: "_circle-end-tip") |     shapes += draw.circle(pts.last(), radius: 3, stroke: none, fill: elmt.color, name: "_circle-end-tip") | ||||||
|     pts.at(pts.len() - 1) = "_circle-end-tip" |     pts.at(pts.len() - 1) = "_circle-end-tip" | ||||||
|    |    | ||||||
|   // End cross tip |   // End cross tip | ||||||
|   | |||||||
| @@ -1,3 +1,12 @@ | |||||||
|  | #let normalize-units(value) = { | ||||||
|  |   if type(value) == int or type(value) == float { | ||||||
|  |     return value | ||||||
|  |   } | ||||||
|  |   if type(value) == length { | ||||||
|  |     return value / 1pt | ||||||
|  |   } | ||||||
|  |   panic("Unsupported type '" + str(type(value)) + "'") | ||||||
|  | } | ||||||
| #let get-participants-i(participants) = { | #let get-participants-i(participants) = { | ||||||
|   let pars-i = (:) |   let pars-i = (:) | ||||||
|   for (i, p) in participants.enumerate() { |   for (i, p) in participants.enumerate() { | ||||||
|   | |||||||
| @@ -1,6 +1,6 @@ | |||||||
| [package] | [package] | ||||||
| name = "chronos" | name = "chronos" | ||||||
| version = "0.1.0" | version = "0.1.1" | ||||||
| compiler = "0.11.0" | compiler = "0.11.0" | ||||||
| repository = "https://git.kb28.ch/HEL/chronos" | repository = "https://git.kb28.ch/HEL/chronos" | ||||||
| entrypoint = "src/lib.typ" | entrypoint = "src/lib.typ" | ||||||
| @@ -11,4 +11,4 @@ categories = ["visualization"] | |||||||
| license = "Apache-2.0" | license = "Apache-2.0" | ||||||
| description = "A package to draw sequence diagrams with CeTZ" | description = "A package to draw sequence diagrams with CeTZ" | ||||||
| keywords = ["sequence", "diagram", "plantuml"] | keywords = ["sequence", "diagram", "plantuml"] | ||||||
| exclude = [ "gallery", "gallery.bash" ] | exclude = [ "gallery", "gallery.bash", "docs" ] | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user