Merge pull request 'Left to right bits + Loading manual section' (#6) from feat/left-to-right-bits-1 into dev

Reviewed-on: #6
This commit is contained in:
Louis Heredero 2025-04-15 17:45:51 +00:00
commit 422681ba6e
16 changed files with 158 additions and 33 deletions

View File

@ -1,5 +1,13 @@
# Changelog # 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 ## [v0.2.0] - 2025-02-23
- updated CeTZ to 0.3.2 - updated CeTZ to 0.3.2
- updated to Typst 0.13.0 - updated to Typst 0.13.0

View File

@ -25,6 +25,7 @@
/// - height (float): TODO -> remove /// - height (float): TODO -> remove
/// - full-page (bool): If true, the page will be resized to fit the diagram and take the background color /// - 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 /// - 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 /// -> dictionary
#let config( #let config(
default-font-family: "Ubuntu Mono", default-font-family: "Ubuntu Mono",
@ -51,7 +52,8 @@
width: 1200, width: 1200,
height: 800, height: 800,
full-page: false, full-page: false,
all-bit-i: true all-bit-i: true,
ltr-bits: false
) = {} ) = {}
/// Dark theme config /// Dark theme config

View File

@ -1,5 +1,6 @@
/// Loads a schema from a file or a raw block. /// 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>)[Loading] chapter for examples of schema loading for each supported format
/// ///
/// Supported formats: #schema.valid-extensions.map(e => raw("." + e)).join(", ") /// Supported formats: #schema.valid-extensions.map(e => raw("." + e)).join(", ")
/// - path-or-schema (str, raw, dictionary): /// - path-or-schema (str, raw, dictionary):
@ -12,7 +13,6 @@
#let load(path-or-schema) = {} #let load(path-or-schema) = {}
/// Renders the given schema /// Renders the given schema
/// This functions
/// - schema (dictionary): A schema dictionary, as returned by @@load() /// - schema (dictionary): A schema dictionary, as returned by @@load()
/// - config (auto, dictionary): The configuration parameters, as returned by #doc-ref("config.config") /// - config (auto, dictionary): The configuration parameters, as returned by #doc-ref("config.config")
/// - width (ratio, length): The width of the generated figure /// - width (ratio, length): The width of the generated figure

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 490 KiB

After

Width:  |  Height:  |  Size: 485 KiB

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -1,6 +1,6 @@
#import "@preview/tidy:0.4.1" #import "@preview/tidy:0.4.2"
#import "@preview/codly:1.2.0": codly-init, codly #import "@preview/codly:1.3.0": codly-init, codly
#import "@preview/codly-languages:0.1.7": codly-languages #import "@preview/codly-languages:0.1.8": codly-languages
#import "@preview/showybox:2.0.4": showybox #import "@preview/showybox:2.0.4": showybox
#import "src/lib.typ" #import "src/lib.typ"
#import "src/schema.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 = 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à ! #let import-stmt = "#import \"@preview/rivet:" + str(lib.version) + "\""
#pad(left: 1em)[```typ
#import "@preview/rivet:0.1.0": schema Simply import the `schema` module and call `schema.load` to parse a schema description. Then use `schema.render` to render it, et voilà !
#let doc = schema.load("path/to/schema.yaml") #raw(block: true, lang: "typ", ```typ
$import: schema
#let doc = schema.load(yaml("path/to/schema.yaml"))
#schema.render(doc) #schema.render(doc)
```] ```.text.replace("$import", import-stmt))
Please read the #link(<loading>)[Loading] chapter for more detailed explanations on how to load schema descriptions.
= Format = 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. 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 == 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(<format-colors>)[Colors] It can also optionnaly contain a "colors" dictionary. More details about this in #link(<format-colors>)[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(<format-range>)[Range]). A range's structure can also depend on another range's value (see #link(<format-dependencies>)[Dependencies]). 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(<format-range>)[Range]). A range's structure can also depend on another range's value (see #link(<format-dependencies>)[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 ```json
"main": { "main": {
@ -177,7 +181,7 @@ For values depending on other ranges, see #link(<format-dependencies>)[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. 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 ```json
"7-4": { "7-4": {
@ -270,6 +274,81 @@ Valid color formats are:
#pagebreak(weak: true) #pagebreak(weak: true)
= Loading <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
<schema>
<structure id="main" bits="32">
...
</structure>
</schema>
```)
````
#pagebreak(weak: true)
= Config presets = Config presets
Aside from the default config, some example presets are also provided: Aside from the default config, some example presets are also provided:

View File

@ -23,7 +23,8 @@
width: 1200, width: 1200,
height: 800, height: 800,
full-page: false, full-page: false,
all-bit-i: true all-bit-i: true,
ltr-bits: false,
) = { ) = {
return ( return (
default-font-family: default-font-family, default-font-family: default-font-family,
@ -50,7 +51,8 @@
width: width, width: width,
height: height, height: height,
full-page: full-page, full-page: full-page,
all-bit-i: all-bit-i all-bit-i: all-bit-i,
ltr-bits: ltr-bits,
) )
} }

View File

@ -1,4 +1,4 @@
#let version = version(0,2,0) #let version = version(0,3,0)
#import "config.typ" #import "config.typ"
#import "schema.typ" #import "schema.typ"

View File

@ -15,6 +15,9 @@
} }
let start = int(start-end.last()) let start = int(start-end.last())
let end = int(start-end.first()) let end = int(start-end.first())
if end < start {
(start, end) = (end, start)
}
return (start, end) return (start, end)
} }

View File

@ -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 "range.typ" as rng
#import "structure.typ" #import "structure.typ"
@ -253,7 +253,15 @@
let bit-h = config.bit-height let bit-h = config.bit-height
let arrow-margin = config.arrow-margin 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 start-x = bits-x + start-i * bit-w
let width = rng.bits(range_) * bit-w let width = rng.bits(range_) * bit-w
@ -268,7 +276,7 @@
depend-range.last-value-y 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-start-x = bits-x + depend-start-i * bit-w
let depend-width = rng.bits(depend-range) * bit-w let depend-width = rng.bits(depend-range) * bit-w
let depend-mid = depend-start-x + depend-width / 2 let depend-mid = depend-start-x + depend-width / 2
@ -302,7 +310,9 @@
let x2 let x2
// Arrow from left to right // 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 x1 = depend-start-x + depend-width + arrow-margin
x2 = start-x - arrow-margin x2 = start-x - arrow-margin
@ -346,6 +356,23 @@
let bits-width = struct.bits * bit-w let bits-width = struct.bits * bit-w
let start-bit = struct.start let start-bit = struct.start
let bit-colors = (:) 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) { for i in range(struct.bits) {
bit-colors.insert(str(i), bg-col) bit-colors.insert(str(i), bg-col)
} }
@ -353,14 +380,14 @@
for (s, col) in colors.at(struct.name) { for (s, col) in colors.at(struct.name) {
let (start, end) = rng.parse-span(s) let (start, end) = rng.parse-span(s)
for i in range(start, end + 1) { 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) bit-colors.insert(str(real-i), col)
} }
} }
} }
let range-boundaries = () let range-boundaries = ()
for r in struct.ranges.values() { 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) range-boundaries.push(i)
} }
@ -384,11 +411,11 @@
for i in range(struct.bits) { for i in range(struct.bits) {
let bit-x = ox + i * bit-w 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( shapes += draw-text(
str(real-i), str(bit-i),
txt-col, txt-col,
bit-x + bit-w / 2, bit-x + bit-w / 2,
oy + bit-h / 2 oy + bit-h / 2
@ -403,13 +430,16 @@
} }
let ranges = structure.get-sorted-ranges(struct) let ranges = structure.get-sorted-ranges(struct)
if config.ltr-bits {
ranges = ranges.rev()
}
if config.left-labels { if config.left-labels {
ranges = ranges.rev() ranges = ranges.rev()
} }
let desc-x let desc-x
if config.force-descs-on-side { 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 { if config.left-labels {
desc-x = config.width - desc-x desc-x = config.width - desc-x
} }
@ -424,14 +454,15 @@
// Names + simple descriptions // Names + simple descriptions
for range_ in ranges { 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 start-x = bits-x + start-i * bit-w
let width = rng.bits(range_) * bit-w let width = rng.bits(range_) * bit-w
let name-x = start-x + width / 2 let name-x = start-x + width / 2
let name-y = bits-y + bit-h / 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) shapes += draw-text(range_.name, txt-col, name-x, name-y, fill: bg-col)
if range_.description != "" { if range_.description != "" {

View File

@ -1,7 +1,7 @@
[package] [package]
name = "rivet" name = "rivet"
version = "0.2.0" version = "0.3.0"
compiler = "0.13.0" compiler = "0.13.1"
repository = "https://git.kb28.ch/HEL/rivet-typst" repository = "https://git.kb28.ch/HEL/rivet-typst"
entrypoint = "src/lib.typ" entrypoint = "src/lib.typ"
authors = [ authors = [