use std::path::PathBuf;
use serde::Deserialize;
use serde_json::Value as JsonValue;
use tinymist_project::{
ExportHtmlTask, ExportPdfTask, ExportPngTask, ExportSvgTask, ExportTeXTask, ExportTextTask,
Pages, ProjectTask, QueryTask,
};
use tinymist_std::error::prelude::*;
use tinymist_task::{ExportMarkdownTask, PageMerge};
use super::*;
use crate::lsp::query::run_query;
#[derive(Debug, Clone, Default, Deserialize)]
#[serde(default)]
#[serde(rename_all = "camelCase")]
struct ExportOpts {}
#[derive(Debug, Clone, Default, Deserialize)]
#[serde(default, rename_all = "camelCase")]
struct ExportPdfOpts {
pages: Option<Vec<Pages>>,
creation_timestamp: Option<String>,
pdf_standard: Option<Vec<PdfStandard>>,
processor: Option<String>,
pub no_pdf_tags: Option<bool>,
}
#[derive(Debug, Clone, Default, Deserialize)]
#[serde(default, rename_all = "camelCase")]
struct ExportSvgOpts {
pages: Option<Vec<Pages>>,
page_number_template: Option<String>,
merge: Option<PageMerge>,
}
#[derive(Debug, Clone, Default, Deserialize)]
#[serde(default, rename_all = "camelCase")]
struct ExportPngOpts {
pages: Option<Vec<Pages>>,
page_number_template: Option<String>,
merge: Option<PageMerge>,
fill: Option<String>,
ppi: Option<f32>,
}
#[derive(Debug, Clone, Default, Deserialize)]
#[serde(default, rename_all = "camelCase")]
struct ExportTypliteOpts {
processor: Option<String>,
assets_path: Option<PathBuf>,
}
#[derive(Debug, Clone, Default, Deserialize)]
#[serde(default, rename_all = "camelCase")]
struct ExportQueryOpts {
format: String,
output_extension: Option<String>,
strict: Option<bool>,
pretty: Option<bool>,
selector: String,
field: Option<String>,
one: Option<bool>,
}
#[derive(Debug, Clone, Default, Deserialize)]
#[serde(default, rename_all = "camelCase")]
struct ExportActionOpts {
write: Option<bool>,
open: bool,
}
impl ServerState {
pub fn export_pdf(&mut self, mut args: Vec<JsonValue>) -> ScheduleResult {
let path = get_arg!(args[0] as PathBuf);
let opts = get_arg_or_default!(args[1] as ExportPdfOpts);
let creation_timestamp = if let Some(value) = opts.creation_timestamp {
Some(
parse_source_date_epoch(&value)
.map_err(|e| invalid_params(format!("Cannot parse creation timestamp: {e}")))?,
)
} else {
self.config.creation_timestamp()
};
let no_pdf_tags = opts.no_pdf_tags.unwrap_or(self.config.no_pdf_tags());
let pdf_standards = opts
.pdf_standard
.or_else(|| self.config.pdf_standards())
.unwrap_or_default();
let export = self.config.export_task();
let task = ProjectTask::ExportPdf(ExportPdfTask {
export,
pages: opts.pages,
pdf_standards,
no_pdf_tags,
creation_timestamp,
});
if path.extension().and_then(|ext| ext.to_str()) == Some("md") {
self.export_md(path, opts.processor, task, args)
} else {
self.export(path, task, args)
}
}
pub fn export_html(&mut self, mut args: Vec<JsonValue>) -> ScheduleResult {
let path = get_arg!(args[0] as PathBuf);
let _opts = get_arg_or_default!(args[1] as ExportOpts);
let export = self.config.export_task();
self.export(
path,
ProjectTask::ExportHtml(ExportHtmlTask { export }),
args,
)
}
pub fn export_markdown(&mut self, mut args: Vec<JsonValue>) -> ScheduleResult {
let path = get_arg!(args[0] as PathBuf);
let opts = get_arg_or_default!(args[1] as ExportTypliteOpts);
let export = self.config.export_task();
self.export(
path,
ProjectTask::ExportMd(ExportMarkdownTask {
processor: opts.processor,
assets_path: opts.assets_path,
export,
}),
args,
)
}
pub fn export_tex(&mut self, mut args: Vec<JsonValue>) -> ScheduleResult {
let path = get_arg!(args[0] as PathBuf);
let opts = get_arg_or_default!(args[1] as ExportTypliteOpts);
let export = self.config.export_task();
self.export(
path,
ProjectTask::ExportTeX(ExportTeXTask {
processor: opts.processor,
assets_path: opts.assets_path,
export,
}),
args,
)
}
pub fn export_text(&mut self, mut args: Vec<JsonValue>) -> ScheduleResult {
let path = get_arg!(args[0] as PathBuf);
let _opts = get_arg_or_default!(args[1] as ExportOpts);
let export = self.config.export_task();
self.export(
path,
ProjectTask::ExportText(ExportTextTask { export }),
args,
)
}
pub fn export_query(&mut self, mut args: Vec<JsonValue>) -> ScheduleResult {
let path = get_arg!(args[0] as PathBuf);
let opts = get_arg_or_default!(args[1] as ExportQueryOpts);
let _ = opts.strict;
let mut export = self.config.export_task();
if opts.pretty.unwrap_or(true) {
export.apply_pretty();
}
self.export(
path,
ProjectTask::Query(QueryTask {
format: opts.format,
output_extension: opts.output_extension,
selector: opts.selector,
field: opts.field,
one: opts.one.unwrap_or(false),
export,
}),
args,
)
}
pub fn export_svg(&mut self, mut args: Vec<JsonValue>) -> ScheduleResult {
let path = get_arg!(args[0] as PathBuf);
let opts = get_arg_or_default!(args[1] as ExportSvgOpts);
let export = self.config.export_task();
self.export(
path,
ProjectTask::ExportSvg(ExportSvgTask {
export,
pages: opts.pages,
page_number_template: opts.page_number_template,
merge: opts.merge,
}),
args,
)
}
pub fn export_png(&mut self, mut args: Vec<JsonValue>) -> ScheduleResult {
let path = get_arg!(args[0] as PathBuf);
let opts = get_arg_or_default!(args[1] as ExportPngOpts);
let ppi = opts.ppi.or_else(|| self.config.ppi()).unwrap_or(144.);
let ppi = ppi
.try_into()
.context("cannot convert ppi")
.map_err(invalid_params)?;
let export = self.config.export_task();
self.export(
path,
ProjectTask::ExportPng(ExportPngTask {
export,
pages: opts.pages,
page_number_template: opts.page_number_template,
merge: opts.merge,
fill: opts.fill,
ppi,
}),
args,
)
}
pub fn export(
&mut self,
path: PathBuf,
task: ProjectTask,
mut args: Vec<JsonValue>,
) -> ScheduleResult {
let action_opts = get_arg_or_default!(args[2] as ExportActionOpts);
let write = action_opts.write.unwrap_or(true);
let open = action_opts.open;
run_query!(self.OnExport(path, task, write, open))
}
pub fn export_md(
&mut self,
path: PathBuf,
processor: Option<String>,
task: ProjectTask,
mut args: Vec<JsonValue>,
) -> ScheduleResult {
let action_opts = get_arg_or_default!(args[2] as ExportActionOpts);
let write = action_opts.write.unwrap_or(true);
let open = action_opts.open;
run_query!(self.OnExportMd(path, processor, task, write, open))
}
}