refactor: tidy up main and let converter know the target (#1729)

This commit is contained in:
Myriad-Dreamin 2025-05-01 18:48:29 +08:00 committed by GitHub
parent d85bd7428a
commit e4ed9defb1
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 48 additions and 111 deletions

View file

@ -15,8 +15,9 @@ pub enum ListState {
} }
/// Valid formats for the conversion. /// Valid formats for the conversion.
#[derive(Debug, Clone, Copy, PartialEq, Eq)] #[derive(Default, Debug, Clone, Copy, PartialEq, Eq)]
pub enum Format { pub enum Format {
#[default]
Md, Md,
LaTeX, LaTeX,
#[cfg(feature = "docx")] #[cfg(feature = "docx")]

View file

@ -127,6 +127,8 @@ pub struct TypliteFeat {
pub soft_error: bool, pub soft_error: bool,
/// Remove HTML tags from the output. /// Remove HTML tags from the output.
pub remove_html: bool, pub remove_html: bool,
/// The target to convert
pub target: Format,
} }
/// Task builder for converting a typst document to Markdown. /// Task builder for converting a typst document to Markdown.
@ -166,8 +168,8 @@ impl Typlite {
/// Convert the content to a markdown string. /// Convert the content to a markdown string.
pub fn convert(self) -> Result<ecow::EcoString> { pub fn convert(self) -> Result<ecow::EcoString> {
match self.format { match self.format {
Format::Md => self.convert_doc()?.to_md_string(), Format::Md => self.convert_doc(Format::Md)?.to_md_string(),
Format::LaTeX => self.convert_doc()?.to_tex_string(true), Format::LaTeX => self.convert_doc(Format::LaTeX)?.to_tex_string(true),
#[cfg(feature = "docx")] #[cfg(feature = "docx")]
Format::Docx => Err("docx format is not supported".into()), Format::Docx => Err("docx format is not supported".into()),
} }
@ -179,11 +181,11 @@ impl Typlite {
if self.format != Format::Docx { if self.format != Format::Docx {
return Err("format is not DOCX".into()); 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. /// Convert the content to a markdown document.
pub fn convert_doc(self) -> Result<MarkdownDocument> { pub fn convert_doc(self, format: Format) -> Result<MarkdownDocument> {
let entry = self.world.entry_state(); let entry = self.world.entry_state();
let main = entry.main(); let main = entry.main();
let current = main.ok_or("no main file in workspace")?; let current = main.ok_or("no main file in workspace")?;
@ -236,7 +238,9 @@ impl Typlite {
let base = typst::compile(&world) let base = typst::compile(&world)
.output .output
.map_err(|err| format!("convert source for main file: {err:?}"))?; .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))
} }
} }

View file

@ -10,6 +10,7 @@ use clap::Parser;
use tinymist_project::WorldProvider; use tinymist_project::WorldProvider;
use typlite::{common::Format, TypliteFeat}; use typlite::{common::Format, TypliteFeat};
use typlite::{CompileOnceArgs, Typlite}; use typlite::{CompileOnceArgs, Typlite};
use typst::foundations::Bytes;
/// Common arguments of compile, watch, and query. /// Common arguments of compile, watch, and query.
#[derive(Debug, Clone, Parser, Default)] #[derive(Debug, Clone, Parser, Default)]
@ -17,9 +18,9 @@ pub struct CompileArgs {
#[clap(flatten)] #[clap(flatten)]
pub compile: CompileOnceArgs, pub compile: CompileOnceArgs,
/// Path to output file(s) /// Path to output file
#[clap(value_name = "OUTPUT", action = clap::ArgAction::Append)] #[clap(value_name = "OUTPUT", default_value = None)]
pub outputs: Vec<String>, pub output: Option<String>,
/// Configures the path of assets directory /// Configures the path of assets directory
#[clap(long, default_value = None, value_name = "ASSETS_PATH")] #[clap(long, default_value = None, value_name = "ASSETS_PATH")]
@ -36,13 +37,17 @@ fn main() -> typlite::Result<()> {
.as_ref() .as_ref()
.ok_or("Missing required argument: INPUT")?; .ok_or("Missing required argument: INPUT")?;
let outputs = if args.outputs.is_empty() { let is_stdout = args.output.as_deref() == Some("-");
vec![Path::new(input) let output_path = args
.with_extension("md") .output
.to_string_lossy() .map(PathBuf::from)
.to_string()] .unwrap_or_else(|| Path::new(input).with_extension("md"));
} else {
args.outputs.clone() 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 { let assets_path = match args.assets_path {
@ -65,102 +70,22 @@ fn main() -> typlite::Result<()> {
assets_path: assets_path.clone(), assets_path: assets_path.clone(),
..Default::default() ..Default::default()
}); });
let doc = match converter.convert_doc() { let doc = converter.convert_doc(output_format)?;
Ok(doc) => doc,
Err(err) => return Err(format!("failed to convert document: {err}").into()),
};
for output_path in &outputs { let result = match output_format {
let is_stdout = output_path == "-"; Format::Md => Bytes::from_string(doc.to_md_string()?),
let output = if is_stdout { Format::LaTeX => Bytes::from_string(doc.to_tex_string(true)?),
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")] #[cfg(feature = "docx")]
Some(output) if output.extension() == Some(std::ffi::OsStr::new("docx")) => { Format::Docx => Bytes::new(doc.to_docx()?),
Format::Docx
}
_ => Format::Md,
}; };
match format { if is_stdout {
#[cfg(feature = "docx")] std::io::stdout().write_all(result.as_slice()).unwrap();
Format::Docx => { } else if let Err(err) = std::fs::write(&output_path, result.as_slice()) {
let docx_data = match doc.to_docx() { Err(format!(
Ok(data) => data, "failed to write file {}: {err}",
Err(err) => { output_path.display()
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;
}
}
}
}
} }
Ok(()) Ok(())

View file

@ -81,6 +81,13 @@ impl ConvKind {
ConvKind::LaTeX => false, ConvKind::LaTeX => false,
} }
} }
fn kind(&self) -> Format {
match self {
ConvKind::Md { .. } => Format::Md,
ConvKind::LaTeX => Format::LaTeX,
}
}
} }
fn conv(world: LspWorld, kind: ConvKind) -> String { fn conv(world: LspWorld, kind: ConvKind) -> String {
@ -88,7 +95,7 @@ fn conv(world: LspWorld, kind: ConvKind) -> String {
annotate_elem: kind.for_docs(), annotate_elem: kind.for_docs(),
..Default::default() ..Default::default()
}); });
let doc = match converter.convert_doc() { let doc = match converter.convert_doc(kind.kind()) {
Ok(doc) => doc, Ok(doc) => doc,
Err(err) => return format!("failed to convert to markdown: {err}"), Err(err) => return format!("failed to convert to markdown: {err}"),
}; };