Skip to content

Commit

Permalink
tricorder:0.1.0 (#1829)
Browse files Browse the repository at this point in the history
  • Loading branch information
YDX-2147483647 authored Feb 24, 2025
1 parent c2438c3 commit aa2a4ba
Show file tree
Hide file tree
Showing 9 changed files with 323 additions and 0 deletions.
7 changes: 7 additions & 0 deletions packages/preview/tricorder/0.1.0/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
*.pdf

# Downloaded by `just setup`
/fonts/*.otf

# Generated by tytanic
/tests/**/.gitignore
21 changes: 21 additions & 0 deletions packages/preview/tricorder/0.1.0/LICENSE
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
MIT License

Copyright (c) 2025 Y.D.X.

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
120 changes: 120 additions & 0 deletions packages/preview/tricorder/0.1.0/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
# Typst Tricorder——占三格法花名册

Record Chinese names with a rhythm of three characters.
按占三格的节奏记录中文人名。

```typst
#import "@preview/tricorder:0.1.0": tricorder
#tricorder(
.."丁声树、黎锦熙、李荣、陆志韦、陆宗达、吕叔湘、石明远、王力、魏建功、叶籁士、叶圣陶、周定一、周浩然、周祖谟、朱文叔".split("、"),
"成吉思汗(蒙古族,古人)", "张大三", "李小四",
)
```

![](./assets/1.png)

## 用法 Usage

- [如何控制布局 How to control the layout](#如何控制布局-how-to-control-the-layout)
- [如何记录名字 How to record names](#如何记录名字-how-to-record-names)

### 如何控制布局 How to control the layout

- `columns`:列数 Number of columns

**默认:**`auto`,会填充所有可用空间。若从头设计版面,无需更改。

**Default:** `auto`, which will use all available space. This is suitable if you design the whole layout from the beginning.

可用正的`int`直接规定列数。

Use a positive `int` to specify the number of columns explicitly.

```typst
#tricorder(columns: auto, ..names)
#align(
center,
tricorder(columns: 3, ..names),
)
```

![](./assets/2.png)

- `row-gutter`/`column-gutter`:行/列间隙 Gaps between rows/columns

**默认:**`1em`,这会在行/列间空一个字。

**Default:** `1em`, which will leave a space of one Han character between rows/columns. This is suitable if you have

如果两个字的名字较多,默认`1em`易引发歧义,可适当增加。

If there are too many two-character names, the default `1em` may cause ambiguity. A larger value would be better.

这两个选项类似[`grid`][grid-gutter],但只有`1em``1.5em``2em`认真测试过。请谨慎使用其它值。

These two arguments are similar to [`grid`][grid-gutter], but only `1em`, `1.5em`, and `2em` are properly tested. Use other values at your own risk.

[grid-gutter]: https://typst.app/docs/reference/layout/grid/#parameters-column-gutter

### 如何记录名字 How to record names

有两种方法。There are two ways.

- `str`:按标准方法处理 Process in the standard way

例 Example: `"张飞"`

- `((span, overflow), …)`:不再自动处理名字或计算列数 Do not touch the name or calculate the span automatically

例 Example: `((span: 1, overflow: false), "张 飞")`

- `span`:这个名字占据的列数 The amount of columns spanned by this name

**默认:**`1`

**Default:** `1`

- `overflow`:是否允许溢出到列间 Whether to allow overflowing into the column gutter

**默认:**`false`

**Default:** `false`

此外,`((span: 1, overflow: false), […])`可被省略成`[…]`

Besides, `((span: 1, overflow: false), […])` can be shortened into `[…]`.

![](./assets/3.png)

## 实现细节 Implementation detail

`#tricorder(…)`始终生成块级容器,但固定列数和自动列数的实现不同。

`#tricorder(…)` always gives a block-level container, but the implementation of fixed columns and auto columns are different.

- `#tricorder(columns: 2, …)`

```typst
#grid(
columns: (3em,) * 2,
column-gutter: column-gutter,
row-gutter: row-gutter,
[孔乙己], [孔乙己],
)
```

- `#tricorder(columns: auto, …)`

```typst
#set par(leading: row-gutter)
#block(
box(width: 3em, "孔乙己"),
h(column-gutter, weak: true),
box(width: 3em, "孔乙己"),
)
```

固定列数会略快一点。

Fixed columns would be slightly faster.
Binary file added packages/preview/tricorder/0.1.0/assets/1.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added packages/preview/tricorder/0.1.0/assets/2.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added packages/preview/tricorder/0.1.0/assets/3.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions packages/preview/tricorder/0.1.0/src/lib.typ
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
#import "./tricorder.typ": tricorder
158 changes: 158 additions & 0 deletions packages/preview/tricorder/0.1.0/src/tricorder.typ
Original file line number Diff line number Diff line change
@@ -0,0 +1,158 @@
/// U+3000 CJK Symbols and Punctuation IDEOGRAPHIC SPACE
#let SPACE = "\u{3000}"

/// Insert a space for 2-character names.
/// Do nothing for other names
///
/// - name (str):
/// -> str
#let fill-name(name) = {
// Name without the annotation
let bare = name.match(regex("^[^(]+")).text

if bare.clusters().len() == 2 {
let (a, ..b) = name.clusters()
(a, SPACE, ..b).join()
} else {
name
}
}

/// Measure the number of cells that will be occupied by the `name`
///
/// - name (str):
/// - column-gutter (length):
/// -> span (int):
/// -> overflow (bool):
#let measure-span(name, column-gutter) = {
let len = name
.clusters()
// TODO: Hard-coded
.map(c => if "·,()".contains(c) {
0.5em
} else { 1em })
.sum()

let span = 1 + calc.floor(len / (3em + column-gutter))
(
span: span,
overflow: span != calc.ceil((len + column-gutter) / (3em + column-gutter)),
)
}

/// Put blocks before a wall
/// - blocks (array): A list of ((span, overflow), content)
/// - wall (int): Number of available cells in each row
/// -> array
#let put-before-wall(blocks, wall) = {
let result = ()
// Rest space to the wall
let rest = wall

for ((span, overflow), value) in blocks {
assert(
span + int(overflow) <= wall,
message: "impossible to place such a long block: (span: "
+ repr(span)
+ ", overflow: "
+ repr(overflow)
+ ", "
+ repr(value)
+ ")",
)

if span + int(overflow) > rest {
if rest > 0 {
// Fill the rest space with empty blocks
result.push(((span: rest, overflow: false), none))
}
// Start a new row
rest = wall
}

// Put a block
result.push(((span: span, overflow: overflow), value))
rest -= span
}

result
}

#let tricorder(columns: auto, column-gutter: 1em, row-gutter: 1em, ..names) = {
assert(names.named().len() == 0)
let names = names.pos()
assert(columns == auto or (type(columns) == int and columns > 0))

// Convert `names` to a list of `((span, overflow), name)`

let default-span = (span: 1, overflow: false)
let spans-and-names = names
.map(n => if type(n) == str {
// Fill name for regular names
fill-name(n)
} else {
// Skip others
n
})
.map(n => if type(n) == str {
// Measure span for regular names
(measure-span(n, column-gutter), n)
} else if type(n) != array {
// Set default span for content-ish items
(default-span, n)
} else {
// Parse others
assert(
n.len() == 2
and type(n.first()) == dictionary
and (not n.first().keys().contains("span") or (type(n.first().span) == int and n.first().span > 0))
and (not n.first().keys().contains("overflow") or type(n.first().overflow) == bool),
message: "fail to parse as ((span, overflow), name): " + repr(n),
)
let (span, name) = n
(default-span + span, name)
})

// TODO: Hard-coded
show "": it => h(-0.5em) + it
show regex("[,)]"): it => it + h(-0.5em)

// Write out contents

if columns == auto {
// Auto columns
block({
set par(leading: row-gutter)

// The whole block can be arbitrarily aligned,
// but its last line is always aligned left.
set align(start)

spans-and-names
.map((((span, overflow), name)) => (
// If not overflow, write `name` and a weak gutter.
// Otherwise, write `name` and the gutter into a single box.
box(
width: (3em + column-gutter) * span - if not overflow { column-gutter } else { 0em },
name,
),
if not overflow { h(column-gutter, weak: true) } else { none },
))
.flatten()
.join()
})
} else {
// Fixed columns
grid(
columns: (3em,) * columns,
column-gutter: column-gutter,
row-gutter: row-gutter,
align: start,
..put-before-wall(spans-and-names, columns).map((((span, overflow), name)) => grid.cell(
colspan: span,
inset: if overflow { (right: -column-gutter) } else { (:) },
name,
))
)
}
}
16 changes: 16 additions & 0 deletions packages/preview/tricorder/0.1.0/typst.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
[package]
name = "tricorder"
version = "0.1.0"
entrypoint = "src/lib.typ"
authors = ["Y.D.X."]
license = "MIT"
description = "按占三格的节奏记录中文人名(花名册)Record Chinese names with a rhythm of three characters"
repository = "https://github.com/YDX-2147483647/typst-tricorder"
categories = [
"components",
"layout",
"languages",
]
exclude = [
"assets",
]

0 comments on commit aa2a4ba

Please sign in to comment.