Skip to content

Commit

Permalink
Merge pull request #3 from PgBiel/adapt-to-pkg-manager
Browse files Browse the repository at this point in the history
Oxifmt v0.2.0 (submit to package manager)
  • Loading branch information
PgBiel authored Aug 3, 2023
2 parents e768e0c + 450472c commit 9c0e0e4
Show file tree
Hide file tree
Showing 5 changed files with 37 additions and 23 deletions.
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
typst-oxifmt.pdf
oxifmt.pdf
strfmt-tests.pdf
50 changes: 32 additions & 18 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# typst-oxifmt (v0.1.0)
# typst-oxifmt (v0.2.0)

A Typst library that brings convenient string formatting and interpolation through the `strfmt` function. Its syntax is taken directly from Rust's `format!` syntax, so feel free to read its page for more information (https://doc.rust-lang.org/std/fmt/); however, this README should have enough information and examples for all expected uses of the library. Only a few things aren't supported from the Rust syntax, such as the `p` (pointer) format type, or the `.*` precision specifier.

Expand All @@ -19,21 +19,27 @@ A few extras (beyond the Rust-like syntax) will be added over time, though (feel

## Usage

Download the `typst-oxifmt.typ` file either from Releases or directly from the repository. Then, move it to your project's folder, and write at the top of your typst file(s):
You can use this library through Typst's package manager (for Typst v0.6.0+):

```js
#import "typst-oxifmt.typ": strfmt
#import "@preview/oxifmt:0.2.0": strfmt
```

For older Typst versions, download the `oxifmt.typ` file either from Releases or directly from the repository. Then, move it to your project's folder, and write at the top of your Typst file(s):

```js
#import "oxifmt.typ": strfmt
```

Doing the above will give you access to the main function provided by this library (`strfmt`), which accepts a format string, followed by zero or more replacements to insert in that string (according to `{...}` formats inserted in that string), an optional `fmt-decimal-separator` parameter, and returns the formatted string, as described below.

Its syntax is almost identical to Rust's `format!` (as specified here: https://doc.rust-lang.org/std/fmt/). You can escape formats by duplicating braces (`{{` and `}}` become `{` and `}`). Here's an example (see more examples in the file `tests/strfmt-tests.typ`):

```js
#import "typst-oxifmt.typ": strfmt
#import "@preview/oxifmt:0.2.0": strfmt

let s = strfmt("I'm {}. I have {num} cars. I'm {0}. {} is {{cool}}.", "John", "Carl", num: 10)
assert.eq(s, "I'm John. I have 10 cars. I'm John. Carl is {cool}.")
#let s = strfmt("I'm {}. I have {num} cars. I'm {0}. {} is {{cool}}.", "John", "Carl", num: 10)
#assert.eq(s, "I'm John. I have 10 cars. I'm John. Carl is {cool}.")
```

Note that `{}` extracts positional arguments after the string sequentially (the first `{}` extracts the first one, the second `{}` extracts the second one, and so on), while `{0}`, `{1}`, etc. will always extract the first, the second etc. positional arguments after the string. Additionally, `{bananas}` will extract the named argument "bananas".
Expand Down Expand Up @@ -68,7 +74,7 @@ You can use `{:spec}` to customize your output. See the Rust docs linked above f
Some examples:

```js
#import "typst-oxifmt.typ": strfmt
#import "@preview/oxifmt:0.2.0": strfmt

#let s1 = strfmt("{0:?}, {test:+012e}, {1:-<#8x}", "hi", -74, test: 569.4)
#assert.eq(s1, "\"hi\", +00005.694e2, -0x4a---")
Expand All @@ -84,31 +90,31 @@ Some examples:

- **Inserting labels, text and numbers into strings:**
```js
#import "typst-oxifmt.typ": strfmt
#import "@preview/oxifmt:0.2.0": strfmt

#let s = strfmt("First: {}, Second: {}, Fourth: {3}, Banana: {banana} (brackets: {{escaped}})", 1, 2.1, 3, label("four"), banana: "Banana!!")
#assert.eq(s, "First: 1, Second: 2.1, Fourth: four, Banana: Banana!! (brackets: {escaped})")
```

- **Forcing `repr()` with `{:?}`** (which adds quotes around strings, and other things - basically represents a Typst value):
```js
#import "typst-oxifmt.typ": strfmt
#import "@preview/oxifmt:0.2.0": strfmt

#let s = strfmt("The value is: {:?} | Also the label is {:?}", "something", label("label"))
#assert.eq(s, "The value is: \"something\" | Also the label is <label>")
```

- **Inserting other types than numbers and strings** (for now, they will always use `repr()`, even without `{...:?}`, although that is more explicit):
```js
#import "typst-oxifmt.typ": strfmt
#import "@preview/oxifmt:0.2.0": strfmt

#let s = strfmt("Values: {:?}, {1:?}, {stuff:?}", (test: 500), ("a", 5.1), stuff: [a])
#assert.eq(s, "Values: (test: 500), (\"a\", 5.1), [a]")
```

- **Padding to a certain width with characters:** Use `{:x<8}`, where `x` is the **character to pad with** (e.g. space or `_`, but can be anything), `<` is the **alignment of the original text** relative to the padding (can be `<` for left aligned (padding goes to the right), `>` for right aligned (padded to its left) and `^` for center aligned (padded at both left and right)), and `8` is the **desired total width** (padding will add enough characters to reach this width; if the replacement string already has this width, no padding will be added):
```js
#import "typst-oxifmt.typ": strfmt
#import "@preview/oxifmt:0.2.0": strfmt

#let s = strfmt("Left5 {:_<5}, Right6 {:*>6}, Center10 {centered: ^10?}, Left3 {tleft:_<3}", "xx", 539, tleft: "okay", centered: [a])
#assert.eq(s, "Left5 xx___, Right6 ***539, Center10 [a] , Left3 okay")
Expand All @@ -117,23 +123,23 @@ Some examples:

- **Padding numbers with zeroes to the left:** It's a similar functionality to the above, however you write `{:08}` for 8 characters (for instance) - note that any characters in the number's representation matter for width (including sign, dot and decimal part):
```js
#import "typst-oxifmt.typ": strfmt
#import "@preview/oxifmt:0.2.0": strfmt

#let s = strfmt("Left-padded7 numbers: {:07} {:07} {:07} {3:07}", 123, -344, 44224059, 45.32)
#assert.eq(s, "Left-padded7 numbers: 0000123 -000344 44224059 0045.32")
```

- **Defining padding-to width using parameters, not literals:** If you want the desired replacement width (the `8` in `{:08}` or `{: ^8}`) to be passed via parameter (instead of being hardcoded into the format string), you can specify `parameter$` in place of the width, e.g. `{:02$}` to take it from the third positional parameter, or `{:a>banana$}` to take it from the parameter named `banana` - note that the chosen parameter **must be an integer** (desired total width):
```js
#import "typst-oxifmt.typ": strfmt
#import "@preview/oxifmt:0.2.0": strfmt

#let s = strfmt("Padding depending on parameter: {0:02$} and {0:a>banana$}", 432, 0, 5, banana: 9)
#assert.eq(s, "Padding depending on parameter: 00432 aaaaaa432") // widths 5 and 9
```

- **Displaying `+` on positive numbers:** Just add a `+` at the "beginning", i.e., before the `#0` (if either is there), or after the custom fill and align (if it's there and not `0` - see [Grammar](#grammar) for the exact positioning), like so:
```js
#import "typst-oxifmt.typ": strfmt
#import "@preview/oxifmt:0.2.0": strfmt

#let s = strfmt("Some numbers: {:+} {:+08}; With fill and align: {:_<+8}; Negative (no-op): {neg:+}", 123, 456, 4444, neg: -435)
#assert.eq(s, "Some numbers: +123 +0000456; With fill and align: +4444___; Negative (no-op): -435")
Expand All @@ -142,31 +148,31 @@ Some examples:

- **Converting numbers to bases 2, 8 and 16:** Use one of the following specifier types (i.e., characters which always go at the very end of the format): `b` (binary), `o` (octal), `x` (lowercase hexadecimal) or `X` (uppercase hexadecimal). You can also add a `#` between `+` and `0` (see the exact position at the [Grammar](#grammar)) to display a **base prefix** before the number (i.e. `0b` for binary, `0o` for octal and `0x` for hexadecimal):
```js
#import "typst-oxifmt.typ": strfmt
#import "@preview/oxifmt:0.2.0": strfmt

#let s = strfmt("Bases (10, 2, 8, 16(l), 16(U):) {0} {0:b} {0:o} {0:x} {0:X} | W/ prefixes and modifiers: {0:#b} {0:+#09o} {0:_>+#9X}", 124)
#assert.eq(s, "Bases (10, 2, 8, 16(l), 16(U):) 124 1111100 174 7c 7C | W/ prefixes and modifiers: 0b1111100 +0o000174 ____+0x7C")
```

- **Picking float precision (right-extending with zeroes):** Add, at the end of the format (just before the spec type (such as `?`), if there's any), either `.precision` (hardcoded, e.g. `.8` for 8 decimal digits) or `.parameter$` (taking the precision value from the specified parameter, like with `width`):
```js
#import "typst-oxifmt.typ": strfmt
#import "@preview/oxifmt:0.2.0": strfmt

#let s = strfmt("{0:.8} {0:.2$} {0:.potato$}", 1.234, 0, 2, potato: 5)
#assert.eq(s, "1.23400000 1.23 1.23400")
```

- **Scientific notation:** Use `e` (lowercase) or `E` (uppercase) as specifier types (can be combined with precision):
```js
#import "typst-oxifmt.typ": strfmt
#import "@preview/oxifmt:0.2.0": strfmt

#let s = strfmt("{0:e} {0:E} {0:+.9e} | {1:e} | {2:.4E}", 124.2312, 50, -0.02)
#assert.eq(s, "1.242312e2 1.242312E2 +1.242312000e2 | 5e1 | -2.0000E-2")
```

- **Customizing the decimal separator on floats:** Just specify `fmt-decimal-separator: ","` (comma as an example):
```js
#import "typst-oxifmt.typ": strfmt
#import "@preview/oxifmt:0.2.0": strfmt

#let s = strfmt("{0} {0:.6} {0:.5e}", 1.432, fmt-decimal-separator: ",")
#assert.eq(s, "1,432 1,432000 1,43200e0")
Expand Down Expand Up @@ -208,6 +214,14 @@ The tests succeeded if you received no error messages from the last command (ple

## Changelog

### v0.2.0

- The package's name is now `oxifmt`!
- `oxifmt:0.2.0` is now available through Typst's Package Manager! You can now write `#import "@preview/oxifmt:0.2.0": strfmt` to use the library.
- Greatly improved the README, adding a section for common examples.
- Fixed negative numbers being formatted with two minus signs.
- Fixed custom precision of floats not working when they are exact integers.

### v0.1.0

- Initial release, added `strfmt`.
Expand Down
4 changes: 2 additions & 2 deletions typst-oxifmt.typ → oxifmt.typ
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// typst-oxifmt v0.1.1 (WIP)
// oxifmt v0.2.0
#let _strfmt_formatparser(s) = {
if type(s) != "string" {
panic("String format parsing internal error: String format parser given non-string.")
Expand Down Expand Up @@ -317,7 +317,7 @@ parameter := argument '$'
let valid-specs = ("", "?", "b", "x", "X", "o", "x?", "X?", "e", "E")
let spec-error() = {
panic(
"String formatter error: Unknown spec type '" + spectype + "', from '{" + fullname.replace("{", "{{").replace("}", "}}") + "}'. Valid options include: '" + valid-specs.join("', '") + "'. Maybe you specified some invalid formatting spec syntax (after the ':'), which can also prompt this error. Check the typst-oxifmt docs for more information.")
"String formatter error: Unknown spec type '" + spectype + "', from '{" + fullname.replace("{", "{{").replace("}", "}}") + "}'. Valid options include: '" + valid-specs.join("', '") + "'. Maybe you specified some invalid formatting spec syntax (after the ':'), which can also prompt this error. Check the oxifmt docs for more information.")
}
if spectype not in valid-specs {
spec-error()
Expand Down
2 changes: 1 addition & 1 deletion tests/strfmt-tests.typ
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
#import "../typst-oxifmt.typ": strfmt
#import "../oxifmt.typ": strfmt

#{
// test basics (sequential args, named args, pos args)
Expand Down
2 changes: 1 addition & 1 deletion typst.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,5 @@ version = "0.2.0"
authors = ["PgBiel <https://github.com/PgBiel>"]
license = "MIT-0"
description = "Convenient Rust-like string formatting in Typst"
entrypoint = "typst-oxifmt.typ"
entrypoint = "oxifmt.typ"
repository = "https://github.com/PgBiel/typst-oxifmt"

0 comments on commit 9c0e0e4

Please sign in to comment.