5 changed files with 19 additions and 110 deletions
-3
View File
@@ -1,8 +1,5 @@
# Changelog # Changelog
## [Unreleased]
- Added `description-width` config option, wrapping descriptions and values instead of drawing them on a single line
## [v0.3.1] - 2026-06-14 ## [v0.3.1] - 2026-06-14
- Support for non-consecutive ranges ([#13](https://git.kb28.ch/HEL/rivet-typst/pulls/13)) - 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)) - Prevent drawing separators on starting lines of fields ([#17](https://git.kb28.ch/HEL/rivet-typst/pulls/17))
+1 -3
View File
@@ -26,7 +26,6 @@
/// - 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 /// - ltr-bits (bool): If true, bits are placed with the LSB on the left instead of the right
/// - description-width (float | none): If set, descriptions and values wrap at this width instead of being drawn on a single line
/// -> dictionary /// -> dictionary
#let config( #let config(
default-font-family: "Ubuntu Mono", default-font-family: "Ubuntu Mono",
@@ -54,8 +53,7 @@
height: 800, height: 800,
full-page: false, full-page: false,
all-bit-i: true, all-bit-i: true,
ltr-bits: false, ltr-bits: false
description-width: none
) = {} ) = {}
/// Dark theme config /// Dark theme config
-30
View File
@@ -203,36 +203,6 @@ For values depending on other ranges, see #link(<format-dependencies>)[Dependenc
} }
``` ```
=== Wrapping descriptions <format-description-width>
Descriptions and values are drawn on a single line. A diagram is scaled to fit
the width it is given, so a long description makes the whole diagram, bit cells
and all, shrink until it fits:
#let long-schema = (structures: (main: (bits: 16, ranges: (
"15-8": (name: "op", description: "Operation to perform on the two operands"),
"7-0": (
name: "flags",
description: "Flags applied to the operation, see the table below for the meaning of each bit",
values: ("00000001": "carry in, added to the result before the flags are evaluated")
)
))))
#let long-sch = schema.load(long-schema)
#align(center, schema.render(long-sch, width: 75%))
Setting the #doc-ref("config.config") option `description-width` wraps them at
that width instead, leaving the diagram at its natural size. The width is given
in the same units as `bit-width`, and values wrap at the same right edge as the
description they belong to. Each label is offset by the height it actually
occupies, so wrapping onto several lines does not make labels overlap.
```typ
schema.render(sch, config: config.config(description-width: 300))
```
#align(center, schema.render(long-sch, width: 75%, config: lib.config.config(description-width: 300)))
#pagebreak(weak: true) #pagebreak(weak: true)
== Dependencies <format-dependencies> == Dependencies <format-dependencies>
-2
View File
@@ -25,7 +25,6 @@
full-page: false, full-page: false,
all-bit-i: true, all-bit-i: true,
ltr-bits: false, ltr-bits: false,
description-width: none,
) = { ) = {
return ( return (
default-font-family: default-font-family, default-font-family: default-font-family,
@@ -54,7 +53,6 @@
full-page: full-page, full-page: full-page,
all-bit-i: all-bit-i, all-bit-i: all-bit-i,
ltr-bits: ltr-bits, ltr-bits: ltr-bits,
description-width: description-width,
) )
} }
+18 -72
View File
@@ -41,24 +41,6 @@
) )
} }
// A wrapped label is built as plain content so that its height can be measured
// before it is placed, and the label after it offset by what it really takes.
#let text-block(txt, color, width, font: none, italic: false, size: 1em) = {
let text-params = (:)
if font != none {
text-params.insert("font", font)
}
if italic {
text-params.insert("style", "italic")
}
box(width: width * 1pt, text(txt, fill: color, size: size, ..text-params))
}
#let draw-block(block, x, y) = {
draw.content((x, -y), block, anchor: "north-west", stroke: none)
}
#let draw-line(color, a, b) = { #let draw-line(color, a, b) = {
let (x0, y0) = a let (x0, y0) = a
let (x1, y1) = b let (x1, y1) = b
@@ -131,26 +113,15 @@
for (val, desc) in values.pairs().sorted(key: p => p.first()) { for (val, desc) in values.pairs().sorted(key: p => p.first()) {
desc-y += gap desc-y += gap
let txt = val + " = " + desc let txt = val + " = " + desc
if config.description-width == none { shapes += draw-text(
shapes += draw-text( txt, txt-col, desc-x + bit-w / 2, desc-y,
txt, txt-col, desc-x + bit-w / 2, desc-y, anchor: "north-west",
anchor: "north-west", font: config.italic-font-family,
font: config.italic-font-family, italic: true,
italic: true, size: config.italic-font-size
size: config.italic-font-size )
)
desc-y += config.italic-font-size / 1.2pt desc-y += config.italic-font-size / 1.2pt
} else {
let block = text-block(
txt, txt-col, config.description-width - bit-w / 2,
font: config.italic-font-family,
italic: true,
size: config.italic-font-size
)
shapes += draw-block(block, desc-x + bit-w / 2, desc-y)
desc-y += measure(block).height.pt()
}
} }
return (shapes, desc-x, desc-y) return (shapes, desc-x, desc-y)
@@ -178,47 +149,22 @@
shapes += draw-underbracket(config, start-x, start-x + width, start-y) shapes += draw-underbracket(config, start-x, start-x + width, start-y)
let mid-x = start-x + width / 2 let mid-x = start-x + width / 2
let link-y = if config.description-width == none { shapes += draw-link(config, mid-x, start-y, desc-x, desc-y)
desc-y
} else {
// wrapped labels hang from desc-y, so aim at the middle of their first line
desc-y + config.default-font-size.pt() / 2 - bit-h / 2
}
shapes += draw-link(config, mid-x, start-y, desc-x, link-y)
let txt-x = desc-x let txt-x = desc-x
if config.left-labels { if config.left-labels {
// desc-x is the right edge of the label when they are on the left, so shift txt-x -= range_.description.len() * config.default-font-size / 2pt
// to its left edge: exactly the box width when wrapping, an estimate from
// the character count otherwise
txt-x -= if config.description-width == none {
range_.description.len() * config.default-font-size / 2pt
} else {
config.description-width
}
} }
if config.description-width == none { shapes += draw-text(
shapes += draw-text( range_.description,
range_.description, config.text-color,
config.text-color, txt-x, desc-y + bit-h / 2,
txt-x, desc-y + bit-h / 2, anchor: "west"
anchor: "west" )
)
desc-y += config.default-font-size / 0.75pt desc-y += config.default-font-size / 0.75pt
} else {
let block = text-block(
range_.description,
config.text-color,
config.description-width,
font: config.default-font-family,
size: config.default-font-size
)
shapes += draw-block(block, txt-x, desc-y)
desc-y += measure(block).height.pt()
}
if range_.values != none and range_.depends-on == none { if range_.values != none and range_.depends-on == none {
let shapes_ let shapes_
@@ -573,7 +519,7 @@
return (shapes, desc-y) return (shapes, desc-y)
} }
#let render(config, schema, width: 100%) = context { #let render(config, schema, width: 100%) = {
set text( set text(
font: config.default-font-family, font: config.default-font-family,
size: config.default-font-size size: config.default-font-size