mirror of
https://github.com/Myriad-Dreamin/tinymist.git
synced 2025-08-04 10:18:16 +00:00
fix: example impl is not correct (#1770)
Some checks are pending
tinymist::ci / Check Minimum Rust version and Tests (Windows) (push) Waiting to run
tinymist::ci / E2E Tests (darwin-arm64 on macos-latest) (push) Blocked by required conditions
tinymist::ci / E2E Tests (linux-x64 on ubuntu-22.04) (push) Blocked by required conditions
tinymist::ci / E2E Tests (linux-x64 on ubuntu-latest) (push) Blocked by required conditions
tinymist::ci / E2E Tests (win32-x64 on windows-2019) (push) Blocked by required conditions
tinymist::ci / E2E Tests (win32-x64 on windows-latest) (push) Blocked by required conditions
tinymist::ci / prepare-build (push) Waiting to run
tinymist::ci / build-binary (push) Blocked by required conditions
tinymist::ci / build-vsc-assets (push) Blocked by required conditions
tinymist::ci / build-vscode (push) Blocked by required conditions
tinymist::ci / build-vscode-others (push) Blocked by required conditions
tinymist::ci / publish-vscode (push) Blocked by required conditions
tinymist::ci / Duplicate Actions Detection (push) Waiting to run
tinymist::ci / Check Clippy, Formatting, Completion, Documentation, and Tests (Linux) (push) Waiting to run
tinymist::gh_pages / build-gh-pages (push) Waiting to run
Some checks are pending
tinymist::ci / Check Minimum Rust version and Tests (Windows) (push) Waiting to run
tinymist::ci / E2E Tests (darwin-arm64 on macos-latest) (push) Blocked by required conditions
tinymist::ci / E2E Tests (linux-x64 on ubuntu-22.04) (push) Blocked by required conditions
tinymist::ci / E2E Tests (linux-x64 on ubuntu-latest) (push) Blocked by required conditions
tinymist::ci / E2E Tests (win32-x64 on windows-2019) (push) Blocked by required conditions
tinymist::ci / E2E Tests (win32-x64 on windows-latest) (push) Blocked by required conditions
tinymist::ci / prepare-build (push) Waiting to run
tinymist::ci / build-binary (push) Blocked by required conditions
tinymist::ci / build-vsc-assets (push) Blocked by required conditions
tinymist::ci / build-vscode (push) Blocked by required conditions
tinymist::ci / build-vscode-others (push) Blocked by required conditions
tinymist::ci / publish-vscode (push) Blocked by required conditions
tinymist::ci / Duplicate Actions Detection (push) Waiting to run
tinymist::ci / Check Clippy, Formatting, Completion, Documentation, and Tests (Linux) (push) Waiting to run
tinymist::gh_pages / build-gh-pages (push) Waiting to run
* fix: example impl is not correct * fix(typlite): example impl (#1800) * fix: readme generation (#1754) * fix: readme generation * feat: markdown-aware export * feat: add ieee example * fix: fix wrong behavior of list parsing and <div> elem parsing * test: update snapshot Co-authored-by: Hong Jiarong <me@jrhim.com> * fix: clippy warnings * fix: handle br tag as hard break in HTML parsing (#1769) * fix: handle br tag as hard break in HTML parsing * Revert "svg gen" This reverts commit 1ff4c0af33c209a9f653c879f2f7d504bad1ff32. --------- Co-authored-by: Myriad-Dreamin <camiyoru@gmail.com> * feat: some md-specific impl * test: bad changes --------- Co-authored-by: Hong Jiarong <me@jrhim.com> * fix(typlite): recover readme (#1759) * fix: recover readme * docs: rewrite readme * fix: compile warnings (#1774) * fix: correct link to Automattic/haper (#1748) * fix: correct link to Automattic/haper * build: generate readme * fix: heading-hash is broken by readme generation (#1779) * feat: bump typstyle to v0.13.4 and add config for hard wrap (#1737) * feat: only scroll when selection is not adjacent (#1787) * fix: quote should work as a blocks container; escape special chars in text (#1771) * feat: add protip component with markdown note block conversion * refactor: remove ProtipNode and update related parsing and tag definitions * fix: escape special characters in markdown output and update cmark-writer dependency * fix: try getting font index again (#1213, #1645) (#1790) * feat: build theme-aware pictures (equations) (#1772) * revert: "test: bad changes" * feat: m1source * fix: example impl * fix(typlite): highlight in docx export (#1798) * fix: highlight in docx export * fmt * fix: correct hover docs generated by typlite (#1761) * fix: annotate fn * fix(typlite): duplicate docs description (#1799) * fix: avoid duplicate docs description * fix: clippy error * test: flat repr of hover snapshots * g * test: update snapshots --------- Co-authored-by: Myriad-Dreamin <camiyoru@gmail.com> * test: update snapshot --------- Co-authored-by: Hong Jiarong <me@jrhim.com> * feat: `expr_tooltip` should not return docs (#1801) * fix: render example * fix: clean code --------- Co-authored-by: Myriad-Dreamin <35292584+Myriad-Dreamin@users.noreply.github.com> Co-authored-by: Wenzhuo Liu <mgt@oi-wiki.org> Co-authored-by: Myriad-Dreamin <camiyoru@gmail.com> * test: update snapshot --------- Co-authored-by: Hong Jiarong <me@jrhim.com> Co-authored-by: Wenzhuo Liu <mgt@oi-wiki.org>
This commit is contained in:
parent
7a30cbdc73
commit
c85247a85c
11 changed files with 185 additions and 13 deletions
|
@ -21,7 +21,11 @@ Speaker notes are a way to add additional information to your slides that is not
|
|||
|
||||
### Example
|
||||
|
||||
This is a speaker note
|
||||
```typ
|
||||
#box[This is a speaker note]
|
||||
```
|
||||
|
||||
<img alt="typst-block" src="data:image-hash/svg+xml;base64,redacted" />
|
||||
|
||||
# Positional Parameters
|
||||
|
||||
|
|
|
@ -28,12 +28,19 @@ pub mod md_attr {
|
|||
lang -> lang
|
||||
block -> block
|
||||
text -> text
|
||||
mode -> mode
|
||||
value -> value
|
||||
caption -> caption
|
||||
class -> class
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(TypliteAttr, Default)]
|
||||
pub struct IdocAttr {
|
||||
pub src: EcoString,
|
||||
pub mode: EcoString,
|
||||
}
|
||||
|
||||
#[derive(TypliteAttr, Default)]
|
||||
pub struct HeadingAttr {
|
||||
pub level: usize,
|
||||
|
|
|
@ -40,27 +40,35 @@ pub use cmark_writer::ast;
|
|||
pub use tinymist_project::CompileOnceArgs;
|
||||
pub use tinymist_std;
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
#[derive(Clone)]
|
||||
pub struct MarkdownDocument {
|
||||
pub base: HtmlDocument,
|
||||
world: Arc<LspWorld>,
|
||||
feat: TypliteFeat,
|
||||
ast: Option<Node>,
|
||||
}
|
||||
|
||||
impl MarkdownDocument {
|
||||
/// Create a new MarkdownDocument instance
|
||||
pub fn new(base: HtmlDocument, feat: TypliteFeat) -> Self {
|
||||
pub fn new(base: HtmlDocument, world: Arc<LspWorld>, feat: TypliteFeat) -> Self {
|
||||
Self {
|
||||
base,
|
||||
world,
|
||||
feat,
|
||||
ast: None,
|
||||
}
|
||||
}
|
||||
|
||||
/// Create a MarkdownDocument instance with pre-parsed AST
|
||||
pub fn with_ast(base: HtmlDocument, feat: TypliteFeat, ast: Node) -> Self {
|
||||
pub fn with_ast(
|
||||
base: HtmlDocument,
|
||||
world: Arc<LspWorld>,
|
||||
feat: TypliteFeat,
|
||||
ast: Node,
|
||||
) -> Self {
|
||||
Self {
|
||||
base,
|
||||
world,
|
||||
feat,
|
||||
ast: Some(ast),
|
||||
}
|
||||
|
@ -71,7 +79,7 @@ impl MarkdownDocument {
|
|||
if let Some(ast) = &self.ast {
|
||||
return Ok(ast.clone());
|
||||
}
|
||||
let parser = HtmlToAstParser::new(self.feat.clone());
|
||||
let parser = HtmlToAstParser::new(self.feat.clone(), &self.world);
|
||||
parser.parse(&self.base.root).context_ut("failed to parse")
|
||||
}
|
||||
|
||||
|
@ -209,6 +217,7 @@ impl Typlite {
|
|||
let entry = self.world.entry_state();
|
||||
let main = entry.main();
|
||||
let current = main.context("no main file in workspace")?;
|
||||
let world_origin = self.world.clone();
|
||||
let world = self.world;
|
||||
|
||||
if WorkspaceResolver::is_package_file(current) {
|
||||
|
@ -273,7 +282,7 @@ impl Typlite {
|
|||
let base = typst::compile(&world).output?;
|
||||
let mut feat = self.feat;
|
||||
feat.target = format;
|
||||
Ok(MarkdownDocument::new(base, feat))
|
||||
Ok(MarkdownDocument::new(base, world_origin, feat))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -75,7 +75,7 @@ fn run(args: CompileArgs, world: Arc<LspWorld>) -> tinymist_std::Result<()> {
|
|||
None => None,
|
||||
};
|
||||
|
||||
let converter = Typlite::new(world).with_feature(TypliteFeat {
|
||||
let converter = Typlite::new(world.clone()).with_feature(TypliteFeat {
|
||||
assets_path: assets_path.clone(),
|
||||
..Default::default()
|
||||
});
|
||||
|
|
|
@ -114,7 +114,36 @@
|
|||
}
|
||||
}
|
||||
|
||||
#let example(code) = eval(code.text, mode: "markup")
|
||||
#let example(code) = {
|
||||
let lang = if code.has("lang") and code.lang != none { code.lang } else { "typ" }
|
||||
|
||||
let lines = code.text.split("\n")
|
||||
let display = ""
|
||||
let compile = ""
|
||||
|
||||
for line in lines {
|
||||
if line.starts-with(">>>") {
|
||||
compile += line.slice(3) + "\n"
|
||||
} else if line.starts-with("<<< ") {
|
||||
display += line.slice(4) + "\n"
|
||||
} else {
|
||||
display += (line + "\n")
|
||||
compile += (line + "\n")
|
||||
}
|
||||
}
|
||||
|
||||
let result = raw(block: true, lang: lang, display)
|
||||
|
||||
result
|
||||
if sys.inputs.at("x-remove-html", default: none) != "true" {
|
||||
let mode = if lang == "typc" { "code" } else { "markup" }
|
||||
|
||||
html.elem(
|
||||
"m1idoc",
|
||||
attrs: (src: compile, mode: mode),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
#let process-math-eq(item) = {
|
||||
if type(item) == str {
|
||||
|
|
|
@ -1,7 +1,10 @@
|
|||
//! HTML parser core, containing main structures and general parsing logic
|
||||
|
||||
use std::sync::Arc;
|
||||
|
||||
use cmark_writer::ast::{CustomNode, HtmlAttribute, HtmlElement as CmarkHtmlElement, Node};
|
||||
use cmark_writer::{CommonMarkWriter, WriteResult};
|
||||
use tinymist_project::LspWorld;
|
||||
use typst::html::{tag, HtmlElement, HtmlNode};
|
||||
|
||||
use crate::attributes::{AlertsAttr, HeadingAttr, RawAttr, TypliteAttrsParser};
|
||||
|
@ -16,6 +19,7 @@ use super::{list::ListParser, table::TableParser};
|
|||
pub struct HtmlToAstParser {
|
||||
pub asset_counter: usize,
|
||||
pub feat: TypliteFeat,
|
||||
pub world: Arc<LspWorld>,
|
||||
pub list_state: Option<ListState>,
|
||||
pub list_level: usize,
|
||||
pub blocks: Vec<Node>,
|
||||
|
@ -23,9 +27,10 @@ pub struct HtmlToAstParser {
|
|||
}
|
||||
|
||||
impl HtmlToAstParser {
|
||||
pub fn new(feat: TypliteFeat) -> Self {
|
||||
pub fn new(feat: TypliteFeat, world: &Arc<LspWorld>) -> Self {
|
||||
Self {
|
||||
feat,
|
||||
world: world.clone(),
|
||||
asset_counter: 0,
|
||||
list_level: 0,
|
||||
list_state: None,
|
||||
|
@ -138,6 +143,12 @@ impl HtmlToAstParser {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
md_tag::idoc => {
|
||||
let src = self.convert_idoc(element);
|
||||
self.inline_buffer.push(src);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
md_tag::math_equation_inline | md_tag::math_equation_block => {
|
||||
if element.tag == md_tag::math_equation_block {
|
||||
self.flush_inline_buffer();
|
||||
|
|
|
@ -2,15 +2,25 @@
|
|||
|
||||
use core::fmt;
|
||||
use std::path::PathBuf;
|
||||
use std::sync::{Arc, LazyLock};
|
||||
|
||||
use base64::Engine;
|
||||
use cmark_writer::ast::{HtmlAttribute, HtmlElement as CmarkHtmlElement, Node};
|
||||
use ecow::eco_format;
|
||||
use tinymist_project::{base::ShadowApi, EntryReader, TaskInputs, MEMORY_MAIN_ENTRY};
|
||||
use typst::{
|
||||
foundations::{Bytes, Dict, IntoValue},
|
||||
html::{HtmlElement, HtmlNode},
|
||||
layout::Frame,
|
||||
layout::{Abs, Frame},
|
||||
utils::LazyHash,
|
||||
World,
|
||||
};
|
||||
|
||||
use crate::{attributes::md_attr, common::ExternalFrameNode};
|
||||
use crate::{
|
||||
attributes::{md_attr, IdocAttr, TypliteAttrsParser},
|
||||
common::ExternalFrameNode,
|
||||
ColorTheme,
|
||||
};
|
||||
|
||||
use super::core::HtmlToAstParser;
|
||||
|
||||
|
@ -119,6 +129,10 @@ impl HtmlToAstParser {
|
|||
}
|
||||
|
||||
let svg = typst_svg::svg_frame(frame);
|
||||
self.convert_svg(svg)
|
||||
}
|
||||
|
||||
fn convert_svg(&mut self, svg: String) -> Node {
|
||||
let frame_url = self.create_asset_url(&svg);
|
||||
|
||||
match frame_url {
|
||||
|
@ -187,4 +201,97 @@ impl HtmlToAstParser {
|
|||
fn base64_url(data: &str) -> AssetUrl {
|
||||
AssetUrl::Embedded(base64::engine::general_purpose::STANDARD.encode(data.as_bytes()))
|
||||
}
|
||||
/// Convert Typst inline document to CommonMark node
|
||||
pub fn convert_idoc(&mut self, element: &HtmlElement) -> Node {
|
||||
static DARK_THEME_INPUT: LazyLock<Arc<LazyHash<Dict>>> = LazyLock::new(|| {
|
||||
Arc::new(LazyHash::new(Dict::from_iter(std::iter::once((
|
||||
"x-color-theme".into(),
|
||||
"dark".into_value(),
|
||||
)))))
|
||||
});
|
||||
|
||||
if self.feat.remove_html {
|
||||
eprintln!("Removing idoc element due to remove_html feature");
|
||||
// todo: make error silent is not good.
|
||||
return Node::Text(String::new());
|
||||
}
|
||||
let attrs = match IdocAttr::parse(&element.attrs) {
|
||||
Ok(attrs) => attrs,
|
||||
Err(e) => {
|
||||
if self.feat.soft_error {
|
||||
return Node::Text(format!("Error parsing idoc attributes: {e}"));
|
||||
} else {
|
||||
// Construct error node
|
||||
return Node::HtmlElement(CmarkHtmlElement {
|
||||
tag: "div".to_string(),
|
||||
attributes: vec![HtmlAttribute {
|
||||
name: "class".to_string(),
|
||||
value: "error".to_string(),
|
||||
}],
|
||||
children: vec![Node::Text(format!("Error parsing idoc attributes: {e}"))],
|
||||
self_closing: false,
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
let src = attrs.src;
|
||||
let mode = attrs.mode;
|
||||
|
||||
let mut world = self.world.clone().task(TaskInputs {
|
||||
entry: Some(
|
||||
self.world
|
||||
.entry_state()
|
||||
.select_in_workspace(MEMORY_MAIN_ENTRY.vpath().as_rooted_path()),
|
||||
),
|
||||
inputs: match self.feat.color_theme {
|
||||
Some(ColorTheme::Dark) => Some(DARK_THEME_INPUT.clone()),
|
||||
None | Some(ColorTheme::Light) => None,
|
||||
},
|
||||
});
|
||||
// todo: cost some performance.
|
||||
world.take_db();
|
||||
|
||||
let main = world.main();
|
||||
|
||||
const PRELUDE: &str = r##"#set page(width: auto, height: auto, margin: (y: 0.45em, rest: 0em), fill: none);
|
||||
#set text(fill: rgb("#c0caf5")) if sys.inputs.at("x-color-theme", default: none) == "dark";"##;
|
||||
world
|
||||
.map_shadow_by_id(
|
||||
main,
|
||||
Bytes::from_string(match mode.as_str() {
|
||||
"code" => eco_format!("{PRELUDE}#{{{src}}}"),
|
||||
"math" => eco_format!("{PRELUDE}${src}$"),
|
||||
"markup" => eco_format!("{PRELUDE}#[{}]", src),
|
||||
// todo check mode
|
||||
// "markup" |
|
||||
_ => eco_format!("{PRELUDE}#[{}]", src),
|
||||
}),
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let doc = typst::compile(&world);
|
||||
let doc = match doc.output {
|
||||
Ok(doc) => doc,
|
||||
Err(e) => {
|
||||
if self.feat.soft_error {
|
||||
return Node::Text(format!("Error compiling idoc: {e:?}"));
|
||||
} else {
|
||||
// Construct error node
|
||||
return Node::HtmlElement(CmarkHtmlElement {
|
||||
tag: "div".to_string(),
|
||||
attributes: vec![HtmlAttribute {
|
||||
name: "class".to_string(),
|
||||
value: "error".to_string(),
|
||||
}],
|
||||
children: vec![Node::Text(format!("Error compiling idoc: {e:?}"))],
|
||||
self_closing: false,
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
let svg = typst_svg::svg_merged(&doc, Abs::zero());
|
||||
self.convert_svg(svg)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -29,6 +29,7 @@ pub mod md_tag {
|
|||
outline_entry -> m1outentry
|
||||
quote -> m1quote
|
||||
table -> m1table
|
||||
idoc -> m1idoc
|
||||
source -> m1source
|
||||
// table_cell -> m1tablecell
|
||||
grid -> m1grid
|
||||
|
|
|
@ -91,7 +91,8 @@ impl ConvKind {
|
|||
}
|
||||
|
||||
fn conv(world: LspWorld, kind: ConvKind) -> String {
|
||||
let converter = Typlite::new(Arc::new(world)).with_feature(TypliteFeat {
|
||||
let world = Arc::new(world);
|
||||
let converter = Typlite::new(world.clone()).with_feature(TypliteFeat {
|
||||
annotate_elem: kind.for_docs(),
|
||||
..Default::default()
|
||||
});
|
||||
|
|
|
@ -35,8 +35,10 @@ import { testingDebugActivate } from "./features/testing/debug";
|
|||
import { FeatureEntry, tinymistActivate, tinymistDeactivate } from "./extension.shared";
|
||||
import { commandShow, exportActivate, quickExports } from "./features/export";
|
||||
import { resolveCodeAction } from "./lsp.code-action";
|
||||
import { HoverTmpStorage } from "./features/hover-storage.tmp";
|
||||
|
||||
LanguageState.Client = LanguageClient;
|
||||
LanguageState.HoverTmpStorage = HoverTmpStorage;
|
||||
|
||||
const systemActivateTable = (): FeatureEntry[] => [
|
||||
[extensionState.features.label, labelActivate],
|
||||
|
|
|
@ -31,8 +31,9 @@ export class HoverTmpStorage {
|
|||
try {
|
||||
await vscode.workspace.fs.createDirectory(tmpImageDir);
|
||||
return new HoverStorageTmpFsHandler(Uri.joinPath(this.context.storageUri, "tmp/"));
|
||||
} catch (_err) {
|
||||
} catch (err) {
|
||||
// todo: handle errors safely
|
||||
console.error("Failed to create hover image directory:", err);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue