mirror of
https://github.com/Myriad-Dreamin/tinymist.git
synced 2025-07-24 05:05:00 +00:00
refactor: combine typst-preview and tinymist compiler (#337)
* refactor: combine typst-preview and tinymist compiler * dev: update link * fix: bad changes * dev: sync snapshot compiler
This commit is contained in:
parent
b265dd49d6
commit
7d65829ed7
19 changed files with 397 additions and 418 deletions
87
Cargo.lock
generated
87
Cargo.lock
generated
|
@ -140,6 +140,16 @@ dependencies = [
|
||||||
"num-traits",
|
"num-traits",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "archery"
|
||||||
|
version = "1.2.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "8967cd1cc9e9e1954f644e14fbd6042fe9a37da96c52a67e44a2ac18261f8561"
|
||||||
|
dependencies = [
|
||||||
|
"static_assertions",
|
||||||
|
"triomphe",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "arraydeque"
|
name = "arraydeque"
|
||||||
version = "0.5.1"
|
version = "0.5.1"
|
||||||
|
@ -2889,8 +2899,7 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "reflexo"
|
name = "reflexo"
|
||||||
version = "0.5.0-rc4"
|
version = "0.5.0-rc4"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "git+https://github.com/Myriad-Dreamin/typst.ts/?rev=36b969e2d5743544dca8679c53c89129b989ec80#36b969e2d5743544dca8679c53c89129b989ec80"
|
||||||
checksum = "803cbdda7d5beefc048966f342ba9a13dab586f136a8fe7f6d915b2f073a9151"
|
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"base64 0.22.1",
|
"base64 0.22.1",
|
||||||
"bitvec",
|
"bitvec",
|
||||||
|
@ -2898,10 +2907,12 @@ dependencies = [
|
||||||
"dashmap",
|
"dashmap",
|
||||||
"ecow 0.2.2",
|
"ecow 0.2.2",
|
||||||
"fxhash",
|
"fxhash",
|
||||||
|
"instant",
|
||||||
"once_cell",
|
"once_cell",
|
||||||
"parking_lot",
|
"parking_lot",
|
||||||
"path-clean",
|
"path-clean",
|
||||||
"rkyv",
|
"rkyv",
|
||||||
|
"rustc-hash",
|
||||||
"serde",
|
"serde",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
"serde_repr",
|
"serde_repr",
|
||||||
|
@ -2910,6 +2921,55 @@ dependencies = [
|
||||||
"tiny-skia-path",
|
"tiny-skia-path",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "reflexo-vfs"
|
||||||
|
version = "0.5.0-rc4"
|
||||||
|
source = "git+https://github.com/Myriad-Dreamin/typst.ts/?rev=36b969e2d5743544dca8679c53c89129b989ec80#36b969e2d5743544dca8679c53c89129b989ec80"
|
||||||
|
dependencies = [
|
||||||
|
"append-only-vec",
|
||||||
|
"indexmap 2.2.6",
|
||||||
|
"log",
|
||||||
|
"nohash-hasher",
|
||||||
|
"once_cell",
|
||||||
|
"parking_lot",
|
||||||
|
"reflexo",
|
||||||
|
"rpds",
|
||||||
|
"rustc-hash",
|
||||||
|
"typst",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "reflexo-world"
|
||||||
|
version = "0.5.0-rc4"
|
||||||
|
source = "git+https://github.com/Myriad-Dreamin/typst.ts/?rev=36b969e2d5743544dca8679c53c89129b989ec80#36b969e2d5743544dca8679c53c89129b989ec80"
|
||||||
|
dependencies = [
|
||||||
|
"append-only-vec",
|
||||||
|
"chrono",
|
||||||
|
"codespan-reporting",
|
||||||
|
"comemo 0.4.0",
|
||||||
|
"dashmap",
|
||||||
|
"dirs",
|
||||||
|
"flate2",
|
||||||
|
"fontdb",
|
||||||
|
"hex",
|
||||||
|
"indexmap 2.2.6",
|
||||||
|
"log",
|
||||||
|
"nohash-hasher",
|
||||||
|
"once_cell",
|
||||||
|
"parking_lot",
|
||||||
|
"reflexo",
|
||||||
|
"reflexo-vfs",
|
||||||
|
"reqwest",
|
||||||
|
"rustc-hash",
|
||||||
|
"serde",
|
||||||
|
"serde_json",
|
||||||
|
"sha2",
|
||||||
|
"strum 0.25.0",
|
||||||
|
"tar",
|
||||||
|
"typst",
|
||||||
|
"typst-ts-core",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "regex"
|
name = "regex"
|
||||||
version = "1.10.4"
|
version = "1.10.4"
|
||||||
|
@ -3075,6 +3135,15 @@ version = "0.19.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "3cd14fd5e3b777a7422cca79358c57a8f6e3a703d9ac187448d0daf220c2407f"
|
checksum = "3cd14fd5e3b777a7422cca79358c57a8f6e3a703d9ac187448d0daf220c2407f"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rpds"
|
||||||
|
version = "1.1.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "a0e15515d3ce3313324d842629ea4905c25a13f81953eadb88f85516f59290a4"
|
||||||
|
dependencies = [
|
||||||
|
"archery",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rust_iso3166"
|
name = "rust_iso3166"
|
||||||
version = "0.1.13"
|
version = "0.1.13"
|
||||||
|
@ -4425,12 +4494,10 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "typst-ts-compiler"
|
name = "typst-ts-compiler"
|
||||||
version = "0.5.0-rc4"
|
version = "0.5.0-rc4"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "git+https://github.com/Myriad-Dreamin/typst.ts/?rev=36b969e2d5743544dca8679c53c89129b989ec80#36b969e2d5743544dca8679c53c89129b989ec80"
|
||||||
checksum = "1b5d68fc30324347a294155cc4691defa4e01aaff23d7e3c1c40a3c8e5d22e3f"
|
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"append-only-vec",
|
"append-only-vec",
|
||||||
"base64 0.22.1",
|
"base64 0.22.1",
|
||||||
"chrono",
|
|
||||||
"codespan-reporting",
|
"codespan-reporting",
|
||||||
"comemo 0.4.0",
|
"comemo 0.4.0",
|
||||||
"dirs",
|
"dirs",
|
||||||
|
@ -4446,7 +4513,8 @@ dependencies = [
|
||||||
"once_cell",
|
"once_cell",
|
||||||
"parking_lot",
|
"parking_lot",
|
||||||
"pathdiff",
|
"pathdiff",
|
||||||
"reqwest",
|
"reflexo-vfs",
|
||||||
|
"reflexo-world",
|
||||||
"rustc-hash",
|
"rustc-hash",
|
||||||
"serde",
|
"serde",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
|
@ -4463,8 +4531,7 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "typst-ts-core"
|
name = "typst-ts-core"
|
||||||
version = "0.5.0-rc4"
|
version = "0.5.0-rc4"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "git+https://github.com/Myriad-Dreamin/typst.ts/?rev=36b969e2d5743544dca8679c53c89129b989ec80#36b969e2d5743544dca8679c53c89129b989ec80"
|
||||||
checksum = "5b9355a7f3b2f687088524fa1d5c0d0cbe45878e9672d7a321aec491ae10b1dd"
|
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"base64 0.22.1",
|
"base64 0.22.1",
|
||||||
"base64-serde",
|
"base64-serde",
|
||||||
|
@ -4491,6 +4558,7 @@ dependencies = [
|
||||||
"serde_with",
|
"serde_with",
|
||||||
"sha2",
|
"sha2",
|
||||||
"siphasher 1.0.1",
|
"siphasher 1.0.1",
|
||||||
|
"svgtypes",
|
||||||
"tiny-skia",
|
"tiny-skia",
|
||||||
"tiny-skia-path",
|
"tiny-skia-path",
|
||||||
"ttf-parser",
|
"ttf-parser",
|
||||||
|
@ -4501,8 +4569,7 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "typst-ts-svg-exporter"
|
name = "typst-ts-svg-exporter"
|
||||||
version = "0.5.0-rc4"
|
version = "0.5.0-rc4"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "git+https://github.com/Myriad-Dreamin/typst.ts/?rev=36b969e2d5743544dca8679c53c89129b989ec80#36b969e2d5743544dca8679c53c89129b989ec80"
|
||||||
checksum = "13b1e7baba2453d072cbc1e97a43d5a8ecfe36299fc103e9156bb9470abd35e0"
|
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"base64 0.22.1",
|
"base64 0.22.1",
|
||||||
"comemo 0.4.0",
|
"comemo 0.4.0",
|
||||||
|
|
11
Cargo.toml
11
Cargo.toml
|
@ -51,6 +51,7 @@ typst-assets = "0.11.1"
|
||||||
reflexo = { version = "0.5.0-rc4", default-features = false, features = [
|
reflexo = { version = "0.5.0-rc4", default-features = false, features = [
|
||||||
"flat-vector",
|
"flat-vector",
|
||||||
] }
|
] }
|
||||||
|
reflexo-world = { version = "0.5.0-rc4", features = ["system"] }
|
||||||
typst-ts-core = { version = "0.5.0-rc4", default-features = false }
|
typst-ts-core = { version = "0.5.0-rc4", default-features = false }
|
||||||
typst-ts-compiler = { version = "0.5.0-rc4" }
|
typst-ts-compiler = { version = "0.5.0-rc4" }
|
||||||
typst-ts-svg-exporter = { version = "0.5.0-rc4" }
|
typst-ts-svg-exporter = { version = "0.5.0-rc4" }
|
||||||
|
@ -143,13 +144,15 @@ typst-syntax = { git = "https://github.com/Myriad-Dreamin/typst.git", branch = "
|
||||||
# typst-render = { path = "../typst/crates/typst-render" }
|
# typst-render = { path = "../typst/crates/typst-render" }
|
||||||
# typst-syntax = { path = "../typst/crates/typst-syntax" }
|
# typst-syntax = { path = "../typst/crates/typst-syntax" }
|
||||||
|
|
||||||
# typst-ts-svg-exporter = { git = "https://github.com/Myriad-Dreamin/typst.ts/", rev = "9cced415e29e5e341ad4bdcc32ab3e67ffad74db" }
|
typst-ts-svg-exporter = { git = "https://github.com/Myriad-Dreamin/typst.ts/", rev = "36b969e2d5743544dca8679c53c89129b989ec80" }
|
||||||
# reflexo = { git = "https://github.com/Myriad-Dreamin/typst.ts/", rev = "9cced415e29e5e341ad4bdcc32ab3e67ffad74db" }
|
reflexo = { git = "https://github.com/Myriad-Dreamin/typst.ts/", rev = "36b969e2d5743544dca8679c53c89129b989ec80" }
|
||||||
# typst-ts-core = { git = "https://github.com/Myriad-Dreamin/typst.ts/", rev = "9cced415e29e5e341ad4bdcc32ab3e67ffad74db" }
|
reflexo-world = { git = "https://github.com/Myriad-Dreamin/typst.ts/", rev = "36b969e2d5743544dca8679c53c89129b989ec80" }
|
||||||
# typst-ts-compiler = { git = "https://github.com/Myriad-Dreamin/typst.ts/", rev = "9cced415e29e5e341ad4bdcc32ab3e67ffad74db" }
|
typst-ts-core = { git = "https://github.com/Myriad-Dreamin/typst.ts/", rev = "36b969e2d5743544dca8679c53c89129b989ec80" }
|
||||||
|
typst-ts-compiler = { git = "https://github.com/Myriad-Dreamin/typst.ts/", rev = "36b969e2d5743544dca8679c53c89129b989ec80" }
|
||||||
|
|
||||||
# typst-ts-svg-exporter = { path = "../typst.ts/exporter/svg" }
|
# typst-ts-svg-exporter = { path = "../typst.ts/exporter/svg" }
|
||||||
# reflexo = { path = "../typst.ts/crates/reflexo/" }
|
# reflexo = { path = "../typst.ts/crates/reflexo/" }
|
||||||
|
# reflexo-world = { path = "../typst.ts/crates/reflexo-world/" }
|
||||||
# typst-ts-core = { path = "../typst.ts/core" }
|
# typst-ts-core = { path = "../typst.ts/core" }
|
||||||
# typst-ts-compiler = { path = "../typst.ts/compiler" }
|
# typst-ts-compiler = { path = "../typst.ts/compiler" }
|
||||||
# typstyle = { path = "../typstyle" }
|
# typstyle = { path = "../typstyle" }
|
||||||
|
|
|
@ -420,10 +420,7 @@ pub trait AnalysisResources {
|
||||||
fn resolve(&self, spec: &PackageSpec) -> Result<Arc<Path>, PackageError>;
|
fn resolve(&self, spec: &PackageSpec) -> Result<Arc<Path>, PackageError>;
|
||||||
|
|
||||||
/// Get all the files in the workspace.
|
/// Get all the files in the workspace.
|
||||||
fn iter_dependencies<'a>(
|
fn iter_dependencies(&self, f: &mut dyn FnMut(ImmutPath));
|
||||||
&'a self,
|
|
||||||
f: &mut dyn FnMut(&'a ImmutPath, FileResult<&std::time::SystemTime>),
|
|
||||||
);
|
|
||||||
|
|
||||||
/// Resolve extra font information.
|
/// Resolve extra font information.
|
||||||
fn font_info(&self, _font: Font) -> Option<Arc<DataSource>> {
|
fn font_info(&self, _font: Font) -> Option<Arc<DataSource>> {
|
||||||
|
|
|
@ -36,11 +36,11 @@ impl SemanticRequest for SymbolRequest {
|
||||||
|
|
||||||
let mut symbols = vec![];
|
let mut symbols = vec![];
|
||||||
|
|
||||||
ctx.resources.iter_dependencies(&mut |path, _| {
|
ctx.resources.iter_dependencies(&mut |path| {
|
||||||
let Ok(source) = ctx.source_by_path(path) else {
|
let Ok(source) = ctx.source_by_path(&path) else {
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
let uri = path_to_url(path).unwrap();
|
let uri = path_to_url(&path).unwrap();
|
||||||
let res = get_lexical_hierarchy(source.clone(), LexicalScopeKind::Symbol).and_then(
|
let res = get_lexical_hierarchy(source.clone(), LexicalScopeKind::Symbol).and_then(
|
||||||
|symbols| {
|
|symbols| {
|
||||||
self.pattern.as_ref().map(|pattern| {
|
self.pattern.as_ref().map(|pattern| {
|
||||||
|
|
|
@ -8,17 +8,13 @@ use std::{
|
||||||
use once_cell::sync::Lazy;
|
use once_cell::sync::Lazy;
|
||||||
pub use serde::Serialize;
|
pub use serde::Serialize;
|
||||||
use serde_json::{ser::PrettyFormatter, Serializer, Value};
|
use serde_json::{ser::PrettyFormatter, Serializer, Value};
|
||||||
use typst::{
|
use typst::syntax::{
|
||||||
diag::FileResult,
|
ast::{self, AstNode},
|
||||||
syntax::{
|
FileId as TypstFileId, LinkedNode, Source, SyntaxKind, VirtualPath,
|
||||||
ast::{self, AstNode},
|
|
||||||
FileId as TypstFileId, LinkedNode, Source, SyntaxKind, VirtualPath,
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
use typst::{diag::PackageError, foundations::Bytes};
|
use typst::{diag::PackageError, foundations::Bytes};
|
||||||
use typst_ts_compiler::{
|
use typst_ts_compiler::{
|
||||||
service::{CompileDriver, Compiler, EntryManager},
|
service::CompileDriver, EntryManager, EntryReader, ShadowApi, TypstSystemUniverse, WorldDeps,
|
||||||
NotifyApi, ShadowApi,
|
|
||||||
};
|
};
|
||||||
use typst_ts_core::{
|
use typst_ts_core::{
|
||||||
config::compiler::{EntryOpts, EntryState},
|
config::compiler::{EntryOpts, EntryState},
|
||||||
|
@ -46,10 +42,7 @@ impl<'a> AnalysisResources for WrapWorld<'a> {
|
||||||
self.0.registry.resolve(spec)
|
self.0.registry.resolve(spec)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn iter_dependencies<'b>(
|
fn iter_dependencies(&self, f: &mut dyn FnMut(reflexo::ImmutPath)) {
|
||||||
&'b self,
|
|
||||||
f: &mut dyn FnMut(&'b reflexo::ImmutPath, FileResult<&typst_ts_compiler::Time>),
|
|
||||||
) {
|
|
||||||
self.0.iter_dependencies(f)
|
self.0.iter_dependencies(f)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -65,7 +58,7 @@ pub fn snapshot_testing(name: &str, f: &impl Fn(&mut AnalysisContext, PathBuf))
|
||||||
#[cfg(windows)]
|
#[cfg(windows)]
|
||||||
let contents = contents.replace("\r\n", "\n");
|
let contents = contents.replace("\r\n", "\n");
|
||||||
|
|
||||||
run_with_sources(&contents, |w: &mut TypstSystemWorld, p| {
|
run_with_sources(&contents, |w: &mut TypstSystemUniverse, p| {
|
||||||
let root = w.workspace_root().unwrap();
|
let root = w.workspace_root().unwrap();
|
||||||
let paths = w
|
let paths = w
|
||||||
.shadow_paths()
|
.shadow_paths()
|
||||||
|
@ -74,7 +67,8 @@ pub fn snapshot_testing(name: &str, f: &impl Fn(&mut AnalysisContext, PathBuf))
|
||||||
TypstFileId::new(None, VirtualPath::new(p.strip_prefix(&root).unwrap()))
|
TypstFileId::new(None, VirtualPath::new(p.strip_prefix(&root).unwrap()))
|
||||||
})
|
})
|
||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
let w = WrapWorld(w);
|
let mut w = w.spawn();
|
||||||
|
let w = WrapWorld(&mut w);
|
||||||
let mut ctx = AnalysisContext::new(
|
let mut ctx = AnalysisContext::new(
|
||||||
&w,
|
&w,
|
||||||
Analysis {
|
Analysis {
|
||||||
|
@ -103,13 +97,16 @@ pub fn get_test_properties(s: &str) -> HashMap<&'_ str, &'_ str> {
|
||||||
props
|
props
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn run_with_sources<T>(source: &str, f: impl FnOnce(&mut TypstSystemWorld, PathBuf) -> T) -> T {
|
pub fn run_with_sources<T>(
|
||||||
|
source: &str,
|
||||||
|
f: impl FnOnce(&mut TypstSystemUniverse, PathBuf) -> T,
|
||||||
|
) -> T {
|
||||||
let root = if cfg!(windows) {
|
let root = if cfg!(windows) {
|
||||||
PathBuf::from("C:\\")
|
PathBuf::from("C:\\")
|
||||||
} else {
|
} else {
|
||||||
PathBuf::from("/")
|
PathBuf::from("/")
|
||||||
};
|
};
|
||||||
let mut world = TypstSystemWorld::new(CompileOpts {
|
let mut world = TypstSystemUniverse::new(CompileOpts {
|
||||||
entry: EntryOpts::new_rooted(root.as_path().into(), None),
|
entry: EntryOpts::new_rooted(root.as_path().into(), None),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
})
|
})
|
||||||
|
@ -145,12 +142,12 @@ pub fn run_with_sources<T>(source: &str, f: impl FnOnce(&mut TypstSystemWorld, P
|
||||||
}
|
}
|
||||||
|
|
||||||
world.mutate_entry(EntryState::new_detached()).unwrap();
|
world.mutate_entry(EntryState::new_detached()).unwrap();
|
||||||
let mut driver = CompileDriver::new(world);
|
let mut driver = CompileDriver::new(std::marker::PhantomData, world);
|
||||||
let _ = driver.compile(&mut Default::default());
|
let _ = driver.compile(&mut Default::default());
|
||||||
|
|
||||||
let pw = last_pw.unwrap();
|
let pw = last_pw.unwrap();
|
||||||
driver
|
driver
|
||||||
.world_mut()
|
.universe_mut()
|
||||||
.mutate_entry(EntryState::new_rooted(
|
.mutate_entry(EntryState::new_rooted(
|
||||||
root.as_path().into(),
|
root.as_path().into(),
|
||||||
Some(TypstFileId::new(
|
Some(TypstFileId::new(
|
||||||
|
@ -159,7 +156,7 @@ pub fn run_with_sources<T>(source: &str, f: impl FnOnce(&mut TypstSystemWorld, P
|
||||||
)),
|
)),
|
||||||
))
|
))
|
||||||
.unwrap();
|
.unwrap();
|
||||||
f(driver.world_mut(), pw)
|
f(driver.universe_mut(), pw)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn find_test_range(s: &Source) -> Range<usize> {
|
pub fn find_test_range(s: &Source) -> Range<usize> {
|
||||||
|
|
|
@ -13,10 +13,7 @@ use tinymist_query::analysis::Analysis;
|
||||||
use tinymist_query::ExportKind;
|
use tinymist_query::ExportKind;
|
||||||
use tinymist_render::PeriscopeRenderer;
|
use tinymist_render::PeriscopeRenderer;
|
||||||
use tokio::sync::{mpsc, watch};
|
use tokio::sync::{mpsc, watch};
|
||||||
use typst_ts_compiler::{
|
use typst_ts_compiler::vfs::notify::{FileChangeSet, MemoryEvent};
|
||||||
service::CompileDriverImpl,
|
|
||||||
vfs::notify::{FileChangeSet, MemoryEvent},
|
|
||||||
};
|
|
||||||
use typst_ts_core::config::compiler::EntryState;
|
use typst_ts_core::config::compiler::EntryState;
|
||||||
|
|
||||||
use self::{
|
use self::{
|
||||||
|
@ -28,12 +25,10 @@ use self::{
|
||||||
};
|
};
|
||||||
use crate::{
|
use crate::{
|
||||||
compiler::CompileServer,
|
compiler::CompileServer,
|
||||||
world::{ImmutDict, LspWorld, LspWorldBuilder},
|
world::{ImmutDict, LspWorldBuilder},
|
||||||
TypstLanguageServer,
|
TypstLanguageServer,
|
||||||
};
|
};
|
||||||
|
|
||||||
type CompileDriverInner = CompileDriverImpl<LspWorld>;
|
|
||||||
|
|
||||||
impl CompileServer {
|
impl CompileServer {
|
||||||
pub fn restart_server(&mut self, group: &str) {
|
pub fn restart_server(&mut self, group: &str) {
|
||||||
let server = self.server(
|
let server = self.server(
|
||||||
|
@ -102,13 +97,12 @@ impl CompileServer {
|
||||||
self.handle.spawn_blocking(move || {
|
self.handle.spawn_blocking(move || {
|
||||||
// Create the world
|
// Create the world
|
||||||
let font_resolver = font_resolver.wait().clone();
|
let font_resolver = font_resolver.wait().clone();
|
||||||
let world = LspWorldBuilder::build(entry_.clone(), font_resolver, inputs)
|
let verse = LspWorldBuilder::build(entry_.clone(), font_resolver, inputs)
|
||||||
.expect("incorrect options");
|
.expect("incorrect options");
|
||||||
|
|
||||||
// Create the compiler
|
// Create the compiler
|
||||||
let driver = CompileDriverInner::new(world);
|
|
||||||
let driver = CompileDriver {
|
let driver = CompileDriver {
|
||||||
inner: driver,
|
inner: std::marker::PhantomData,
|
||||||
handler,
|
handler,
|
||||||
analysis: Analysis {
|
analysis: Analysis {
|
||||||
position_encoding,
|
position_encoding,
|
||||||
|
@ -121,7 +115,7 @@ impl CompileServer {
|
||||||
|
|
||||||
// Create the actor
|
// Create the actor
|
||||||
tokio::spawn(
|
tokio::spawn(
|
||||||
CompileServerActor::new(driver, entry_, intr_tx, intr_rx)
|
CompileServerActor::new(driver, verse, entry_, intr_tx, intr_rx)
|
||||||
.with_watch(true)
|
.with_watch(true)
|
||||||
.spawn(),
|
.spawn(),
|
||||||
);
|
);
|
||||||
|
|
|
@ -42,16 +42,16 @@ use tinymist_query::{
|
||||||
use tinymist_render::PeriscopeRenderer;
|
use tinymist_render::PeriscopeRenderer;
|
||||||
use tokio::sync::{mpsc, oneshot, watch};
|
use tokio::sync::{mpsc, oneshot, watch};
|
||||||
use typst::{
|
use typst::{
|
||||||
diag::{FileResult, PackageError, SourceDiagnostic, SourceResult},
|
diag::{PackageError, SourceDiagnostic, SourceResult},
|
||||||
layout::Position,
|
layout::Position,
|
||||||
model::Document as TypstDocument,
|
model::Document as TypstDocument,
|
||||||
syntax::package::PackageSpec,
|
syntax::package::PackageSpec,
|
||||||
World as TypstWorld,
|
World as TypstWorld,
|
||||||
};
|
};
|
||||||
use typst_ts_compiler::{
|
use typst_ts_compiler::{
|
||||||
service::{CompileDriverImpl, CompileEnv, CompileMiddleware, Compiler, EntryManager, EnvWorld},
|
service::{CompileEnv, CompileMiddleware, Compiler, PureCompiler},
|
||||||
vfs::notify::MemoryEvent,
|
vfs::notify::MemoryEvent,
|
||||||
Time,
|
EntryManager, EntryReader,
|
||||||
};
|
};
|
||||||
use typst_ts_core::{
|
use typst_ts_core::{
|
||||||
config::compiler::EntryState, debug_loc::DataSource, error::prelude::*, typst::prelude::EcoVec,
|
config::compiler::EntryState, debug_loc::DataSource, error::prelude::*, typst::prelude::EcoVec,
|
||||||
|
@ -61,18 +61,18 @@ use typst_ts_core::{
|
||||||
use super::{
|
use super::{
|
||||||
editor::{EditorRequest, TinymistCompileStatusEnum},
|
editor::{EditorRequest, TinymistCompileStatusEnum},
|
||||||
export::ExportConfig,
|
export::ExportConfig,
|
||||||
typ_server::{is_inactive, CompileServerActor, Interrupt},
|
typ_server::{CompileServerActor, Interrupt},
|
||||||
};
|
};
|
||||||
use crate::{
|
use crate::{
|
||||||
actor::export::ExportRequest,
|
actor::export::ExportRequest,
|
||||||
compiler_init::CompileConfig,
|
compiler_init::CompileConfig,
|
||||||
tools::preview::{CompilationHandle, CompileStatus},
|
tools::preview::{CompilationHandle, CompileStatus},
|
||||||
utils,
|
utils,
|
||||||
world::LspWorld,
|
world::{LspCompilerFeat, LspWorld},
|
||||||
};
|
};
|
||||||
|
|
||||||
type CompileDriverInner = CompileDriverImpl<LspWorld>;
|
type CompileService<C> = CompileServerActor<C, LspCompilerFeat>;
|
||||||
type CompileService = CompileServerActor<CompileDriver>;
|
pub type CompileClientActor = CompileClientActorImpl<CompileDriver>;
|
||||||
|
|
||||||
type EditorSender = mpsc::UnboundedSender<EditorRequest>;
|
type EditorSender = mpsc::UnboundedSender<EditorRequest>;
|
||||||
|
|
||||||
|
@ -131,7 +131,7 @@ impl CompileHandler {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct CompileDriver {
|
pub struct CompileDriver {
|
||||||
pub(super) inner: CompileDriverInner,
|
pub(super) inner: PureCompiler<LspWorld>,
|
||||||
#[allow(unused)]
|
#[allow(unused)]
|
||||||
pub(super) handler: CompileHandler,
|
pub(super) handler: CompileHandler,
|
||||||
pub(super) analysis: Analysis,
|
pub(super) analysis: Analysis,
|
||||||
|
@ -139,7 +139,7 @@ pub struct CompileDriver {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl CompileMiddleware for CompileDriver {
|
impl CompileMiddleware for CompileDriver {
|
||||||
type Compiler = CompileDriverInner;
|
type Compiler = PureCompiler<LspWorld>;
|
||||||
|
|
||||||
fn inner(&self) -> &Self::Compiler {
|
fn inner(&self) -> &Self::Compiler {
|
||||||
&self.inner
|
&self.inner
|
||||||
|
@ -149,7 +149,11 @@ impl CompileMiddleware for CompileDriver {
|
||||||
&mut self.inner
|
&mut self.inner
|
||||||
}
|
}
|
||||||
|
|
||||||
fn wrap_compile(&mut self, env: &mut CompileEnv) -> SourceResult<Arc<typst::model::Document>> {
|
fn wrap_compile(
|
||||||
|
&mut self,
|
||||||
|
world: &LspWorld,
|
||||||
|
env: &mut CompileEnv,
|
||||||
|
) -> SourceResult<Arc<typst::model::Document>> {
|
||||||
self.handler
|
self.handler
|
||||||
.editor_tx
|
.editor_tx
|
||||||
.send(EditorRequest::Status(
|
.send(EditorRequest::Status(
|
||||||
|
@ -158,10 +162,14 @@ impl CompileMiddleware for CompileDriver {
|
||||||
))
|
))
|
||||||
.unwrap();
|
.unwrap();
|
||||||
self.handler.status(CompileStatus::Compiling);
|
self.handler.status(CompileStatus::Compiling);
|
||||||
match self.inner_mut().compile(env) {
|
match self
|
||||||
|
.ensure_main(world)
|
||||||
|
.and_then(|_| self.inner_mut().compile(world, env))
|
||||||
|
{
|
||||||
Ok(doc) => {
|
Ok(doc) => {
|
||||||
self.handler.notify_compile(Ok(doc.clone()));
|
self.handler.notify_compile(Ok(doc.clone()));
|
||||||
self.notify_diagnostics(
|
self.notify_diagnostics(
|
||||||
|
world,
|
||||||
EcoVec::new(),
|
EcoVec::new(),
|
||||||
env.tracer.as_ref().map(|e| e.clone().warnings()),
|
env.tracer.as_ref().map(|e| e.clone().warnings()),
|
||||||
);
|
);
|
||||||
|
@ -170,7 +178,11 @@ impl CompileMiddleware for CompileDriver {
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
self.handler
|
self.handler
|
||||||
.notify_compile(Err(CompileStatus::CompileError));
|
.notify_compile(Err(CompileStatus::CompileError));
|
||||||
self.notify_diagnostics(err, env.tracer.as_ref().map(|e| e.clone().warnings()));
|
self.notify_diagnostics(
|
||||||
|
world,
|
||||||
|
err,
|
||||||
|
env.tracer.as_ref().map(|e| e.clone().warnings()),
|
||||||
|
);
|
||||||
Err(EcoVec::new())
|
Err(EcoVec::new())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -180,20 +192,22 @@ impl CompileMiddleware for CompileDriver {
|
||||||
impl CompileDriver {
|
impl CompileDriver {
|
||||||
fn notify_diagnostics(
|
fn notify_diagnostics(
|
||||||
&mut self,
|
&mut self,
|
||||||
|
world: &LspWorld,
|
||||||
errors: EcoVec<SourceDiagnostic>,
|
errors: EcoVec<SourceDiagnostic>,
|
||||||
warnings: Option<EcoVec<SourceDiagnostic>>,
|
warnings: Option<EcoVec<SourceDiagnostic>>,
|
||||||
) {
|
) {
|
||||||
trace!("notify diagnostics: {errors:#?} {warnings:#?}");
|
trace!("notify diagnostics: {errors:#?} {warnings:#?}");
|
||||||
|
|
||||||
let diagnostics = self.run_analysis(|ctx| {
|
let diagnostics = self.run_analysis(world, |ctx| {
|
||||||
tinymist_query::convert_diagnostics(ctx, errors.iter().chain(warnings.iter().flatten()))
|
tinymist_query::convert_diagnostics(ctx, errors.iter().chain(warnings.iter().flatten()))
|
||||||
});
|
});
|
||||||
|
|
||||||
match diagnostics {
|
match diagnostics {
|
||||||
Ok(diagnostics) => {
|
Ok(diagnostics) => {
|
||||||
|
let entry = world.entry_state();
|
||||||
// todo: better way to remove diagnostics
|
// todo: better way to remove diagnostics
|
||||||
// todo: check all errors in this file
|
// todo: check all errors in this file
|
||||||
let detached = is_inactive(&self.inner.world().entry);
|
let detached = entry.is_inactive();
|
||||||
let valid = !detached;
|
let valid = !detached;
|
||||||
self.handler.push_diagnostics(valid.then_some(diagnostics));
|
self.handler.push_diagnostics(valid.then_some(diagnostics));
|
||||||
}
|
}
|
||||||
|
@ -206,15 +220,14 @@ impl CompileDriver {
|
||||||
|
|
||||||
pub fn run_analysis<T>(
|
pub fn run_analysis<T>(
|
||||||
&mut self,
|
&mut self,
|
||||||
|
w: &LspWorld,
|
||||||
f: impl FnOnce(&mut AnalysisContext<'_>) -> T,
|
f: impl FnOnce(&mut AnalysisContext<'_>) -> T,
|
||||||
) -> anyhow::Result<T> {
|
) -> anyhow::Result<T> {
|
||||||
let w = self.inner.world_mut();
|
|
||||||
|
|
||||||
let Some(main) = w.main_id() else {
|
let Some(main) = w.main_id() else {
|
||||||
error!("TypstActor: main file is not set");
|
error!("TypstActor: main file is not set");
|
||||||
bail!("main file is not set");
|
bail!("main file is not set");
|
||||||
};
|
};
|
||||||
let Some(root) = w.entry.root() else {
|
let Some(root) = w.entry_state().root() else {
|
||||||
error!("TypstActor: root is not set");
|
error!("TypstActor: root is not set");
|
||||||
bail!("root is not set");
|
bail!("root is not set");
|
||||||
};
|
};
|
||||||
|
@ -222,12 +235,8 @@ impl CompileDriver {
|
||||||
info!("TypstActor: failed to prepare main file: {err:?}");
|
info!("TypstActor: failed to prepare main file: {err:?}");
|
||||||
anyhow!("failed to get source: {err}")
|
anyhow!("failed to get source: {err}")
|
||||||
})?;
|
})?;
|
||||||
w.prepare_env(&mut Default::default()).map_err(|err| {
|
|
||||||
error!("TypstActor: failed to prepare env: {err:?}");
|
|
||||||
anyhow!("failed to prepare env")
|
|
||||||
})?;
|
|
||||||
|
|
||||||
struct WrapWorld<'a>(&'a mut LspWorld, &'a PeriscopeRenderer);
|
struct WrapWorld<'a>(&'a LspWorld, &'a PeriscopeRenderer);
|
||||||
|
|
||||||
impl<'a> AnalysisResources for WrapWorld<'a> {
|
impl<'a> AnalysisResources for WrapWorld<'a> {
|
||||||
fn world(&self) -> &dyn typst::World {
|
fn world(&self) -> &dyn typst::World {
|
||||||
|
@ -239,17 +248,14 @@ impl CompileDriver {
|
||||||
self.0.registry.resolve(spec)
|
self.0.registry.resolve(spec)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn iter_dependencies<'b>(
|
fn iter_dependencies(&self, f: &mut dyn FnMut(ImmutPath)) {
|
||||||
&'b self,
|
use typst_ts_compiler::WorldDeps;
|
||||||
f: &mut dyn FnMut(&'b ImmutPath, FileResult<&Time>),
|
|
||||||
) {
|
|
||||||
use typst_ts_compiler::NotifyApi;
|
|
||||||
self.0.iter_dependencies(f)
|
self.0.iter_dependencies(f)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Resolve extra font information.
|
/// Resolve extra font information.
|
||||||
fn font_info(&self, font: TypstFont) -> Option<Arc<DataSource>> {
|
fn font_info(&self, font: TypstFont) -> Option<Arc<DataSource>> {
|
||||||
self.0.font_resolver.inner.describe_font(&font)
|
self.0.font_resolver.describe_font(&font)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Resolve periscope image at the given position.
|
/// Resolve periscope image at the given position.
|
||||||
|
@ -270,20 +276,20 @@ impl CompileDriver {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct CompileClientActor {
|
pub struct CompileClientActorImpl<C: Compiler> {
|
||||||
pub diag_group: String,
|
pub diag_group: String,
|
||||||
pub config: CompileConfig,
|
pub config: CompileConfig,
|
||||||
entry: EntryState,
|
entry: EntryState,
|
||||||
intr_tx: mpsc::UnboundedSender<Interrupt<CompileService>>,
|
intr_tx: mpsc::UnboundedSender<Interrupt<CompileService<C>>>,
|
||||||
export_tx: mpsc::UnboundedSender<ExportRequest>,
|
export_tx: mpsc::UnboundedSender<ExportRequest>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl CompileClientActor {
|
impl<C: Compiler<W = LspWorld> + Send> CompileClientActorImpl<C> {
|
||||||
pub(crate) fn new(
|
pub(crate) fn new(
|
||||||
diag_group: String,
|
diag_group: String,
|
||||||
config: CompileConfig,
|
config: CompileConfig,
|
||||||
entry: EntryState,
|
entry: EntryState,
|
||||||
intr_tx: mpsc::UnboundedSender<Interrupt<CompileService>>,
|
intr_tx: mpsc::UnboundedSender<Interrupt<CompileService<C>>>,
|
||||||
export_tx: mpsc::UnboundedSender<ExportRequest>,
|
export_tx: mpsc::UnboundedSender<ExportRequest>,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
Self {
|
Self {
|
||||||
|
@ -297,11 +303,11 @@ impl CompileClientActor {
|
||||||
|
|
||||||
fn steal_inner<Ret: Send + 'static>(
|
fn steal_inner<Ret: Send + 'static>(
|
||||||
&self,
|
&self,
|
||||||
f: impl FnOnce(&mut CompileService) -> Ret + Send + 'static,
|
f: impl FnOnce(&mut CompileService<C>) -> Ret + Send + 'static,
|
||||||
) -> ZResult<oneshot::Receiver<Ret>> {
|
) -> ZResult<oneshot::Receiver<Ret>> {
|
||||||
let (tx, rx) = oneshot::channel();
|
let (tx, rx) = oneshot::channel();
|
||||||
|
|
||||||
let task = Box::new(move |this: &mut CompileService| {
|
let task = Box::new(move |this: &mut CompileService<C>| {
|
||||||
if tx.send(f(this)).is_err() {
|
if tx.send(f(this)).is_err() {
|
||||||
// Receiver was dropped. The main thread may have exited, or the request may
|
// Receiver was dropped. The main thread may have exited, or the request may
|
||||||
// have been cancelled.
|
// have been cancelled.
|
||||||
|
@ -319,7 +325,7 @@ impl CompileClientActor {
|
||||||
/// Steal the compiler thread and run the given function.
|
/// Steal the compiler thread and run the given function.
|
||||||
pub fn steal<Ret: Send + 'static>(
|
pub fn steal<Ret: Send + 'static>(
|
||||||
&self,
|
&self,
|
||||||
f: impl FnOnce(&mut CompileService) -> Ret + Send + 'static,
|
f: impl FnOnce(&mut CompileService<C>) -> Ret + Send + 'static,
|
||||||
) -> ZResult<Ret> {
|
) -> ZResult<Ret> {
|
||||||
utils::threaded_receive(self.steal_inner(f)?)
|
utils::threaded_receive(self.steal_inner(f)?)
|
||||||
}
|
}
|
||||||
|
@ -327,31 +333,46 @@ impl CompileClientActor {
|
||||||
/// Steal the compiler thread and run the given function.
|
/// Steal the compiler thread and run the given function.
|
||||||
pub async fn steal_async<Ret: Send + 'static>(
|
pub async fn steal_async<Ret: Send + 'static>(
|
||||||
&self,
|
&self,
|
||||||
f: impl FnOnce(&mut CompileService) -> Ret + Send + 'static,
|
f: impl FnOnce(&mut CompileService<C>) -> Ret + Send + 'static,
|
||||||
) -> ZResult<Ret> {
|
) -> ZResult<Ret> {
|
||||||
self.steal_inner(f)?
|
self.steal_inner(f)?
|
||||||
.await
|
.await
|
||||||
.map_err(map_string_err("failed to call steal_async"))
|
.map_err(map_string_err("failed to call steal_async"))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn steal_state<T: Send + Sync + 'static>(
|
pub fn sync_config(&mut self, config: CompileConfig) {
|
||||||
&self,
|
self.config = config;
|
||||||
f: impl FnOnce(&mut AnalysisContext, Option<VersionedDocument>) -> T + Send + Sync + 'static,
|
|
||||||
) -> anyhow::Result<T> {
|
|
||||||
self.steal(move |compiler| {
|
|
||||||
let doc = compiler.success_doc();
|
|
||||||
let c = &mut compiler.compiler.compiler;
|
|
||||||
c.run_analysis(move |ctx| f(ctx, doc))
|
|
||||||
})?
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn steal_world<T: Send + Sync + 'static>(
|
pub fn add_memory_changes(&self, event: MemoryEvent) {
|
||||||
&self,
|
let _ = self.intr_tx.send(Interrupt::Memory(event));
|
||||||
f: impl FnOnce(&mut AnalysisContext) -> T + Send + Sync + 'static,
|
|
||||||
) -> anyhow::Result<T> {
|
|
||||||
self.steal(move |compiler| compiler.compiler.compiler.run_analysis(f))?
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(crate) fn change_export_pdf(&mut self, config: ExportConfig) {
|
||||||
|
let _ = self.export_tx.send(ExportRequest::ChangeConfig(config));
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn on_export(&self, kind: ExportKind, path: PathBuf) -> anyhow::Result<Option<PathBuf>> {
|
||||||
|
// todo: we currently doesn't respect the path argument...
|
||||||
|
info!("CompileActor: on export: {}", path.display());
|
||||||
|
|
||||||
|
let (tx, rx) = oneshot::channel();
|
||||||
|
let _ = self.export_tx.send(ExportRequest::Oneshot(Some(kind), tx));
|
||||||
|
let res: Option<PathBuf> = utils::threaded_receive(rx)?;
|
||||||
|
|
||||||
|
info!("CompileActor: on export end: {path:?} as {res:?}");
|
||||||
|
Ok(res)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn on_save_export(&self, path: PathBuf) -> anyhow::Result<()> {
|
||||||
|
info!("CompileActor: on save export: {}", path.display());
|
||||||
|
let _ = self.export_tx.send(ExportRequest::OnSaved);
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl CompileClientActorImpl<CompileDriver> {
|
||||||
pub fn settle(&mut self) {
|
pub fn settle(&mut self) {
|
||||||
let _ = self.change_entry(None);
|
let _ = self.change_entry(None);
|
||||||
info!("TypstActor({}): settle requested", self.diag_group);
|
info!("TypstActor({}): settle requested", self.diag_group);
|
||||||
|
@ -363,10 +384,6 @@ impl CompileClientActor {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn sync_config(&mut self, config: CompileConfig) {
|
|
||||||
self.config = config;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn change_entry(&mut self, path: Option<ImmutPath>) -> Result<bool, Error> {
|
pub fn change_entry(&mut self, path: Option<ImmutPath>) -> Result<bool, Error> {
|
||||||
if path
|
if path
|
||||||
.as_deref()
|
.as_deref()
|
||||||
|
@ -388,8 +405,8 @@ impl CompileClientActor {
|
||||||
self.steal(move |compiler| {
|
self.steal(move |compiler| {
|
||||||
compiler.change_entry(next.clone());
|
compiler.change_entry(next.clone());
|
||||||
|
|
||||||
let next_is_inactive = is_inactive(&next);
|
let next_is_inactive = next.is_inactive();
|
||||||
let res = compiler.compiler.world_mut().mutate_entry(next);
|
let res = compiler.verse.mutate_entry(next);
|
||||||
|
|
||||||
if next_is_inactive {
|
if next_is_inactive {
|
||||||
info!("TypstActor: removing diag");
|
info!("TypstActor: removing diag");
|
||||||
|
@ -408,12 +425,26 @@ impl CompileClientActor {
|
||||||
Ok(true)
|
Ok(true)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn add_memory_changes(&self, event: MemoryEvent) {
|
pub fn steal_state<T: Send + Sync + 'static>(
|
||||||
let _ = self.intr_tx.send(Interrupt::Memory(event));
|
&self,
|
||||||
|
f: impl FnOnce(&mut AnalysisContext, Option<VersionedDocument>) -> T + Send + Sync + 'static,
|
||||||
|
) -> anyhow::Result<T> {
|
||||||
|
self.steal(move |compiler| {
|
||||||
|
let doc = compiler.success_doc();
|
||||||
|
let w = compiler.verse.spawn();
|
||||||
|
let c = &mut compiler.compiler.compiler;
|
||||||
|
c.run_analysis(&w, move |ctx| f(ctx, doc))
|
||||||
|
})?
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn change_export_pdf(&mut self, config: ExportConfig) {
|
pub fn steal_world<T: Send + Sync + 'static>(
|
||||||
let _ = self.export_tx.send(ExportRequest::ChangeConfig(config));
|
&self,
|
||||||
|
f: impl FnOnce(&mut AnalysisContext) -> T + Send + Sync + 'static,
|
||||||
|
) -> anyhow::Result<T> {
|
||||||
|
self.steal(move |compiler| {
|
||||||
|
let w = compiler.verse.spawn();
|
||||||
|
compiler.compiler.compiler.run_analysis(&w, f)
|
||||||
|
})?
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn clear_cache(&self) {
|
pub fn clear_cache(&self) {
|
||||||
|
@ -426,13 +457,15 @@ impl CompileClientActor {
|
||||||
let dg = self.diag_group.clone();
|
let dg = self.diag_group.clone();
|
||||||
self.steal(move |c| {
|
self.steal(move |c| {
|
||||||
let cc = &c.compiler.compiler;
|
let cc = &c.compiler.compiler;
|
||||||
|
let w = c.verse.spawn();
|
||||||
|
|
||||||
let info = ServerInfoResponse {
|
let info = ServerInfoResponse {
|
||||||
root: cc.world().entry.root().map(|e| e.as_ref().to_owned()),
|
root: w.entry_state().root().map(|e| e.as_ref().to_owned()),
|
||||||
font_paths: cc.world().font_resolver.font_paths().to_owned(),
|
font_paths: w.font_resolver.font_paths().to_owned(),
|
||||||
inputs: cc.world().inputs.as_ref().deref().clone(),
|
inputs: c.verse.inputs().as_ref().deref().clone(),
|
||||||
estimated_memory_usage: HashMap::from_iter([
|
estimated_memory_usage: HashMap::from_iter([
|
||||||
("vfs".to_owned(), cc.world().vfs.memory_usage()),
|
// todo: vfs memory usage
|
||||||
|
// ("vfs".to_owned(), w.vfs.read().memory_usage()),
|
||||||
("analysis".to_owned(), cc.analysis.estimated_memory()),
|
("analysis".to_owned(), cc.analysis.estimated_memory()),
|
||||||
]),
|
]),
|
||||||
};
|
};
|
||||||
|
@ -441,23 +474,4 @@ impl CompileClientActor {
|
||||||
})
|
})
|
||||||
.map_err(|e| e.into())
|
.map_err(|e| e.into())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn on_export(&self, kind: ExportKind, path: PathBuf) -> anyhow::Result<Option<PathBuf>> {
|
|
||||||
// todo: we currently doesn't respect the path argument...
|
|
||||||
info!("CompileActor: on export: {}", path.display());
|
|
||||||
|
|
||||||
let (tx, rx) = oneshot::channel();
|
|
||||||
let _ = self.export_tx.send(ExportRequest::Oneshot(Some(kind), tx));
|
|
||||||
let res: Option<PathBuf> = utils::threaded_receive(rx)?;
|
|
||||||
|
|
||||||
info!("CompileActor: on export end: {path:?} as {res:?}");
|
|
||||||
Ok(res)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn on_save_export(&self, path: PathBuf) -> anyhow::Result<()> {
|
|
||||||
info!("CompileActor: on save export: {}", path.display());
|
|
||||||
let _ = self.export_tx.send(ExportRequest::OnSaved);
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,20 +7,28 @@ use std::{collections::HashSet, path::Path, sync::Arc, thread::JoinHandle};
|
||||||
use tinymist_query::VersionedDocument;
|
use tinymist_query::VersionedDocument;
|
||||||
use tokio::sync::{mpsc, oneshot};
|
use tokio::sync::{mpsc, oneshot};
|
||||||
|
|
||||||
use typst_ts_compiler::service::{
|
use typst_ts_compiler::{
|
||||||
features::{FeatureSet, WITH_COMPILING_STATUS_FEATURE},
|
service::{
|
||||||
watch_deps, CompileEnv, CompileReporter, Compiler, ConsoleDiagReporter,
|
features::{FeatureSet, WITH_COMPILING_STATUS_FEATURE},
|
||||||
|
watch_deps, CompileEnv, CompileReporter, Compiler, ConsoleDiagReporter,
|
||||||
|
},
|
||||||
|
vfs::notify::{FilesystemEvent, MemoryEvent, NotifyMessage},
|
||||||
|
world::{CompilerFeat, CompilerUniverse, CompilerWorld},
|
||||||
|
Revising, WorldDeps,
|
||||||
};
|
};
|
||||||
use typst_ts_compiler::vfs::notify::{FilesystemEvent, MemoryEvent, NotifyMessage};
|
use typst_ts_core::{config::compiler::EntryState, TypstDocument};
|
||||||
use typst_ts_compiler::ShadowApi;
|
|
||||||
use typst_ts_core::{config::compiler::EntryState, TypstDocument, TypstFileId};
|
/// A task that can be sent to the context (compiler thread)
|
||||||
|
///
|
||||||
|
/// The internal function will be dereferenced and called on the context.
|
||||||
|
type BorrowTask<Ctx> = Box<dyn FnOnce(&mut Ctx) + Send + 'static>;
|
||||||
|
|
||||||
pub enum Interrupt<Ctx> {
|
pub enum Interrupt<Ctx> {
|
||||||
/// Compile anyway.
|
/// Compile anyway.
|
||||||
Compile,
|
Compile,
|
||||||
/// Borrow the compiler thread and run the task.
|
/// Borrow the compiler thread and run the task.
|
||||||
///
|
///
|
||||||
/// See [`CompileClient<Ctx>::steal`] for more information.
|
/// See [`CompileClient<Ctx>::steal_async`] for more information.
|
||||||
Task(BorrowTask<Ctx>),
|
Task(BorrowTask<Ctx>),
|
||||||
/// Memory file changes.
|
/// Memory file changes.
|
||||||
Memory(MemoryEvent),
|
Memory(MemoryEvent),
|
||||||
|
@ -30,11 +38,6 @@ pub enum Interrupt<Ctx> {
|
||||||
Settle(oneshot::Sender<()>),
|
Settle(oneshot::Sender<()>),
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A task that can be sent to the context (compiler/render thread)
|
|
||||||
///
|
|
||||||
/// The internal function will be dereferenced and called on the context.
|
|
||||||
pub type BorrowTask<Ctx> = Box<dyn FnOnce(&mut Ctx) + Send + 'static>;
|
|
||||||
|
|
||||||
/// Responses from the compiler thread.
|
/// Responses from the compiler thread.
|
||||||
enum CompilerResponse {
|
enum CompilerResponse {
|
||||||
/// Response to the file watcher
|
/// Response to the file watcher
|
||||||
|
@ -55,9 +58,11 @@ struct SuspendState {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The compiler thread.
|
/// The compiler thread.
|
||||||
pub struct CompileServerActor<C: Compiler> {
|
pub struct CompileServerActor<C: Compiler, F: CompilerFeat> {
|
||||||
|
/// The underlying universe.
|
||||||
|
pub verse: CompilerUniverse<F>,
|
||||||
/// The underlying compiler.
|
/// The underlying compiler.
|
||||||
pub compiler: CompileReporter<C>,
|
pub compiler: CompileReporter<C, CompilerWorld<F>>,
|
||||||
/// Whether to enable file system watching.
|
/// Whether to enable file system watching.
|
||||||
pub enable_watch: bool,
|
pub enable_watch: bool,
|
||||||
|
|
||||||
|
@ -85,12 +90,12 @@ pub struct CompileServerActor<C: Compiler> {
|
||||||
suspend_state: SuspendState,
|
suspend_state: SuspendState,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<C: Compiler + ShadowApi + Send + 'static> CompileServerActor<C>
|
impl<F: CompilerFeat + Send + 'static, C: Compiler<W = CompilerWorld<F>> + Send + 'static>
|
||||||
where
|
CompileServerActor<C, F>
|
||||||
C::World: for<'files> codespan_reporting::files::Files<'files, FileId = TypstFileId>,
|
|
||||||
{
|
{
|
||||||
pub fn new_with_features(
|
pub fn new_with_features(
|
||||||
compiler: C,
|
compiler: C,
|
||||||
|
verse: CompilerUniverse<F>,
|
||||||
entry: EntryState,
|
entry: EntryState,
|
||||||
feature_set: FeatureSet,
|
feature_set: FeatureSet,
|
||||||
intr_tx: mpsc::UnboundedSender<Interrupt<Self>>,
|
intr_tx: mpsc::UnboundedSender<Interrupt<Self>>,
|
||||||
|
@ -99,6 +104,7 @@ where
|
||||||
Self {
|
Self {
|
||||||
compiler: CompileReporter::new(compiler)
|
compiler: CompileReporter::new(compiler)
|
||||||
.with_generic_reporter(ConsoleDiagReporter::default()),
|
.with_generic_reporter(ConsoleDiagReporter::default()),
|
||||||
|
verse,
|
||||||
|
|
||||||
logical_tick: 1,
|
logical_tick: 1,
|
||||||
enable_watch: false,
|
enable_watch: false,
|
||||||
|
@ -116,7 +122,7 @@ where
|
||||||
intr_rx,
|
intr_rx,
|
||||||
|
|
||||||
suspend_state: SuspendState {
|
suspend_state: SuspendState {
|
||||||
suspended: is_inactive(&entry),
|
suspended: entry.is_inactive(),
|
||||||
dirty: false,
|
dirty: false,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
@ -125,18 +131,29 @@ where
|
||||||
/// Create a new compiler thread.
|
/// Create a new compiler thread.
|
||||||
pub fn new(
|
pub fn new(
|
||||||
compiler: C,
|
compiler: C,
|
||||||
|
world: CompilerUniverse<F>,
|
||||||
entry: EntryState,
|
entry: EntryState,
|
||||||
intr_tx: mpsc::UnboundedSender<Interrupt<Self>>,
|
intr_tx: mpsc::UnboundedSender<Interrupt<Self>>,
|
||||||
intr_rx: mpsc::UnboundedReceiver<Interrupt<Self>>,
|
intr_rx: mpsc::UnboundedReceiver<Interrupt<Self>>,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
Self::new_with_features(compiler, entry, FeatureSet::default(), intr_tx, intr_rx)
|
Self::new_with_features(
|
||||||
|
compiler,
|
||||||
|
world,
|
||||||
|
entry,
|
||||||
|
FeatureSet::default(),
|
||||||
|
intr_tx,
|
||||||
|
intr_rx,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn with_watch(mut self, enable_watch: bool) -> Self {
|
pub fn with_watch(mut self, enable_watch: bool) -> Self {
|
||||||
self.enable_watch = enable_watch;
|
self.enable_watch = enable_watch;
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn intr_tx(&self) -> mpsc::UnboundedSender<Interrupt<Self>> {
|
||||||
|
self.intr_tx.clone()
|
||||||
|
}
|
||||||
|
|
||||||
pub fn success_doc(&self) -> Option<VersionedDocument> {
|
pub fn success_doc(&self) -> Option<VersionedDocument> {
|
||||||
self.latest_success_doc
|
self.latest_success_doc
|
||||||
.clone()
|
.clone()
|
||||||
|
@ -174,7 +191,8 @@ where
|
||||||
async fn block_run_inner(mut self) -> bool {
|
async fn block_run_inner(mut self) -> bool {
|
||||||
if !self.enable_watch {
|
if !self.enable_watch {
|
||||||
let mut env = self.make_env(self.once_feature_set.clone());
|
let mut env = self.make_env(self.once_feature_set.clone());
|
||||||
let compiled = self.compiler.compile(&mut env);
|
let w = self.verse.spawn();
|
||||||
|
let compiled = self.compiler.compile(&w, &mut env);
|
||||||
return compiled.is_ok();
|
return compiled.is_ok();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -191,7 +209,8 @@ where
|
||||||
pub async fn spawn(mut self) -> Option<JoinHandle<()>> {
|
pub async fn spawn(mut self) -> Option<JoinHandle<()>> {
|
||||||
if !self.enable_watch {
|
if !self.enable_watch {
|
||||||
let mut env = self.make_env(self.once_feature_set.clone());
|
let mut env = self.make_env(self.once_feature_set.clone());
|
||||||
self.compiler.compile(&mut env).ok();
|
let w = self.verse.spawn();
|
||||||
|
self.compiler.compile(&w, &mut env).ok();
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -268,8 +287,8 @@ where
|
||||||
Some(compile_thread.unwrap())
|
Some(compile_thread.unwrap())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn change_entry(&mut self, entry: EntryState) {
|
pub fn change_entry(&mut self, entry: EntryState) {
|
||||||
self.suspend_state.suspended = is_inactive(&entry);
|
self.suspend_state.suspended = entry.is_inactive();
|
||||||
if !self.suspend_state.suspended && self.suspend_state.dirty {
|
if !self.suspend_state.suspended && self.suspend_state.dirty {
|
||||||
self.intr_tx.send(Interrupt::Compile).ok();
|
self.intr_tx.send(Interrupt::Compile).ok();
|
||||||
}
|
}
|
||||||
|
@ -288,9 +307,11 @@ where
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let w = self.verse.spawn();
|
||||||
|
|
||||||
// Compile the document.
|
// Compile the document.
|
||||||
let mut env = self.make_env(self.watch_feature_set.clone());
|
let mut env = self.make_env(self.watch_feature_set.clone());
|
||||||
self.latest_doc = self.compiler.compile(&mut env).ok();
|
self.latest_doc = self.compiler.compile(&w, &mut env).ok();
|
||||||
if self.latest_doc.is_some() {
|
if self.latest_doc.is_some() {
|
||||||
self.latest_success_doc.clone_from(&self.latest_doc);
|
self.latest_success_doc.clone_from(&self.latest_doc);
|
||||||
}
|
}
|
||||||
|
@ -303,8 +324,7 @@ where
|
||||||
|
|
||||||
// Notify the new file dependencies.
|
// Notify the new file dependencies.
|
||||||
let mut deps = vec![];
|
let mut deps = vec![];
|
||||||
self.compiler
|
w.iter_dependencies(&mut |dep| deps.push(dep.clone()));
|
||||||
.iter_dependencies(&mut |dep, _| deps.push(dep.clone()));
|
|
||||||
send(Notify(NotifyMessage::SyncDependency(deps)));
|
send(Notify(NotifyMessage::SyncDependency(deps)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -340,7 +360,8 @@ where
|
||||||
|
|
||||||
// If there is no invalidation happening, apply memory changes directly.
|
// If there is no invalidation happening, apply memory changes directly.
|
||||||
if files.is_empty() && self.dirty_shadow_logical_tick == 0 {
|
if files.is_empty() && self.dirty_shadow_logical_tick == 0 {
|
||||||
self.apply_memory_changes(event);
|
self.verse
|
||||||
|
.increment_revision(|verse| Self::apply_memory_changes(verse, event));
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -362,13 +383,15 @@ where
|
||||||
Interrupt::Fs(mut event) => {
|
Interrupt::Fs(mut event) => {
|
||||||
log::debug!("CompileServerActor: fs event incoming {event:?}");
|
log::debug!("CompileServerActor: fs event incoming {event:?}");
|
||||||
|
|
||||||
// Handle delayed upstream update event before applying file system changes
|
|
||||||
if self.apply_delayed_memory_changes(&mut event).is_none() {
|
|
||||||
log::warn!("CompileServerActor: unknown upstream update event");
|
|
||||||
}
|
|
||||||
|
|
||||||
// Apply file system changes.
|
// Apply file system changes.
|
||||||
self.compiler.notify_fs_event(event);
|
let dirty_tick = &mut self.dirty_shadow_logical_tick;
|
||||||
|
self.verse.increment_revision(|verse| {
|
||||||
|
// Handle delayed upstream update event before applying file system changes
|
||||||
|
if Self::apply_delayed_memory_changes(verse, dirty_tick, &mut event).is_none() {
|
||||||
|
log::warn!("CompileServerActor: unknown upstream update event");
|
||||||
|
}
|
||||||
|
verse.notify_fs_event(event)
|
||||||
|
});
|
||||||
|
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
@ -377,7 +400,11 @@ where
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Apply delayed memory changes to underlying compiler.
|
/// Apply delayed memory changes to underlying compiler.
|
||||||
fn apply_delayed_memory_changes(&mut self, event: &mut FilesystemEvent) -> Option<()> {
|
fn apply_delayed_memory_changes(
|
||||||
|
verse: &mut Revising<CompilerUniverse<F>>,
|
||||||
|
dirty_shadow_logical_tick: &mut usize,
|
||||||
|
event: &mut FilesystemEvent,
|
||||||
|
) -> Option<()> {
|
||||||
// Handle delayed upstream update event before applying file system changes
|
// Handle delayed upstream update event before applying file system changes
|
||||||
if let FilesystemEvent::UpstreamUpdate { upstream_event, .. } = event {
|
if let FilesystemEvent::UpstreamUpdate { upstream_event, .. } = event {
|
||||||
let event = upstream_event.take()?.opaque;
|
let event = upstream_event.take()?.opaque;
|
||||||
|
@ -387,25 +414,25 @@ where
|
||||||
} = *event.downcast().ok()?;
|
} = *event.downcast().ok()?;
|
||||||
|
|
||||||
// Recovery from dirty shadow state.
|
// Recovery from dirty shadow state.
|
||||||
if logical_tick == self.dirty_shadow_logical_tick {
|
if logical_tick == *dirty_shadow_logical_tick {
|
||||||
self.dirty_shadow_logical_tick = 0;
|
*dirty_shadow_logical_tick = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
self.apply_memory_changes(event);
|
Self::apply_memory_changes(verse, event);
|
||||||
}
|
}
|
||||||
|
|
||||||
Some(())
|
Some(())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Apply memory changes to underlying compiler.
|
/// Apply memory changes to underlying compiler.
|
||||||
fn apply_memory_changes(&mut self, event: MemoryEvent) {
|
fn apply_memory_changes(verse: &mut Revising<CompilerUniverse<F>>, event: MemoryEvent) {
|
||||||
if matches!(event, MemoryEvent::Sync(..)) {
|
if matches!(event, MemoryEvent::Sync(..)) {
|
||||||
self.compiler.reset_shadow();
|
verse.reset_shadow();
|
||||||
}
|
}
|
||||||
match event {
|
match event {
|
||||||
MemoryEvent::Update(event) | MemoryEvent::Sync(event) => {
|
MemoryEvent::Update(event) | MemoryEvent::Sync(event) => {
|
||||||
for removes in event.removes {
|
for removes in event.removes {
|
||||||
let _ = self.compiler.unmap_shadow(&removes);
|
let _ = verse.unmap_shadow(&removes);
|
||||||
}
|
}
|
||||||
for (p, t) in event.inserts {
|
for (p, t) in event.inserts {
|
||||||
let insert_file = match t.content().cloned() {
|
let insert_file = match t.content().cloned() {
|
||||||
|
@ -420,18 +447,13 @@ where
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let _ = self.compiler.map_shadow(&p, insert_file);
|
let _ = verse.map_shadow(&p, insert_file);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn is_inactive(entry: &EntryState) -> bool {
|
|
||||||
use EntryState::*;
|
|
||||||
matches!(entry, Detached | Workspace { main: None, .. })
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn log_send_error<T>(chan: &'static str, res: Result<(), mpsc::error::SendError<T>>) -> bool {
|
fn log_send_error<T>(chan: &'static str, res: Result<(), mpsc::error::SendError<T>>) -> bool {
|
||||||
res.map_err(|err| log::warn!("CompileServerActor: send to {chan} error: {err}"))
|
res.map_err(|err| log::warn!("CompileServerActor: send to {chan} error: {err}"))
|
||||||
|
|
|
@ -42,7 +42,9 @@ pub use server::compiler_init;
|
||||||
pub use server::lsp::*;
|
pub use server::lsp::*;
|
||||||
pub use server::lsp_init::*;
|
pub use server::lsp_init::*;
|
||||||
pub use server::preview;
|
pub use server::preview;
|
||||||
pub use world::{CompileFontOpts, CompileOnceOpts, CompileOpts, LspWorld, LspWorldBuilder};
|
pub use world::{
|
||||||
|
CompileFontOpts, CompileOnceOpts, CompileOpts, LspUniverse, LspWorld, LspWorldBuilder,
|
||||||
|
};
|
||||||
|
|
||||||
use lsp_server::ResponseError;
|
use lsp_server::ResponseError;
|
||||||
|
|
||||||
|
|
|
@ -10,12 +10,6 @@ use comemo::Prehashed;
|
||||||
use lsp_types::{InitializeParams, InitializedParams};
|
use lsp_types::{InitializeParams, InitializedParams};
|
||||||
use once_cell::sync::Lazy;
|
use once_cell::sync::Lazy;
|
||||||
use parking_lot::RwLock;
|
use parking_lot::RwLock;
|
||||||
use tokio::sync::mpsc;
|
|
||||||
use typst::{eval::Tracer, foundations::IntoValue, syntax::Span};
|
|
||||||
use typst_ts_compiler::service::{CompileEnv, Compiler, EntryManager};
|
|
||||||
use typst_ts_core::{typst::prelude::EcoVec, TypstDict};
|
|
||||||
|
|
||||||
use crate::args::{CliArguments, Commands, CompileArgs, LspArgs};
|
|
||||||
use tinymist::{
|
use tinymist::{
|
||||||
compiler_init::{CompileInit, CompileInitializeParams},
|
compiler_init::{CompileInit, CompileInitializeParams},
|
||||||
harness::{lsp_harness, InitializedLspDriver, LspDriver, LspHost},
|
harness::{lsp_harness, InitializedLspDriver, LspDriver, LspHost},
|
||||||
|
@ -23,6 +17,13 @@ use tinymist::{
|
||||||
transport::with_stdio_transport,
|
transport::with_stdio_transport,
|
||||||
CompileFontOpts, Init, LspWorld, TypstLanguageServer,
|
CompileFontOpts, Init, LspWorld, TypstLanguageServer,
|
||||||
};
|
};
|
||||||
|
use tokio::sync::mpsc;
|
||||||
|
use typst::World;
|
||||||
|
use typst::{eval::Tracer, foundations::IntoValue, syntax::Span};
|
||||||
|
use typst_ts_compiler::service::{CompileEnv, Compiler};
|
||||||
|
use typst_ts_core::{typst::prelude::EcoVec, TypstDict};
|
||||||
|
|
||||||
|
use crate::args::{CliArguments, Commands, CompileArgs, LspArgs};
|
||||||
|
|
||||||
#[cfg(feature = "dhat-heap")]
|
#[cfg(feature = "dhat-heap")]
|
||||||
#[global_allocator]
|
#[global_allocator]
|
||||||
|
@ -183,8 +184,12 @@ pub fn compiler_main(args: CompileArgs) -> anyhow::Result<()> {
|
||||||
let (timings, _doc, diagnostics) = service
|
let (timings, _doc, diagnostics) = service
|
||||||
.compiler()
|
.compiler()
|
||||||
.steal(|c| {
|
.steal(|c| {
|
||||||
c.compiler.world_mut().mutate_entry(entry).unwrap();
|
c.verse.increment_revision(|verse| {
|
||||||
c.compiler.world_mut().inputs = inputs;
|
verse.mutate_entry(entry).unwrap();
|
||||||
|
verse.set_inputs(inputs);
|
||||||
|
});
|
||||||
|
|
||||||
|
let w = c.verse.spawn();
|
||||||
|
|
||||||
let mut env = CompileEnv {
|
let mut env = CompileEnv {
|
||||||
tracer: Some(Tracer::default()),
|
tracer: Some(Tracer::default()),
|
||||||
|
@ -192,24 +197,23 @@ pub fn compiler_main(args: CompileArgs) -> anyhow::Result<()> {
|
||||||
};
|
};
|
||||||
typst_timing::enable();
|
typst_timing::enable();
|
||||||
let mut errors = EcoVec::new();
|
let mut errors = EcoVec::new();
|
||||||
let res = match c.compiler.pure_compile(&mut env) {
|
let res = match c.compiler.pure_compile(&w, &mut env) {
|
||||||
Ok(doc) => Some(doc),
|
Ok(doc) => Some(doc),
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
errors = e;
|
errors = e;
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
let world = c.compiler.world();
|
|
||||||
let mut writer = std::io::BufWriter::new(Vec::new());
|
let mut writer = std::io::BufWriter::new(Vec::new());
|
||||||
let _ = typst_timing::export_json(&mut writer, |span| {
|
let _ = typst_timing::export_json(&mut writer, |span| {
|
||||||
resolve_span(world, span).unwrap_or_else(|| ("unknown".to_string(), 0))
|
resolve_span(&w, span).unwrap_or_else(|| ("unknown".to_string(), 0))
|
||||||
});
|
});
|
||||||
|
|
||||||
let s = String::from_utf8(writer.into_inner().unwrap()).unwrap();
|
let s = String::from_utf8(writer.into_inner().unwrap()).unwrap();
|
||||||
|
|
||||||
let warnings = env.tracer.map(|e| e.warnings());
|
let warnings = env.tracer.map(|e| e.warnings());
|
||||||
|
|
||||||
let diagnostics = c.compiler.compiler.run_analysis(|ctx| {
|
let diagnostics = c.compiler.compiler.run_analysis(&w, |ctx| {
|
||||||
tinymist_query::convert_diagnostics(
|
tinymist_query::convert_diagnostics(
|
||||||
ctx,
|
ctx,
|
||||||
warnings.iter().flatten().chain(errors.iter()),
|
warnings.iter().flatten().chain(errors.iter()),
|
||||||
|
@ -261,7 +265,6 @@ impl<T> Drop for ForceDrop<T> {
|
||||||
|
|
||||||
/// Turns a span into a (file, line) pair.
|
/// Turns a span into a (file, line) pair.
|
||||||
fn resolve_span(world: &LspWorld, span: Span) -> Option<(String, u32)> {
|
fn resolve_span(world: &LspWorld, span: Span) -> Option<(String, u32)> {
|
||||||
use typst::World;
|
|
||||||
let id = span.id()?;
|
let id = span.id()?;
|
||||||
let source = world.source(id).ok()?;
|
let source = world.source(id).ok()?;
|
||||||
let range = source.range(span)?;
|
let range = source.range(span)?;
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
use std::{collections::BTreeMap, path::Path, sync::Arc};
|
use std::{collections::BTreeMap, path::Path, sync::Arc};
|
||||||
|
|
||||||
use typst_ts_compiler::{service::EntryManager, ShadowApi};
|
|
||||||
use typst_ts_core::{config::compiler::EntryState, font::GlyphId, TypstDocument, TypstFont};
|
use typst_ts_core::{config::compiler::EntryState, font::GlyphId, TypstDocument, TypstFont};
|
||||||
|
|
||||||
pub use super::prelude::*;
|
pub use super::prelude::*;
|
||||||
|
@ -188,16 +187,23 @@ impl TypstLanguageServer {
|
||||||
let font = self
|
let font = self
|
||||||
.primary()
|
.primary()
|
||||||
.steal(move |e| {
|
.steal(move |e| {
|
||||||
|
let verse = &mut e.verse;
|
||||||
let entry_path: Arc<Path> = Path::new("/._sym_.typ").into();
|
let entry_path: Arc<Path> = Path::new("/._sym_.typ").into();
|
||||||
|
|
||||||
let new_entry = EntryState::new_rootless(entry_path.clone())?;
|
let new_entry = EntryState::new_rootless(entry_path.clone())?;
|
||||||
let old_entry = e.compiler.world_mut().mutate_entry(new_entry).ok()?;
|
let (old_entry, prepared) = verse.increment_revision(|verse| {
|
||||||
let prepared = e
|
let old_entry = verse.mutate_entry(new_entry).ok()?;
|
||||||
.compiler
|
let prepared = verse
|
||||||
.map_shadow(&entry_path, math_shaping_text.into_bytes().into())
|
.map_shadow(&entry_path, math_shaping_text.into_bytes().into())
|
||||||
.is_ok();
|
.is_ok();
|
||||||
let sym_doc = prepared.then(|| e.compiler.pure_compile(&mut Default::default()));
|
|
||||||
e.compiler.world_mut().mutate_entry(old_entry).ok()?;
|
Some((old_entry, prepared))
|
||||||
|
})?;
|
||||||
|
|
||||||
|
let w = verse.spawn();
|
||||||
|
let sym_doc =
|
||||||
|
prepared.then(|| e.compiler.pure_compile(&w, &mut Default::default()));
|
||||||
|
verse.increment_revision(|verse| verse.mutate_entry(old_entry).ok())?;
|
||||||
|
|
||||||
log::debug!(
|
log::debug!(
|
||||||
"sym doc: {doc:?}",
|
"sym doc: {doc:?}",
|
||||||
|
|
|
@ -23,7 +23,6 @@ use tinymist_query::{
|
||||||
use tokio::sync::mpsc;
|
use tokio::sync::mpsc;
|
||||||
use typst::diag::StrResult;
|
use typst::diag::StrResult;
|
||||||
use typst::syntax::package::{PackageSpec, VersionlessPackageSpec};
|
use typst::syntax::package::{PackageSpec, VersionlessPackageSpec};
|
||||||
use typst_ts_compiler::service::Compiler;
|
|
||||||
use typst_ts_core::path::PathClean;
|
use typst_ts_core::path::PathClean;
|
||||||
use typst_ts_core::{error::prelude::*, ImmutPath};
|
use typst_ts_core::{error::prelude::*, ImmutPath};
|
||||||
|
|
||||||
|
@ -646,7 +645,7 @@ impl TypstLanguageServer {
|
||||||
let res = self
|
let res = self
|
||||||
.primary()
|
.primary()
|
||||||
.steal(move |c| {
|
.steal(move |c| {
|
||||||
let cc = &c.compiler;
|
let verse = &c.verse;
|
||||||
|
|
||||||
// todo: rootless file
|
// todo: rootless file
|
||||||
// todo: memory dirty file
|
// todo: memory dirty file
|
||||||
|
@ -665,8 +664,8 @@ impl TypstLanguageServer {
|
||||||
compiler_program: self_path,
|
compiler_program: self_path,
|
||||||
root: root.as_ref().to_owned(),
|
root: root.as_ref().to_owned(),
|
||||||
main,
|
main,
|
||||||
inputs: cc.world().inputs.as_ref().deref().clone(),
|
inputs: verse.inputs().as_ref().deref().clone(),
|
||||||
font_paths: cc.world().font_resolver.font_paths().to_owned(),
|
font_paths: verse.font_resolver.font_paths().to_owned(),
|
||||||
},
|
},
|
||||||
))
|
))
|
||||||
.context("cannot send trace request")?;
|
.context("cannot send trace request")?;
|
||||||
|
@ -770,6 +769,7 @@ impl TypstLanguageServer {
|
||||||
let res = self
|
let res = self
|
||||||
.primary()
|
.primary()
|
||||||
.steal(move |c| {
|
.steal(move |c| {
|
||||||
|
let world = c.verse.spawn();
|
||||||
// Parse the package specification. If the user didn't specify the version,
|
// Parse the package specification. If the user didn't specify the version,
|
||||||
// we try to figure it out automatically by downloading the package index
|
// we try to figure it out automatically by downloading the package index
|
||||||
// or searching the disk.
|
// or searching the disk.
|
||||||
|
@ -779,7 +779,7 @@ impl TypstLanguageServer {
|
||||||
// Try to parse without version, but prefer the error message of the
|
// Try to parse without version, but prefer the error message of the
|
||||||
// normal package spec parsing if it fails.
|
// normal package spec parsing if it fails.
|
||||||
let spec: VersionlessPackageSpec = from_source.parse().map_err(|_| err)?;
|
let spec: VersionlessPackageSpec = from_source.parse().map_err(|_| err)?;
|
||||||
let version = determine_latest_version(c.compiler.world(), &spec)?;
|
let version = determine_latest_version(&c.verse, &spec)?;
|
||||||
StrResult::Ok(spec.at(version))
|
StrResult::Ok(spec.at(version))
|
||||||
})
|
})
|
||||||
.map_err(map_string_err("failed to parse package spec"))?;
|
.map_err(map_string_err("failed to parse package spec"))?;
|
||||||
|
@ -787,7 +787,7 @@ impl TypstLanguageServer {
|
||||||
let from_source = TemplateSource::Package(spec);
|
let from_source = TemplateSource::Package(spec);
|
||||||
|
|
||||||
let entry_path = package::init(
|
let entry_path = package::init(
|
||||||
c.compiler.world(),
|
&world,
|
||||||
InitTask {
|
InitTask {
|
||||||
tmpl: from_source.clone(),
|
tmpl: from_source.clone(),
|
||||||
dir: to_path.clone(),
|
dir: to_path.clone(),
|
||||||
|
@ -827,14 +827,14 @@ impl TypstLanguageServer {
|
||||||
// Try to parse without version, but prefer the error message of the
|
// Try to parse without version, but prefer the error message of the
|
||||||
// normal package spec parsing if it fails.
|
// normal package spec parsing if it fails.
|
||||||
let spec: VersionlessPackageSpec = from_source.parse().map_err(|_| err)?;
|
let spec: VersionlessPackageSpec = from_source.parse().map_err(|_| err)?;
|
||||||
let version = determine_latest_version(c.compiler.world(), &spec)?;
|
let version = determine_latest_version(&c.verse, &spec)?;
|
||||||
StrResult::Ok(spec.at(version))
|
StrResult::Ok(spec.at(version))
|
||||||
})
|
})
|
||||||
.map_err(map_string_err("failed to parse package spec"))?;
|
.map_err(map_string_err("failed to parse package spec"))?;
|
||||||
|
|
||||||
let from_source = TemplateSource::Package(spec);
|
let from_source = TemplateSource::Package(spec);
|
||||||
|
|
||||||
let entry = package::get_entry(c.compiler.world(), from_source)
|
let entry = package::get_entry(&c.verse, from_source)
|
||||||
.map_err(map_string_err("failed to get template entry"))?;
|
.map_err(map_string_err("failed to get template entry"))?;
|
||||||
|
|
||||||
ZResult::Ok(entry)
|
ZResult::Ok(entry)
|
||||||
|
|
|
@ -5,8 +5,7 @@ use await_tree::InstrumentAwait;
|
||||||
use log::{error, info};
|
use log::{error, info};
|
||||||
|
|
||||||
use typst::foundations::{Str, Value};
|
use typst::foundations::{Str, Value};
|
||||||
use typst_ts_compiler::service::CompileDriver;
|
use typst_ts_compiler::{service::CompileDriver, TypstSystemUniverse};
|
||||||
use typst_ts_compiler::TypstSystemWorld;
|
|
||||||
use typst_ts_core::config::{compiler::EntryOpts, CompileOpts};
|
use typst_ts_core::config::{compiler::EntryOpts, CompileOpts};
|
||||||
|
|
||||||
use hyper::{
|
use hyper::{
|
||||||
|
@ -139,7 +138,7 @@ pub async fn preview_main(args: PreviewCliArgs) -> anyhow::Result<()> {
|
||||||
}
|
}
|
||||||
|
|
||||||
let compiler_driver = {
|
let compiler_driver = {
|
||||||
let world = TypstSystemWorld::new(CompileOpts {
|
let world = TypstSystemUniverse::new(CompileOpts {
|
||||||
entry: EntryOpts::new_rooted(root.clone(), Some(entry.clone())),
|
entry: EntryOpts::new_rooted(root.clone(), Some(entry.clone())),
|
||||||
inputs,
|
inputs,
|
||||||
no_system_fonts: args.compile.font.ignore_system_fonts,
|
no_system_fonts: args.compile.font.ignore_system_fonts,
|
||||||
|
@ -149,7 +148,7 @@ pub async fn preview_main(args: PreviewCliArgs) -> anyhow::Result<()> {
|
||||||
})
|
})
|
||||||
.expect("incorrect options");
|
.expect("incorrect options");
|
||||||
|
|
||||||
CompileDriver::new(world).with_entry_file(entry)
|
CompileDriver::new(std::marker::PhantomData, world.with_entry_file(entry))
|
||||||
};
|
};
|
||||||
|
|
||||||
tokio::spawn(async move {
|
tokio::spawn(async move {
|
||||||
|
|
|
@ -1,32 +1,31 @@
|
||||||
use std::path::Path;
|
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
use await_tree::InstrumentAwait;
|
use await_tree::InstrumentAwait;
|
||||||
use log::error;
|
|
||||||
|
|
||||||
|
use tokio::sync::mpsc;
|
||||||
use typst::diag::SourceResult;
|
use typst::diag::SourceResult;
|
||||||
use typst::layout::Position;
|
|
||||||
use typst::model::Document;
|
use typst::model::Document;
|
||||||
use typst::syntax::Span;
|
|
||||||
|
|
||||||
use typst_ts_compiler::service::{
|
use typst::World;
|
||||||
CompileActor, CompileClient as TsCompileClient, CompileExporter, Compiler, WorldExporter,
|
|
||||||
};
|
|
||||||
use typst_ts_compiler::service::{CompileDriver, CompileMiddleware};
|
use typst_ts_compiler::service::{CompileDriver, CompileMiddleware};
|
||||||
use typst_ts_compiler::vfs::notify::{FileChangeSet, MemoryEvent};
|
use typst_ts_compiler::service::{CompileExporter, Compiler, PureCompiler, WorldExporter};
|
||||||
use typst_ts_core::debug_loc::SourceSpanOffset;
|
use typst_ts_compiler::{EntryReader, TypstSystemWorld};
|
||||||
use typst_ts_core::Error;
|
use typst_ts_core::Error;
|
||||||
|
|
||||||
use typst_preview::{CompilationHandle, CompileStatus};
|
use typst_preview::{CompilationHandle, CompileStatus};
|
||||||
use typst_preview::{CompileHost, EditorServer, MemoryFiles, MemoryFilesShort, SourceFileServer};
|
|
||||||
use typst_preview::{DocToSrcJumpInfo, Location};
|
|
||||||
|
|
||||||
pub type CompileService<H> = CompileActor<Reporter<CompileExporter<CompileDriver>, H>>;
|
use crate::actor::typ_client::CompileClientActorImpl;
|
||||||
pub type CompileClient<H> = TsCompileClient<CompileService<H>>;
|
use crate::actor::typ_server::CompileServerActor;
|
||||||
|
use crate::compiler_init::CompileConfig;
|
||||||
|
use crate::world::{LspCompilerFeat, LspWorld};
|
||||||
|
|
||||||
|
pub type CompileService<H> =
|
||||||
|
CompileServerActor<Reporter<CompileExporter<PureCompiler<LspWorld>>, H>, LspCompilerFeat>;
|
||||||
|
pub type CompileClient<H> =
|
||||||
|
CompileClientActorImpl<Reporter<CompileExporter<PureCompiler<LspWorld>>, H>>;
|
||||||
|
|
||||||
pub struct CompileServer<H: CompilationHandle> {
|
pub struct CompileServer<H: CompilationHandle> {
|
||||||
inner: CompileService<H>,
|
inner: CompileService<H>,
|
||||||
client: TypstClient<H>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct Reporter<C, H> {
|
pub struct Reporter<C, H> {
|
||||||
|
@ -47,10 +46,11 @@ impl<C: Compiler, H: CompilationHandle> CompileMiddleware for Reporter<C, H> {
|
||||||
|
|
||||||
fn wrap_compile(
|
fn wrap_compile(
|
||||||
&mut self,
|
&mut self,
|
||||||
|
world: &<C as typst_ts_compiler::service::Compiler>::W,
|
||||||
env: &mut typst_ts_compiler::service::CompileEnv,
|
env: &mut typst_ts_compiler::service::CompileEnv,
|
||||||
) -> SourceResult<Arc<Document>> {
|
) -> SourceResult<Arc<Document>> {
|
||||||
self.cb.status(CompileStatus::Compiling);
|
self.cb.status(CompileStatus::Compiling);
|
||||||
match self.inner_mut().compile(env) {
|
match self.inner_mut().compile(world, env) {
|
||||||
Ok(doc) => {
|
Ok(doc) => {
|
||||||
self.cb.notify_compile(Ok(doc.clone()));
|
self.cb.notify_compile(Ok(doc.clone()));
|
||||||
Ok(doc)
|
Ok(doc)
|
||||||
|
@ -63,138 +63,45 @@ impl<C: Compiler, H: CompilationHandle> CompileMiddleware for Reporter<C, H> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<C: Compiler + WorldExporter, H> WorldExporter for Reporter<C, H> {
|
impl<W: World, C: Compiler<W = W> + WorldExporter<W>, H> WorldExporter<W> for Reporter<C, H> {
|
||||||
fn export(&mut self, output: Arc<typst::model::Document>) -> SourceResult<()> {
|
fn export(&mut self, world: &W, output: Arc<typst::model::Document>) -> SourceResult<()> {
|
||||||
self.inner.export(output)
|
self.inner.export(world, output)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<H: CompilationHandle> CompileServer<H> {
|
impl<H: CompilationHandle> CompileServer<H> {
|
||||||
pub fn new(
|
pub fn new(
|
||||||
compiler_driver: CompileDriver,
|
compiler_driver: CompileDriver<PureCompiler<TypstSystemWorld>>,
|
||||||
cb: H,
|
cb: H,
|
||||||
// renderer_sender: broadcast::Sender<RenderActorRequest>,
|
// renderer_sender: broadcast::Sender<RenderActorRequest>,
|
||||||
// editor_conn_sender: mpsc::UnboundedSender<EditorActorRequest>,
|
// editor_conn_sender: mpsc::UnboundedSender<EditorActorRequest>,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
|
let (intr_tx, intr_rx) = mpsc::unbounded_channel();
|
||||||
|
let CompileDriver { compiler, universe } = compiler_driver;
|
||||||
|
let entry = universe.entry_state();
|
||||||
|
|
||||||
// CompileExporter + DynamicLayoutCompiler + WatchDriver
|
// CompileExporter + DynamicLayoutCompiler + WatchDriver
|
||||||
let driver = CompileExporter::new(compiler_driver);
|
let driver = CompileExporter::new(compiler);
|
||||||
let driver = Reporter { inner: driver, cb };
|
let driver = Reporter { inner: driver, cb };
|
||||||
let inner = CompileActor::new(driver).with_watch(true);
|
let inner =
|
||||||
|
CompileServerActor::new(driver, universe, entry, intr_tx, intr_rx).with_watch(true);
|
||||||
|
|
||||||
Self {
|
Self { inner }
|
||||||
inner,
|
|
||||||
client: TypstClient {
|
|
||||||
inner: once_cell::sync::OnceCell::new(),
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn spawn(self) -> Result<TypstClient<H>, Error> {
|
pub fn spawn(self) -> Result<CompileClient<H>, Error> {
|
||||||
let (server, client) = self.inner.split();
|
let (export_tx, mut export_rx) = mpsc::unbounded_channel();
|
||||||
tokio::spawn(server.spawn().instrument_await("spawn typst server"));
|
let intr_tx = self.inner.intr_tx();
|
||||||
|
let entry = self.inner.verse.entry_state();
|
||||||
self.client.inner.set(client).ok().unwrap();
|
tokio::spawn(self.inner.spawn().instrument_await("spawn typst server"));
|
||||||
|
// drop all export events
|
||||||
Ok(self.client)
|
tokio::spawn(async move { while export_rx.recv().await.is_some() {} });
|
||||||
|
Ok(CompileClient::new(
|
||||||
|
"main".to_owned(),
|
||||||
|
CompileConfig::default(),
|
||||||
|
entry,
|
||||||
|
intr_tx,
|
||||||
|
export_tx,
|
||||||
|
))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct TypstClient<H: CompilationHandle> {
|
|
||||||
inner: once_cell::sync::OnceCell<CompileClient<H>>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<H: CompilationHandle> TypstClient<H> {
|
|
||||||
fn inner(&mut self) -> &mut CompileClient<H> {
|
|
||||||
self.inner.get_mut().unwrap()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<H: CompilationHandle> SourceFileServer for TypstClient<H> {
|
|
||||||
async fn resolve_source_span(
|
|
||||||
&mut self,
|
|
||||||
loc: Location,
|
|
||||||
) -> Result<Option<SourceSpanOffset>, Error> {
|
|
||||||
let Location::Src(src_loc) = loc;
|
|
||||||
self.inner()
|
|
||||||
.resolve_src_location(src_loc)
|
|
||||||
.instrument_await("resolve src location")
|
|
||||||
.await
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn resolve_document_position(
|
|
||||||
&mut self,
|
|
||||||
loc: Location,
|
|
||||||
) -> Result<Option<Position>, Error> {
|
|
||||||
let Location::Src(src_loc) = loc;
|
|
||||||
|
|
||||||
let path = Path::new(&src_loc.filepath).to_owned();
|
|
||||||
let line = src_loc.pos.line;
|
|
||||||
let column = src_loc.pos.column;
|
|
||||||
|
|
||||||
self.inner()
|
|
||||||
.resolve_src_to_doc_jump(path, line, column)
|
|
||||||
.instrument_await("resolve src to doc jump")
|
|
||||||
.await
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn resolve_source_location(
|
|
||||||
&mut self,
|
|
||||||
s: Span,
|
|
||||||
offset: Option<usize>,
|
|
||||||
) -> Result<Option<DocToSrcJumpInfo>, Error> {
|
|
||||||
Ok(self
|
|
||||||
.inner()
|
|
||||||
.resolve_span_and_offset(s, offset)
|
|
||||||
.instrument_await("resolve span offset")
|
|
||||||
.await
|
|
||||||
.map_err(|err| {
|
|
||||||
error!("TypstActor: failed to resolve doc to src jump: {:#}", err);
|
|
||||||
})
|
|
||||||
.ok()
|
|
||||||
.flatten()
|
|
||||||
.map(|e| DocToSrcJumpInfo {
|
|
||||||
filepath: e.filepath,
|
|
||||||
start: e.start,
|
|
||||||
end: e.end,
|
|
||||||
}))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<H: CompilationHandle> EditorServer for TypstClient<H> {
|
|
||||||
async fn update_memory_files(
|
|
||||||
&mut self,
|
|
||||||
files: MemoryFiles,
|
|
||||||
reset_shadow: bool,
|
|
||||||
) -> Result<(), Error> {
|
|
||||||
// todo: is it safe to believe that the path is normalized?
|
|
||||||
let now = std::time::SystemTime::now();
|
|
||||||
let files = FileChangeSet::new_inserts(
|
|
||||||
files
|
|
||||||
.files
|
|
||||||
.into_iter()
|
|
||||||
.map(|(path, content)| {
|
|
||||||
let content = content.as_bytes().into();
|
|
||||||
// todo: cloning PathBuf -> Arc<Path>
|
|
||||||
(path.into(), Ok((now, content)).into())
|
|
||||||
})
|
|
||||||
.collect(),
|
|
||||||
);
|
|
||||||
self.inner().add_memory_changes(if reset_shadow {
|
|
||||||
MemoryEvent::Sync(files)
|
|
||||||
} else {
|
|
||||||
MemoryEvent::Update(files)
|
|
||||||
});
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn remove_shadow_files(&mut self, files: MemoryFilesShort) -> Result<(), Error> {
|
|
||||||
// todo: is it safe to believe that the path is normalized?
|
|
||||||
let files = FileChangeSet::new_removes(files.files.into_iter().map(From::from).collect());
|
|
||||||
self.inner().add_memory_changes(MemoryEvent::Update(files));
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<H: CompilationHandle> CompileHost for TypstClient<H> {}
|
|
||||||
|
|
|
@ -7,7 +7,7 @@ use typst::syntax::VirtualPath;
|
||||||
use typst::World;
|
use typst::World;
|
||||||
use typst_ts_core::{Bytes, ImmutPath, TypstFileId};
|
use typst_ts_core::{Bytes, ImmutPath, TypstFileId};
|
||||||
|
|
||||||
use crate::world::LspWorld;
|
use crate::world::{LspUniverse, LspWorld};
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub enum TemplateSource {
|
pub enum TemplateSource {
|
||||||
|
@ -20,13 +20,15 @@ pub struct InitTask {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Execute an initialization command.
|
/// Execute an initialization command.
|
||||||
pub fn get_entry(world: &LspWorld, tmpl: TemplateSource) -> StrResult<Bytes> {
|
pub fn get_entry(verse: &LspUniverse, tmpl: TemplateSource) -> StrResult<Bytes> {
|
||||||
let TemplateSource::Package(spec) = tmpl;
|
let TemplateSource::Package(spec) = tmpl;
|
||||||
|
|
||||||
let toml_id = TypstFileId::new(Some(spec.clone()), VirtualPath::new("typst.toml"));
|
let toml_id = TypstFileId::new(Some(spec.clone()), VirtualPath::new("typst.toml"));
|
||||||
|
|
||||||
|
let world = verse.spawn();
|
||||||
|
|
||||||
// Parse the manifest.
|
// Parse the manifest.
|
||||||
let manifest = parse_manifest(world, toml_id)?;
|
let manifest = parse_manifest(&world, toml_id)?;
|
||||||
manifest.validate(&spec)?;
|
manifest.validate(&spec)?;
|
||||||
|
|
||||||
// Ensure that it is indeed a template.
|
// Ensure that it is indeed a template.
|
||||||
|
|
|
@ -2,14 +2,14 @@ use typst::diag::{eco_format, StrResult};
|
||||||
use typst::syntax::package::{PackageVersion, VersionlessPackageSpec};
|
use typst::syntax::package::{PackageVersion, VersionlessPackageSpec};
|
||||||
use typst_ts_compiler::package::Registry;
|
use typst_ts_compiler::package::Registry;
|
||||||
|
|
||||||
use crate::world::LspWorld;
|
use crate::world::LspUniverse;
|
||||||
|
|
||||||
mod init;
|
mod init;
|
||||||
pub use init::*;
|
pub use init::*;
|
||||||
|
|
||||||
/// Try to determine the latest version of a package.
|
/// Try to determine the latest version of a package.
|
||||||
pub fn determine_latest_version(
|
pub fn determine_latest_version(
|
||||||
world: &LspWorld,
|
world: &LspUniverse,
|
||||||
spec: &VersionlessPackageSpec,
|
spec: &VersionlessPackageSpec,
|
||||||
) -> StrResult<PackageVersion> {
|
) -> StrResult<PackageVersion> {
|
||||||
if spec.namespace == "preview" {
|
if spec.namespace == "preview" {
|
||||||
|
|
|
@ -9,14 +9,15 @@ use typst_preview::{
|
||||||
CompileHost, DocToSrcJumpInfo, EditorServer, Location, MemoryFiles, MemoryFilesShort,
|
CompileHost, DocToSrcJumpInfo, EditorServer, Location, MemoryFiles, MemoryFilesShort,
|
||||||
SourceFileServer,
|
SourceFileServer,
|
||||||
};
|
};
|
||||||
use typst_ts_compiler::service::{Compiler, EntryManager};
|
|
||||||
use typst_ts_compiler::vfs::notify::{FileChangeSet, MemoryEvent};
|
use typst_ts_compiler::vfs::notify::{FileChangeSet, MemoryEvent};
|
||||||
|
use typst_ts_compiler::{service::Compiler, EntryReader};
|
||||||
use typst_ts_core::debug_loc::SourceSpanOffset;
|
use typst_ts_core::debug_loc::SourceSpanOffset;
|
||||||
use typst_ts_core::{Error, TypstDocument, TypstFileId};
|
use typst_ts_core::{Error, TypstDocument, TypstFileId};
|
||||||
|
|
||||||
use crate::actor::typ_client::CompileClientActor;
|
use crate::actor::typ_client::CompileClientActorImpl;
|
||||||
|
use crate::world::LspWorld;
|
||||||
|
|
||||||
impl SourceFileServer for CompileClientActor {
|
impl<C: Compiler<W = LspWorld> + Send> SourceFileServer for CompileClientActorImpl<C> {
|
||||||
/// fixme: character is 0-based, UTF-16 code unit.
|
/// fixme: character is 0-based, UTF-16 code unit.
|
||||||
/// We treat it as UTF-8 now.
|
/// We treat it as UTF-8 now.
|
||||||
async fn resolve_source_span(
|
async fn resolve_source_span(
|
||||||
|
@ -25,12 +26,10 @@ impl SourceFileServer for CompileClientActor {
|
||||||
) -> Result<Option<SourceSpanOffset>, Error> {
|
) -> Result<Option<SourceSpanOffset>, Error> {
|
||||||
let Location::Src(loc) = loc;
|
let Location::Src(loc) = loc;
|
||||||
self.steal_async(move |this| {
|
self.steal_async(move |this| {
|
||||||
let world = this.compiler.world();
|
let world = this.verse.spawn();
|
||||||
|
|
||||||
let filepath = Path::new(&loc.filepath);
|
let filepath = Path::new(&loc.filepath);
|
||||||
let relative_path = filepath
|
let relative_path = filepath.strip_prefix(&world.workspace_root()?).ok()?;
|
||||||
.strip_prefix(&this.compiler.world().workspace_root()?)
|
|
||||||
.ok()?;
|
|
||||||
|
|
||||||
let source_id = TypstFileId::new(None, VirtualPath::new(relative_path));
|
let source_id = TypstFileId::new(None, VirtualPath::new(relative_path));
|
||||||
let source = world.source(source_id).ok()?;
|
let source = world.source(source_id).ok()?;
|
||||||
|
@ -64,11 +63,9 @@ impl SourceFileServer for CompileClientActor {
|
||||||
self.steal_async(move |this| {
|
self.steal_async(move |this| {
|
||||||
let doc = this.latest_doc.as_deref()?;
|
let doc = this.latest_doc.as_deref()?;
|
||||||
|
|
||||||
let world = this.compiler.world();
|
let world = this.verse.spawn();
|
||||||
|
|
||||||
let relative_path = path
|
let relative_path = path.strip_prefix(&world.workspace_root()?).ok()?;
|
||||||
.strip_prefix(&this.compiler.world().workspace_root()?)
|
|
||||||
.ok()?;
|
|
||||||
|
|
||||||
let source_id = TypstFileId::new(None, VirtualPath::new(relative_path));
|
let source_id = TypstFileId::new(None, VirtualPath::new(relative_path));
|
||||||
let source = world.source(source_id).ok()?;
|
let source = world.source(source_id).ok()?;
|
||||||
|
@ -89,7 +86,7 @@ impl SourceFileServer for CompileClientActor {
|
||||||
|
|
||||||
let ret = self
|
let ret = self
|
||||||
.steal_async(move |this| {
|
.steal_async(move |this| {
|
||||||
let world = this.compiler.world();
|
let world = this.verse.spawn();
|
||||||
let src_id = span.id()?;
|
let src_id = span.id()?;
|
||||||
let source = world.source(src_id).ok()?;
|
let source = world.source(src_id).ok()?;
|
||||||
let mut range = source.find(span)?.range();
|
let mut range = source.find(span)?.range();
|
||||||
|
@ -181,7 +178,7 @@ fn find_in_frame(frame: &Frame, span: Span, min_dis: &mut u64, p: &mut Point) ->
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
impl EditorServer for CompileClientActor {
|
impl<C: Compiler<W = LspWorld> + Send> EditorServer for CompileClientActorImpl<C> {
|
||||||
async fn update_memory_files(
|
async fn update_memory_files(
|
||||||
&mut self,
|
&mut self,
|
||||||
files: MemoryFiles,
|
files: MemoryFiles,
|
||||||
|
@ -218,4 +215,4 @@ impl EditorServer for CompileClientActor {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl CompileHost for CompileClientActor {}
|
impl<C: Compiler<W = LspWorld> + Send> CompileHost for CompileClientActorImpl<C> {}
|
||||||
|
|
|
@ -13,7 +13,7 @@ use typst_ts_compiler::{
|
||||||
font::system::SystemFontSearcher,
|
font::system::SystemFontSearcher,
|
||||||
package::http::HttpRegistry,
|
package::http::HttpRegistry,
|
||||||
vfs::{system::SystemAccessModel, Vfs},
|
vfs::{system::SystemAccessModel, Vfs},
|
||||||
world::CompilerWorld,
|
SystemCompilerFeat, TypstSystemUniverse, TypstSystemWorld,
|
||||||
};
|
};
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Default, Serialize, Deserialize)]
|
#[derive(Debug, Clone, PartialEq, Default, Serialize, Deserialize)]
|
||||||
|
@ -49,7 +49,6 @@ pub struct CompileFontOpts {
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct SharedFontResolver {
|
pub struct SharedFontResolver {
|
||||||
font_paths: Vec<PathBuf>,
|
|
||||||
pub inner: Arc<FontResolverImpl>,
|
pub inner: Arc<FontResolverImpl>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -63,58 +62,24 @@ impl FontResolver for SharedFontResolver {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl SharedFontResolver {
|
impl SharedFontResolver {
|
||||||
pub fn new(mut opts: CompileFontOpts) -> ZResult<Self> {
|
pub fn new(opts: CompileFontOpts) -> ZResult<Self> {
|
||||||
// todo: relative paths?
|
|
||||||
let mut has_relative_path = false;
|
|
||||||
for p in &opts.font_paths {
|
|
||||||
if p.is_relative() {
|
|
||||||
has_relative_path = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if has_relative_path {
|
|
||||||
let current_dir = std::env::current_dir()
|
|
||||||
.context("failed to get current directory for relative font paths")?;
|
|
||||||
for p in &mut opts.font_paths {
|
|
||||||
if p.is_relative() {
|
|
||||||
*p = current_dir.join(&p);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let font_paths = opts.font_paths.clone();
|
|
||||||
let res = crate::world::LspWorldBuilder::resolve_fonts(opts)?;
|
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
font_paths,
|
inner: Arc::new(crate::world::LspWorldBuilder::resolve_fonts(opts)?),
|
||||||
inner: Arc::new(res),
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn font_paths(&self) -> &[PathBuf] {
|
pub fn font_paths(&self) -> &[PathBuf] {
|
||||||
&self.font_paths
|
self.inner.font_paths()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// type trait of [`LspWorld`].
|
pub type LspCompilerFeat = SystemCompilerFeat;
|
||||||
#[derive(Debug, Clone, Copy)]
|
pub type LspUniverse = TypstSystemUniverse;
|
||||||
pub struct SystemCompilerFeat;
|
pub type LspWorld = TypstSystemWorld;
|
||||||
|
|
||||||
impl typst_ts_compiler::world::CompilerFeat for SystemCompilerFeat {
|
|
||||||
/// Uses [`SharedFontResolver`] directly.
|
|
||||||
type FontResolver = SharedFontResolver;
|
|
||||||
/// It accesses a physical file system.
|
|
||||||
type AccessModel = SystemAccessModel;
|
|
||||||
/// It performs native HTTP requests for fetching package data.
|
|
||||||
type Registry = HttpRegistry;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// The compiler world in system environment.
|
|
||||||
pub type LspWorld = CompilerWorld<SystemCompilerFeat>;
|
|
||||||
|
|
||||||
pub type ImmutDict = Arc<Prehashed<TypstDict>>;
|
pub type ImmutDict = Arc<Prehashed<TypstDict>>;
|
||||||
|
|
||||||
pub struct LspWorldBuilder;
|
pub struct LspWorldBuilder;
|
||||||
// Self::resolve_fonts(opts)?,
|
|
||||||
|
|
||||||
impl LspWorldBuilder {
|
impl LspWorldBuilder {
|
||||||
/// Create [`LspWorld`] with the given options.
|
/// Create [`LspWorld`] with the given options.
|
||||||
|
@ -124,15 +89,14 @@ impl LspWorldBuilder {
|
||||||
entry: EntryState,
|
entry: EntryState,
|
||||||
font_resolver: SharedFontResolver,
|
font_resolver: SharedFontResolver,
|
||||||
inputs: ImmutDict,
|
inputs: ImmutDict,
|
||||||
) -> ZResult<LspWorld> {
|
) -> ZResult<LspUniverse> {
|
||||||
let mut res = CompilerWorld::new_raw(
|
Ok(LspUniverse::new_raw(
|
||||||
entry,
|
entry,
|
||||||
|
Some(inputs),
|
||||||
Vfs::new(SystemAccessModel {}),
|
Vfs::new(SystemAccessModel {}),
|
||||||
HttpRegistry::default(),
|
HttpRegistry::default(),
|
||||||
font_resolver,
|
font_resolver.inner,
|
||||||
);
|
))
|
||||||
res.inputs = inputs;
|
|
||||||
Ok(res)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Resolve fonts from given options.
|
/// Resolve fonts from given options.
|
||||||
|
|
|
@ -13,7 +13,7 @@ use ::await_tree::InstrumentAwait;
|
||||||
use debug_loc::SpanInterner;
|
use debug_loc::SpanInterner;
|
||||||
use futures::SinkExt;
|
use futures::SinkExt;
|
||||||
use log::info;
|
use log::info;
|
||||||
use serde::Deserialize;
|
use serde::{Deserialize, Serialize};
|
||||||
use tokio::net::{TcpListener, TcpStream};
|
use tokio::net::{TcpListener, TcpStream};
|
||||||
use tokio_tungstenite::tungstenite::Message;
|
use tokio_tungstenite::tungstenite::Message;
|
||||||
use tokio_tungstenite::WebSocketStream;
|
use tokio_tungstenite::WebSocketStream;
|
||||||
|
@ -22,7 +22,12 @@ use typst_ts_core::debug_loc::SourceSpanOffset;
|
||||||
use typst_ts_core::Error;
|
use typst_ts_core::Error;
|
||||||
use typst_ts_core::{ImmutStr, TypstDocument as Document};
|
use typst_ts_core::{ImmutStr, TypstDocument as Document};
|
||||||
|
|
||||||
pub use typst_ts_compiler::service::DocToSrcJumpInfo;
|
#[derive(Debug, Serialize)]
|
||||||
|
pub struct DocToSrcJumpInfo {
|
||||||
|
pub filepath: String,
|
||||||
|
pub start: Option<(usize, usize)>, // row, column
|
||||||
|
pub end: Option<(usize, usize)>,
|
||||||
|
}
|
||||||
|
|
||||||
use actor::editor::EditorActor;
|
use actor::editor::EditorActor;
|
||||||
use actor::typst::TypstActor;
|
use actor::typst::TypstActor;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue