diff --git a/.cargo/config.toml b/.cargo/config.toml new file mode 100644 index 0000000..bcfd1b1 --- /dev/null +++ b/.cargo/config.toml @@ -0,0 +1,2 @@ +[build] +target = ["wasm32-unknown-unknown"] diff --git a/.gitignore b/.gitignore index e69de29..2f7896d 100644 --- a/.gitignore +++ b/.gitignore @@ -0,0 +1 @@ +target/ diff --git a/.typstignore b/.typstignore index 02e6a46..d19ec6a 100644 --- a/.typstignore +++ b/.typstignore @@ -16,3 +16,10 @@ docs/* !docs/*.pdf gallery/* !gallery/*.pdf + +# ignore plugin-related files +.cargo +plugin +target +Cargo.lock +Cargo.toml diff --git a/Cargo.lock b/Cargo.lock new file mode 100644 index 0000000..9cd0830 --- /dev/null +++ b/Cargo.lock @@ -0,0 +1,111 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "adler" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "crc32fast" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b3855a8a784b474f333699ef2bbca9db2c4a1f6d9088a90a2d25b1eb53111eaa" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "flate2" +version = "1.0.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "46303f565772937ffe1d394a4fac6f411c6013172fadde9dcdb1e147a086940e" +dependencies = [ + "crc32fast", + "miniz_oxide", +] + +[[package]] +name = "hex" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" + +[[package]] +name = "miniz_oxide" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d811f3e15f28568be3407c8e7fdb6514c1cda3cb30683f15b6a1a1dc4ea14a7" +dependencies = [ + "adler", +] + +[[package]] +name = "plantuml-url" +version = "0.1.0" +dependencies = [ + "plantuml_encoding", + "wasm-minimal-protocol", +] + +[[package]] +name = "plantuml_encoding" +version = "2.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "46fbad4d55343fcd16dd6089e926f7e42dbd1f96ed5b2aea9cc5948274435eb8" +dependencies = [ + "flate2", + "hex", +] + +[[package]] +name = "proc-macro2" +version = "1.0.79" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e835ff2298f5721608eb1a980ecaee1aef2c132bf95ecc026a11b7bf3c01c02e" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "291ec9ab5efd934aaf503a6466c5d5251535d108ee747472c3977cc5acc868ef" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "unicode-ident" +version = "1.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" + +[[package]] +name = "venial" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61584a325b16f97b5b25fcc852eb9550843a251057a5e3e5992d2376f3df4bb2" +dependencies = [ + "proc-macro2", + "quote", +] + +[[package]] +name = "wasm-minimal-protocol" +version = "0.1.0" +source = "git+https://github.com/astrale-sharp/wasm-minimal-protocol#637508c184c7bfad7caadf109e2fa3871d99c57e" +dependencies = [ + "proc-macro2", + "quote", + "venial", +] diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..920d928 --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,13 @@ +[workspace] +resolver = "2" + +members = [ + "plugin", +] + +[profile.release] +lto = true # Enable link-time optimization +strip = true # Strip symbols from binary* +opt-level = 'z' # Optimize for size +codegen-units = 1 # Reduce number of codegen units to increase optimizations +panic = 'abort' # Abort on panic diff --git a/Justfile b/Justfile index 7d922b7..0a9a2db 100644 --- a/Justfile +++ b/Justfile @@ -9,7 +9,7 @@ default: # generate manual doc: typst compile docs/manual.typ docs/manual.pdf - for f in $(find gallery -maxdepth 1 -name '*.typ'); do typst c "$f"; done + # for f in $(find gallery -maxdepth 1 -name '*.typ'); do typst c "$f"; done # run test suite test *args: @@ -19,6 +19,11 @@ test *args: update *args: typst-test update {{ args }} +# build the PlantUML URL encoding WASM plugin +plugin: + cargo build --release + cp target/wasm32-unknown-unknown/release/plantuml_url.wasm src/ + # package the library into the specified destination folder package target: ./scripts/package "{{target}}" diff --git a/README.md b/README.md index f3493b8..cfca8d7 100644 --- a/README.md +++ b/README.md @@ -1,37 +1,15 @@ -# The `my-package` Package +# pre-plantuml -A short description about the project and/or client. - -## Template adaptation checklist - -- [ ] Fill out `README.md` - - Change the `my-package` package name, including code snippets - - Check section contents and/or delete sections that don't apply -- [ ] Check and/or replace `LICENSE` by something that suits your needs -- [ ] Fill out `typst.toml` - - See also the [typst/packages README](https://github.com/typst/packages/?tab=readme-ov-file#package-format) -- [ ] Adapt Repository URLs in `CHANGELOG.md` - - Consider only committing that file with your first release, or removing the "Initial Release" part in the beginning -- [ ] Adapt or deactivate the release workflow in `.github/workflows/release.yml` - - to deactivate it, delete that file or remove/comment out lines 2-4 (`on:` and following) - - to use the workflow - - [ ] check the values under `env:`, particularly `REGISTRY_REPO` - - [ ] if you don't have one, [create a fine-grained personal access token](https://github.com/settings/tokens?type=beta) with [only Contents permission](https://stackoverflow.com/a/75116350/371191) for the `REGISTRY_REPO` - - [ ] on this repo, create a secret `REGISTRY_TOKEN` (at `https://github.com/[user]/[repo]/settings/secrets/actions`) that contains the so created token - - if configured correctly, whenever you create a tag `v...`, your package will be pushed onto a branch on the `REGISTRY_REPO`, from which you can then create a pull request against [typst/packages](https://github.com/typst/packages/) -- [ ] remove/replace the example test case -- [ ] (add your actual code, docs and tests) -- [ ] remove this section from the README +This package provides a [prequery](https://typst.app/universe/package/prequery) for UML diagrams specified using [PlantUML](https://www.plantuml.com/) syntax. The diagrams can be extracted either as source code, or as URLs to a specific PlantUML Webservice. ## Getting Started To add this package to your project, use this: ```typ -#import "@preview/typst-package-template:0.1.0": * +#import "@preview/pre-plantuml:0.1.0": * -#id[Hello World] +... ``` ## Usage diff --git a/docs/manual.typ b/docs/manual.typ index 8987b08..d05b3aa 100644 --- a/docs/manual.typ +++ b/docs/manual.typ @@ -1,20 +1,20 @@ #import "@preview/tidy:0.3.0" -#import "@preview/crudo:0.1.0" +// #import "@preview/crudo:0.1.0" #import "template.typ": * -#import "/src/lib.typ" as template +#import "/src/lib.typ" as pre-plantuml #let package-meta = toml("/typst.toml").package #let date = none // #let date = datetime(year: ..., month: ..., day: ...) #show: project.with( - title: "Template", + title: "pre-plantuml", // subtitle: "...", authors: package-meta.authors.map(a => a.split("<").at(0).trim()), abstract: [ - A template for typst packages + Extract PlantUML diagrams from Typst documents to be rendered into images. ], url: package-meta.repository, version: package-meta.version, @@ -22,17 +22,15 @@ ) // the scope for evaluating expressions and documentation -#let scope = (template: template) +#let scope = (pre-plantuml: pre-plantuml) = Introduction -This is a template for typst packages. It provides the #ref-fn("template.id()") function: +This package provides two #link("https://typst.app/universe/package/prequery")[prequeries] for using PlantUML in Typst: +- #ref-fn("plantuml-url()") provides the encoded diagram URL to preprocessors for downloading the diagram file; +- #ref-fn("plantuml-source()") provides the diagram source code to preprocessors for generating the diagram image locally. -#{ - let lib = raw(block: true, lang: "typ", read("/src/lib.typ").trim()) - lib = crudo.slice(lib, 4) - lib -} +See the Prequery library documentation for more general information on how this can be used. = Module reference @@ -41,7 +39,7 @@ This is a template for typst packages. It provides the #ref-fn("template.id()") #{ let module = tidy.parse-module( read("/src/lib.typ"), - label-prefix: "template.", + // label-prefix: "pre-plantuml.", scope: scope, ) tidy.show-module( diff --git a/gallery/.gitignore b/gallery/.gitignore new file mode 100644 index 0000000..3ed09ab --- /dev/null +++ b/gallery/.gitignore @@ -0,0 +1 @@ +assets/ \ No newline at end of file diff --git a/gallery/test-fallback.pdf b/gallery/test-fallback.pdf new file mode 100644 index 0000000..2743f4c Binary files /dev/null and b/gallery/test-fallback.pdf differ diff --git a/gallery/test.pdf b/gallery/test.pdf new file mode 100644 index 0000000..11b916b Binary files /dev/null and b/gallery/test.pdf differ diff --git a/gallery/test.typ b/gallery/test.typ new file mode 100644 index 0000000..adb6ecb --- /dev/null +++ b/gallery/test.typ @@ -0,0 +1,25 @@ +// make the PDF reproducible to ease version control +#set document(date: none) + +#import "/src/lib.typ": plantuml-url, plantuml-source +#import "@preview/prequery:0.1.0" +// #import "@preview/pre-plantuml:0.0.1": plantuml-url, plantuml-source + +// toggle this comment or pass `--input prequery-fallback=true` to enable fallback +// #prequery.fallback.update(true) + +#let plantuml = plantuml-url.with("https://www.plantuml.com/plantuml/png/") + += Test + +#plantuml("assets/uml.png", ``` +@startuml +PUML -> RUST: HELLO +@enduml +```) + +#plantuml-source("assets/uml.png", ``` +@startuml +PUML -> RUST: HELLO +@enduml +```) diff --git a/plugin/Cargo.toml b/plugin/Cargo.toml new file mode 100644 index 0000000..0bfabb8 --- /dev/null +++ b/plugin/Cargo.toml @@ -0,0 +1,11 @@ +[package] +name = "plantuml-url" +version = "0.1.0" +edition = "2021" + +[lib] +crate-type = ["cdylib"] + +[dependencies] +wasm-minimal-protocol = { git = "https://github.com/astrale-sharp/wasm-minimal-protocol" } +plantuml_encoding = "2.0.3" diff --git a/plugin/src/lib.rs b/plugin/src/lib.rs new file mode 100644 index 0000000..eb80487 --- /dev/null +++ b/plugin/src/lib.rs @@ -0,0 +1,29 @@ +use std::str; + +use wasm_minimal_protocol::*; +use plantuml_encoding::encode_plantuml_deflate; + +initiate_protocol!(); + +#[wasm_func] +pub fn encode(source: &[u8]) -> Vec { + match encode_impl(source) { + Ok(result) => { + let mut result = result.into_bytes(); + result.insert(0, 1u8); + result + } + Err(result) => { + let mut result = result.into_bytes(); + result.insert(0, 0u8); + result + } + } +} + +fn encode_impl(source: &[u8]) -> Result { + let source = str::from_utf8(source).map_err(|err| format!("{:?}", err))?; + let encoded = encode_plantuml_deflate(source).map_err(|err| err.0)?; + + Ok(encoded) +} diff --git a/src/lib.typ b/src/lib.typ index 43af152..6cac702 100644 --- a/src/lib.typ +++ b/src/lib.typ @@ -1,5 +1,72 @@ -/// The identity function +#import "@preview/prequery:0.1.0": prequery + +#let p = plugin("./plantuml_url.wasm") + +#let encode(source) = { + let source = bytes(source) + let result = p.encode(source) + let (status, result) = (result.at(0), str(result.slice(1))) + assert(status == 1, message: result) + result +} + +/// A prequery for PlantUML diagrams. Apart from the `base-url` and trailing `source` parameter, the +/// image file name is also mandatory; it is part of `args` for technical reasons. Outside fallback +/// mode, rendering this fails when the rendered diagram file is missing; diagrams need to be +/// rendered in a preprocessing step. /// -/// - x (any): some parameter -/// -> any -#let id(x) = x +/// This function provides a dictionary with `url` and `path` as metadata under the label +/// ``. The URL is formed by adding the +/// #link("https://plantuml.com/text-encoding")[encoded form of the diagram] to the base URL. This +/// metadata can be queried like this: +/// +/// ```sh +/// typst query --input prequery-fallback=true --field value ... '' +/// ``` +/// +/// *Fallback:* renders the raw source block. +/// +/// - base-url (string): the PlantUML base URL to be used for generated URLs +/// - ..args (arguments): arguments to be forwarded to `image` +/// - source (raw): the PlantUML source code as a raw block +/// -> content +#let plantuml-url(base-url, ..args, source) = { + let url = base-url + encode(source.text) + let path = args.pos().at(0) + prequery( + (url: url, path: path), + , + image.with(..args), + fallback: source, + ) +} + + +/// A prequery for PlantUML diagrams. Apart from the trailing `source` parameter, the image file +/// name is also mandatory; it is part of `args` for technical reasons. Outside fallback mode, +/// rendering this fails when the rendered diagram file is missing; diagrams need to be rendered in +/// a preprocessing step. +/// +/// This function provides a dictionary with `source` and `path` as metadata under the label +/// ``. The sources are strings that can be given to the +/// #link("https://plantuml.com/command-line#f92fb84f0d5ea07f")[PlantUML CLI] via stdin. This +/// metadata can be queried like this: +/// +/// ```sh +/// typst query --input prequery-fallback=true --field value ... '' +/// ``` +/// +/// *Fallback:* renders the raw source block. +/// +/// - ..args (arguments): arguments to be forwarded to `image` +/// - source (raw): the PlantUML source code as a raw block +/// -> content +#let plantuml-source(..args, source) = { + let path = args.pos().at(0) + prequery( + (source: source.text, path: path), + , + image.with(..args), + fallback: source, + ) +} diff --git a/src/plantuml_url.wasm b/src/plantuml_url.wasm new file mode 100755 index 0000000..0d49f35 Binary files /dev/null and b/src/plantuml_url.wasm differ diff --git a/typst.toml b/typst.toml index 526c486..ed5c3e4 100644 --- a/typst.toml +++ b/typst.toml @@ -1,7 +1,7 @@ # for a description of available keys, see https://github.com/typst/packages/?tab=readme-ov-file#package-format [package] -name = "my-package" +name = "pre-plantuml" version = "0.0.1" entrypoint = "src/lib.typ" authors = [ @@ -10,11 +10,11 @@ authors = [ license = "MIT" description = "template package" # homepage = "" -repository = "https://github.com/SillyFreak/typst-package-template" -keywords = [] -categories = [] +repository = "https://github.com/SillyFreak/typst-pre-plantuml" +keywords = ["uml", "diagram", "software", "modelling"] +categories = ["visualization"] disciplines = [] -compiler = "" +compiler = "0.11" exclude = ["README.md", "CHANGELOG.md", "Justfile", "docs", "gallery"] # [template]