这是indexloc提供的服务,不要输入任何密码
Skip to content

Oxifmt v0.2.0 (submit to package manager) #3

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 6 commits into from
Aug 3, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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"