diff --git a/CHANGELOG.md b/CHANGELOG.md
index fa4eb7c..cc083ae 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,11 @@
# Changelog
+## [v0.3.1] - 2026-06-14
+- Support for non-consecutive ranges ([#13](https://git.kb28.ch/HEL/rivet-typst/pulls/13))
+- Prevent drawing separators on starting lines of fields ([#17](https://git.kb28.ch/HEL/rivet-typst/pulls/17))
+- Fix end line on non-consecutive ranges ending at the highest bit not being draw ([#18](https://git.kb28.ch/HEL/rivet-typst/pulls/18))
+- Add documentation for `start` property of structures ([61f13df815f](https://git.kb28.ch/HEL/rivet-typst/commit/6f13df815f99fd6be8b6b3a02b4d53bcc8fe0aff))
+
## [v0.3.0] - 2025-05-03
- updated CeTZ to 0.3.4
- updated to Typst 0.13.1
diff --git a/README.md b/README.md
index a928135..5eb5249 100644
--- a/README.md
+++ b/README.md
@@ -9,7 +9,7 @@ It is based on the [homonymous Python script](https://git.kb28.ch/HEL/rivet/)
-
+
|
@@ -19,7 +19,7 @@ It is based on the [homonymous Python script](https://git.kb28.ch/HEL/rivet/)
-
+
|
@@ -35,7 +35,7 @@ For more information, see the [manual](manual.pdf)
To use this package, simply import `schema` from [rivet](https://typst.app/universe/package/rivet) and call `schema.load` to parse a schema description. Then use `schema.render` to render it, et voilĂ !
```typ
-#import "@preview/rivet:0.3.0": schema
-#let doc = schema.load("path/to/schema.yaml")
+#import "@preview/rivet:0.3.1": schema
+#let doc = schema.load(yaml("path/to/schema.yaml"))
#schema.render(doc)
```
\ No newline at end of file
diff --git a/gallery/example1.pdf b/gallery/example1.pdf
index 96dbf60..22d52c8 100644
Binary files a/gallery/example1.pdf and b/gallery/example1.pdf differ
diff --git a/gallery/example1.typ b/gallery/example1.typ
index bfb9ca0..17e095b 100644
--- a/gallery/example1.typ
+++ b/gallery/example1.typ
@@ -1,6 +1,6 @@
-#import "../src/lib.typ": schema, config
+#import "@preview/rivet:0.3.1": schema, config
-#let example = schema.load("/gallery/example1.yaml")
+#let example = schema.load(yaml("./example1.yaml"))
#schema.render(example, config: config.config(
full-page: true
))
\ No newline at end of file
diff --git a/gallery/example2.pdf b/gallery/example2.pdf
index ee09bba..0692021 100644
Binary files a/gallery/example2.pdf and b/gallery/example2.pdf differ
diff --git a/gallery/example2.typ b/gallery/example2.typ
index 012dd9b..0fddad6 100644
--- a/gallery/example2.typ
+++ b/gallery/example2.typ
@@ -1,6 +1,6 @@
-#import "../src/lib.typ": schema, config
+#import "@preview/rivet:0.3.1": schema, config
-#let example = schema.load("/gallery/example2.yaml")
+#let example = schema.load(yaml("./example2.yaml"))
#schema.render(example, config: config.blueprint(
full-page: true,
left-labels: true
diff --git a/gallery/example3.pdf b/gallery/example3.pdf
index 0cb441b..de8082b 100644
Binary files a/gallery/example3.pdf and b/gallery/example3.pdf differ
diff --git a/gallery/example3.typ b/gallery/example3.typ
index cf04b43..c2f28a6 100644
--- a/gallery/example3.typ
+++ b/gallery/example3.typ
@@ -1,6 +1,6 @@
-#import "../src/lib.typ": schema, config
+#import "@preview/rivet:0.3.1": schema, config
-#let example = schema.load("/gallery/example1.yaml")
+#let example = schema.load(yaml("/gallery/example1.yaml"))
//#schema.render(example)
= Chapter 1
diff --git a/gallery/riscv/riscv.typ b/gallery/riscv/riscv.typ
index 0802ad9..7b9f3c5 100644
--- a/gallery/riscv/riscv.typ
+++ b/gallery/riscv/riscv.typ
@@ -1,14 +1,14 @@
-#import "../../src/lib.typ": *
+#import "@preview/rivet:0.3.1": *
#let conf = config.config(
full-page: true,
left-labels: true
)
-#let alu = schema.load("/gallery/riscv/alu_instr.yaml")
+#let alu = schema.load(yaml("./alu_instr.yaml"))
#schema.render(alu, config: conf)
-#let branch = schema.load("/gallery/riscv/branch_instr.yaml")
+#let branch = schema.load(yaml("./branch_instr.yaml"))
#schema.render(branch, config: conf)
-#let mem = schema.load("/gallery/riscv/mem_instr.yaml")
+#let mem = schema.load(yaml("./mem_instr.yaml"))
#schema.render(mem, config: conf)
diff --git a/gallery/test.pdf b/gallery/test.pdf
index c8d4a11..929dd14 100644
Binary files a/gallery/test.pdf and b/gallery/test.pdf differ
diff --git a/gallery/test.typ b/gallery/test.typ
index 515a846..d5348f8 100644
--- a/gallery/test.typ
+++ b/gallery/test.typ
@@ -1,16 +1,17 @@
-#import "../src/lib.typ": *
+#import "@preview/rivet:0.3.1": *
-#let test-yaml = schema.load("/gallery/test.yaml")
+#let test-yaml = schema.load(yaml("./test.yaml"))
#schema.render(test-yaml, config: config.config(
full-page: true
))
-#let test-json = schema.load("/gallery/test.json")
+#let test-json = schema.load(json("./test.json"))
#schema.render(test-json, config: config.blueprint(
full-page: true
))
-#let test-xml = schema.load("/gallery/test.xml")
+#let test-xml-raw = schema.xml-loader.parse(xml("./test.xml").first())
+#let test-xml = schema.load(test-xml-raw)
#schema.render(test-xml, config: config.dark(
full-page: true
))
diff --git a/manual.pdf b/manual.pdf
index 35debf3..6fcd811 100644
Binary files a/manual.pdf and b/manual.pdf differ
diff --git a/manual.typ b/manual.typ
index 6445fa4..65d75d0 100644
--- a/manual.typ
+++ b/manual.typ
@@ -105,7 +105,7 @@ Since the XML format is quite different from the other, you might find it helpfu
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]
+It can also optionally contain a "colors" dictionary. More details about this in #link()[Colors]
```json
{
@@ -152,6 +152,34 @@ The range name (or key) defines the left- and rightmost bits (e.g. `7-4` goes fr
}
```
+=== Start
+
+By default, structures start at bit 0, but you may want to number bits from 1, or another arbitrary value. To do this, you can set the `start` property of a structure to the desired start value. For example,
+
+```json
+"main": {
+ "bits": 8,
+ "start": 4,
+ "ranges": {
+ "11-7": { ... },
+ "6-4": { ... }
+ }
+}
+```
+
+#let start-schema = (structures: (main: (bits: 8, start: 4, ranges: ("11-7": (name: ""), "6-4": (name: "")))))
+
+would render as
+
+#align(
+ center,
+ schema.render(
+ schema.load(start-schema),
+ width: 50%
+ )
+)
+
+
== Range
A range represents a group of consecutive bits. It can have a name (displayed in the bit cells), a description (displayed under the structure) and / or values.
@@ -335,7 +363,7 @@ structures:
#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 x = schema.xml-loader.parse(xml("schema.xml").first())
#let s = schema.load(x)
// Raw block
#let s = schema.load(```xml
diff --git a/src/lib.typ b/src/lib.typ
index ed44ea6..defd663 100644
--- a/src/lib.typ
+++ b/src/lib.typ
@@ -1,4 +1,4 @@
-#let version = version(0,3,0)
+#let version = version(0,3,1)
#import "config.typ"
#import "schema.typ"
\ No newline at end of file
diff --git a/src/renderer.typ b/src/renderer.typ
index 39ecb2e..ec0c3d3 100644
--- a/src/renderer.typ
+++ b/src/renderer.typ
@@ -387,8 +387,10 @@
}
let range-boundaries = ()
for r in struct.ranges.values() {
- let i = to-real-i(if config.ltr-bits {r.start} else {r.end})
- range-boundaries.push(i)
+ let start-i = to-real-i(if config.ltr-bits {r.start} else {r.end})
+ let end-i = to-real-i(if config.ltr-bits {r.end} else {r.start}) + 1
+ range-boundaries.push(start-i)
+ range-boundaries.push(end-i)
}
// Draw colors
@@ -407,6 +409,11 @@
indices.push(r.start)
indices.push(r.end)
}
+ // ensure first and last bits are included
+ if not indices.contains(0) { indices.insert(0, struct.start) }
+ if not indices.contains(struct.bits + struct.start - 1) {
+ indices.push(struct.bits + struct.start - 1)
+ }
}
for i in range(struct.bits) {
@@ -453,8 +460,9 @@
let desc-y = bits-y + bit-h * 2
// Names + simple descriptions
- for range_ in ranges {
+ for (i, range_) in ranges.enumerate() {
let start-i = to-real-i(if config.ltr-bits {range_.start} else {range_.end})
+ let end-i = to-real-i(if config.ltr-bits {range_.end} else {range_.start})
let start-x = bits-x + start-i * bit-w
let width = rng.bits(range_) * bit-w
@@ -464,6 +472,28 @@
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)
+
+ // paint end line only if needed
+ let is-not-limit = if config.ltr-bits { start-i != 0 } else { end-i != struct.bits - 1 }
+ if (
+ is-not-limit
+ and ranges
+ .at(
+ i
+ + {
+ if config.ltr-bits and i < ranges.len() - 1 { 1 } else { -1 }
+ },
+ )
+ .end
+ != range_.start - 1
+ ) {
+ line-x += if config.ltr-bits { -width } else { width }
+ shapes += draw-line(
+ border-col,
+ (line-x, bits-y),
+ (line-x, bits-y + bit-h),
+ )
+ }
if range_.description != "" {
let shapes_
@@ -568,4 +598,4 @@
config: config,
render: render.with(config)
)
-}
\ No newline at end of file
+}
diff --git a/src/xml-loader.typ b/src/xml-loader.typ
index 9513766..ac3962f 100644
--- a/src/xml-loader.typ
+++ b/src/xml-loader.typ
@@ -76,8 +76,9 @@
}
return (
- bits: elmt.attrs.bits,
- ranges: ranges
+ bits: int(elmt.attrs.bits),
+ ranges: ranges,
+ start: elmt.attrs.at("start", default: 0)
)
}
diff --git a/typst.toml b/typst.toml
index 878fc30..f8c6645 100644
--- a/typst.toml
+++ b/typst.toml
@@ -1,6 +1,6 @@
[package]
name = "rivet"
-version = "0.3.0"
+version = "0.3.1"
compiler = "0.13.1"
repository = "https://git.kb28.ch/HEL/rivet-typst"
entrypoint = "src/lib.typ"
@@ -9,6 +9,6 @@ authors = [
]
categories = [ "visualization" ]
license = "Apache-2.0"
-description = "Register / Instruction Visualizer & Explainer Tool with Typst, using CeTZ"
+description = "Register / Instruction Visualizer & Explainer Tool, using CeTZ"
keywords = [ "assembly", "instruction", "binary" ]
exclude = [ "gallery", "justfile", "docs" ]
\ No newline at end of file