mirror of
https://github.com/Myriad-Dreamin/tinymist.git
synced 2025-08-03 01:42:14 +00:00
feat: support vscode tasks for exporting html, md, and txt (#489)
* feat: support vscode tasks for exporting html, md, and txt * chore: styling * docs: update * test: update snapshot
This commit is contained in:
parent
140299f0ce
commit
56e20b2590
14 changed files with 156 additions and 10 deletions
1
Cargo.lock
generated
1
Cargo.lock
generated
|
@ -3777,6 +3777,7 @@ dependencies = [
|
|||
"toml 0.8.14",
|
||||
"tower-layer",
|
||||
"tower-service",
|
||||
"typlite",
|
||||
"typst",
|
||||
"typst-assets",
|
||||
"typst-pdf",
|
||||
|
|
|
@ -105,6 +105,7 @@ typst-ts-compiler = { version = "0.5.0-rc5" }
|
|||
typst-ts-svg-exporter = { version = "0.5.0-rc5" }
|
||||
typstfmt_lib = { git = "https://github.com/astrale-sharp/typstfmt", tag = "0.2.7" }
|
||||
typstyle = { version = "0.11.30", default-features = false }
|
||||
typlite = { path = "./crates/typlite" }
|
||||
|
||||
# LSP
|
||||
crossbeam-channel = "0.5.12"
|
||||
|
|
|
@ -150,6 +150,9 @@ mod polymorphic {
|
|||
Pdf {
|
||||
creation_timestamp: Option<chrono::DateTime<chrono::Utc>>,
|
||||
},
|
||||
Html {},
|
||||
Markdown {},
|
||||
Text {},
|
||||
Svg {
|
||||
page: PageSelection,
|
||||
},
|
||||
|
@ -172,6 +175,9 @@ mod polymorphic {
|
|||
pub fn extension(&self) -> &str {
|
||||
match self {
|
||||
Self::Pdf { .. } => "pdf",
|
||||
Self::Html { .. } => "html",
|
||||
Self::Markdown { .. } => "md",
|
||||
Self::Text { .. } => "txt",
|
||||
Self::Svg { .. } => "svg",
|
||||
Self::Png { .. } => "png",
|
||||
}
|
||||
|
|
|
@ -15,6 +15,7 @@ repository.workspace = true
|
|||
tinymist-assets = { workspace = true }
|
||||
tinymist-query.workspace = true
|
||||
tinymist-render.workspace = true
|
||||
typlite.workspace = true
|
||||
sync-lsp.workspace = true
|
||||
chrono.workspace = true
|
||||
|
||||
|
|
|
@ -44,6 +44,21 @@ impl LanguageState {
|
|||
self.export(req_id, ExportKind::Pdf { creation_timestamp }, args)
|
||||
}
|
||||
|
||||
/// Export the current document as HTML file(s).
|
||||
pub fn export_html(&mut self, req_id: RequestId, args: Vec<JsonValue>) -> ScheduledResult {
|
||||
self.export(req_id, ExportKind::Html {}, args)
|
||||
}
|
||||
|
||||
/// Export the current document as Markdown file(s).
|
||||
pub fn export_markdown(&mut self, req_id: RequestId, args: Vec<JsonValue>) -> ScheduledResult {
|
||||
self.export(req_id, ExportKind::Markdown {}, args)
|
||||
}
|
||||
|
||||
/// Export the current document as Text file(s).
|
||||
pub fn export_text(&mut self, req_id: RequestId, args: Vec<JsonValue>) -> ScheduledResult {
|
||||
self.export(req_id, ExportKind::Text {}, args)
|
||||
}
|
||||
|
||||
/// Export the current document as Svg file(s).
|
||||
pub fn export_svg(&mut self, req_id: RequestId, mut args: Vec<JsonValue>) -> ScheduledResult {
|
||||
let opts = get_arg_or_default!(args[1] as ExportOpts);
|
||||
|
|
|
@ -254,6 +254,9 @@ impl LanguageState {
|
|||
.with_command_("tinymist.exportPdf", State::export_pdf)
|
||||
.with_command_("tinymist.exportSvg", State::export_svg)
|
||||
.with_command_("tinymist.exportPng", State::export_png)
|
||||
.with_command_("tinymist.exportText", State::export_text)
|
||||
.with_command_("tinymist.exportHtml", State::export_html)
|
||||
.with_command_("tinymist.exportMarkdown", State::export_markdown)
|
||||
.with_command("tinymist.doClearCache", State::clear_cache)
|
||||
.with_command("tinymist.pinMain", State::pin_document)
|
||||
.with_command("tinymist.focusMain", State::focus_document)
|
||||
|
|
|
@ -7,15 +7,18 @@ use anyhow::{bail, Context};
|
|||
use once_cell::sync::Lazy;
|
||||
use tinymist_query::{ExportKind, PageSelection};
|
||||
use tokio::sync::mpsc;
|
||||
use typlite::Typlite;
|
||||
use typst::{
|
||||
foundations::Smart,
|
||||
layout::{Abs, Frame},
|
||||
syntax::{ast, SyntaxNode},
|
||||
visualize::Color,
|
||||
World,
|
||||
};
|
||||
use typst_ts_compiler::{EntryReader, EntryState, TaskInputs};
|
||||
use typst_ts_core::TypstDatetime;
|
||||
|
||||
use crate::tool::text::FullTextDigest;
|
||||
use crate::{
|
||||
actor::{
|
||||
editor::EditorRequest,
|
||||
|
@ -210,6 +213,16 @@ impl ExportConfig {
|
|||
// todo: timestamp world.now()
|
||||
typst_pdf::pdf(doc, Smart::Auto, timestamp)
|
||||
}
|
||||
Html {} => typst_ts_svg_exporter::render_svg_html(doc).into_bytes(),
|
||||
Text {} => format!("{}", FullTextDigest(doc.clone())).into_bytes(),
|
||||
Markdown {} => {
|
||||
let main = artifact.world.main();
|
||||
let conv = Typlite::new_with_src(main)
|
||||
.convert()
|
||||
.map_err(|e| anyhow::anyhow!("failed to convert to markdown: {e}"))?;
|
||||
|
||||
conv.as_bytes().to_owned()
|
||||
}
|
||||
Svg { page: First } => typst_svg::svg(first_frame()).into_bytes(),
|
||||
Svg {
|
||||
page: Merged { .. },
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
//! All the language tools provided by the `tinymist` crate.
|
||||
|
||||
pub mod package;
|
||||
pub mod text;
|
||||
pub mod word_count;
|
||||
|
||||
#[cfg(feature = "preview")]
|
||||
|
|
40
crates/tinymist/src/tool/text.rs
Normal file
40
crates/tinymist/src/tool/text.rs
Normal file
|
@ -0,0 +1,40 @@
|
|||
//! Text export utilities.
|
||||
|
||||
use core::fmt;
|
||||
use std::sync::Arc;
|
||||
|
||||
use typst_ts_core::TypstDocument;
|
||||
|
||||
/// A full text digest of a document.
|
||||
pub struct FullTextDigest(pub Arc<TypstDocument>);
|
||||
|
||||
impl FullTextDigest {
|
||||
fn export_frame(f: &mut fmt::Formatter<'_>, doc: &typst::layout::Frame) -> fmt::Result {
|
||||
for (_, item) in doc.items() {
|
||||
Self::export_item(f, item)?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn export_item(f: &mut fmt::Formatter<'_>, item: &typst::layout::FrameItem) -> fmt::Result {
|
||||
use typst::introspection::Meta::*;
|
||||
use typst::layout::FrameItem::*;
|
||||
match item {
|
||||
Group(g) => Self::export_frame(f, &g.frame),
|
||||
Text(t) => f.write_str(t.text.as_str()),
|
||||
#[cfg(not(feature = "no-content-hint"))]
|
||||
Meta(ContentHint(c), _) => f.write_char(*c),
|
||||
Meta(Link(..) | Elem(..) | Hide, _) | Shape(..) | Image(..) => Ok(()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for FullTextDigest {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
for page in self.0.pages.iter() {
|
||||
Self::export_frame(f, &page.frame)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
|
@ -15,7 +15,31 @@ Example:
|
|||
"version": "2.0.0",
|
||||
"tasks": [
|
||||
{
|
||||
"label": "Export SVG",
|
||||
"label": "Export as Html",
|
||||
"type": "typst",
|
||||
"command": "export",
|
||||
"export": {
|
||||
"format": "html"
|
||||
}
|
||||
},
|
||||
{
|
||||
"label": "Export as Markdown",
|
||||
"type": "typst",
|
||||
"command": "export",
|
||||
"export": {
|
||||
"format": "markdown"
|
||||
}
|
||||
},
|
||||
{
|
||||
"label": "Export as Plain Text",
|
||||
"type": "typst",
|
||||
"command": "export",
|
||||
"export": {
|
||||
"format": "html"
|
||||
}
|
||||
},
|
||||
{
|
||||
"label": "Export as SVG",
|
||||
"type": "typst",
|
||||
"command": "export",
|
||||
"export": {
|
||||
|
@ -24,7 +48,7 @@ Example:
|
|||
}
|
||||
},
|
||||
{
|
||||
"label": "Export PNG",
|
||||
"label": "Export as PNG",
|
||||
"type": "typst",
|
||||
"command": "export",
|
||||
"export": {
|
||||
|
@ -35,10 +59,11 @@ Example:
|
|||
}
|
||||
},
|
||||
{
|
||||
"label": "Export PNG and SVG",
|
||||
"label": "Export as PNG and SVG",
|
||||
"type": "typst",
|
||||
"command": "export",
|
||||
"export": {
|
||||
// You can export multiple formats at once.
|
||||
"format": ["png", "svg"],
|
||||
// To make a visual effect, we set an obvious low resolution.
|
||||
// For a nice result, you should set a higher resolution like 288.
|
||||
|
@ -53,7 +78,11 @@ Example:
|
|||
}
|
||||
```
|
||||
|
||||
todo: documenting export options.
|
||||
#let packages = json("/editors/vscode/package.json")
|
||||
|
||||
*todo: documenting export options.*
|
||||
|
||||
#raw(lang: "json", json.encode(packages.contributes.taskDefinitions, pretty: true), block: true)
|
||||
|
||||
After configuring the tasks, you can run them using the command palette.
|
||||
+ Press `Ctrl+Shift+P` to open the command palette.
|
||||
|
@ -66,5 +95,8 @@ You can call the following export commands.
|
|||
- `tinymist.exportSvg`
|
||||
- `tinymist.exportPng`
|
||||
- `tinymist.exportPdf`
|
||||
- `tinymist.exportHtml`
|
||||
- `tinymist.exportMarkdown`
|
||||
- `tinymist.exportText`
|
||||
|
||||
The first argument is the path to the file you want to export and the second argument is an object containing additional options.
|
||||
|
|
|
@ -108,12 +108,18 @@
|
|||
"enum": [
|
||||
"pdf",
|
||||
"png",
|
||||
"svg"
|
||||
"svg",
|
||||
"html",
|
||||
"markdown",
|
||||
"text"
|
||||
],
|
||||
"enumDescriptions": [
|
||||
"PDF",
|
||||
"PNG",
|
||||
"SVG"
|
||||
"SVG",
|
||||
"HTML",
|
||||
"Markdown",
|
||||
"Plain Text"
|
||||
],
|
||||
"default": "pdf"
|
||||
}
|
||||
|
|
|
@ -41,6 +41,15 @@ export const tinymist = {
|
|||
exportPng(uri: string, extraOpts?: any) {
|
||||
return doExport("tinymist.exportPng", uri, extraOpts);
|
||||
},
|
||||
exportHtml(uri: string, extraOpts?: any) {
|
||||
return doExport("tinymist.exportHtml", uri, extraOpts);
|
||||
},
|
||||
exportMarkdown(uri: string, extraOpts?: any) {
|
||||
return doExport("tinymist.exportMarkdown", uri, extraOpts);
|
||||
},
|
||||
exportText(uri: string, extraOpts?: any) {
|
||||
return doExport("tinymist.exportText", uri, extraOpts);
|
||||
},
|
||||
};
|
||||
|
||||
function doExport(command: string, uri: string, extraOpts?: any): Promise<string> {
|
||||
|
|
|
@ -103,6 +103,24 @@ export async function callTypstExportCommand(): Promise<vscode.CustomExecution>
|
|||
},
|
||||
export: tinymist.exportSvg,
|
||||
},
|
||||
html: {
|
||||
opts() {
|
||||
return {};
|
||||
},
|
||||
export: tinymist.exportHtml,
|
||||
},
|
||||
markdown: {
|
||||
opts() {
|
||||
return {};
|
||||
},
|
||||
export: tinymist.exportMarkdown,
|
||||
},
|
||||
text: {
|
||||
opts() {
|
||||
return {};
|
||||
},
|
||||
export: tinymist.exportText,
|
||||
},
|
||||
};
|
||||
|
||||
return Promise.resolve({
|
||||
|
|
|
@ -374,7 +374,7 @@ fn e2e() {
|
|||
});
|
||||
|
||||
let hash = replay_log(&tinymist_binary, &root.join("neovim"));
|
||||
insta::assert_snapshot!(hash, @"siphash128_13:52e650bc01755a6389e98fbe14b4aeef");
|
||||
insta::assert_snapshot!(hash, @"siphash128_13:a54cfbafc7174bc8465fc0adb99aa28d");
|
||||
}
|
||||
|
||||
{
|
||||
|
@ -385,7 +385,7 @@ fn e2e() {
|
|||
});
|
||||
|
||||
let hash = replay_log(&tinymist_binary, &root.join("vscode"));
|
||||
insta::assert_snapshot!(hash, @"siphash128_13:430e28c24ca45b226c12ce9bf6f55c91");
|
||||
insta::assert_snapshot!(hash, @"siphash128_13:5c9f14019d55dc472177fff5f215fa40");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue