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",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "archery"
|
||||
version = "1.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8967cd1cc9e9e1954f644e14fbd6042fe9a37da96c52a67e44a2ac18261f8561"
|
||||
dependencies = [
|
||||
"static_assertions",
|
||||
"triomphe",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "arraydeque"
|
||||
version = "0.5.1"
|
||||
|
@ -2889,8 +2899,7 @@ dependencies = [
|
|||
[[package]]
|
||||
name = "reflexo"
|
||||
version = "0.5.0-rc4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "803cbdda7d5beefc048966f342ba9a13dab586f136a8fe7f6d915b2f073a9151"
|
||||
source = "git+https://github.com/Myriad-Dreamin/typst.ts/?rev=36b969e2d5743544dca8679c53c89129b989ec80#36b969e2d5743544dca8679c53c89129b989ec80"
|
||||
dependencies = [
|
||||
"base64 0.22.1",
|
||||
"bitvec",
|
||||
|
@ -2898,10 +2907,12 @@ dependencies = [
|
|||
"dashmap",
|
||||
"ecow 0.2.2",
|
||||
"fxhash",
|
||||
"instant",
|
||||
"once_cell",
|
||||
"parking_lot",
|
||||
"path-clean",
|
||||
"rkyv",
|
||||
"rustc-hash",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"serde_repr",
|
||||
|
@ -2910,6 +2921,55 @@ dependencies = [
|
|||
"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]]
|
||||
name = "regex"
|
||||
version = "1.10.4"
|
||||
|
@ -3075,6 +3135,15 @@ version = "0.19.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3cd14fd5e3b777a7422cca79358c57a8f6e3a703d9ac187448d0daf220c2407f"
|
||||
|
||||
[[package]]
|
||||
name = "rpds"
|
||||
version = "1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a0e15515d3ce3313324d842629ea4905c25a13f81953eadb88f85516f59290a4"
|
||||
dependencies = [
|
||||
"archery",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rust_iso3166"
|
||||
version = "0.1.13"
|
||||
|
@ -4425,12 +4494,10 @@ dependencies = [
|
|||
[[package]]
|
||||
name = "typst-ts-compiler"
|
||||
version = "0.5.0-rc4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1b5d68fc30324347a294155cc4691defa4e01aaff23d7e3c1c40a3c8e5d22e3f"
|
||||
source = "git+https://github.com/Myriad-Dreamin/typst.ts/?rev=36b969e2d5743544dca8679c53c89129b989ec80#36b969e2d5743544dca8679c53c89129b989ec80"
|
||||
dependencies = [
|
||||
"append-only-vec",
|
||||
"base64 0.22.1",
|
||||
"chrono",
|
||||
"codespan-reporting",
|
||||
"comemo 0.4.0",
|
||||
"dirs",
|
||||
|
@ -4446,7 +4513,8 @@ dependencies = [
|
|||
"once_cell",
|
||||
"parking_lot",
|
||||
"pathdiff",
|
||||
"reqwest",
|
||||
"reflexo-vfs",
|
||||
"reflexo-world",
|
||||
"rustc-hash",
|
||||
"serde",
|
||||
"serde_json",
|
||||
|
@ -4463,8 +4531,7 @@ dependencies = [
|
|||
[[package]]
|
||||
name = "typst-ts-core"
|
||||
version = "0.5.0-rc4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5b9355a7f3b2f687088524fa1d5c0d0cbe45878e9672d7a321aec491ae10b1dd"
|
||||
source = "git+https://github.com/Myriad-Dreamin/typst.ts/?rev=36b969e2d5743544dca8679c53c89129b989ec80#36b969e2d5743544dca8679c53c89129b989ec80"
|
||||
dependencies = [
|
||||
"base64 0.22.1",
|
||||
"base64-serde",
|
||||
|
@ -4491,6 +4558,7 @@ dependencies = [
|
|||
"serde_with",
|
||||
"sha2",
|
||||
"siphasher 1.0.1",
|
||||
"svgtypes",
|
||||
"tiny-skia",
|
||||
"tiny-skia-path",
|
||||
"ttf-parser",
|
||||
|
@ -4501,8 +4569,7 @@ dependencies = [
|
|||
[[package]]
|
||||
name = "typst-ts-svg-exporter"
|
||||
version = "0.5.0-rc4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "13b1e7baba2453d072cbc1e97a43d5a8ecfe36299fc103e9156bb9470abd35e0"
|
||||
source = "git+https://github.com/Myriad-Dreamin/typst.ts/?rev=36b969e2d5743544dca8679c53c89129b989ec80#36b969e2d5743544dca8679c53c89129b989ec80"
|
||||
dependencies = [
|
||||
"base64 0.22.1",
|
||||
"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 = [
|
||||
"flat-vector",
|
||||
] }
|
||||
reflexo-world = { version = "0.5.0-rc4", features = ["system"] }
|
||||
typst-ts-core = { version = "0.5.0-rc4", default-features = false }
|
||||
typst-ts-compiler = { 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-syntax = { path = "../typst/crates/typst-syntax" }
|
||||
|
||||
# typst-ts-svg-exporter = { git = "https://github.com/Myriad-Dreamin/typst.ts/", rev = "9cced415e29e5e341ad4bdcc32ab3e67ffad74db" }
|
||||
# reflexo = { git = "https://github.com/Myriad-Dreamin/typst.ts/", rev = "9cced415e29e5e341ad4bdcc32ab3e67ffad74db" }
|
||||
# typst-ts-core = { git = "https://github.com/Myriad-Dreamin/typst.ts/", rev = "9cced415e29e5e341ad4bdcc32ab3e67ffad74db" }
|
||||
# typst-ts-compiler = { 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 = "36b969e2d5743544dca8679c53c89129b989ec80" }
|
||||
reflexo-world = { git = "https://github.com/Myriad-Dreamin/typst.ts/", rev = "36b969e2d5743544dca8679c53c89129b989ec80" }
|
||||
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" }
|
||||
# reflexo = { path = "../typst.ts/crates/reflexo/" }
|
||||
# reflexo-world = { path = "../typst.ts/crates/reflexo-world/" }
|
||||
# typst-ts-core = { path = "../typst.ts/core" }
|
||||
# typst-ts-compiler = { path = "../typst.ts/compiler" }
|
||||
# typstyle = { path = "../typstyle" }
|
||||
|
|
|
@ -420,10 +420,7 @@ pub trait AnalysisResources {
|
|||
fn resolve(&self, spec: &PackageSpec) -> Result<Arc<Path>, PackageError>;
|
||||
|
||||
/// Get all the files in the workspace.
|
||||
fn iter_dependencies<'a>(
|
||||
&'a self,
|
||||
f: &mut dyn FnMut(&'a ImmutPath, FileResult<&std::time::SystemTime>),
|
||||
);
|
||||
fn iter_dependencies(&self, f: &mut dyn FnMut(ImmutPath));
|
||||
|
||||
/// Resolve extra font information.
|
||||
fn font_info(&self, _font: Font) -> Option<Arc<DataSource>> {
|
||||
|
|
|
@ -36,11 +36,11 @@ impl SemanticRequest for SymbolRequest {
|
|||
|
||||
let mut symbols = vec![];
|
||||
|
||||
ctx.resources.iter_dependencies(&mut |path, _| {
|
||||
let Ok(source) = ctx.source_by_path(path) else {
|
||||
ctx.resources.iter_dependencies(&mut |path| {
|
||||
let Ok(source) = ctx.source_by_path(&path) else {
|
||||
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(
|
||||
|symbols| {
|
||||
self.pattern.as_ref().map(|pattern| {
|
||||
|
|
|
@ -8,17 +8,13 @@ use std::{
|
|||
use once_cell::sync::Lazy;
|
||||
pub use serde::Serialize;
|
||||
use serde_json::{ser::PrettyFormatter, Serializer, Value};
|
||||
use typst::{
|
||||
diag::FileResult,
|
||||
syntax::{
|
||||
use typst::syntax::{
|
||||
ast::{self, AstNode},
|
||||
FileId as TypstFileId, LinkedNode, Source, SyntaxKind, VirtualPath,
|
||||
},
|
||||
};
|
||||
use typst::{diag::PackageError, foundations::Bytes};
|
||||
use typst_ts_compiler::{
|
||||
service::{CompileDriver, Compiler, EntryManager},
|
||||
NotifyApi, ShadowApi,
|
||||
service::CompileDriver, EntryManager, EntryReader, ShadowApi, TypstSystemUniverse, WorldDeps,
|
||||
};
|
||||
use typst_ts_core::{
|
||||
config::compiler::{EntryOpts, EntryState},
|
||||
|
@ -46,10 +42,7 @@ impl<'a> AnalysisResources for WrapWorld<'a> {
|
|||
self.0.registry.resolve(spec)
|
||||
}
|
||||
|
||||
fn iter_dependencies<'b>(
|
||||
&'b self,
|
||||
f: &mut dyn FnMut(&'b reflexo::ImmutPath, FileResult<&typst_ts_compiler::Time>),
|
||||
) {
|
||||
fn iter_dependencies(&self, f: &mut dyn FnMut(reflexo::ImmutPath)) {
|
||||
self.0.iter_dependencies(f)
|
||||
}
|
||||
}
|
||||
|
@ -65,7 +58,7 @@ pub fn snapshot_testing(name: &str, f: &impl Fn(&mut AnalysisContext, PathBuf))
|
|||
#[cfg(windows)]
|
||||
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 paths = w
|
||||
.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()))
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
let w = WrapWorld(w);
|
||||
let mut w = w.spawn();
|
||||
let w = WrapWorld(&mut w);
|
||||
let mut ctx = AnalysisContext::new(
|
||||
&w,
|
||||
Analysis {
|
||||
|
@ -103,13 +97,16 @@ pub fn get_test_properties(s: &str) -> HashMap<&'_ str, &'_ str> {
|
|||
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) {
|
||||
PathBuf::from("C:\\")
|
||||
} else {
|
||||
PathBuf::from("/")
|
||||
};
|
||||
let mut world = TypstSystemWorld::new(CompileOpts {
|
||||
let mut world = TypstSystemUniverse::new(CompileOpts {
|
||||
entry: EntryOpts::new_rooted(root.as_path().into(), None),
|
||||
..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();
|
||||
let mut driver = CompileDriver::new(world);
|
||||
let mut driver = CompileDriver::new(std::marker::PhantomData, world);
|
||||
let _ = driver.compile(&mut Default::default());
|
||||
|
||||
let pw = last_pw.unwrap();
|
||||
driver
|
||||
.world_mut()
|
||||
.universe_mut()
|
||||
.mutate_entry(EntryState::new_rooted(
|
||||
root.as_path().into(),
|
||||
Some(TypstFileId::new(
|
||||
|
@ -159,7 +156,7 @@ pub fn run_with_sources<T>(source: &str, f: impl FnOnce(&mut TypstSystemWorld, P
|
|||
)),
|
||||
))
|
||||
.unwrap();
|
||||
f(driver.world_mut(), pw)
|
||||
f(driver.universe_mut(), pw)
|
||||
}
|
||||
|
||||
pub fn find_test_range(s: &Source) -> Range<usize> {
|
||||
|
|
|
@ -13,10 +13,7 @@ use tinymist_query::analysis::Analysis;
|
|||
use tinymist_query::ExportKind;
|
||||
use tinymist_render::PeriscopeRenderer;
|
||||
use tokio::sync::{mpsc, watch};
|
||||
use typst_ts_compiler::{
|
||||
service::CompileDriverImpl,
|
||||
vfs::notify::{FileChangeSet, MemoryEvent},
|
||||
};
|
||||
use typst_ts_compiler::vfs::notify::{FileChangeSet, MemoryEvent};
|
||||
use typst_ts_core::config::compiler::EntryState;
|
||||
|
||||
use self::{
|
||||
|
@ -28,12 +25,10 @@ use self::{
|
|||
};
|
||||
use crate::{
|
||||
compiler::CompileServer,
|
||||
world::{ImmutDict, LspWorld, LspWorldBuilder},
|
||||
world::{ImmutDict, LspWorldBuilder},
|
||||
TypstLanguageServer,
|
||||
};
|
||||
|
||||
type CompileDriverInner = CompileDriverImpl<LspWorld>;
|
||||
|
||||
impl CompileServer {
|
||||
pub fn restart_server(&mut self, group: &str) {
|
||||
let server = self.server(
|
||||
|
@ -102,13 +97,12 @@ impl CompileServer {
|
|||
self.handle.spawn_blocking(move || {
|
||||
// Create the world
|
||||
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");
|
||||
|
||||
// Create the compiler
|
||||
let driver = CompileDriverInner::new(world);
|
||||
let driver = CompileDriver {
|
||||
inner: driver,
|
||||
inner: std::marker::PhantomData,
|
||||
handler,
|
||||
analysis: Analysis {
|
||||
position_encoding,
|
||||
|
@ -121,7 +115,7 @@ impl CompileServer {
|
|||
|
||||
// Create the actor
|
||||
tokio::spawn(
|
||||
CompileServerActor::new(driver, entry_, intr_tx, intr_rx)
|
||||
CompileServerActor::new(driver, verse, entry_, intr_tx, intr_rx)
|
||||
.with_watch(true)
|
||||
.spawn(),
|
||||
);
|
||||
|
|
|
@ -42,16 +42,16 @@ use tinymist_query::{
|
|||
use tinymist_render::PeriscopeRenderer;
|
||||
use tokio::sync::{mpsc, oneshot, watch};
|
||||
use typst::{
|
||||
diag::{FileResult, PackageError, SourceDiagnostic, SourceResult},
|
||||
diag::{PackageError, SourceDiagnostic, SourceResult},
|
||||
layout::Position,
|
||||
model::Document as TypstDocument,
|
||||
syntax::package::PackageSpec,
|
||||
World as TypstWorld,
|
||||
};
|
||||
use typst_ts_compiler::{
|
||||
service::{CompileDriverImpl, CompileEnv, CompileMiddleware, Compiler, EntryManager, EnvWorld},
|
||||
service::{CompileEnv, CompileMiddleware, Compiler, PureCompiler},
|
||||
vfs::notify::MemoryEvent,
|
||||
Time,
|
||||
EntryManager, EntryReader,
|
||||
};
|
||||
use typst_ts_core::{
|
||||
config::compiler::EntryState, debug_loc::DataSource, error::prelude::*, typst::prelude::EcoVec,
|
||||
|
@ -61,18 +61,18 @@ use typst_ts_core::{
|
|||
use super::{
|
||||
editor::{EditorRequest, TinymistCompileStatusEnum},
|
||||
export::ExportConfig,
|
||||
typ_server::{is_inactive, CompileServerActor, Interrupt},
|
||||
typ_server::{CompileServerActor, Interrupt},
|
||||
};
|
||||
use crate::{
|
||||
actor::export::ExportRequest,
|
||||
compiler_init::CompileConfig,
|
||||
tools::preview::{CompilationHandle, CompileStatus},
|
||||
utils,
|
||||
world::LspWorld,
|
||||
world::{LspCompilerFeat, LspWorld},
|
||||
};
|
||||
|
||||
type CompileDriverInner = CompileDriverImpl<LspWorld>;
|
||||
type CompileService = CompileServerActor<CompileDriver>;
|
||||
type CompileService<C> = CompileServerActor<C, LspCompilerFeat>;
|
||||
pub type CompileClientActor = CompileClientActorImpl<CompileDriver>;
|
||||
|
||||
type EditorSender = mpsc::UnboundedSender<EditorRequest>;
|
||||
|
||||
|
@ -131,7 +131,7 @@ impl CompileHandler {
|
|||
}
|
||||
|
||||
pub struct CompileDriver {
|
||||
pub(super) inner: CompileDriverInner,
|
||||
pub(super) inner: PureCompiler<LspWorld>,
|
||||
#[allow(unused)]
|
||||
pub(super) handler: CompileHandler,
|
||||
pub(super) analysis: Analysis,
|
||||
|
@ -139,7 +139,7 @@ pub struct CompileDriver {
|
|||
}
|
||||
|
||||
impl CompileMiddleware for CompileDriver {
|
||||
type Compiler = CompileDriverInner;
|
||||
type Compiler = PureCompiler<LspWorld>;
|
||||
|
||||
fn inner(&self) -> &Self::Compiler {
|
||||
&self.inner
|
||||
|
@ -149,7 +149,11 @@ impl CompileMiddleware for CompileDriver {
|
|||
&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
|
||||
.editor_tx
|
||||
.send(EditorRequest::Status(
|
||||
|
@ -158,10 +162,14 @@ impl CompileMiddleware for CompileDriver {
|
|||
))
|
||||
.unwrap();
|
||||
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) => {
|
||||
self.handler.notify_compile(Ok(doc.clone()));
|
||||
self.notify_diagnostics(
|
||||
world,
|
||||
EcoVec::new(),
|
||||
env.tracer.as_ref().map(|e| e.clone().warnings()),
|
||||
);
|
||||
|
@ -170,7 +178,11 @@ impl CompileMiddleware for CompileDriver {
|
|||
Err(err) => {
|
||||
self.handler
|
||||
.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())
|
||||
}
|
||||
}
|
||||
|
@ -180,20 +192,22 @@ impl CompileMiddleware for CompileDriver {
|
|||
impl CompileDriver {
|
||||
fn notify_diagnostics(
|
||||
&mut self,
|
||||
world: &LspWorld,
|
||||
errors: EcoVec<SourceDiagnostic>,
|
||||
warnings: Option<EcoVec<SourceDiagnostic>>,
|
||||
) {
|
||||
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()))
|
||||
});
|
||||
|
||||
match diagnostics {
|
||||
Ok(diagnostics) => {
|
||||
let entry = world.entry_state();
|
||||
// todo: better way to remove diagnostics
|
||||
// todo: check all errors in this file
|
||||
let detached = is_inactive(&self.inner.world().entry);
|
||||
let detached = entry.is_inactive();
|
||||
let valid = !detached;
|
||||
self.handler.push_diagnostics(valid.then_some(diagnostics));
|
||||
}
|
||||
|
@ -206,15 +220,14 @@ impl CompileDriver {
|
|||
|
||||
pub fn run_analysis<T>(
|
||||
&mut self,
|
||||
w: &LspWorld,
|
||||
f: impl FnOnce(&mut AnalysisContext<'_>) -> T,
|
||||
) -> anyhow::Result<T> {
|
||||
let w = self.inner.world_mut();
|
||||
|
||||
let Some(main) = w.main_id() else {
|
||||
error!("TypstActor: 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");
|
||||
bail!("root is not set");
|
||||
};
|
||||
|
@ -222,12 +235,8 @@ impl CompileDriver {
|
|||
info!("TypstActor: failed to prepare main file: {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> {
|
||||
fn world(&self) -> &dyn typst::World {
|
||||
|
@ -239,17 +248,14 @@ impl CompileDriver {
|
|||
self.0.registry.resolve(spec)
|
||||
}
|
||||
|
||||
fn iter_dependencies<'b>(
|
||||
&'b self,
|
||||
f: &mut dyn FnMut(&'b ImmutPath, FileResult<&Time>),
|
||||
) {
|
||||
use typst_ts_compiler::NotifyApi;
|
||||
fn iter_dependencies(&self, f: &mut dyn FnMut(ImmutPath)) {
|
||||
use typst_ts_compiler::WorldDeps;
|
||||
self.0.iter_dependencies(f)
|
||||
}
|
||||
|
||||
/// Resolve extra font information.
|
||||
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.
|
||||
|
@ -270,20 +276,20 @@ impl CompileDriver {
|
|||
}
|
||||
}
|
||||
|
||||
pub struct CompileClientActor {
|
||||
pub struct CompileClientActorImpl<C: Compiler> {
|
||||
pub diag_group: String,
|
||||
pub config: CompileConfig,
|
||||
entry: EntryState,
|
||||
intr_tx: mpsc::UnboundedSender<Interrupt<CompileService>>,
|
||||
intr_tx: mpsc::UnboundedSender<Interrupt<CompileService<C>>>,
|
||||
export_tx: mpsc::UnboundedSender<ExportRequest>,
|
||||
}
|
||||
|
||||
impl CompileClientActor {
|
||||
impl<C: Compiler<W = LspWorld> + Send> CompileClientActorImpl<C> {
|
||||
pub(crate) fn new(
|
||||
diag_group: String,
|
||||
config: CompileConfig,
|
||||
entry: EntryState,
|
||||
intr_tx: mpsc::UnboundedSender<Interrupt<CompileService>>,
|
||||
intr_tx: mpsc::UnboundedSender<Interrupt<CompileService<C>>>,
|
||||
export_tx: mpsc::UnboundedSender<ExportRequest>,
|
||||
) -> Self {
|
||||
Self {
|
||||
|
@ -297,11 +303,11 @@ impl CompileClientActor {
|
|||
|
||||
fn steal_inner<Ret: Send + 'static>(
|
||||
&self,
|
||||
f: impl FnOnce(&mut CompileService) -> Ret + Send + 'static,
|
||||
f: impl FnOnce(&mut CompileService<C>) -> Ret + Send + 'static,
|
||||
) -> ZResult<oneshot::Receiver<Ret>> {
|
||||
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() {
|
||||
// Receiver was dropped. The main thread may have exited, or the request may
|
||||
// have been cancelled.
|
||||
|
@ -319,7 +325,7 @@ impl CompileClientActor {
|
|||
/// Steal the compiler thread and run the given function.
|
||||
pub fn steal<Ret: Send + 'static>(
|
||||
&self,
|
||||
f: impl FnOnce(&mut CompileService) -> Ret + Send + 'static,
|
||||
f: impl FnOnce(&mut CompileService<C>) -> Ret + Send + 'static,
|
||||
) -> ZResult<Ret> {
|
||||
utils::threaded_receive(self.steal_inner(f)?)
|
||||
}
|
||||
|
@ -327,31 +333,46 @@ impl CompileClientActor {
|
|||
/// Steal the compiler thread and run the given function.
|
||||
pub async fn steal_async<Ret: Send + 'static>(
|
||||
&self,
|
||||
f: impl FnOnce(&mut CompileService) -> Ret + Send + 'static,
|
||||
f: impl FnOnce(&mut CompileService<C>) -> Ret + Send + 'static,
|
||||
) -> ZResult<Ret> {
|
||||
self.steal_inner(f)?
|
||||
.await
|
||||
.map_err(map_string_err("failed to call steal_async"))
|
||||
}
|
||||
|
||||
pub fn steal_state<T: Send + Sync + 'static>(
|
||||
&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 c = &mut compiler.compiler.compiler;
|
||||
c.run_analysis(move |ctx| f(ctx, doc))
|
||||
})?
|
||||
pub fn sync_config(&mut self, config: CompileConfig) {
|
||||
self.config = config;
|
||||
}
|
||||
|
||||
pub fn steal_world<T: Send + Sync + 'static>(
|
||||
&self,
|
||||
f: impl FnOnce(&mut AnalysisContext) -> T + Send + Sync + 'static,
|
||||
) -> anyhow::Result<T> {
|
||||
self.steal(move |compiler| compiler.compiler.compiler.run_analysis(f))?
|
||||
pub fn add_memory_changes(&self, event: MemoryEvent) {
|
||||
let _ = self.intr_tx.send(Interrupt::Memory(event));
|
||||
}
|
||||
|
||||
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) {
|
||||
let _ = self.change_entry(None);
|
||||
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> {
|
||||
if path
|
||||
.as_deref()
|
||||
|
@ -388,8 +405,8 @@ impl CompileClientActor {
|
|||
self.steal(move |compiler| {
|
||||
compiler.change_entry(next.clone());
|
||||
|
||||
let next_is_inactive = is_inactive(&next);
|
||||
let res = compiler.compiler.world_mut().mutate_entry(next);
|
||||
let next_is_inactive = next.is_inactive();
|
||||
let res = compiler.verse.mutate_entry(next);
|
||||
|
||||
if next_is_inactive {
|
||||
info!("TypstActor: removing diag");
|
||||
|
@ -408,12 +425,26 @@ impl CompileClientActor {
|
|||
Ok(true)
|
||||
}
|
||||
|
||||
pub fn add_memory_changes(&self, event: MemoryEvent) {
|
||||
let _ = self.intr_tx.send(Interrupt::Memory(event));
|
||||
pub fn steal_state<T: Send + Sync + 'static>(
|
||||
&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) {
|
||||
let _ = self.export_tx.send(ExportRequest::ChangeConfig(config));
|
||||
pub fn steal_world<T: Send + Sync + 'static>(
|
||||
&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) {
|
||||
|
@ -426,13 +457,15 @@ impl CompileClientActor {
|
|||
let dg = self.diag_group.clone();
|
||||
self.steal(move |c| {
|
||||
let cc = &c.compiler.compiler;
|
||||
let w = c.verse.spawn();
|
||||
|
||||
let info = ServerInfoResponse {
|
||||
root: cc.world().entry.root().map(|e| e.as_ref().to_owned()),
|
||||
font_paths: cc.world().font_resolver.font_paths().to_owned(),
|
||||
inputs: cc.world().inputs.as_ref().deref().clone(),
|
||||
root: w.entry_state().root().map(|e| e.as_ref().to_owned()),
|
||||
font_paths: w.font_resolver.font_paths().to_owned(),
|
||||
inputs: c.verse.inputs().as_ref().deref().clone(),
|
||||
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()),
|
||||
]),
|
||||
};
|
||||
|
@ -441,23 +474,4 @@ impl CompileClientActor {
|
|||
})
|
||||
.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 tokio::sync::{mpsc, oneshot};
|
||||
|
||||
use typst_ts_compiler::service::{
|
||||
use typst_ts_compiler::{
|
||||
service::{
|
||||
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_compiler::ShadowApi;
|
||||
use typst_ts_core::{config::compiler::EntryState, TypstDocument, TypstFileId};
|
||||
use typst_ts_core::{config::compiler::EntryState, TypstDocument};
|
||||
|
||||
/// 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> {
|
||||
/// Compile anyway.
|
||||
Compile,
|
||||
/// 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>),
|
||||
/// Memory file changes.
|
||||
Memory(MemoryEvent),
|
||||
|
@ -30,11 +38,6 @@ pub enum Interrupt<Ctx> {
|
|||
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.
|
||||
enum CompilerResponse {
|
||||
/// Response to the file watcher
|
||||
|
@ -55,9 +58,11 @@ struct SuspendState {
|
|||
}
|
||||
|
||||
/// 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.
|
||||
pub compiler: CompileReporter<C>,
|
||||
pub compiler: CompileReporter<C, CompilerWorld<F>>,
|
||||
/// Whether to enable file system watching.
|
||||
pub enable_watch: bool,
|
||||
|
||||
|
@ -85,12 +90,12 @@ pub struct CompileServerActor<C: Compiler> {
|
|||
suspend_state: SuspendState,
|
||||
}
|
||||
|
||||
impl<C: Compiler + ShadowApi + Send + 'static> CompileServerActor<C>
|
||||
where
|
||||
C::World: for<'files> codespan_reporting::files::Files<'files, FileId = TypstFileId>,
|
||||
impl<F: CompilerFeat + Send + 'static, C: Compiler<W = CompilerWorld<F>> + Send + 'static>
|
||||
CompileServerActor<C, F>
|
||||
{
|
||||
pub fn new_with_features(
|
||||
compiler: C,
|
||||
verse: CompilerUniverse<F>,
|
||||
entry: EntryState,
|
||||
feature_set: FeatureSet,
|
||||
intr_tx: mpsc::UnboundedSender<Interrupt<Self>>,
|
||||
|
@ -99,6 +104,7 @@ where
|
|||
Self {
|
||||
compiler: CompileReporter::new(compiler)
|
||||
.with_generic_reporter(ConsoleDiagReporter::default()),
|
||||
verse,
|
||||
|
||||
logical_tick: 1,
|
||||
enable_watch: false,
|
||||
|
@ -116,7 +122,7 @@ where
|
|||
intr_rx,
|
||||
|
||||
suspend_state: SuspendState {
|
||||
suspended: is_inactive(&entry),
|
||||
suspended: entry.is_inactive(),
|
||||
dirty: false,
|
||||
},
|
||||
}
|
||||
|
@ -125,18 +131,29 @@ where
|
|||
/// Create a new compiler thread.
|
||||
pub fn new(
|
||||
compiler: C,
|
||||
world: CompilerUniverse<F>,
|
||||
entry: EntryState,
|
||||
intr_tx: mpsc::UnboundedSender<Interrupt<Self>>,
|
||||
intr_rx: mpsc::UnboundedReceiver<Interrupt<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 {
|
||||
self.enable_watch = enable_watch;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn intr_tx(&self) -> mpsc::UnboundedSender<Interrupt<Self>> {
|
||||
self.intr_tx.clone()
|
||||
}
|
||||
|
||||
pub fn success_doc(&self) -> Option<VersionedDocument> {
|
||||
self.latest_success_doc
|
||||
.clone()
|
||||
|
@ -174,7 +191,8 @@ where
|
|||
async fn block_run_inner(mut self) -> bool {
|
||||
if !self.enable_watch {
|
||||
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();
|
||||
}
|
||||
|
||||
|
@ -191,7 +209,8 @@ where
|
|||
pub async fn spawn(mut self) -> Option<JoinHandle<()>> {
|
||||
if !self.enable_watch {
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -268,8 +287,8 @@ where
|
|||
Some(compile_thread.unwrap())
|
||||
}
|
||||
|
||||
pub(crate) fn change_entry(&mut self, entry: EntryState) {
|
||||
self.suspend_state.suspended = is_inactive(&entry);
|
||||
pub fn change_entry(&mut self, entry: EntryState) {
|
||||
self.suspend_state.suspended = entry.is_inactive();
|
||||
if !self.suspend_state.suspended && self.suspend_state.dirty {
|
||||
self.intr_tx.send(Interrupt::Compile).ok();
|
||||
}
|
||||
|
@ -288,9 +307,11 @@ where
|
|||
return;
|
||||
}
|
||||
|
||||
let w = self.verse.spawn();
|
||||
|
||||
// Compile the document.
|
||||
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() {
|
||||
self.latest_success_doc.clone_from(&self.latest_doc);
|
||||
}
|
||||
|
@ -303,8 +324,7 @@ where
|
|||
|
||||
// Notify the new file dependencies.
|
||||
let mut deps = vec![];
|
||||
self.compiler
|
||||
.iter_dependencies(&mut |dep, _| deps.push(dep.clone()));
|
||||
w.iter_dependencies(&mut |dep| deps.push(dep.clone()));
|
||||
send(Notify(NotifyMessage::SyncDependency(deps)));
|
||||
}
|
||||
|
||||
|
@ -340,7 +360,8 @@ where
|
|||
|
||||
// If there is no invalidation happening, apply memory changes directly.
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -362,13 +383,15 @@ where
|
|||
Interrupt::Fs(mut event) => {
|
||||
log::debug!("CompileServerActor: fs event incoming {event:?}");
|
||||
|
||||
// Apply file system changes.
|
||||
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(&mut event).is_none() {
|
||||
if Self::apply_delayed_memory_changes(verse, dirty_tick, &mut event).is_none() {
|
||||
log::warn!("CompileServerActor: unknown upstream update event");
|
||||
}
|
||||
|
||||
// Apply file system changes.
|
||||
self.compiler.notify_fs_event(event);
|
||||
verse.notify_fs_event(event)
|
||||
});
|
||||
|
||||
true
|
||||
}
|
||||
|
@ -377,7 +400,11 @@ where
|
|||
}
|
||||
|
||||
/// 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
|
||||
if let FilesystemEvent::UpstreamUpdate { upstream_event, .. } = event {
|
||||
let event = upstream_event.take()?.opaque;
|
||||
|
@ -387,25 +414,25 @@ where
|
|||
} = *event.downcast().ok()?;
|
||||
|
||||
// Recovery from dirty shadow state.
|
||||
if logical_tick == self.dirty_shadow_logical_tick {
|
||||
self.dirty_shadow_logical_tick = 0;
|
||||
if logical_tick == *dirty_shadow_logical_tick {
|
||||
*dirty_shadow_logical_tick = 0;
|
||||
}
|
||||
|
||||
self.apply_memory_changes(event);
|
||||
Self::apply_memory_changes(verse, event);
|
||||
}
|
||||
|
||||
Some(())
|
||||
}
|
||||
|
||||
/// 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(..)) {
|
||||
self.compiler.reset_shadow();
|
||||
verse.reset_shadow();
|
||||
}
|
||||
match event {
|
||||
MemoryEvent::Update(event) | MemoryEvent::Sync(event) => {
|
||||
for removes in event.removes {
|
||||
let _ = self.compiler.unmap_shadow(&removes);
|
||||
let _ = verse.unmap_shadow(&removes);
|
||||
}
|
||||
for (p, t) in event.inserts {
|
||||
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]
|
||||
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}"))
|
||||
|
|
|
@ -42,7 +42,9 @@ pub use server::compiler_init;
|
|||
pub use server::lsp::*;
|
||||
pub use server::lsp_init::*;
|
||||
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;
|
||||
|
||||
|
|
|
@ -10,12 +10,6 @@ use comemo::Prehashed;
|
|||
use lsp_types::{InitializeParams, InitializedParams};
|
||||
use once_cell::sync::Lazy;
|
||||
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::{
|
||||
compiler_init::{CompileInit, CompileInitializeParams},
|
||||
harness::{lsp_harness, InitializedLspDriver, LspDriver, LspHost},
|
||||
|
@ -23,6 +17,13 @@ use tinymist::{
|
|||
transport::with_stdio_transport,
|
||||
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")]
|
||||
#[global_allocator]
|
||||
|
@ -183,8 +184,12 @@ pub fn compiler_main(args: CompileArgs) -> anyhow::Result<()> {
|
|||
let (timings, _doc, diagnostics) = service
|
||||
.compiler()
|
||||
.steal(|c| {
|
||||
c.compiler.world_mut().mutate_entry(entry).unwrap();
|
||||
c.compiler.world_mut().inputs = inputs;
|
||||
c.verse.increment_revision(|verse| {
|
||||
verse.mutate_entry(entry).unwrap();
|
||||
verse.set_inputs(inputs);
|
||||
});
|
||||
|
||||
let w = c.verse.spawn();
|
||||
|
||||
let mut env = CompileEnv {
|
||||
tracer: Some(Tracer::default()),
|
||||
|
@ -192,24 +197,23 @@ pub fn compiler_main(args: CompileArgs) -> anyhow::Result<()> {
|
|||
};
|
||||
typst_timing::enable();
|
||||
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),
|
||||
Err(e) => {
|
||||
errors = e;
|
||||
None
|
||||
}
|
||||
};
|
||||
let world = c.compiler.world();
|
||||
let mut writer = std::io::BufWriter::new(Vec::new());
|
||||
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 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(
|
||||
ctx,
|
||||
warnings.iter().flatten().chain(errors.iter()),
|
||||
|
@ -261,7 +265,6 @@ impl<T> Drop for ForceDrop<T> {
|
|||
|
||||
/// Turns a span into a (file, line) pair.
|
||||
fn resolve_span(world: &LspWorld, span: Span) -> Option<(String, u32)> {
|
||||
use typst::World;
|
||||
let id = span.id()?;
|
||||
let source = world.source(id).ok()?;
|
||||
let range = source.range(span)?;
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
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};
|
||||
|
||||
pub use super::prelude::*;
|
||||
|
@ -188,16 +187,23 @@ impl TypstLanguageServer {
|
|||
let font = self
|
||||
.primary()
|
||||
.steal(move |e| {
|
||||
let verse = &mut e.verse;
|
||||
let entry_path: Arc<Path> = Path::new("/._sym_.typ").into();
|
||||
|
||||
let new_entry = EntryState::new_rootless(entry_path.clone())?;
|
||||
let old_entry = e.compiler.world_mut().mutate_entry(new_entry).ok()?;
|
||||
let prepared = e
|
||||
.compiler
|
||||
let (old_entry, prepared) = verse.increment_revision(|verse| {
|
||||
let old_entry = verse.mutate_entry(new_entry).ok()?;
|
||||
let prepared = verse
|
||||
.map_shadow(&entry_path, math_shaping_text.into_bytes().into())
|
||||
.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!(
|
||||
"sym doc: {doc:?}",
|
||||
|
|
|
@ -23,7 +23,6 @@ use tinymist_query::{
|
|||
use tokio::sync::mpsc;
|
||||
use typst::diag::StrResult;
|
||||
use typst::syntax::package::{PackageSpec, VersionlessPackageSpec};
|
||||
use typst_ts_compiler::service::Compiler;
|
||||
use typst_ts_core::path::PathClean;
|
||||
use typst_ts_core::{error::prelude::*, ImmutPath};
|
||||
|
||||
|
@ -646,7 +645,7 @@ impl TypstLanguageServer {
|
|||
let res = self
|
||||
.primary()
|
||||
.steal(move |c| {
|
||||
let cc = &c.compiler;
|
||||
let verse = &c.verse;
|
||||
|
||||
// todo: rootless file
|
||||
// todo: memory dirty file
|
||||
|
@ -665,8 +664,8 @@ impl TypstLanguageServer {
|
|||
compiler_program: self_path,
|
||||
root: root.as_ref().to_owned(),
|
||||
main,
|
||||
inputs: cc.world().inputs.as_ref().deref().clone(),
|
||||
font_paths: cc.world().font_resolver.font_paths().to_owned(),
|
||||
inputs: verse.inputs().as_ref().deref().clone(),
|
||||
font_paths: verse.font_resolver.font_paths().to_owned(),
|
||||
},
|
||||
))
|
||||
.context("cannot send trace request")?;
|
||||
|
@ -770,6 +769,7 @@ impl TypstLanguageServer {
|
|||
let res = self
|
||||
.primary()
|
||||
.steal(move |c| {
|
||||
let world = c.verse.spawn();
|
||||
// Parse the package specification. If the user didn't specify the version,
|
||||
// we try to figure it out automatically by downloading the package index
|
||||
// or searching the disk.
|
||||
|
@ -779,7 +779,7 @@ impl TypstLanguageServer {
|
|||
// Try to parse without version, but prefer the error message of the
|
||||
// normal package spec parsing if it fails.
|
||||
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))
|
||||
})
|
||||
.map_err(map_string_err("failed to parse package spec"))?;
|
||||
|
@ -787,7 +787,7 @@ impl TypstLanguageServer {
|
|||
let from_source = TemplateSource::Package(spec);
|
||||
|
||||
let entry_path = package::init(
|
||||
c.compiler.world(),
|
||||
&world,
|
||||
InitTask {
|
||||
tmpl: from_source.clone(),
|
||||
dir: to_path.clone(),
|
||||
|
@ -827,14 +827,14 @@ impl TypstLanguageServer {
|
|||
// Try to parse without version, but prefer the error message of the
|
||||
// normal package spec parsing if it fails.
|
||||
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))
|
||||
})
|
||||
.map_err(map_string_err("failed to parse 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"))?;
|
||||
|
||||
ZResult::Ok(entry)
|
||||
|
|
|
@ -5,8 +5,7 @@ use await_tree::InstrumentAwait;
|
|||
use log::{error, info};
|
||||
|
||||
use typst::foundations::{Str, Value};
|
||||
use typst_ts_compiler::service::CompileDriver;
|
||||
use typst_ts_compiler::TypstSystemWorld;
|
||||
use typst_ts_compiler::{service::CompileDriver, TypstSystemUniverse};
|
||||
use typst_ts_core::config::{compiler::EntryOpts, CompileOpts};
|
||||
|
||||
use hyper::{
|
||||
|
@ -139,7 +138,7 @@ pub async fn preview_main(args: PreviewCliArgs) -> anyhow::Result<()> {
|
|||
}
|
||||
|
||||
let compiler_driver = {
|
||||
let world = TypstSystemWorld::new(CompileOpts {
|
||||
let world = TypstSystemUniverse::new(CompileOpts {
|
||||
entry: EntryOpts::new_rooted(root.clone(), Some(entry.clone())),
|
||||
inputs,
|
||||
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");
|
||||
|
||||
CompileDriver::new(world).with_entry_file(entry)
|
||||
CompileDriver::new(std::marker::PhantomData, world.with_entry_file(entry))
|
||||
};
|
||||
|
||||
tokio::spawn(async move {
|
||||
|
|
|
@ -1,32 +1,31 @@
|
|||
use std::path::Path;
|
||||
use std::sync::Arc;
|
||||
|
||||
use await_tree::InstrumentAwait;
|
||||
use log::error;
|
||||
|
||||
use tokio::sync::mpsc;
|
||||
use typst::diag::SourceResult;
|
||||
use typst::layout::Position;
|
||||
use typst::model::Document;
|
||||
use typst::syntax::Span;
|
||||
|
||||
use typst_ts_compiler::service::{
|
||||
CompileActor, CompileClient as TsCompileClient, CompileExporter, Compiler, WorldExporter,
|
||||
};
|
||||
use typst::World;
|
||||
use typst_ts_compiler::service::{CompileDriver, CompileMiddleware};
|
||||
use typst_ts_compiler::vfs::notify::{FileChangeSet, MemoryEvent};
|
||||
use typst_ts_core::debug_loc::SourceSpanOffset;
|
||||
use typst_ts_compiler::service::{CompileExporter, Compiler, PureCompiler, WorldExporter};
|
||||
use typst_ts_compiler::{EntryReader, TypstSystemWorld};
|
||||
use typst_ts_core::Error;
|
||||
|
||||
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>>;
|
||||
pub type CompileClient<H> = TsCompileClient<CompileService<H>>;
|
||||
use crate::actor::typ_client::CompileClientActorImpl;
|
||||
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> {
|
||||
inner: CompileService<H>,
|
||||
client: TypstClient<H>,
|
||||
}
|
||||
|
||||
pub struct Reporter<C, H> {
|
||||
|
@ -47,10 +46,11 @@ impl<C: Compiler, H: CompilationHandle> CompileMiddleware for Reporter<C, H> {
|
|||
|
||||
fn wrap_compile(
|
||||
&mut self,
|
||||
world: &<C as typst_ts_compiler::service::Compiler>::W,
|
||||
env: &mut typst_ts_compiler::service::CompileEnv,
|
||||
) -> SourceResult<Arc<Document>> {
|
||||
self.cb.status(CompileStatus::Compiling);
|
||||
match self.inner_mut().compile(env) {
|
||||
match self.inner_mut().compile(world, env) {
|
||||
Ok(doc) => {
|
||||
self.cb.notify_compile(Ok(doc.clone()));
|
||||
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> {
|
||||
fn export(&mut self, output: Arc<typst::model::Document>) -> SourceResult<()> {
|
||||
self.inner.export(output)
|
||||
impl<W: World, C: Compiler<W = W> + WorldExporter<W>, H> WorldExporter<W> for Reporter<C, H> {
|
||||
fn export(&mut self, world: &W, output: Arc<typst::model::Document>) -> SourceResult<()> {
|
||||
self.inner.export(world, output)
|
||||
}
|
||||
}
|
||||
|
||||
impl<H: CompilationHandle> CompileServer<H> {
|
||||
pub fn new(
|
||||
compiler_driver: CompileDriver,
|
||||
compiler_driver: CompileDriver<PureCompiler<TypstSystemWorld>>,
|
||||
cb: H,
|
||||
// renderer_sender: broadcast::Sender<RenderActorRequest>,
|
||||
// editor_conn_sender: mpsc::UnboundedSender<EditorActorRequest>,
|
||||
) -> Self {
|
||||
let (intr_tx, intr_rx) = mpsc::unbounded_channel();
|
||||
let CompileDriver { compiler, universe } = compiler_driver;
|
||||
let entry = universe.entry_state();
|
||||
|
||||
// CompileExporter + DynamicLayoutCompiler + WatchDriver
|
||||
let driver = CompileExporter::new(compiler_driver);
|
||||
let driver = CompileExporter::new(compiler);
|
||||
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 {
|
||||
inner,
|
||||
client: TypstClient {
|
||||
inner: once_cell::sync::OnceCell::new(),
|
||||
},
|
||||
}
|
||||
Self { inner }
|
||||
}
|
||||
|
||||
pub fn spawn(self) -> Result<TypstClient<H>, Error> {
|
||||
let (server, client) = self.inner.split();
|
||||
tokio::spawn(server.spawn().instrument_await("spawn typst server"));
|
||||
|
||||
self.client.inner.set(client).ok().unwrap();
|
||||
|
||||
Ok(self.client)
|
||||
pub fn spawn(self) -> Result<CompileClient<H>, Error> {
|
||||
let (export_tx, mut export_rx) = mpsc::unbounded_channel();
|
||||
let intr_tx = self.inner.intr_tx();
|
||||
let entry = self.inner.verse.entry_state();
|
||||
tokio::spawn(self.inner.spawn().instrument_await("spawn typst server"));
|
||||
// drop all export events
|
||||
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_ts_core::{Bytes, ImmutPath, TypstFileId};
|
||||
|
||||
use crate::world::LspWorld;
|
||||
use crate::world::{LspUniverse, LspWorld};
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum TemplateSource {
|
||||
|
@ -20,13 +20,15 @@ pub struct InitTask {
|
|||
}
|
||||
|
||||
/// 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 toml_id = TypstFileId::new(Some(spec.clone()), VirtualPath::new("typst.toml"));
|
||||
|
||||
let world = verse.spawn();
|
||||
|
||||
// Parse the manifest.
|
||||
let manifest = parse_manifest(world, toml_id)?;
|
||||
let manifest = parse_manifest(&world, toml_id)?;
|
||||
manifest.validate(&spec)?;
|
||||
|
||||
// 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_ts_compiler::package::Registry;
|
||||
|
||||
use crate::world::LspWorld;
|
||||
use crate::world::LspUniverse;
|
||||
|
||||
mod init;
|
||||
pub use init::*;
|
||||
|
||||
/// Try to determine the latest version of a package.
|
||||
pub fn determine_latest_version(
|
||||
world: &LspWorld,
|
||||
world: &LspUniverse,
|
||||
spec: &VersionlessPackageSpec,
|
||||
) -> StrResult<PackageVersion> {
|
||||
if spec.namespace == "preview" {
|
||||
|
|
|
@ -9,14 +9,15 @@ use typst_preview::{
|
|||
CompileHost, DocToSrcJumpInfo, EditorServer, Location, MemoryFiles, MemoryFilesShort,
|
||||
SourceFileServer,
|
||||
};
|
||||
use typst_ts_compiler::service::{Compiler, EntryManager};
|
||||
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::{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.
|
||||
/// We treat it as UTF-8 now.
|
||||
async fn resolve_source_span(
|
||||
|
@ -25,12 +26,10 @@ impl SourceFileServer for CompileClientActor {
|
|||
) -> Result<Option<SourceSpanOffset>, Error> {
|
||||
let Location::Src(loc) = loc;
|
||||
self.steal_async(move |this| {
|
||||
let world = this.compiler.world();
|
||||
let world = this.verse.spawn();
|
||||
|
||||
let filepath = Path::new(&loc.filepath);
|
||||
let relative_path = filepath
|
||||
.strip_prefix(&this.compiler.world().workspace_root()?)
|
||||
.ok()?;
|
||||
let relative_path = filepath.strip_prefix(&world.workspace_root()?).ok()?;
|
||||
|
||||
let source_id = TypstFileId::new(None, VirtualPath::new(relative_path));
|
||||
let source = world.source(source_id).ok()?;
|
||||
|
@ -64,11 +63,9 @@ impl SourceFileServer for CompileClientActor {
|
|||
self.steal_async(move |this| {
|
||||
let doc = this.latest_doc.as_deref()?;
|
||||
|
||||
let world = this.compiler.world();
|
||||
let world = this.verse.spawn();
|
||||
|
||||
let relative_path = path
|
||||
.strip_prefix(&this.compiler.world().workspace_root()?)
|
||||
.ok()?;
|
||||
let relative_path = path.strip_prefix(&world.workspace_root()?).ok()?;
|
||||
|
||||
let source_id = TypstFileId::new(None, VirtualPath::new(relative_path));
|
||||
let source = world.source(source_id).ok()?;
|
||||
|
@ -89,7 +86,7 @@ impl SourceFileServer for CompileClientActor {
|
|||
|
||||
let ret = self
|
||||
.steal_async(move |this| {
|
||||
let world = this.compiler.world();
|
||||
let world = this.verse.spawn();
|
||||
let src_id = span.id()?;
|
||||
let source = world.source(src_id).ok()?;
|
||||
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
|
||||
}
|
||||
|
||||
impl EditorServer for CompileClientActor {
|
||||
impl<C: Compiler<W = LspWorld> + Send> EditorServer for CompileClientActorImpl<C> {
|
||||
async fn update_memory_files(
|
||||
&mut self,
|
||||
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,
|
||||
package::http::HttpRegistry,
|
||||
vfs::{system::SystemAccessModel, Vfs},
|
||||
world::CompilerWorld,
|
||||
SystemCompilerFeat, TypstSystemUniverse, TypstSystemWorld,
|
||||
};
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Default, Serialize, Deserialize)]
|
||||
|
@ -49,7 +49,6 @@ pub struct CompileFontOpts {
|
|||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct SharedFontResolver {
|
||||
font_paths: Vec<PathBuf>,
|
||||
pub inner: Arc<FontResolverImpl>,
|
||||
}
|
||||
|
||||
|
@ -63,58 +62,24 @@ impl FontResolver for SharedFontResolver {
|
|||
}
|
||||
|
||||
impl SharedFontResolver {
|
||||
pub fn new(mut 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)?;
|
||||
pub fn new(opts: CompileFontOpts) -> ZResult<Self> {
|
||||
Ok(Self {
|
||||
font_paths,
|
||||
inner: Arc::new(res),
|
||||
inner: Arc::new(crate::world::LspWorldBuilder::resolve_fonts(opts)?),
|
||||
})
|
||||
}
|
||||
|
||||
pub fn font_paths(&self) -> &[PathBuf] {
|
||||
&self.font_paths
|
||||
self.inner.font_paths()
|
||||
}
|
||||
}
|
||||
|
||||
/// type trait of [`LspWorld`].
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub struct SystemCompilerFeat;
|
||||
|
||||
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 LspCompilerFeat = SystemCompilerFeat;
|
||||
pub type LspUniverse = TypstSystemUniverse;
|
||||
pub type LspWorld = TypstSystemWorld;
|
||||
|
||||
pub type ImmutDict = Arc<Prehashed<TypstDict>>;
|
||||
|
||||
pub struct LspWorldBuilder;
|
||||
// Self::resolve_fonts(opts)?,
|
||||
|
||||
impl LspWorldBuilder {
|
||||
/// Create [`LspWorld`] with the given options.
|
||||
|
@ -124,15 +89,14 @@ impl LspWorldBuilder {
|
|||
entry: EntryState,
|
||||
font_resolver: SharedFontResolver,
|
||||
inputs: ImmutDict,
|
||||
) -> ZResult<LspWorld> {
|
||||
let mut res = CompilerWorld::new_raw(
|
||||
) -> ZResult<LspUniverse> {
|
||||
Ok(LspUniverse::new_raw(
|
||||
entry,
|
||||
Some(inputs),
|
||||
Vfs::new(SystemAccessModel {}),
|
||||
HttpRegistry::default(),
|
||||
font_resolver,
|
||||
);
|
||||
res.inputs = inputs;
|
||||
Ok(res)
|
||||
font_resolver.inner,
|
||||
))
|
||||
}
|
||||
|
||||
/// Resolve fonts from given options.
|
||||
|
|
|
@ -13,7 +13,7 @@ use ::await_tree::InstrumentAwait;
|
|||
use debug_loc::SpanInterner;
|
||||
use futures::SinkExt;
|
||||
use log::info;
|
||||
use serde::Deserialize;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use tokio::net::{TcpListener, TcpStream};
|
||||
use tokio_tungstenite::tungstenite::Message;
|
||||
use tokio_tungstenite::WebSocketStream;
|
||||
|
@ -22,7 +22,12 @@ use typst_ts_core::debug_loc::SourceSpanOffset;
|
|||
use typst_ts_core::Error;
|
||||
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::typst::TypstActor;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue