diff --git a/CHANGELOG.md b/CHANGELOG.md index 4dd3686..ab035ed 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,13 @@ # Changelog +## [v0.3.0] - WIP +- updated CeTZ to 0.3.4 +- updated to Typst 0.13.1 +- updated Tidy to 0.4.2 +- updated Codly to 1.3.0 and codly-languages to 0.1.8 +- added `ltr-bits` config option +- added a "Loading" section to the manual + ## [v0.2.0] - 2025-02-23 - updated CeTZ to 0.3.2 - updated to Typst 0.13.0 diff --git a/docs/config.typ b/docs/config.typ index 2046f8c..d3c3ed0 100644 --- a/docs/config.typ +++ b/docs/config.typ @@ -25,6 +25,7 @@ /// - height (float): TODO -> remove /// - full-page (bool): If true, the page will be resized to fit the diagram and take the background color /// - all-bit-i (bool): If true, all bit indices will be rendered, otherwise, only the ends of each range will be displayed +/// - ltr-bits (bool): If true, bits are placed with the LSB on the left instead of the right /// -> dictionary #let config( default-font-family: "Ubuntu Mono", @@ -51,7 +52,8 @@ width: 1200, height: 800, full-page: false, - all-bit-i: true + all-bit-i: true, + ltr-bits: false ) = {} /// Dark theme config diff --git a/docs/schema.typ b/docs/schema.typ index 48d539e..c2aa221 100644 --- a/docs/schema.typ +++ b/docs/schema.typ @@ -1,5 +1,6 @@ /// Loads a schema from a file or a raw block. -/// This function returns a dictionary of structures +/// This function returns a dictionary of structures\ +/// See the #link()[Loading] chapter for examples of schema loading for each supported format /// /// Supported formats: #schema.valid-extensions.map(e => raw("." + e)).join(", ") /// - path-or-schema (str, raw, dictionary): @@ -12,7 +13,6 @@ #let load(path-or-schema) = {} /// Renders the given schema -/// This functions /// - schema (dictionary): A schema dictionary, as returned by @@load() /// - config (auto, dictionary): The configuration parameters, as returned by #doc-ref("config.config") /// - width (ratio, length): The width of the generated figure diff --git a/gallery/example1.pdf b/gallery/example1.pdf index ca2330e..96dbf60 100644 Binary files a/gallery/example1.pdf and b/gallery/example1.pdf differ diff --git a/gallery/example2.pdf b/gallery/example2.pdf index 20678da..ee09bba 100644 Binary files a/gallery/example2.pdf and b/gallery/example2.pdf differ diff --git a/gallery/example3.pdf b/gallery/example3.pdf index d5156f4..0cb441b 100644 Binary files a/gallery/example3.pdf and b/gallery/example3.pdf differ diff --git a/gallery/example3.png b/gallery/example3.png index d2d70e8..6fd2e20 100644 Binary files a/gallery/example3.png and b/gallery/example3.png differ diff --git a/gallery/riscv/riscv.pdf b/gallery/riscv/riscv.pdf index ca9bca8..6716397 100644 Binary files a/gallery/riscv/riscv.pdf and b/gallery/riscv/riscv.pdf differ diff --git a/gallery/test.pdf b/gallery/test.pdf index aa076ba..c8d4a11 100644 Binary files a/gallery/test.pdf and b/gallery/test.pdf differ diff --git a/manual.pdf b/manual.pdf index 8597825..35debf3 100644 Binary files a/manual.pdf and b/manual.pdf differ diff --git a/manual.typ b/manual.typ index a97b449..6445fa4 100644 --- a/manual.typ +++ b/manual.typ @@ -1,6 +1,6 @@ -#import "@preview/tidy:0.4.1" -#import "@preview/codly:1.2.0": codly-init, codly -#import "@preview/codly-languages:0.1.7": codly-languages +#import "@preview/tidy:0.4.2" +#import "@preview/codly:1.3.0": codly-init, codly +#import "@preview/codly-languages:0.1.8": codly-languages #import "@preview/showybox:2.0.4": showybox #import "src/lib.typ" #import "src/schema.typ" @@ -84,22 +84,26 @@ This is a port of the #link("https://git.kb28.ch/HEL/rivet")[homonymous Python s = Usage -Simply import `schema` from #link("src/lib.typ") and call `schema.load` to parse a schema description. Then use `schema.render` to render it, et voilĂ  ! -#pad(left: 1em)[```typ -#import "@preview/rivet:0.1.0": schema -#let doc = schema.load("path/to/schema.yaml") +#let import-stmt = "#import \"@preview/rivet:" + str(lib.version) + "\"" + +Simply import the `schema` module and call `schema.load` to parse a schema description. Then use `schema.render` to render it, et voilĂ  ! +#raw(block: true, lang: "typ", ```typ +$import: schema +#let doc = schema.load(yaml("path/to/schema.yaml")) #schema.render(doc) -```] +```.text.replace("$import", import-stmt)) + +Please read the #link()[Loading] chapter for more detailed explanations on how to load schema descriptions. = Format This section describes the structure of a schema definition. The examples given use the JSON syntax. For examples in different formats, see #link("https://git.kb28.ch/HEL/rivet-typst/src/branch/main/gallery/test.yaml")[test.yaml], #link("https://git.kb28.ch/HEL/rivet-typst/src/branch/main/gallery/test.json")[test.json] and #link("https://git.kb28.ch/HEL/rivet-typst/src/branch/main/gallery/test.xml")[test.xml]. You can also directly define a schema using Typst dictionaries and arrays. -Since the XML format is quite different from the other, you might find it helpful to look at the examples on GitHub to get familiar with it. +Since the XML format is quite different from the other, you might find it helpful to look at the examples in the #link("https://git.kb28.ch/HEL/rivet-typst/src/branch/main/gallery/")[Gitea repo] to get familiar with it. == Main layout -A schema contains a dictionary of structures. The must be at least one defined structure named "main". +A schema contains a dictionary of structures. There must be at least one defined structure named "main". It can also optionnaly contain a "colors" dictionary. More details about this in #link()[Colors] @@ -126,7 +130,7 @@ It can also optionnaly contain a "colors" dictionary. More details about this in A structure has a given number of bits and one or multiple ranges. Each range of bits can have a name, a description and / or values with special meaning (see #link()[Range]). A range's structure can also depend on another range's value (see #link()[Dependencies]). -The range name (or key) defines the left- and rightmost bits (e.g. `7-4` goes from bit 7 down to bit 4). Bits are displayed in big-endian, i.e. the leftmost bit has the highest value. +The range name (or key) defines the left- and rightmost bits (e.g. `7-4` goes from bit 7 down to bit 4). The order in which you write the range is not important, meaning `7-4` is equivalent to `4-7`. Bits are displayed in big-endian, i.e. the leftmost bit has the highest value, except if you enable the `ltr-bits` #doc-ref("config.config") option. ```json "main": { @@ -177,7 +181,7 @@ For values depending on other ranges, see #link()[Dependenc The structure of one range may depend on the value of another. To represent this situation, first indicate on the child range the range on which it depends. -Then, in its values, indicate which structure to use. A description can also be added (displayed above the horizontal dependency arrow) +Then, in its values, indicate which structure to use. A description can also be added (displayed below the horizontal dependency arrow) ```json "7-4": { @@ -270,6 +274,81 @@ Valid color formats are: #pagebreak(weak: true) += Loading + +Due to current limitations of the Typst compiler, the package can only access its own files, unless directly included in your project. For this reason, rivet cannot load a schema from a path, and you will need to read the files yourself to pass their contents to the package. + +Here are a number of ways you can load your schemas: + +== JSON Format + +````typ +// From file (ONLY IF PACKAGE INSTALLED IN PROJECT) +#let s = schema.load("schema.json") +// From file +#let s = schema.load(json("schema.json")) +// Raw block +#let s = schema.load(```json +{ + "structures": { + "main": { + ... + } + } +} +```) +```` + +== YAML Format + +````typ +// From file (ONLY IF PACKAGE INSTALLED IN PROJECT) +#let s = schema.load("schema.yaml") +// From file +#let s = schema.load(yaml("schema.yaml")) +// Raw block +#let s = schema.load(```yaml +structures: + main: + ... +```) +```` + +== Typst Format + +```typ +#let s = schema.load(( + structures: ( + main: ( + ... + ) + ) +)) +``` + +#pagebreak(weak: true) + +== XML Format + +````typ +// From file (ONLY IF PACKAGE INSTALLED IN PROJECT) +#let x = schema.xml-loader.load("schema.xml") +#let s = schema.load(x) +// From file +#let x = schema.xml-loader.parse(yaml("schema.yaml").first()) +#let s = schema.load(x) +// Raw block +#let s = schema.load(```xml + + + ... + + +```) +```` + +#pagebreak(weak: true) + = Config presets Aside from the default config, some example presets are also provided: diff --git a/src/config.typ b/src/config.typ index f3868ad..5b7fac0 100644 --- a/src/config.typ +++ b/src/config.typ @@ -23,7 +23,8 @@ width: 1200, height: 800, full-page: false, - all-bit-i: true + all-bit-i: true, + ltr-bits: false, ) = { return ( default-font-family: default-font-family, @@ -50,7 +51,8 @@ width: width, height: height, full-page: full-page, - all-bit-i: all-bit-i + all-bit-i: all-bit-i, + ltr-bits: ltr-bits, ) } diff --git a/src/lib.typ b/src/lib.typ index 6d7aa1d..ed44ea6 100644 --- a/src/lib.typ +++ b/src/lib.typ @@ -1,4 +1,4 @@ -#let version = version(0,2,0) +#let version = version(0,3,0) #import "config.typ" #import "schema.typ" \ No newline at end of file diff --git a/src/range.typ b/src/range.typ index 96a7ce4..0834376 100644 --- a/src/range.typ +++ b/src/range.typ @@ -15,6 +15,9 @@ } let start = int(start-end.last()) let end = int(start-end.first()) + if end < start { + (start, end) = (end, start) + } return (start, end) } diff --git a/src/renderer.typ b/src/renderer.typ index 94f4b0e..39ecb2e 100644 --- a/src/renderer.typ +++ b/src/renderer.typ @@ -1,4 +1,4 @@ -#import "@preview/cetz:0.3.2": canvas, draw +#import "@preview/cetz:0.3.4": canvas, draw #import "range.typ" as rng #import "structure.typ" @@ -253,7 +253,15 @@ let bit-h = config.bit-height let arrow-margin = config.arrow-margin - let start-i = struct.bits - range_.end - 1 + let to-real-i(i) = { + return if config.ltr-bits { + i + } else { + struct.bits - i - 1 + } + } + + let start-i = to-real-i(if config.ltr-bits {range_.start} else {range_.end}) let start-x = bits-x + start-i * bit-w let width = rng.bits(range_) * bit-w @@ -268,7 +276,7 @@ depend-range.last-value-y } - let depend-start-i = struct.bits - depend-range.end - 1 + let depend-start-i = to-real-i(depend-range.end) let depend-start-x = bits-x + depend-start-i * bit-w let depend-width = rng.bits(depend-range) * bit-w let depend-mid = depend-start-x + depend-width / 2 @@ -302,7 +310,9 @@ let x2 // Arrow from left to right - if depend-range.end > range_.start { + let i1 = to-real-i(range_.start) + let i2 = to-real-i(depend-range.end) + if i2 < i1 { x1 = depend-start-x + depend-width + arrow-margin x2 = start-x - arrow-margin @@ -346,6 +356,23 @@ let bits-width = struct.bits * bit-w let start-bit = struct.start let bit-colors = (:) + + let to-real-i(i) = { + return if config.ltr-bits { + i - start-bit + } else { + struct.bits - i - 1 + start-bit + } + } + + let to-bit-i(real-i) = { + return if config.ltr-bits { + real-i + start-bit + } else { + struct.bits - real-i - 1 + start-bit + } + } + for i in range(struct.bits) { bit-colors.insert(str(i), bg-col) } @@ -353,14 +380,14 @@ for (s, col) in colors.at(struct.name) { let (start, end) = rng.parse-span(s) for i in range(start, end + 1) { - let real-i = struct.bits - i - 1 + start-bit + let real-i = to-real-i(i) bit-colors.insert(str(real-i), col) } } } let range-boundaries = () for r in struct.ranges.values() { - let i = struct.bits - r.end - 1 + start-bit + let i = to-real-i(if config.ltr-bits {r.start} else {r.end}) range-boundaries.push(i) } @@ -384,11 +411,11 @@ for i in range(struct.bits) { let bit-x = ox + i * bit-w - let real-i = struct.bits - i - 1 + start-bit + let bit-i = to-bit-i(i) - if real-i in indices { + if bit-i in indices { shapes += draw-text( - str(real-i), + str(bit-i), txt-col, bit-x + bit-w / 2, oy + bit-h / 2 @@ -403,13 +430,16 @@ } let ranges = structure.get-sorted-ranges(struct) + if config.ltr-bits { + ranges = ranges.rev() + } if config.left-labels { ranges = ranges.rev() } let desc-x if config.force-descs-on-side { - desc-x = config.margins.at(3) + structures.main.bits * bit-w + desc-x = config.margins.at(3) + schema.structures.main.bits * bit-w if config.left-labels { desc-x = config.width - desc-x } @@ -424,14 +454,15 @@ // Names + simple descriptions for range_ in ranges { - let start-i = struct.bits - range_.end + start-bit - 1 + let start-i = to-real-i(if config.ltr-bits {range_.start} else {range_.end}) let start-x = bits-x + start-i * bit-w let width = rng.bits(range_) * bit-w let name-x = start-x + width / 2 let name-y = bits-y + bit-h / 2 - - shapes += draw-line(border-col, (start-x, bits-y), (start-x, bits-y + bit-h)) + + let line-x = if config.ltr-bits {start-x + width} else {start-x} + shapes += draw-line(border-col, (line-x, bits-y), (line-x, bits-y + bit-h)) shapes += draw-text(range_.name, txt-col, name-x, name-y, fill: bg-col) if range_.description != "" { diff --git a/typst.toml b/typst.toml index a0c5417..878fc30 100644 --- a/typst.toml +++ b/typst.toml @@ -1,7 +1,7 @@ [package] name = "rivet" -version = "0.2.0" -compiler = "0.13.0" +version = "0.3.0" +compiler = "0.13.1" repository = "https://git.kb28.ch/HEL/rivet-typst" entrypoint = "src/lib.typ" authors = [