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.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[derive(Default, Debug, Clone, Copy, PartialEq, Eq)]
pub enum Format {
#[default]
Md,
LaTeX,
#[cfg(feature = "docx")]

View file

@ -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<ecow::EcoString> {
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<MarkdownDocument> {
pub fn convert_doc(self, format: Format) -> Result<MarkdownDocument> {
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))
}
}

View file

@ -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<String>,
/// Path to output file
#[clap(value_name = "OUTPUT", default_value = None)]
pub output: Option<String>,
/// 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(())

View file

@ -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}"),
};