mirror of
https://github.com/Myriad-Dreamin/tinymist.git
synced 2025-11-22 12:34:39 +00:00
feat: compile tinymist-query for wasm32 target (#1947)
- #2025 - #2026 --------- Co-authored-by: Momijiichigo <ichigomomiji436@gmail.com>
This commit is contained in:
parent
b102b42d2c
commit
79f68dc94d
12 changed files with 191 additions and 88 deletions
3
Cargo.lock
generated
3
Cargo.lock
generated
|
|
@ -4250,7 +4250,8 @@ dependencies = [
|
|||
"console_error_panic_hook",
|
||||
"js-sys",
|
||||
"reflexo-typst",
|
||||
"tinymist-world",
|
||||
"tinymist-project",
|
||||
"tinymist-query",
|
||||
"vergen",
|
||||
"wasm-bindgen",
|
||||
]
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@ web = [
|
|||
"js-sys",
|
||||
"console_error_panic_hook",
|
||||
"no-content-hint",
|
||||
"tinymist-world/web",
|
||||
"tinymist-project/web",
|
||||
"reflexo-typst/web",
|
||||
]
|
||||
|
||||
|
|
@ -31,7 +31,8 @@ no-content-hint = ["reflexo-typst/no-content-hint"]
|
|||
[dependencies]
|
||||
wasm-bindgen = { version = "0.2.100", optional = true }
|
||||
js-sys = { version = "0.3.77", optional = true }
|
||||
tinymist-world.workspace = true
|
||||
tinymist-project.workspace = true
|
||||
tinymist-query.workspace = true
|
||||
reflexo-typst.workspace = true
|
||||
|
||||
console_error_panic_hook = { version = "0.1.2", optional = true }
|
||||
|
|
|
|||
|
|
@ -40,9 +40,11 @@ notify.workspace = true
|
|||
|
||||
fonts = ["typst-assets/fonts"]
|
||||
no-content-hint = ["tinymist-task/no-content-hint"]
|
||||
lsp = ["system", "toml"]
|
||||
lsp = ["toml"]
|
||||
# "system",
|
||||
|
||||
system = ["tinymist-std/system", "tinymist-world/system"]
|
||||
web = ["tinymist-std/web", "tinymist-world/web"]
|
||||
|
||||
[lints]
|
||||
workspace = true
|
||||
|
|
|
|||
|
|
@ -11,22 +11,20 @@ mod lock;
|
|||
mod lsp;
|
||||
#[cfg(feature = "system")]
|
||||
mod watch;
|
||||
#[cfg(feature = "system")]
|
||||
|
||||
pub mod world;
|
||||
|
||||
pub use args::*;
|
||||
pub use compiler::*;
|
||||
pub use entry::*;
|
||||
pub use model::*;
|
||||
|
||||
#[cfg(feature = "lsp")]
|
||||
pub use lock::*;
|
||||
pub use model::*;
|
||||
pub use world::*;
|
||||
|
||||
#[cfg(feature = "lsp")]
|
||||
pub use lsp::*;
|
||||
#[cfg(feature = "system")]
|
||||
pub use watch::*;
|
||||
#[cfg(feature = "system")]
|
||||
pub use world::*;
|
||||
|
||||
pub use tinymist_world::{CompileSignal, CompileSnapshot, ProjectInsId};
|
||||
|
||||
|
|
|
|||
|
|
@ -1,24 +1,20 @@
|
|||
use std::path::Path;
|
||||
use std::{borrow::Cow, sync::Arc};
|
||||
use std::sync::Arc;
|
||||
|
||||
use tinymist_std::error::prelude::*;
|
||||
use tinymist_std::{bail, ImmutPath};
|
||||
use tinymist_std::ImmutPath;
|
||||
use tinymist_task::ExportTarget;
|
||||
use tinymist_world::config::CompileFontOpts;
|
||||
use tinymist_world::font::system::SystemFontSearcher;
|
||||
use tinymist_world::package::{registry::HttpRegistry, RegistryPathMapper};
|
||||
use tinymist_world::vfs::{system::SystemAccessModel, Vfs};
|
||||
use tinymist_world::package::RegistryPathMapper;
|
||||
use tinymist_world::vfs::Vfs;
|
||||
use tinymist_world::{args::*, WorldComputeGraph};
|
||||
use tinymist_world::{
|
||||
CompileSnapshot, CompilerFeat, CompilerUniverse, CompilerWorld, EntryOpts, EntryState,
|
||||
};
|
||||
use typst::diag::FileResult;
|
||||
use typst::foundations::{Bytes, Dict, Str, Value};
|
||||
use typst::foundations::{Bytes, Dict};
|
||||
use typst::utils::LazyHash;
|
||||
use typst::Features;
|
||||
|
||||
use crate::ProjectInput;
|
||||
|
||||
use crate::world::font::FontResolverImpl;
|
||||
use crate::{CompiledArtifact, Interrupt};
|
||||
|
||||
|
|
@ -33,7 +29,11 @@ impl CompilerFeat for LspCompilerFeat {
|
|||
/// It accesses a physical file system.
|
||||
type AccessModel = DynAccessModel;
|
||||
/// It performs native HTTP requests for fetching package data.
|
||||
type Registry = HttpRegistry;
|
||||
#[cfg(feature = "system")]
|
||||
type Registry = tinymist_world::package::registry::HttpRegistry;
|
||||
// todo: registry in browser
|
||||
#[cfg(not(feature = "system"))]
|
||||
type Registry = tinymist_world::package::registry::DummyRegistry;
|
||||
}
|
||||
|
||||
/// LSP universe that spawns LSP worlds.
|
||||
|
|
@ -59,6 +59,7 @@ pub trait WorldProvider {
|
|||
fn resolve(&self) -> Result<LspUniverse>;
|
||||
}
|
||||
|
||||
#[cfg(feature = "system")]
|
||||
impl WorldProvider for CompileOnceArgs {
|
||||
fn resolve(&self) -> Result<LspUniverse> {
|
||||
let entry = self.entry()?.try_into()?;
|
||||
|
|
@ -78,7 +79,7 @@ impl WorldProvider for CompileOnceArgs {
|
|||
packages,
|
||||
fonts,
|
||||
self.creation_timestamp,
|
||||
DynAccessModel(Arc::new(SystemAccessModel {})),
|
||||
DynAccessModel(Arc::new(tinymist_world::vfs::system::SystemAccessModel {})),
|
||||
))
|
||||
}
|
||||
|
||||
|
|
@ -129,8 +130,11 @@ impl WorldProvider for CompileOnceArgs {
|
|||
}
|
||||
|
||||
// todo: merge me with the above impl
|
||||
impl WorldProvider for (ProjectInput, ImmutPath) {
|
||||
#[cfg(feature = "system")]
|
||||
impl WorldProvider for (crate::ProjectInput, ImmutPath) {
|
||||
fn resolve(&self) -> Result<LspUniverse> {
|
||||
use typst::foundations::{Str, Value};
|
||||
|
||||
let (proj, lock_dir) = self;
|
||||
let entry = self.entry()?.try_into()?;
|
||||
let inputs = proj
|
||||
|
|
@ -172,7 +176,7 @@ impl WorldProvider for (ProjectInput, ImmutPath) {
|
|||
packages,
|
||||
Arc::new(fonts),
|
||||
None, // creation_timestamp - not available in project file context
|
||||
DynAccessModel(Arc::new(SystemAccessModel {})),
|
||||
DynAccessModel(Arc::new(tinymist_world::vfs::system::SystemAccessModel {})),
|
||||
))
|
||||
}
|
||||
|
||||
|
|
@ -207,6 +211,11 @@ impl WorldProvider for (ProjectInput, ImmutPath) {
|
|||
}
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "system"))]
|
||||
type LspRegistry = tinymist_world::package::registry::DummyRegistry;
|
||||
#[cfg(feature = "system")]
|
||||
type LspRegistry = tinymist_world::package::registry::HttpRegistry;
|
||||
|
||||
/// Builder for LSP universe.
|
||||
pub struct LspUniverseBuilder;
|
||||
|
||||
|
|
@ -219,7 +228,7 @@ impl LspUniverseBuilder {
|
|||
export_target: ExportTarget,
|
||||
features: Features,
|
||||
inputs: ImmutDict,
|
||||
package_registry: HttpRegistry,
|
||||
package_registry: LspRegistry,
|
||||
font_resolver: Arc<FontResolverImpl>,
|
||||
creation_timestamp: Option<i64>,
|
||||
access_model: DynAccessModel,
|
||||
|
|
@ -246,38 +255,54 @@ impl LspUniverseBuilder {
|
|||
}
|
||||
|
||||
/// Resolve fonts from given options.
|
||||
#[cfg(feature = "system")]
|
||||
pub fn only_embedded_fonts() -> Result<FontResolverImpl> {
|
||||
let mut searcher = SystemFontSearcher::new();
|
||||
searcher.resolve_opts(CompileFontOpts {
|
||||
let mut searcher = tinymist_world::font::system::SystemFontSearcher::new();
|
||||
searcher.resolve_opts(tinymist_world::config::CompileFontOpts {
|
||||
font_paths: vec![],
|
||||
no_system_fonts: true,
|
||||
with_embedded_fonts: typst_assets::fonts().map(Cow::Borrowed).collect(),
|
||||
with_embedded_fonts: typst_assets::fonts()
|
||||
.map(std::borrow::Cow::Borrowed)
|
||||
.collect(),
|
||||
})?;
|
||||
Ok(searcher.build())
|
||||
}
|
||||
|
||||
/// Resolve fonts from given options.
|
||||
#[cfg(feature = "system")]
|
||||
pub fn resolve_fonts(args: CompileFontArgs) -> Result<FontResolverImpl> {
|
||||
let mut searcher = SystemFontSearcher::new();
|
||||
searcher.resolve_opts(CompileFontOpts {
|
||||
let mut searcher = tinymist_world::font::system::SystemFontSearcher::new();
|
||||
searcher.resolve_opts(tinymist_world::config::CompileFontOpts {
|
||||
font_paths: args.font_paths,
|
||||
no_system_fonts: args.ignore_system_fonts,
|
||||
with_embedded_fonts: typst_assets::fonts().map(Cow::Borrowed).collect(),
|
||||
with_embedded_fonts: typst_assets::fonts()
|
||||
.map(std::borrow::Cow::Borrowed)
|
||||
.collect(),
|
||||
})?;
|
||||
Ok(searcher.build())
|
||||
}
|
||||
|
||||
/// Resolve package registry from given options.
|
||||
/// Resolves package registry from given options.
|
||||
#[cfg(feature = "system")]
|
||||
pub fn resolve_package(
|
||||
cert_path: Option<ImmutPath>,
|
||||
args: Option<&CompilePackageArgs>,
|
||||
) -> HttpRegistry {
|
||||
HttpRegistry::new(
|
||||
) -> tinymist_world::package::registry::HttpRegistry {
|
||||
tinymist_world::package::registry::HttpRegistry::new(
|
||||
cert_path,
|
||||
args.and_then(|args| Some(args.package_path.clone()?.into())),
|
||||
args.and_then(|args| Some(args.package_cache_path.clone()?.into())),
|
||||
)
|
||||
}
|
||||
|
||||
/// Resolves package registry from given options.
|
||||
#[cfg(not(feature = "system"))]
|
||||
pub fn resolve_package(
|
||||
_cert_path: Option<ImmutPath>,
|
||||
_args: Option<&CompilePackageArgs>,
|
||||
) -> tinymist_world::package::registry::DummyRegistry {
|
||||
tinymist_world::package::registry::DummyRegistry
|
||||
}
|
||||
}
|
||||
|
||||
/// Access model for LSP universe and worlds.
|
||||
|
|
|
|||
|
|
@ -4,8 +4,11 @@ pub use tinymist_world as base;
|
|||
pub use tinymist_world::args::*;
|
||||
pub use tinymist_world::config::CompileFontOpts;
|
||||
pub use tinymist_world::entry::*;
|
||||
pub use tinymist_world::{diag, font, package, system, vfs};
|
||||
pub use tinymist_world::{diag, font, package, vfs};
|
||||
pub use tinymist_world::{
|
||||
with_main, CompilerUniverse, CompilerWorld, DiagnosticFormat, EntryOpts, EntryState,
|
||||
RevisingUniverse, SourceWorld, TaskInputs,
|
||||
};
|
||||
|
||||
#[cfg(feature = "system")]
|
||||
pub use tinymist_world::system;
|
||||
|
|
|
|||
|
|
@ -209,26 +209,28 @@ impl TypeCompletionWorker<'_, '_, '_, '_> {
|
|||
BuiltinTy::TextSize => return None,
|
||||
BuiltinTy::TextLang => {
|
||||
for (&key, desc) in rust_iso639::ALL_MAP.entries() {
|
||||
let detail = eco_format!("An ISO 639-1/2/3 language code, {}.", desc.name);
|
||||
let detail =
|
||||
eco_format!("An ISO 639-1/2/3 language code, {}.", desc.get_name());
|
||||
self.base.push_completion(Completion {
|
||||
kind: CompletionKind::Syntax,
|
||||
label: key.to_lowercase().into(),
|
||||
apply: Some(eco_format!("\"{}\"", key.to_lowercase())),
|
||||
detail: Some(detail),
|
||||
label_details: Some(desc.name.into()),
|
||||
label_details: Some(desc.get_name()),
|
||||
..Completion::default()
|
||||
});
|
||||
}
|
||||
}
|
||||
BuiltinTy::TextRegion => {
|
||||
for (&key, desc) in rust_iso3166::ALPHA2_MAP.entries() {
|
||||
let detail = eco_format!("An ISO 3166-1 alpha-2 region code, {}.", desc.name);
|
||||
let detail =
|
||||
eco_format!("An ISO 3166-1 alpha-2 region code, {}.", desc.get_name());
|
||||
self.base.push_completion(Completion {
|
||||
kind: CompletionKind::Syntax,
|
||||
label: key.to_lowercase().into(),
|
||||
apply: Some(eco_format!("\"{}\"", key.to_lowercase())),
|
||||
detail: Some(detail),
|
||||
label_details: Some(desc.name.into()),
|
||||
label_details: Some(desc.get_name()),
|
||||
..Completion::default()
|
||||
});
|
||||
}
|
||||
|
|
@ -346,3 +348,37 @@ impl TypeCompletionWorker<'_, '_, '_, '_> {
|
|||
Some(())
|
||||
}
|
||||
}
|
||||
|
||||
// desc.name()
|
||||
|
||||
trait GetName {
|
||||
fn get_name(&self) -> EcoString;
|
||||
}
|
||||
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
impl GetName for rust_iso639::LanguageCode<'_> {
|
||||
fn get_name(&self) -> EcoString {
|
||||
self.name.into()
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(all(direct_wasm, target_arch = "wasm32")))]
|
||||
impl GetName for rust_iso3166::CountryCode {
|
||||
fn get_name(&self) -> EcoString {
|
||||
self.name.into()
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(target_arch = "wasm32")]
|
||||
impl GetName for rust_iso639::LanguageCode {
|
||||
fn get_name(&self) -> EcoString {
|
||||
self.name().into()
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(all(direct_wasm, target_arch = "wasm32"))]
|
||||
impl GetName for rust_iso3166::CountryCode {
|
||||
fn get_name(&self) -> EcoString {
|
||||
self.name().into()
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -20,9 +20,7 @@ use tinymist_std::typst::TypstDocument;
|
|||
use tinymist_world::debug_loc::DataSource;
|
||||
use tinymist_world::vfs::{PathResolution, WorkspaceResolver};
|
||||
use tinymist_world::{EntryReader, DETACHED_ENTRY};
|
||||
use typst::diag::{
|
||||
eco_format, At, FileError, FileResult, SourceDiagnostic, SourceResult, StrResult,
|
||||
};
|
||||
use typst::diag::{At, FileError, FileResult, SourceDiagnostic, SourceResult, StrResult};
|
||||
use typst::foundations::{Bytes, IntoValue, Module, StyleChain, Styles};
|
||||
use typst::introspection::Introspector;
|
||||
use typst::layout::Position;
|
||||
|
|
@ -674,6 +672,7 @@ impl SharedContext {
|
|||
}
|
||||
|
||||
/// Get the local packages and their descriptions.
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
pub fn local_packages(&self) -> EcoVec<PackageSpec> {
|
||||
crate::package::list_package_by_namespace(&self.world.registry, eco_format!("local"))
|
||||
.into_iter()
|
||||
|
|
@ -681,6 +680,12 @@ impl SharedContext {
|
|||
.collect()
|
||||
}
|
||||
|
||||
/// Get the local packages and their descriptions.
|
||||
#[cfg(target_arch = "wasm32")]
|
||||
pub fn local_packages(&self) -> EcoVec<PackageSpec> {
|
||||
eco_vec![]
|
||||
}
|
||||
|
||||
pub(crate) fn const_eval(rr: ast::Expr<'_>) -> Option<Value> {
|
||||
Some(match rr {
|
||||
ast::Expr::None(_) => Value::None,
|
||||
|
|
|
|||
|
|
@ -31,11 +31,7 @@ pub fn path_to_url(path: &Path) -> anyhow::Result<Url> {
|
|||
return untitled_url(untitled);
|
||||
}
|
||||
|
||||
Url::from_file_path(path).or_else(|never| {
|
||||
let _: () = never;
|
||||
|
||||
anyhow::bail!("could not convert path to URI: path: {path:?}",)
|
||||
})
|
||||
url_from_file_path(path)
|
||||
}
|
||||
|
||||
/// Convert a path resolution to a URL.
|
||||
|
|
@ -54,9 +50,7 @@ pub fn url_to_path(uri: Url) -> PathBuf {
|
|||
return PathBuf::from("/untitled/nEoViM-BuG");
|
||||
}
|
||||
|
||||
return uri
|
||||
.to_file_path()
|
||||
.unwrap_or_else(|_| panic!("could not convert URI to path: URI: {uri:?}",));
|
||||
return url_to_file_path(&uri);
|
||||
}
|
||||
|
||||
if uri.scheme() == "untitled" {
|
||||
|
|
@ -73,7 +67,40 @@ pub fn url_to_path(uri: Url) -> PathBuf {
|
|||
return Path::new(String::from_utf8_lossy(&bytes).as_ref()).clean();
|
||||
}
|
||||
|
||||
uri.to_file_path().unwrap()
|
||||
url_to_file_path(&uri)
|
||||
}
|
||||
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
fn url_from_file_path(path: &Path) -> anyhow::Result<Url> {
|
||||
Url::from_file_path(path).or_else(|never| {
|
||||
let _: () = never;
|
||||
|
||||
anyhow::bail!("could not convert path to URI: path: {path:?}",)
|
||||
})
|
||||
}
|
||||
|
||||
#[cfg(target_arch = "wasm32")]
|
||||
fn url_from_file_path(path: &Path) -> anyhow::Result<Url> {
|
||||
// In WASM, create a simple file:// URL
|
||||
let path_str = path.to_string_lossy();
|
||||
let url_str = if path_str.starts_with('/') {
|
||||
format!("file://{}", path_str)
|
||||
} else {
|
||||
format!("file:///{}", path_str)
|
||||
};
|
||||
Url::parse(&url_str).map_err(|e| anyhow::anyhow!("could not convert path to URI: {}", e))
|
||||
}
|
||||
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
fn url_to_file_path(uri: &Url) -> PathBuf {
|
||||
uri.to_file_path()
|
||||
.unwrap_or_else(|_| panic!("could not convert URI to path: URI: {uri:?}",))
|
||||
}
|
||||
|
||||
#[cfg(target_arch = "wasm32")]
|
||||
fn url_to_file_path(uri: &Url) -> PathBuf {
|
||||
// In WASM, manually parse the URL path
|
||||
PathBuf::from(uri.path())
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
|
|
|||
|
|
@ -1,14 +1,10 @@
|
|||
//! Package management tools.
|
||||
|
||||
use std::collections::HashSet;
|
||||
use std::path::PathBuf;
|
||||
use std::sync::OnceLock;
|
||||
|
||||
use ecow::{eco_format, eco_vec, EcoVec};
|
||||
use parking_lot::Mutex;
|
||||
use ecow::eco_format;
|
||||
// use reflexo_typst::typst::prelude::*;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use tinymist_world::package::registry::HttpRegistry;
|
||||
use tinymist_world::package::PackageSpec;
|
||||
use typst::diag::{EcoString, StrResult};
|
||||
use typst::syntax::package::PackageManifest;
|
||||
|
|
@ -77,11 +73,47 @@ pub fn check_package(ctx: &mut LocalContext, spec: &PackageInfo) -> StrResult<()
|
|||
Ok(())
|
||||
}
|
||||
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
/// Get the packages in namespaces and their descriptions.
|
||||
pub fn list_package_by_namespace(
|
||||
registry: &HttpRegistry,
|
||||
registry: &tinymist_world::package::registry::HttpRegistry,
|
||||
ns: EcoString,
|
||||
) -> EcoVec<(PathBuf, PackageSpec)> {
|
||||
) -> ecow::EcoVec<(PathBuf, PackageSpec)> {
|
||||
use std::collections::HashSet;
|
||||
use std::sync::OnceLock;
|
||||
|
||||
use ecow::eco_vec;
|
||||
use parking_lot::Mutex;
|
||||
|
||||
trait IsDirFollowLinks {
|
||||
fn is_dir_follow_links(&self) -> bool;
|
||||
}
|
||||
|
||||
impl IsDirFollowLinks for PathBuf {
|
||||
fn is_dir_follow_links(&self) -> bool {
|
||||
// Although `canonicalize` is heavy, we must use it because `symlink_metadata`
|
||||
// is not reliable.
|
||||
self.canonicalize()
|
||||
.map(|meta| meta.is_dir())
|
||||
.unwrap_or(false)
|
||||
}
|
||||
}
|
||||
|
||||
fn once_log<T, E: std::fmt::Display>(result: Result<T, E>, site: &'static str) -> Option<T> {
|
||||
let err = match result {
|
||||
Ok(value) => return Some(value),
|
||||
Err(err) => err,
|
||||
};
|
||||
|
||||
static ONCE: OnceLock<Mutex<HashSet<&'static str>>> = OnceLock::new();
|
||||
let mut once = ONCE.get_or_init(Default::default).lock();
|
||||
if once.insert(site) {
|
||||
log::error!("failed to perform {site}: {err}");
|
||||
}
|
||||
|
||||
None
|
||||
}
|
||||
|
||||
// search packages locally. We only search in the data
|
||||
// directory and not the cache directory, because the latter is not
|
||||
// intended for storage of local packages.
|
||||
|
|
@ -148,32 +180,3 @@ pub fn list_package_by_namespace(
|
|||
|
||||
packages
|
||||
}
|
||||
|
||||
trait IsDirFollowLinks {
|
||||
fn is_dir_follow_links(&self) -> bool;
|
||||
}
|
||||
|
||||
impl IsDirFollowLinks for PathBuf {
|
||||
fn is_dir_follow_links(&self) -> bool {
|
||||
// Although `canonicalize` is heavy, we must use it because `symlink_metadata`
|
||||
// is not reliable.
|
||||
self.canonicalize()
|
||||
.map(|meta| meta.is_dir())
|
||||
.unwrap_or(false)
|
||||
}
|
||||
}
|
||||
|
||||
fn once_log<T, E: std::fmt::Display>(result: Result<T, E>, site: &'static str) -> Option<T> {
|
||||
let err = match result {
|
||||
Ok(value) => return Some(value),
|
||||
Err(err) => err,
|
||||
};
|
||||
|
||||
static ONCE: OnceLock<Mutex<HashSet<&'static str>>> = OnceLock::new();
|
||||
let mut once = ONCE.get_or_init(Default::default).lock();
|
||||
if once.insert(site) {
|
||||
log::error!("failed to perform {site}: {err}");
|
||||
}
|
||||
|
||||
None
|
||||
}
|
||||
|
|
|
|||
|
|
@ -814,7 +814,6 @@ impl<F: CompilerFeat> World for CompilerWorld<F> {
|
|||
if let Some(timestamp) = self.creation_timestamp {
|
||||
tinymist_std::time::UtcDateTime::from_unix_timestamp(timestamp)
|
||||
.unwrap_or_else(|_| now().into())
|
||||
.into()
|
||||
} else {
|
||||
now().into()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -51,10 +51,13 @@ clap = ["dep:clap"]
|
|||
# Note: this is the feature for typlite as a CLI, not for others.
|
||||
# `docx` is enabled in CLI mode, but not in library mode.
|
||||
# `fonts` is enabled in CLI mode.
|
||||
cli = ["clap", "clap/wrap_help", "docx", "fonts"]
|
||||
cli = ["clap", "clap/wrap_help", "docx", "fonts", "system"]
|
||||
no-content-hint = ["tinymist-project/no-content-hint"]
|
||||
docx = ["docx-rs", "image", "resvg"]
|
||||
|
||||
system = ["tinymist-project/system"]
|
||||
web = ["tinymist-project/web"]
|
||||
|
||||
# Embeds Typst's default fonts for
|
||||
# - text (Linux Libertine),
|
||||
# - math (New Computer Modern Math), and
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue