From e4ed9defb1b7ad42c53669ef1496924f6fb35659 Mon Sep 17 00:00:00 2001 From: Myriad-Dreamin <35292584+Myriad-Dreamin@users.noreply.github.com> Date: Thu, 1 May 2025 18:48:29 +0800 Subject: [PATCH] refactor: tidy up main and let converter know the target (#1729) --- crates/typlite/src/common.rs | 3 +- crates/typlite/src/lib.rs | 14 ++-- crates/typlite/src/main.rs | 133 ++++++++--------------------------- crates/typlite/src/tests.rs | 9 ++- 4 files changed, 48 insertions(+), 111 deletions(-) diff --git a/crates/typlite/src/common.rs b/crates/typlite/src/common.rs index ddfcc861..0b9e3ffe 100644 --- a/crates/typlite/src/common.rs +++ b/crates/typlite/src/common.rs @@ -15,8 +15,9 @@ pub enum ListState { } /// Valid formats for the conversion. -#[derive(Debug, Clone, Copy, PartialEq, Eq)] +#[derive(Default, Debug, Clone, Copy, PartialEq, Eq)] pub enum Format { + #[default] Md, LaTeX, #[cfg(feature = "docx")] diff --git a/crates/typlite/src/lib.rs b/crates/typlite/src/lib.rs index 69c97a80..2c29d056 100644 --- a/crates/typlite/src/lib.rs +++ b/crates/typlite/src/lib.rs @@ -127,6 +127,8 @@ pub struct TypliteFeat { pub soft_error: bool, /// Remove HTML tags from the output. pub remove_html: bool, + /// The target to convert + pub target: Format, } /// Task builder for converting a typst document to Markdown. @@ -166,8 +168,8 @@ impl Typlite { /// Convert the content to a markdown string. pub fn convert(self) -> Result { match self.format { - Format::Md => self.convert_doc()?.to_md_string(), - Format::LaTeX => self.convert_doc()?.to_tex_string(true), + Format::Md => self.convert_doc(Format::Md)?.to_md_string(), + Format::LaTeX => self.convert_doc(Format::LaTeX)?.to_tex_string(true), #[cfg(feature = "docx")] Format::Docx => Err("docx format is not supported".into()), } @@ -179,11 +181,11 @@ impl Typlite { if self.format != Format::Docx { return Err("format is not DOCX".into()); } - self.convert_doc()?.to_docx() + self.convert_doc(Format::Docx)?.to_docx() } /// Convert the content to a markdown document. - pub fn convert_doc(self) -> Result { + pub fn convert_doc(self, format: Format) -> Result { let entry = self.world.entry_state(); let main = entry.main(); let current = main.ok_or("no main file in workspace")?; @@ -236,7 +238,9 @@ impl Typlite { let base = typst::compile(&world) .output .map_err(|err| format!("convert source for main file: {err:?}"))?; - Ok(MarkdownDocument::new(base, self.feat)) + let mut feat = self.feat; + feat.target = format; + Ok(MarkdownDocument::new(base, feat)) } } diff --git a/crates/typlite/src/main.rs b/crates/typlite/src/main.rs index 651f4307..360e5430 100644 --- a/crates/typlite/src/main.rs +++ b/crates/typlite/src/main.rs @@ -10,6 +10,7 @@ use clap::Parser; use tinymist_project::WorldProvider; use typlite::{common::Format, TypliteFeat}; use typlite::{CompileOnceArgs, Typlite}; +use typst::foundations::Bytes; /// Common arguments of compile, watch, and query. #[derive(Debug, Clone, Parser, Default)] @@ -17,9 +18,9 @@ pub struct CompileArgs { #[clap(flatten)] pub compile: CompileOnceArgs, - /// Path to output file(s) - #[clap(value_name = "OUTPUT", action = clap::ArgAction::Append)] - pub outputs: Vec, + /// Path to output file + #[clap(value_name = "OUTPUT", default_value = None)] + pub output: Option, /// Configures the path of assets directory #[clap(long, default_value = None, value_name = "ASSETS_PATH")] @@ -36,13 +37,17 @@ fn main() -> typlite::Result<()> { .as_ref() .ok_or("Missing required argument: INPUT")?; - let outputs = if args.outputs.is_empty() { - vec![Path::new(input) - .with_extension("md") - .to_string_lossy() - .to_string()] - } else { - args.outputs.clone() + let is_stdout = args.output.as_deref() == Some("-"); + let output_path = args + .output + .map(PathBuf::from) + .unwrap_or_else(|| Path::new(input).with_extension("md")); + + let output_format = match output_path.extension() { + Some(ext) if ext == std::ffi::OsStr::new("tex") => Format::LaTeX, + #[cfg(feature = "docx")] + Some(ext) if ext == std::ffi::OsStr::new("docx") => Format::Docx, + _ => Format::Md, }; let assets_path = match args.assets_path { @@ -65,102 +70,22 @@ fn main() -> typlite::Result<()> { assets_path: assets_path.clone(), ..Default::default() }); - let doc = match converter.convert_doc() { - Ok(doc) => doc, - Err(err) => return Err(format!("failed to convert document: {err}").into()), + let doc = converter.convert_doc(output_format)?; + + let result = match output_format { + Format::Md => Bytes::from_string(doc.to_md_string()?), + Format::LaTeX => Bytes::from_string(doc.to_tex_string(true)?), + #[cfg(feature = "docx")] + Format::Docx => Bytes::new(doc.to_docx()?), }; - for output_path in &outputs { - let is_stdout = output_path == "-"; - let output = if is_stdout { - None - } else { - Some(PathBuf::from(output_path)) - }; - - let format = match &output { - Some(output) if output.extension() == Some(std::ffi::OsStr::new("tex")) => { - Format::LaTeX - } - #[cfg(feature = "docx")] - Some(output) if output.extension() == Some(std::ffi::OsStr::new("docx")) => { - Format::Docx - } - _ => Format::Md, - }; - - match format { - #[cfg(feature = "docx")] - Format::Docx => { - let docx_data = match doc.to_docx() { - Ok(data) => data, - Err(err) => { - eprintln!("Error generating DOCX for {}: {}", output_path, err); - continue; - } - }; - - match output { - None => { - eprintln!("output file is required for DOCX format"); - continue; - } - Some(output) => { - if let Err(err) = std::fs::write(&output, docx_data) { - eprintln!("failed to write DOCX file {}: {}", output.display(), err); - continue; - } - println!("Generated DOCX file: {}", output.display()); - } - } - } - Format::LaTeX => { - let result = doc.to_tex_string(true); - match (result, output) { - (Ok(content), None) => { - std::io::stdout() - .write_all(content.as_str().as_bytes()) - .unwrap(); - } - (Ok(content), Some(output)) => { - if let Err(err) = std::fs::write(&output, content.as_str()) { - eprintln!("failed to write LaTeX file {}: {}", output.display(), err); - continue; - } - println!("Generated LaTeX file: {}", output.display()); - } - (Err(err), _) => { - eprintln!("Error converting to LaTeX for {}: {}", output_path, err); - continue; - } - } - } - Format::Md => { - let result = doc.to_md_string(); - match (result, output) { - (Ok(content), None) => { - std::io::stdout() - .write_all(content.as_str().as_bytes()) - .unwrap(); - } - (Ok(content), Some(output)) => { - if let Err(err) = std::fs::write(&output, content.as_str()) { - eprintln!( - "failed to write Markdown file {}: {}", - output.display(), - err - ); - continue; - } - println!("Generated Markdown file: {}", output.display()); - } - (Err(err), _) => { - eprintln!("Error converting to Markdown for {}: {}", output_path, err); - continue; - } - } - } - } + if is_stdout { + std::io::stdout().write_all(result.as_slice()).unwrap(); + } else if let Err(err) = std::fs::write(&output_path, result.as_slice()) { + Err(format!( + "failed to write file {}: {err}", + output_path.display() + ))?; } Ok(()) diff --git a/crates/typlite/src/tests.rs b/crates/typlite/src/tests.rs index fc05424e..75cdfcfb 100644 --- a/crates/typlite/src/tests.rs +++ b/crates/typlite/src/tests.rs @@ -81,6 +81,13 @@ impl ConvKind { ConvKind::LaTeX => false, } } + + fn kind(&self) -> Format { + match self { + ConvKind::Md { .. } => Format::Md, + ConvKind::LaTeX => Format::LaTeX, + } + } } fn conv(world: LspWorld, kind: ConvKind) -> String { @@ -88,7 +95,7 @@ fn conv(world: LspWorld, kind: ConvKind) -> String { annotate_elem: kind.for_docs(), ..Default::default() }); - let doc = match converter.convert_doc() { + let doc = match converter.convert_doc(kind.kind()) { Ok(doc) => doc, Err(err) => return format!("failed to convert to markdown: {err}"), };