Use new typst rendering in /test endpoint

This commit is contained in:
Joscha 2025-02-28 23:10:31 +01:00
parent 8526566f39
commit 428b825e43
15 changed files with 128 additions and 14 deletions

View file

@ -1,5 +1,6 @@
{ {
"[html]": { "[html]": { "editor.defaultFormatter": "esbenp.prettier-vscode" },
"editor.defaultFormatter": "esbenp.prettier-vscode" "[json]": { "editor.defaultFormatter": "esbenp.prettier-vscode" },
} "[jsonc]": { "editor.defaultFormatter": "esbenp.prettier-vscode" },
"tinymist.fontPaths": ["showbits-assets/data"]
} }

1
Cargo.lock generated
View file

@ -2514,6 +2514,7 @@ dependencies = [
"serde", "serde",
"showbits-assets", "showbits-assets",
"showbits-common", "showbits-common",
"showbits-typst",
"taffy", "taffy",
"tokio", "tokio",
] ]

View file

@ -28,6 +28,7 @@ rust-embed = "8.5.0"
serde = { version = "1.0.218", features = ["derive"] } serde = { version = "1.0.218", features = ["derive"] }
showbits-assets.path = "./showbits-assets" showbits-assets.path = "./showbits-assets"
showbits-common.path = "./showbits-common" showbits-common.path = "./showbits-common"
showbits-typst.path = "./showbits-typst"
tokio = "1.43.0" tokio = "1.43.0"
typst = "0.13.0" typst = "0.13.0"
typst-assets = { version = "0.13.0", features = ["fonts"] } typst-assets = { version = "0.13.0", features = ["fonts"] }

View file

@ -17,6 +17,7 @@ rust-embed = { workspace = true }
serde = { workspace = true } serde = { workspace = true }
showbits-assets = { workspace = true } showbits-assets = { workspace = true }
showbits-common = { workspace = true } showbits-common = { workspace = true }
showbits-typst = { workspace = true }
taffy = { workspace = true } taffy = { workspace = true }
tokio = { workspace = true, features = ["full"] } tokio = { workspace = true, features = ["full"] }

View file

@ -0,0 +1,9 @@
use showbits_typst::Typst;
pub use self::text::*;
mod text;
fn typst_with_lib() -> Typst {
Typst::new().with_file("/lib.typ", include_str!("documents/lib.typ"))
}

View file

@ -0,0 +1,21 @@
#let init(it) = {
set page(
width: 384pt,
height: auto,
margin: (x: 0pt, y: 4pt),
)
set text(
font: ("Unifont", "Unifont-JP", "Unifont Upper"),
size: 16pt,
fallback: false,
)
set par(
leading: 8pt, // Between lines
spacing: 26pt, // Between paragraphs
)
it
}
// Determined by experiments so that the top and bottom white border are roughly
// the same size after tearing off the paper.
#let feed = v(64pt + 32pt)

View file

@ -0,0 +1,5 @@
{
"text": "Hello world! äöüßÄÖÜẞ😒\nSecond line\nThird line\n\nNew paragraph, with a very long line that hopefully will be word wrapped if everything goes according to plan.\n\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAH",
"force_wrap": true,
"feed": true
}

View file

@ -0,0 +1 @@
../lib.typ

View file

@ -0,0 +1,13 @@
#import "lib.typ";
#show: it => lib.init(it)
#let data = json("data.json")
#if data.at("force_wrap", default: false) {
show regex("."): it => it + sym.zws
data.text
} else { data.text }
#if data.at("feed", default: false) {
lib.feed
}

View file

@ -0,0 +1,19 @@
use serde::{Deserialize, Serialize};
use showbits_typst::Typst;
#[derive(Serialize, Deserialize)]
pub struct Text {
pub text: String,
#[serde(default)]
pub force_wrap: bool,
#[serde(default)]
pub feed: bool,
}
impl From<Text> for Typst {
fn from(value: Text) -> Self {
super::typst_with_lib()
.with_json("/data.json", &value)
.with_main_file(include_str!("main.typ"))
}
}

View file

@ -4,6 +4,7 @@ mod cells;
mod chat_message; mod chat_message;
mod egg; mod egg;
mod image; mod image;
mod new_typst;
mod photo; mod photo;
mod text; mod text;
mod tictactoe; mod tictactoe;
@ -16,8 +17,9 @@ use crate::persistent_printer::PersistentPrinter;
pub use self::{ pub use self::{
backlog::BacklogDrawing, calendar::CalendarDrawing, cells::CellsDrawing, backlog::BacklogDrawing, calendar::CalendarDrawing, cells::CellsDrawing,
chat_message::ChatMessageDrawing, egg::EggDrawing, image::ImageDrawing, photo::PhotoDrawing, chat_message::ChatMessageDrawing, egg::EggDrawing, image::ImageDrawing,
text::TextDrawing, tictactoe::TicTacToeDrawing, typst::TypstDrawing, new_typst::NewTypstDrawing, photo::PhotoDrawing, text::TextDrawing,
tictactoe::TicTacToeDrawing, typst::TypstDrawing,
}; };
pub const FEED: f32 = 96.0; pub const FEED: f32 = 96.0;

View file

@ -0,0 +1,21 @@
use showbits_typst::Typst;
use crate::persistent_printer::PersistentPrinter;
use super::{Context, Drawing};
pub struct NewTypstDrawing(pub Typst);
impl NewTypstDrawing {
pub fn new(typst: impl Into<Typst>) -> Self {
Self(typst.into())
}
}
impl Drawing for NewTypstDrawing {
fn draw(&self, printer: &mut PersistentPrinter, _ctx: &mut Context) -> anyhow::Result<()> {
let image = self.0.render()?;
printer.print_image(&image)?;
Ok(())
}
}

View file

@ -2,6 +2,7 @@ mod drawer;
mod persistent_printer; mod persistent_printer;
mod printer; mod printer;
mod server; mod server;
mod documents;
use std::{path::PathBuf, time::Duration}; use std::{path::PathBuf, time::Duration};

View file

@ -44,7 +44,7 @@ impl PersistentPrinter {
tree.render(ctx, root, available) tree.render(ctx, root, available)
} }
fn print_image(&mut self, image: &RgbaImage) -> anyhow::Result<()> { fn print_image_immediately(&mut self, image: &RgbaImage) -> anyhow::Result<()> {
let Some(printer) = &mut self.printer else { let Some(printer) = &mut self.printer else {
bail!("no printer found"); bail!("no printer found");
}; };
@ -60,12 +60,12 @@ impl PersistentPrinter {
fn print_image_robustly(&mut self, image: &RgbaImage) -> anyhow::Result<()> { fn print_image_robustly(&mut self, image: &RgbaImage) -> anyhow::Result<()> {
println!("Printing image"); println!("Printing image");
if self.print_image(image).is_ok() { if self.print_image_immediately(image).is_ok() {
return Ok(()); return Ok(());
} }
println!("First attempt failed, reconnecting and retrying"); println!("First attempt failed, reconnecting and retrying");
self.reconnect_printer()?; self.reconnect_printer()?;
self.print_image(image)?; self.print_image_immediately(image)?;
Ok(()) Ok(())
} }
@ -86,6 +86,13 @@ impl PersistentPrinter {
Ok(()) Ok(())
} }
pub fn print_image(&mut self, image: &RgbaImage) -> anyhow::Result<()> {
if self.print_image_robustly(image).is_err() {
self.enqueue_image(image)?;
}
Ok(())
}
pub fn print_tree<C>( pub fn print_tree<C>(
&mut self, &mut self,
tree: &mut Tree<C>, tree: &mut Tree<C>,
@ -93,9 +100,7 @@ impl PersistentPrinter {
root: NodeId, root: NodeId,
) -> anyhow::Result<()> { ) -> anyhow::Result<()> {
let image = Self::render_tree_to_image(tree, ctx, root)?; let image = Self::render_tree_to_image(tree, ctx, root)?;
if self.print_image_robustly(&image).is_err() { self.print_image(&image)?;
self.enqueue_image(&image)?;
}
Ok(()) Ok(())
} }

View file

@ -13,9 +13,12 @@ use serde::Deserialize;
use showbits_common::widgets::DitherAlgorithm; use showbits_common::widgets::DitherAlgorithm;
use tokio::{net::TcpListener, sync::mpsc}; use tokio::{net::TcpListener, sync::mpsc};
use crate::drawer::{ use crate::{
documents::Text,
drawer::{
CalendarDrawing, CellsDrawing, ChatMessageDrawing, Command, EggDrawing, ImageDrawing, CalendarDrawing, CellsDrawing, ChatMessageDrawing, Command, EggDrawing, ImageDrawing,
PhotoDrawing, TextDrawing, TicTacToeDrawing, TypstDrawing, NewTypstDrawing, PhotoDrawing, TextDrawing, TicTacToeDrawing, TypstDrawing,
},
}; };
use self::{r#static::get_static_file, statuscode::status_code}; use self::{r#static::get_static_file, statuscode::status_code};
@ -36,6 +39,7 @@ pub async fn run(tx: mpsc::Sender<Command>, addr: String) -> anyhow::Result<()>
.route("/text", post(post_text)) .route("/text", post(post_text))
.route("/tictactoe", post(post_tictactoe)) .route("/tictactoe", post(post_tictactoe))
.route("/typst", post(post_typst).fallback(get_static_file)) .route("/typst", post(post_typst).fallback(get_static_file))
.route("/test", post(post_test).fallback(get_static_file))
.fallback(get(get_static_file)) .fallback(get(get_static_file))
.layer(DefaultBodyLimit::max(32 * 1024 * 1024)) // 32 MiB .layer(DefaultBodyLimit::max(32 * 1024 * 1024)) // 32 MiB
.with_state(Server { tx }); .with_state(Server { tx });
@ -222,3 +226,12 @@ async fn post_typst(server: State<Server>, request: Form<PostTypstForm>) {
.send(Command::draw(TypstDrawing(request.0.source))) .send(Command::draw(TypstDrawing(request.0.source)))
.await; .await;
} }
// /test
async fn post_test(server: State<Server>, request: Form<Text>) {
let _ = server
.tx
.send(Command::draw(NewTypstDrawing::new(request.0)))
.await;
}