diff --git a/Cargo.toml b/Cargo.toml index 16e97e8d..b94cecc3 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -20,7 +20,7 @@ anyhow = "1" fxhash = "0.2.1" ecow = "0.2.0" -comemo = "0.3" +comemo = "0.4" ena = "0.14.2" futures = "0.3" regex = "1.8.1" @@ -36,8 +36,8 @@ thiserror = "1.0.44" typst = "0.10.0" typst-ide = "0.10.0" typst-pdf = "0.10.0" -typst-assets = { git = "https://github.com/typst/typst-assets", rev = "79e1c84" } -typst-ts-core = { git = "https://github.com/Myriad-Dreamin/typst.ts", rev = "98e3d3a42877b195f87223060882d55fd5aaa04a", package = "typst-ts-core" } +typst-assets = { git = "https://github.com/typst/typst-assets", rev = "4d1211a" } +typst-ts-core = { version = "0.4.2-rc6" } typst-ts-compiler = { version = "0.4.2-rc6" } typst-preview = { path = "external/typst-preview" } @@ -102,6 +102,6 @@ typst-syntax = { git = "https://github.com/Myriad-Dreamin/typst.git", branch = " # typst-pdf = { path = "../typst/crates/typst-pdf" } # typst-syntax = { path = "../typst/crates/typst-syntax" } -typst-ts-svg-exporter = { git = "https://github.com/Myriad-Dreamin/typst.ts", rev = "98e3d3a42877b195f87223060882d55fd5aaa04a", package = "typst-ts-svg-exporter" } -typst-ts-core = { git = "https://github.com/Myriad-Dreamin/typst.ts", rev = "98e3d3a42877b195f87223060882d55fd5aaa04a", package = "typst-ts-core" } -typst-ts-compiler = { git = "https://github.com/Myriad-Dreamin/typst.ts", rev = "98e3d3a42877b195f87223060882d55fd5aaa04a", package = "typst-ts-compiler" } +typst-ts-svg-exporter = { git = "https://github.com/Myriad-Dreamin/typst.ts", rev = "b44bc4c46c8ca50d3bc6003784afdbaa484e62bb", package = "typst-ts-svg-exporter" } +typst-ts-core = { git = "https://github.com/Myriad-Dreamin/typst.ts", rev = "b44bc4c46c8ca50d3bc6003784afdbaa484e62bb", package = "typst-ts-core" } +typst-ts-compiler = { git = "https://github.com/Myriad-Dreamin/typst.ts", rev = "b44bc4c46c8ca50d3bc6003784afdbaa484e62bb", package = "typst-ts-compiler" } diff --git a/crates/tinymist-query/src/analysis/definition.rs b/crates/tinymist-query/src/analysis/definition.rs index b1b75a9d..b7f781e4 100644 --- a/crates/tinymist-query/src/analysis/definition.rs +++ b/crates/tinymist-query/src/analysis/definition.rs @@ -89,7 +89,7 @@ fn advance_prev_adjacent(node: LinkedNode) -> Option { } } -#[comemo::memoize] +// #[comemo::memoize] fn find_definition_in_module<'a>( world: Tracked<'a, dyn World>, current: TypstFileId, @@ -239,7 +239,7 @@ fn find_syntax_definition<'a>( if name.get() == self.name { let values = analyze_expr(self.world.deref(), &node.find(name.span())?); - let func = values.into_iter().find_map(|v| match v { + let func = values.into_iter().find_map(|v| match v.0 { Value::Func(f) => Some(f), _ => None, }); @@ -261,6 +261,13 @@ fn find_syntax_definition<'a>( ))) => { return self.resolve_as_var(node.clone(), name); } + ast::LetBindingKind::Normal(ast::Pattern::Parenthesized(e)) => { + let e = deref_lvalue(node.find(e.span())?)?; + if let Some(name) = e.cast::() { + return self.resolve_as_var(e.clone(), name); + } + None + } ast::LetBindingKind::Normal(ast::Pattern::Normal(e)) => { let e = deref_lvalue(node.find(e.span())?)?; if let Some(name) = e.cast::() { @@ -269,7 +276,7 @@ fn find_syntax_definition<'a>( None } ast::LetBindingKind::Normal(ast::Pattern::Destructuring(n)) => { - for i in n.idents() { + for i in n.bindings() { if i.get() == self.name { return self.resolve_as_var(node.clone(), i); } @@ -395,8 +402,8 @@ pub(crate) fn find_definition<'a>( let values = analyze_expr(world.deref(), &use_site); - let func = values.into_iter().find_map(|v| match &v { - Value::Func(..) => Some(v), + let func = values.into_iter().find_map(|v| match &v.0 { + Value::Func(..) => Some(v.0), _ => None, }); diff --git a/crates/tinymist-query/src/analysis/lexical_hierarchy.rs b/crates/tinymist-query/src/analysis/lexical_hierarchy.rs index 2664091a..a7b64f97 100644 --- a/crates/tinymist-query/src/analysis/lexical_hierarchy.rs +++ b/crates/tinymist-query/src/analysis/lexical_hierarchy.rs @@ -183,7 +183,7 @@ pub(crate) fn get_lexical_hierarchy( }; let kind = match parent.kind() { SyntaxKind::Heading => LexicalKind::Namespace( - parent.cast::().unwrap().level().get() as i16, + parent.cast::().unwrap().depth().get() as i16, ), _ => return Ok(None), }; diff --git a/crates/tinymist-query/src/analysis/reference.rs b/crates/tinymist-query/src/analysis/reference.rs index 138a6b3c..b5a48067 100644 --- a/crates/tinymist-query/src/analysis/reference.rs +++ b/crates/tinymist-query/src/analysis/reference.rs @@ -43,7 +43,7 @@ impl<'a> Worker<'a> { match node.kind() { SyntaxKind::LetBinding => { let lb = node.cast::().unwrap(); - let name = lb.kind().idents(); + let name = lb.kind().bindings(); for n in name { if n.get() == self.target { return None; diff --git a/crates/tinymist-query/src/analysis/track_values.rs b/crates/tinymist-query/src/analysis/track_values.rs index d8e93639..c05fcb10 100644 --- a/crates/tinymist-query/src/analysis/track_values.rs +++ b/crates/tinymist-query/src/analysis/track_values.rs @@ -1,36 +1,34 @@ use comemo::Track; -use typst::diag::EcoString; use typst::engine::{Engine, Route}; use typst::eval::{Tracer, Vm}; -use typst::foundations::{Label, Scopes, Value}; +use typst::foundations::{Context, Label, Scopes, Styles, Value}; use typst::introspection::{Introspector, Locator}; use typst::model::{BibliographyElem, Document}; use typst::syntax::{ast, LinkedNode, Span, SyntaxKind}; use typst::World; -use typst_ts_core::typst::prelude::{eco_vec, EcoVec}; +use typst_ts_core::typst::prelude::*; /// Try to determine a set of possible values for an expression. -pub fn analyze_expr(world: &dyn World, node: &LinkedNode) -> EcoVec { - match node.cast::() { - Some(ast::Expr::None(_)) => eco_vec![Value::None], - Some(ast::Expr::Auto(_)) => eco_vec![Value::Auto], - Some(ast::Expr::Bool(v)) => eco_vec![Value::Bool(v.get())], - Some(ast::Expr::Int(v)) => eco_vec![Value::Int(v.get())], - Some(ast::Expr::Float(v)) => eco_vec![Value::Float(v.get())], - Some(ast::Expr::Numeric(v)) => eco_vec![Value::numeric(v.get())], - Some(ast::Expr::Str(v)) => eco_vec![Value::Str(v.get().into())], +pub fn analyze_expr(world: &dyn World, node: &LinkedNode) -> EcoVec<(Value, Option)> { + let Some(expr) = node.cast::() else { + return eco_vec![]; + }; - Some(ast::Expr::FieldAccess(access)) => { - let Some(child) = node.children().next() else { - return eco_vec![]; - }; - analyze_expr(world, &child) - .into_iter() - .filter_map(|target| target.field(&access.field()).ok()) - .collect() - } + let val = match expr { + ast::Expr::None(_) => Value::None, + ast::Expr::Auto(_) => Value::Auto, + ast::Expr::Bool(v) => Value::Bool(v.get()), + ast::Expr::Int(v) => Value::Int(v.get()), + ast::Expr::Float(v) => Value::Float(v.get()), + ast::Expr::Numeric(v) => Value::numeric(v.get()), + ast::Expr::Str(v) => Value::Str(v.get().into()), + _ => { + if node.kind() == SyntaxKind::Contextual { + if let Some(child) = node.children().last() { + return analyze_expr(world, &child); + } + } - Some(_) => { if let Some(parent) = node.parent() { if parent.kind() == SyntaxKind::FieldAccess && node.index() > 0 { return analyze_expr(world, parent); @@ -40,16 +38,16 @@ pub fn analyze_expr(world: &dyn World, node: &LinkedNode) -> EcoVec { let mut tracer = Tracer::new(); tracer.inspect(node.span()); typst::compile(world, &mut tracer).ok(); - tracer.values() + return tracer.values(); } + }; - _ => eco_vec![], - } + eco_vec![(val, None)] } /// Try to load a module from the current source file. pub fn analyze_import(world: &dyn World, source: &LinkedNode) -> Option { - let source = analyze_expr(world, source).into_iter().next()?; + let (source, _) = analyze_expr(world, source).into_iter().next()?; if source.scope().is_some() { return Some(source); } @@ -65,7 +63,13 @@ pub fn analyze_import(world: &dyn World, source: &LinkedNode) -> Option { tracer: tracer.track_mut(), }; - let mut vm = Vm::new(engine, Scopes::new(Some(world.library())), Span::detached()); + let context = Context::none(); + let mut vm = Vm::new( + engine, + &context, + Scopes::new(Some(world.library())), + Span::detached(), + ); typst::eval::import(&mut vm, source, Span::detached(), true) .ok() .map(Value::Module) diff --git a/crates/tinymist-query/src/fixtures/goto_definition/test@paren_lhs.typ.snap b/crates/tinymist-query/src/fixtures/goto_definition/test@paren_lhs.typ.snap index a33e24fd..423e714c 100644 --- a/crates/tinymist-query/src/fixtures/goto_definition/test@paren_lhs.typ.snap +++ b/crates/tinymist-query/src/fixtures/goto_definition/test@paren_lhs.typ.snap @@ -6,7 +6,7 @@ input_file: crates/tinymist-query/src/fixtures/goto_definition/paren_lhs.typ [ { "originSelectionRange": "1:23:1:24", - "targetRange": "0:2:0:13", - "targetSelectionRange": "0:2:0:13" + "targetRange": "0:7:0:8", + "targetSelectionRange": "0:7:0:8" } ] diff --git a/crates/tinymist-query/src/inlay_hint.rs b/crates/tinymist-query/src/inlay_hint.rs index d29b217c..28e01002 100644 --- a/crates/tinymist-query/src/inlay_hint.rs +++ b/crates/tinymist-query/src/inlay_hint.rs @@ -1,11 +1,11 @@ use std::{borrow::Cow, ops::Range}; -use comemo::Prehashed; use log::debug; use tower_lsp::lsp_types::{InlayHintKind, InlayHintLabel}; use typst::{ foundations::{Args, Closure}, syntax::SyntaxNode, + util::LazyHash, }; use typst_ts_core::typst::prelude::eco_vec; @@ -106,7 +106,7 @@ fn inlay_hints( // todo: reduce many such patterns let values = analyze_expr(self.world, &callee_node); - let func = values.into_iter().find_map(|v| match v { + let func = values.into_iter().find_map(|v| match v.0 { Value::Func(f) => Some(f), _ => None, })?; @@ -433,7 +433,7 @@ fn analyze_signature(func: Func) -> Arc { }) } -fn analyze_closure_signature(c: Arc>) -> Vec> { +fn analyze_closure_signature(c: Arc>) -> Vec> { let mut params = vec![]; trace!("closure signature for: {:?}", c.node.kind()); @@ -457,7 +457,7 @@ fn analyze_closure_signature(c: Arc>) -> Vec> } ast::Param::Pos(e) => { // todo: destructing - let name = e.idents(); + let name = e.bindings(); if name.len() != 1 { continue; } @@ -480,13 +480,14 @@ fn analyze_closure_signature(c: Arc>) -> Vec> variadic: false, })); } - ast::Param::Sink(s) => { + ast::Param::Spread(n) => { + let ident = n.sink_ident().map(|e| e.as_str()); params.push(Arc::new(ParamSpec { - name: Cow::Owned(s.name().unwrap_or_default().as_str().to_owned()), + name: Cow::Owned(ident.unwrap_or_default().to_owned()), default: None, positional: false, - named: false, - variadic: true, + named: true, + variadic: false, })); } } diff --git a/crates/tinymist-query/src/rename.rs b/crates/tinymist-query/src/rename.rs index 28ff6e98..929c640d 100644 --- a/crates/tinymist-query/src/rename.rs +++ b/crates/tinymist-query/src/rename.rs @@ -69,7 +69,7 @@ impl RenameRequest { ); let def_func = def_node.cast::()?; - let def_names = def_func.kind().idents(); + let def_names = def_func.kind().bindings(); if def_names.len() != 1 { return None; } diff --git a/crates/tinymist-query/src/signature_help.rs b/crates/tinymist-query/src/signature_help.rs index 8a4efc9b..44897acf 100644 --- a/crates/tinymist-query/src/signature_help.rs +++ b/crates/tinymist-query/src/signature_help.rs @@ -24,7 +24,7 @@ impl SignatureHelpRequest { let values = analyze_expr(world, &callee_node); - let function = values.into_iter().find_map(|v| match v { + let function = values.into_iter().find_map(|v| match v.0 { Value::Func(f) => Some(f), _ => None, })?; diff --git a/crates/tinymist/src/actor/render.rs b/crates/tinymist/src/actor/render.rs index ccf38437..e02ae706 100644 --- a/crates/tinymist/src/actor/render.rs +++ b/crates/tinymist/src/actor/render.rs @@ -11,6 +11,7 @@ use tokio::sync::{ broadcast::{self, error::RecvError}, watch, }; +use typst::foundations::Smart; use typst_ts_core::TypstDocument; use crate::ExportPdfMode; @@ -91,7 +92,7 @@ impl PdfExportActor { // todo: timestamp world.now() info!("exporting PDF {path}", path = path.display()); - let data = typst_pdf::pdf(doc, None, None); + let data = typst_pdf::pdf(doc, Smart::Auto, None); std::fs::write(path, data).context("failed to export PDF")?; diff --git a/crates/tinymist/src/actor/typst.rs b/crates/tinymist/src/actor/typst.rs index b36002b5..450f48d8 100644 --- a/crates/tinymist/src/actor/typst.rs +++ b/crates/tinymist/src/actor/typst.rs @@ -232,7 +232,10 @@ impl CompileClusterActor { pub async fn run(mut self) { loop { tokio::select! { - Some((group, diagnostics)) = self.diag_rx.recv() => { + e = self.diag_rx.recv() => { + let Some((group, diagnostics)) = e else { + break; + }; info!("received diagnostics from {}: diag({:?})", group, diagnostics.as_ref().map(|e| e.len())); let with_primary = (self.affect_map.len() <= 1 && self.affect_map.contains_key("primary")) && group == "primary"; self.publish(group, diagnostics, with_primary).await; @@ -245,6 +248,7 @@ impl CompileClusterActor { } } } + info!("compile cluster actor is stopped"); } } @@ -386,17 +390,15 @@ impl CompileCluster { async fn update_source(&self, files: FileChangeSet) -> Result<(), Error> { let primary = self.primary.clone(); let main = self.main.clone(); - tokio::spawn(async move { - let primary = Some(&primary); - let main = main.lock().await; - let main = main.as_ref(); - let clients_to_notify = (primary.iter()).chain(main.iter()); + let primary = Some(&primary); + let main = main.lock().await; + let main = main.as_ref(); + let clients_to_notify = (primary.iter()).chain(main.iter()); - for client in clients_to_notify { - let iw = client.wait().inner.lock().await; - iw.add_memory_changes(MemoryEvent::Update(files.clone())); - } - }); + for client in clients_to_notify { + let iw = client.wait().inner.lock().await; + iw.add_memory_changes(MemoryEvent::Update(files.clone())); + } Ok(()) } @@ -414,6 +416,7 @@ impl CompileCluster { ); let content: Bytes = content.as_bytes().into(); + log::info!("create source: {:?}", path); // todo: is it safe to believe that the path is normalized? let files = FileChangeSet::new_inserts(vec![(path, FileResult::Ok((now, content)).into())]); @@ -425,6 +428,7 @@ impl CompileCluster { let path: ImmutPath = path.into(); self.memory_changes.write().await.remove(&path); + log::info!("remove source: {:?}", path); // todo: is it safe to believe that the path is normalized? let files = FileChangeSet::new_removes(vec![path]); @@ -494,7 +498,9 @@ macro_rules! query_source { ($self:ident, $method:ident, $req:expr) => {{ let path: ImmutPath = $req.path.clone().into(); let vfs = $self.memory_changes.read().await; - let snapshot = vfs.get(&path).ok_or_else(|| anyhow!("file missing"))?; + let snapshot = vfs + .get(&path) + .ok_or_else(|| anyhow!("file missing {:?}", $self.memory_changes))?; let source = snapshot.content.clone(); let enc = $self.position_encoding;