mirror of
https://github.com/Myriad-Dreamin/tinymist.git
synced 2025-08-03 09:52:27 +00:00
feat: support vscode tasks for exporting query and pdfpc (#490)
* feat: support vscode tasks for exporting query and pdfpc * test: update snapshot
This commit is contained in:
parent
56e20b2590
commit
85c459d4c8
14 changed files with 354 additions and 10 deletions
1
Cargo.lock
generated
1
Cargo.lock
generated
|
@ -3768,6 +3768,7 @@ dependencies = [
|
||||||
"reflexo",
|
"reflexo",
|
||||||
"serde",
|
"serde",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
|
"serde_yaml",
|
||||||
"sync-lsp",
|
"sync-lsp",
|
||||||
"tinymist-assets",
|
"tinymist-assets",
|
||||||
"tinymist-query",
|
"tinymist-query",
|
||||||
|
|
|
@ -153,6 +153,15 @@ mod polymorphic {
|
||||||
Html {},
|
Html {},
|
||||||
Markdown {},
|
Markdown {},
|
||||||
Text {},
|
Text {},
|
||||||
|
Query {
|
||||||
|
format: String,
|
||||||
|
output_extension: Option<String>,
|
||||||
|
strict: bool,
|
||||||
|
selector: String,
|
||||||
|
field: Option<String>,
|
||||||
|
one: bool,
|
||||||
|
pretty: bool,
|
||||||
|
},
|
||||||
Svg {
|
Svg {
|
||||||
page: PageSelection,
|
page: PageSelection,
|
||||||
},
|
},
|
||||||
|
@ -180,6 +189,11 @@ mod polymorphic {
|
||||||
Self::Text { .. } => "txt",
|
Self::Text { .. } => "txt",
|
||||||
Self::Svg { .. } => "svg",
|
Self::Svg { .. } => "svg",
|
||||||
Self::Png { .. } => "png",
|
Self::Png { .. } => "png",
|
||||||
|
Self::Query {
|
||||||
|
format,
|
||||||
|
output_extension,
|
||||||
|
..
|
||||||
|
} => output_extension.as_deref().unwrap_or(format),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -31,6 +31,7 @@ env_logger.workspace = true
|
||||||
log.workspace = true
|
log.workspace = true
|
||||||
serde.workspace = true
|
serde.workspace = true
|
||||||
serde_json.workspace = true
|
serde_json.workspace = true
|
||||||
|
serde_yaml.workspace = true
|
||||||
parking_lot.workspace = true
|
parking_lot.workspace = true
|
||||||
paste.workspace = true
|
paste.workspace = true
|
||||||
|
|
||||||
|
|
|
@ -26,6 +26,18 @@ struct ExportOpts {
|
||||||
page: PageSelection,
|
page: PageSelection,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Default, Deserialize)]
|
||||||
|
#[serde(rename_all = "camelCase")]
|
||||||
|
struct QueryOpts {
|
||||||
|
format: String,
|
||||||
|
output_extension: Option<String>,
|
||||||
|
strict: Option<bool>,
|
||||||
|
pretty: Option<bool>,
|
||||||
|
selector: String,
|
||||||
|
field: Option<String>,
|
||||||
|
one: Option<bool>,
|
||||||
|
}
|
||||||
|
|
||||||
/// Here are implemented the handlers for each command.
|
/// Here are implemented the handlers for each command.
|
||||||
impl LanguageState {
|
impl LanguageState {
|
||||||
/// Export the current document as PDF file(s).
|
/// Export the current document as PDF file(s).
|
||||||
|
@ -59,6 +71,24 @@ impl LanguageState {
|
||||||
self.export(req_id, ExportKind::Text {}, args)
|
self.export(req_id, ExportKind::Text {}, args)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Query the current document and export the result as JSON file(s).
|
||||||
|
pub fn export_query(&mut self, req_id: RequestId, mut args: Vec<JsonValue>) -> ScheduledResult {
|
||||||
|
let opts = get_arg_or_default!(args[1] as QueryOpts);
|
||||||
|
self.export(
|
||||||
|
req_id,
|
||||||
|
ExportKind::Query {
|
||||||
|
format: opts.format,
|
||||||
|
output_extension: opts.output_extension,
|
||||||
|
strict: opts.strict.unwrap_or(true),
|
||||||
|
selector: opts.selector,
|
||||||
|
field: opts.field,
|
||||||
|
pretty: opts.pretty.unwrap_or(true),
|
||||||
|
one: opts.one.unwrap_or(false),
|
||||||
|
},
|
||||||
|
args,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
/// Export the current document as Svg file(s).
|
/// Export the current document as Svg file(s).
|
||||||
pub fn export_svg(&mut self, req_id: RequestId, mut args: Vec<JsonValue>) -> ScheduledResult {
|
pub fn export_svg(&mut self, req_id: RequestId, mut args: Vec<JsonValue>) -> ScheduledResult {
|
||||||
let opts = get_arg_or_default!(args[1] as ExportOpts);
|
let opts = get_arg_or_default!(args[1] as ExportOpts);
|
||||||
|
|
|
@ -257,6 +257,7 @@ impl LanguageState {
|
||||||
.with_command_("tinymist.exportText", State::export_text)
|
.with_command_("tinymist.exportText", State::export_text)
|
||||||
.with_command_("tinymist.exportHtml", State::export_html)
|
.with_command_("tinymist.exportHtml", State::export_html)
|
||||||
.with_command_("tinymist.exportMarkdown", State::export_markdown)
|
.with_command_("tinymist.exportMarkdown", State::export_markdown)
|
||||||
|
.with_command_("tinymist.exportQuery", State::export_query)
|
||||||
.with_command("tinymist.doClearCache", State::clear_cache)
|
.with_command("tinymist.doClearCache", State::clear_cache)
|
||||||
.with_command("tinymist.pinMain", State::pin_document)
|
.with_command("tinymist.pinMain", State::pin_document)
|
||||||
.with_command("tinymist.focusMain", State::focus_document)
|
.with_command("tinymist.focusMain", State::focus_document)
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
//! The actor that handles various document export, like PDF and SVG export.
|
//! The actor that handles various document export, like PDF and SVG export.
|
||||||
|
|
||||||
|
use std::ops::Deref;
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
use std::{path::PathBuf, sync::Arc};
|
use std::{path::PathBuf, sync::Arc};
|
||||||
|
|
||||||
|
@ -8,6 +9,7 @@ use once_cell::sync::Lazy;
|
||||||
use tinymist_query::{ExportKind, PageSelection};
|
use tinymist_query::{ExportKind, PageSelection};
|
||||||
use tokio::sync::mpsc;
|
use tokio::sync::mpsc;
|
||||||
use typlite::Typlite;
|
use typlite::Typlite;
|
||||||
|
use typst::foundations::IntoValue;
|
||||||
use typst::{
|
use typst::{
|
||||||
foundations::Smart,
|
foundations::Smart,
|
||||||
layout::{Abs, Frame},
|
layout::{Abs, Frame},
|
||||||
|
@ -213,6 +215,39 @@ impl ExportConfig {
|
||||||
// todo: timestamp world.now()
|
// todo: timestamp world.now()
|
||||||
typst_pdf::pdf(doc, Smart::Auto, timestamp)
|
typst_pdf::pdf(doc, Smart::Auto, timestamp)
|
||||||
}
|
}
|
||||||
|
Query {
|
||||||
|
format,
|
||||||
|
output_extension: _,
|
||||||
|
strict,
|
||||||
|
selector,
|
||||||
|
field,
|
||||||
|
one,
|
||||||
|
pretty,
|
||||||
|
} => {
|
||||||
|
let elements =
|
||||||
|
typst_ts_compiler::query::retrieve(artifact.world.deref(), &selector, doc)
|
||||||
|
.map_err(|e| anyhow::anyhow!("failed to retrieve: {e}"))?;
|
||||||
|
if one && elements.len() != 1 {
|
||||||
|
bail!("expected exactly one element, found {}", elements.len());
|
||||||
|
}
|
||||||
|
|
||||||
|
let mapped: Vec<_> = elements
|
||||||
|
.into_iter()
|
||||||
|
.filter_map(|c| match &field {
|
||||||
|
Some(field) => c.get_by_name(field),
|
||||||
|
_ => Some(c.into_value()),
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
if one {
|
||||||
|
let Some(value) = mapped.first() else {
|
||||||
|
bail!("no such field found for element");
|
||||||
|
};
|
||||||
|
serialize(value, &format, strict, pretty).map(String::into_bytes)?
|
||||||
|
} else {
|
||||||
|
serialize(&mapped, &format, strict, pretty).map(String::into_bytes)?
|
||||||
|
}
|
||||||
|
}
|
||||||
Html {} => typst_ts_svg_exporter::render_svg_html(doc).into_bytes(),
|
Html {} => typst_ts_svg_exporter::render_svg_html(doc).into_bytes(),
|
||||||
Text {} => format!("{}", FullTextDigest(doc.clone())).into_bytes(),
|
Text {} => format!("{}", FullTextDigest(doc.clone())).into_bytes(),
|
||||||
Markdown {} => {
|
Markdown {} => {
|
||||||
|
@ -355,6 +390,39 @@ fn convert_datetime(date_time: chrono::DateTime<chrono::Utc>) -> Option<TypstDat
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Serialize data to the output format.
|
||||||
|
fn serialize(
|
||||||
|
data: &impl serde::Serialize,
|
||||||
|
format: &str,
|
||||||
|
strict: bool,
|
||||||
|
pretty: bool,
|
||||||
|
) -> anyhow::Result<String> {
|
||||||
|
Ok(match format {
|
||||||
|
"json" if pretty => serde_json::to_string_pretty(data)?,
|
||||||
|
"json" => serde_json::to_string(data)?,
|
||||||
|
"yaml" => serde_yaml::to_string(&data)?,
|
||||||
|
format if format == "txt" || !strict => {
|
||||||
|
use serde_json::Value::*;
|
||||||
|
let value = serde_json::to_value(data)?;
|
||||||
|
match value {
|
||||||
|
String(s) => s,
|
||||||
|
_ => {
|
||||||
|
let kind = match value {
|
||||||
|
Null => "null",
|
||||||
|
Bool(_) => "boolean",
|
||||||
|
Number(_) => "number",
|
||||||
|
String(_) => "string",
|
||||||
|
Array(_) => "array",
|
||||||
|
Object(_) => "object",
|
||||||
|
};
|
||||||
|
bail!("expected a string value for format: {format}, got {kind}")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => bail!("unsupported format for query: {format}"),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
|
@ -4,6 +4,84 @@
|
||||||
|
|
||||||
You can export your documents to various formats using the `export` feature.
|
You can export your documents to various formats using the `export` feature.
|
||||||
|
|
||||||
|
== Export from Query Result
|
||||||
|
|
||||||
|
=== Hello World Example (VSCode Tasks)
|
||||||
|
|
||||||
|
You can export the result of a query as text using the `export` command.
|
||||||
|
|
||||||
|
Given a code:
|
||||||
|
|
||||||
|
```typ
|
||||||
|
#println("Hello World!")
|
||||||
|
#println("Hello World! Again...")
|
||||||
|
```
|
||||||
|
|
||||||
|
LSP should export the result of the query as text with the following content:
|
||||||
|
|
||||||
|
```txt
|
||||||
|
Hello World!
|
||||||
|
Hello World! Again...
|
||||||
|
```
|
||||||
|
|
||||||
|
This requires the following configuration in your `tasks.json` file:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"version": "2.0.0",
|
||||||
|
"tasks": [
|
||||||
|
{
|
||||||
|
"label": "Query as Text",
|
||||||
|
"type": "typst",
|
||||||
|
"command": "export",
|
||||||
|
"export": {
|
||||||
|
"format": "query",
|
||||||
|
"query.format": "txt",
|
||||||
|
"query.outputExtension": "out",
|
||||||
|
"query.field": "value",
|
||||||
|
"query.selector": "<print-effect>",
|
||||||
|
"query.one": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
See the #link("https://github.com/Myriad-Dreamin/tinymist/tree/main/editors/vscode/e2e-workspaces/print-state")[Sample Workspace: print-state] for more details.
|
||||||
|
|
||||||
|
=== Pdfpc Example (VSCode Tasks)
|
||||||
|
|
||||||
|
A more practical example is exporting the result of a query as a pdfpc file. You can use the following configuration in your `tasks.json` file to export the result of a query as a pdfpc file, which is adapted by #link("https://touying-typ.github.io/touying/")[Touying Slides].
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"label": "Query as Pdfpc",
|
||||||
|
"type": "typst",
|
||||||
|
"command": "export",
|
||||||
|
"export": {
|
||||||
|
"format": "query",
|
||||||
|
"query.format": "json",
|
||||||
|
"query.outputExtension": "pdfpc",
|
||||||
|
"query.selector": "<pdfpc-file>",
|
||||||
|
"query.field": "value",
|
||||||
|
"query.one": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
To simplify configuration,
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"label": "Query as Pdfpc",
|
||||||
|
"type": "typst",
|
||||||
|
"command": "export",
|
||||||
|
"export": {
|
||||||
|
"format": "pdfpc"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
== VSCode: Task Configuration
|
== VSCode: Task Configuration
|
||||||
|
|
||||||
You can configure tasks in your `tasks.json` file to "persist" the arguments for exporting documents.
|
You can configure tasks in your `tasks.json` file to "persist" the arguments for exporting documents.
|
||||||
|
@ -58,6 +136,14 @@ Example:
|
||||||
"merged": true
|
"merged": true
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"label": "Query as Pdfpc",
|
||||||
|
"type": "typst",
|
||||||
|
"command": "export",
|
||||||
|
"export": {
|
||||||
|
"format": "pdfpc"
|
||||||
|
}
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"label": "Export as PNG and SVG",
|
"label": "Export as PNG and SVG",
|
||||||
"type": "typst",
|
"type": "typst",
|
||||||
|
|
29
editors/vscode/e2e-workspaces/print-state/.vscode/tasks.json
vendored
Normal file
29
editors/vscode/e2e-workspaces/print-state/.vscode/tasks.json
vendored
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
{
|
||||||
|
"version": "2.0.0",
|
||||||
|
"tasks": [
|
||||||
|
{
|
||||||
|
"label": "Query as Text",
|
||||||
|
"type": "typst",
|
||||||
|
"command": "export",
|
||||||
|
"export": {
|
||||||
|
"format": "query",
|
||||||
|
"query.format": "txt",
|
||||||
|
"query.outputExtension": "out",
|
||||||
|
"query.field": "value",
|
||||||
|
"query.selector": "<print-effect>",
|
||||||
|
"query.one": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"label": "Export PNG and SVG....",
|
||||||
|
"type": "typst",
|
||||||
|
"command": "export",
|
||||||
|
"export": {
|
||||||
|
"format": ["png", "svg"],
|
||||||
|
"png.ppi": 288,
|
||||||
|
"merged": true,
|
||||||
|
"merged.gap": "100pt"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
12
editors/vscode/e2e-workspaces/print-state/effect.typ
Normal file
12
editors/vscode/e2e-workspaces/print-state/effect.typ
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
|
||||||
|
#let print-state = state("print-effect", ())
|
||||||
|
#let print(k, end: none) = print-state.update(it => it + (k, end))
|
||||||
|
#let println = print.with(end: "\n")
|
||||||
|
|
||||||
|
#let main = content => {
|
||||||
|
context [
|
||||||
|
#let prints = print-state.final()
|
||||||
|
#metadata(prints.join()) <print-effect>
|
||||||
|
]
|
||||||
|
content
|
||||||
|
}
|
7
editors/vscode/e2e-workspaces/print-state/main.typ
Normal file
7
editors/vscode/e2e-workspaces/print-state/main.typ
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
|
||||||
|
#import "effect.typ": *
|
||||||
|
|
||||||
|
#show: main
|
||||||
|
|
||||||
|
#println("Hello World!")
|
||||||
|
#println("Hello World! Again...")
|
|
@ -90,12 +90,22 @@
|
||||||
"enum": [
|
"enum": [
|
||||||
"pdf",
|
"pdf",
|
||||||
"png",
|
"png",
|
||||||
"svg"
|
"svg",
|
||||||
|
"html",
|
||||||
|
"markdown",
|
||||||
|
"text",
|
||||||
|
"query",
|
||||||
|
"pdfpc"
|
||||||
],
|
],
|
||||||
"enumDescriptions": [
|
"enumDescriptions": [
|
||||||
"PDF",
|
"PDF",
|
||||||
"PNG",
|
"PNG",
|
||||||
"SVG"
|
"SVG",
|
||||||
|
"HTML",
|
||||||
|
"Markdown",
|
||||||
|
"Plain Text",
|
||||||
|
"Query Result",
|
||||||
|
"Pdfpc (From Query)"
|
||||||
],
|
],
|
||||||
"default": "pdf"
|
"default": "pdf"
|
||||||
},
|
},
|
||||||
|
@ -111,7 +121,9 @@
|
||||||
"svg",
|
"svg",
|
||||||
"html",
|
"html",
|
||||||
"markdown",
|
"markdown",
|
||||||
"text"
|
"text",
|
||||||
|
"query",
|
||||||
|
"pdfpc"
|
||||||
],
|
],
|
||||||
"enumDescriptions": [
|
"enumDescriptions": [
|
||||||
"PDF",
|
"PDF",
|
||||||
|
@ -119,7 +131,9 @@
|
||||||
"SVG",
|
"SVG",
|
||||||
"HTML",
|
"HTML",
|
||||||
"Markdown",
|
"Markdown",
|
||||||
"Plain Text"
|
"Plain Text",
|
||||||
|
"Query Result",
|
||||||
|
"Pdfpc (From Query)"
|
||||||
],
|
],
|
||||||
"default": "pdf"
|
"default": "pdf"
|
||||||
}
|
}
|
||||||
|
@ -192,6 +206,45 @@
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"description": "The gap between the pages when merging **with absolute typst unit**. Affected formats: `png`",
|
"description": "The gap between the pages when merging **with absolute typst unit**. Affected formats: `png`",
|
||||||
"default": "0pt"
|
"default": "0pt"
|
||||||
|
},
|
||||||
|
"query.format": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "The format of the query output. Defaults to `json`.",
|
||||||
|
"default": "json",
|
||||||
|
"enum": [
|
||||||
|
"json",
|
||||||
|
"yaml",
|
||||||
|
"txt"
|
||||||
|
],
|
||||||
|
"enumDescriptions": [
|
||||||
|
"JSON",
|
||||||
|
"YAML",
|
||||||
|
"Plain Text if the result is a string, otherwise raises an error. You may specific the field to use for the query with `query.field` and assert that there is only one result with `query.one`."
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"query.outputExtension": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "The extension of the query output. Inferring from `query.format` if not specified."
|
||||||
|
},
|
||||||
|
"query.strict": {
|
||||||
|
"type": "boolean",
|
||||||
|
"description": "Whether to strictly check the query format. Defaults to `true`."
|
||||||
|
},
|
||||||
|
"query.pretty": {
|
||||||
|
"type": "boolean",
|
||||||
|
"description": "Whether to pretty print the query output. Defaults to `true`."
|
||||||
|
},
|
||||||
|
"query.selector": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "The selector to use for the query. Must specified if `format`."
|
||||||
|
},
|
||||||
|
"query.field": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "The field to use for the query."
|
||||||
|
},
|
||||||
|
"query.one": {
|
||||||
|
"type": "boolean",
|
||||||
|
"description": "Whether to only return one result. Defaults to `false`."
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -50,6 +50,9 @@ export const tinymist = {
|
||||||
exportText(uri: string, extraOpts?: any) {
|
exportText(uri: string, extraOpts?: any) {
|
||||||
return doExport("tinymist.exportText", uri, extraOpts);
|
return doExport("tinymist.exportText", uri, extraOpts);
|
||||||
},
|
},
|
||||||
|
exportQuery(uri: string, extraOpts?: any) {
|
||||||
|
return doExport("tinymist.exportQuery", uri, extraOpts);
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
function doExport(command: string, uri: string, extraOpts?: any): Promise<string> {
|
function doExport(command: string, uri: string, extraOpts?: any): Promise<string> {
|
||||||
|
|
|
@ -13,7 +13,7 @@ export function activateTaskProvider(context: vscode.ExtensionContext): vscode.D
|
||||||
return vscode.tasks.registerTaskProvider(TYPST_TASK_TYPE, provider);
|
return vscode.tasks.registerTaskProvider(TYPST_TASK_TYPE, provider);
|
||||||
}
|
}
|
||||||
|
|
||||||
export type ExportFormat = "pdf" | "png" | "svg";
|
export type ExportFormat = "pdf" | "png" | "svg" | "html" | "markdown" | "text" | "query" | "pdfpc";
|
||||||
|
|
||||||
export type TaskDefinition = vscode.TaskDefinition & {
|
export type TaskDefinition = vscode.TaskDefinition & {
|
||||||
readonly type: typeof TYPST_TASK_TYPE;
|
readonly type: typeof TYPST_TASK_TYPE;
|
||||||
|
@ -32,6 +32,13 @@ export type TaskDefinition = vscode.TaskDefinition & {
|
||||||
"merged.gap"?: string;
|
"merged.gap"?: string;
|
||||||
"png.merged.gap"?: string;
|
"png.merged.gap"?: string;
|
||||||
"svg.merged.gap"?: string;
|
"svg.merged.gap"?: string;
|
||||||
|
"query.format"?: string;
|
||||||
|
"query.outputExtension"?: string;
|
||||||
|
"query.strict"?: boolean;
|
||||||
|
"query.pretty"?: boolean;
|
||||||
|
"query.selector"?: string;
|
||||||
|
"query.field"?: string;
|
||||||
|
"query.one"?: boolean;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -121,6 +128,20 @@ export async function callTypstExportCommand(): Promise<vscode.CustomExecution>
|
||||||
},
|
},
|
||||||
export: tinymist.exportText,
|
export: tinymist.exportText,
|
||||||
},
|
},
|
||||||
|
query: {
|
||||||
|
opts() {
|
||||||
|
return {
|
||||||
|
format: exportArgs["query.format"],
|
||||||
|
outputExtension: exportArgs["query.outputExtension"],
|
||||||
|
strict: exportArgs["query.strict"],
|
||||||
|
pretty: exportArgs["query.pretty"],
|
||||||
|
selector: exportArgs["query.selector"],
|
||||||
|
field: exportArgs["query.field"],
|
||||||
|
one: exportArgs["query.one"],
|
||||||
|
};
|
||||||
|
},
|
||||||
|
export: tinymist.exportQuery,
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
return Promise.resolve({
|
return Promise.resolve({
|
||||||
|
@ -131,8 +152,17 @@ export async function callTypstExportCommand(): Promise<vscode.CustomExecution>
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await run();
|
await run();
|
||||||
} catch (e) {
|
} catch (e: any) {
|
||||||
writeEmitter.fire("Typst export task failed: " + obj(e) + "\r\n");
|
writeEmitter.fire(
|
||||||
|
"Typst export task failed: " +
|
||||||
|
obj({
|
||||||
|
code: e.code,
|
||||||
|
message: e.message,
|
||||||
|
stack: e.stack,
|
||||||
|
error: e,
|
||||||
|
}) +
|
||||||
|
"\r\n",
|
||||||
|
);
|
||||||
} finally {
|
} finally {
|
||||||
closeEmitter.fire(0);
|
closeEmitter.fire(0);
|
||||||
}
|
}
|
||||||
|
@ -152,7 +182,16 @@ export async function callTypstExportCommand(): Promise<vscode.CustomExecution>
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const format of formats) {
|
for (let format of formats) {
|
||||||
|
if (format === "pdfpc") {
|
||||||
|
format = "query";
|
||||||
|
exportArgs["query.format"] = "json";
|
||||||
|
exportArgs["query.outputExtension"] = "pdfpc";
|
||||||
|
exportArgs["query.selector"] = "<pdfpc-file>";
|
||||||
|
exportArgs["query.field"] = "value";
|
||||||
|
exportArgs["query.one"] = true;
|
||||||
|
}
|
||||||
|
|
||||||
const provider = formatProvider[format];
|
const provider = formatProvider[format];
|
||||||
if (!provider) {
|
if (!provider) {
|
||||||
writeEmitter.fire("Unsupported export format: " + format + "\r\n");
|
writeEmitter.fire("Unsupported export format: " + format + "\r\n");
|
||||||
|
|
|
@ -374,7 +374,7 @@ fn e2e() {
|
||||||
});
|
});
|
||||||
|
|
||||||
let hash = replay_log(&tinymist_binary, &root.join("neovim"));
|
let hash = replay_log(&tinymist_binary, &root.join("neovim"));
|
||||||
insta::assert_snapshot!(hash, @"siphash128_13:a54cfbafc7174bc8465fc0adb99aa28d");
|
insta::assert_snapshot!(hash, @"siphash128_13:466ece1c48d23e59d3ff339a4c8ff461");
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
|
@ -385,7 +385,7 @@ fn e2e() {
|
||||||
});
|
});
|
||||||
|
|
||||||
let hash = replay_log(&tinymist_binary, &root.join("vscode"));
|
let hash = replay_log(&tinymist_binary, &root.join("vscode"));
|
||||||
insta::assert_snapshot!(hash, @"siphash128_13:5c9f14019d55dc472177fff5f215fa40");
|
insta::assert_snapshot!(hash, @"siphash128_13:5d7fb66abe6c73f204e5deb44ae6a343");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue