From 2fe992e9335acb474b0e06e2f4de0f7cb9fe334d Mon Sep 17 00:00:00 2001 From: Myriad-Dreamin <35292584+Myriad-Dreamin@users.noreply.github.com> Date: Mon, 18 Mar 2024 17:36:43 +0800 Subject: [PATCH] dev: convert all syntax-level request and check main state before requesting (#67) --- crates/tinymist-query/src/code_lens.rs | 16 +++--- crates/tinymist-query/src/goto_declaration.rs | 28 +++++----- crates/tinymist-query/src/inlay_hint.rs | 24 ++++----- crates/tinymist-query/src/signature_help.rs | 18 +++---- crates/tinymist-query/src/symbol.rs | 23 ++++---- crates/tinymist/src/actor/typst.rs | 54 +++++++++---------- 6 files changed, 78 insertions(+), 85 deletions(-) diff --git a/crates/tinymist-query/src/code_lens.rs b/crates/tinymist-query/src/code_lens.rs index 8d308c43..0e487e53 100644 --- a/crates/tinymist-query/src/code_lens.rs +++ b/crates/tinymist-query/src/code_lens.rs @@ -1,6 +1,6 @@ use lsp_types::Command; -use crate::prelude::*; +use crate::{prelude::*, SyntaxRequest}; /// The [`textDocument/codeLens`] request is sent from the client to the server /// to compute code lenses for a given text document. @@ -12,15 +12,13 @@ pub struct CodeLensRequest { pub path: PathBuf, } -impl CodeLensRequest { - pub fn request( - self, - world: &TypstSystemWorld, - position_encoding: PositionEncoding, - ) -> Option> { - let source = get_suitable_source_in_workspace(world, &self.path).ok()?; +impl SyntaxRequest for CodeLensRequest { + type Response = Vec; - let doc_start = typst_to_lsp::range(0..0, &source, position_encoding); + fn request(self, ctx: &mut AnalysisContext) -> Option { + let source = ctx.source_by_path(&self.path).ok()?; + + let doc_start = ctx.to_lsp_range(0..0, &source); let mut res = vec![]; diff --git a/crates/tinymist-query/src/goto_declaration.rs b/crates/tinymist-query/src/goto_declaration.rs index 9a087c09..8be4ad7f 100644 --- a/crates/tinymist-query/src/goto_declaration.rs +++ b/crates/tinymist-query/src/goto_declaration.rs @@ -6,6 +6,7 @@ use lsp_types::LocationLink; use crate::{ prelude::*, syntax::{get_deref_target, DerefTarget}, + SyntaxRequest, }; #[derive(Debug, Clone)] @@ -14,36 +15,31 @@ pub struct GotoDeclarationRequest { pub position: LspPosition, } -impl GotoDeclarationRequest { - pub fn request( - self, - world: &TypstSystemWorld, - position_encoding: PositionEncoding, - ) -> Option { - let mut ctx = AnalysisContext::new(world, position_encoding); - let source = get_suitable_source_in_workspace(world, &self.path).ok()?; - let offset = lsp_to_typst::position(self.position, position_encoding, &source)?; +impl SyntaxRequest for GotoDeclarationRequest { + type Response = GotoDeclarationResponse; + + fn request(self, ctx: &mut AnalysisContext) -> Option { + let source = ctx.source_by_path(&self.path).ok()?; + let offset = ctx.to_typst_pos(self.position, &source)?; let cursor = offset + 1; - let w: &dyn World = world; let ast_node = LinkedNode::new(source.root()).leaf_at(cursor)?; debug!("ast_node: {ast_node:?}", ast_node = ast_node); let deref_target = get_deref_target(ast_node)?; let use_site = deref_target.node(); - let origin_selection_range = - typst_to_lsp::range(use_site.range(), &source, position_encoding); + let origin_selection_range = ctx.to_lsp_range(use_site.range(), &source); let def_use = ctx.def_use(source.clone())?; - let ref_spans = find_declarations(w, def_use, deref_target)?; + let ref_spans = find_declarations(ctx, def_use, deref_target)?; let mut links = vec![]; for ref_range in ref_spans { let ref_id = source.id(); let ref_source = &source; - let span_path = world.path_for_id(ref_id).ok()?; - let range = typst_to_lsp::range(ref_range, ref_source, position_encoding); + let span_path = ctx.world.path_for_id(ref_id).ok()?; + let range = ctx.to_lsp_range(ref_range, ref_source); let uri = Url::from_file_path(span_path).ok()?; @@ -61,7 +57,7 @@ impl GotoDeclarationRequest { } fn find_declarations( - _w: &dyn World, + _ctx: &AnalysisContext, _def_use: Arc, _deref_target: DerefTarget<'_>, ) -> Option>> { diff --git a/crates/tinymist-query/src/inlay_hint.rs b/crates/tinymist-query/src/inlay_hint.rs index 019a5c51..9892c161 100644 --- a/crates/tinymist-query/src/inlay_hint.rs +++ b/crates/tinymist-query/src/inlay_hint.rs @@ -9,7 +9,7 @@ use typst::{ }; use typst_ts_core::typst::prelude::eco_vec; -use crate::prelude::*; +use crate::{prelude::*, SyntaxRequest}; pub struct InlayHintConfig { // positional arguments group @@ -45,16 +45,14 @@ pub struct InlayHintRequest { pub range: LspRange, } -impl InlayHintRequest { - pub fn request( - self, - world: &TypstSystemWorld, - position_encoding: PositionEncoding, - ) -> Option> { - let source = get_suitable_source_in_workspace(world, &self.path).ok()?; - let range = lsp_to_typst::range(self.range, position_encoding, &source)?; +impl SyntaxRequest for InlayHintRequest { + type Response = Vec; - let hints = inlay_hint(world, &source, range, position_encoding).ok()?; + fn request(self, ctx: &mut AnalysisContext) -> Option { + let source = ctx.source_by_path(&self.path).ok()?; + let range = ctx.to_typst_range(self.range, &source)?; + + let hints = inlay_hint(ctx.world, &source, range, ctx.position_encoding()).ok()?; debug!( "got inlay hints on {source:?} => {hints:?}", source = source.id(), @@ -663,8 +661,8 @@ mod tests { #[test] fn smart() { - snapshot_testing("inlay_hints", &|world, path| { - let source = get_suitable_source_in_workspace(world, &path).unwrap(); + snapshot_testing2("inlay_hints", &|ctx, path| { + let source = ctx.source_by_path(&path).unwrap(); let request = InlayHintRequest { path: path.clone(), @@ -675,7 +673,7 @@ mod tests { ), }; - let result = request.request(world, PositionEncoding::Utf16); + let result = request.request(ctx); assert_snapshot!(JsonRepr::new_redacted(result, &REDACT_LOC)); }); } diff --git a/crates/tinymist-query/src/signature_help.rs b/crates/tinymist-query/src/signature_help.rs index 44897acf..9c057248 100644 --- a/crates/tinymist-query/src/signature_help.rs +++ b/crates/tinymist-query/src/signature_help.rs @@ -1,4 +1,4 @@ -use crate::prelude::*; +use crate::{prelude::*, SyntaxRequest}; #[derive(Debug, Clone)] pub struct SignatureHelpRequest { @@ -6,14 +6,12 @@ pub struct SignatureHelpRequest { pub position: LspPosition, } -impl SignatureHelpRequest { - pub fn request( - self, - world: &TypstSystemWorld, - position_encoding: PositionEncoding, - ) -> Option { - let source = get_suitable_source_in_workspace(world, &self.path).ok()?; - let typst_offset = lsp_to_typst::position(self.position, position_encoding, &source)?; +impl SyntaxRequest for SignatureHelpRequest { + type Response = SignatureHelp; + + fn request(self, ctx: &mut AnalysisContext) -> Option { + let source = ctx.source_by_path(&self.path).ok()?; + let typst_offset = ctx.to_typst_pos(self.position, &source)?; let ast_node = LinkedNode::new(source.root()).leaf_at(typst_offset + 1)?; let (callee, callee_node, args) = surrounding_function_syntax(&ast_node)?; @@ -22,7 +20,7 @@ impl SignatureHelpRequest { return None; } - let values = analyze_expr(world, &callee_node); + let values = analyze_expr(ctx.world, &callee_node); let function = values.into_iter().find_map(|v| match v.0 { Value::Func(f) => Some(f), diff --git a/crates/tinymist-query/src/symbol.rs b/crates/tinymist-query/src/symbol.rs index 75245672..2913c39f 100644 --- a/crates/tinymist-query/src/symbol.rs +++ b/crates/tinymist-query/src/symbol.rs @@ -3,6 +3,7 @@ use typst_ts_compiler::NotifyApi; use crate::{ prelude::*, syntax::{get_lexical_hierarchy, LexicalHierarchy, LexicalScopeKind}, + SyntaxRequest, }; #[derive(Debug, Clone)] @@ -10,25 +11,29 @@ pub struct SymbolRequest { pub pattern: Option, } -impl SymbolRequest { - pub fn request( - self, - world: &TypstSystemWorld, - position_encoding: PositionEncoding, - ) -> Option> { +impl SyntaxRequest for SymbolRequest { + type Response = Vec; + + fn request(self, ctx: &mut AnalysisContext) -> Option { // todo: expose source let mut symbols = vec![]; - world.iter_dependencies(&mut |path, _| { - let Ok(source) = get_suitable_source_in_workspace(world, path) else { + ctx.world.iter_dependencies(&mut |path, _| { + let Ok(source) = ctx.source_by_path(path) else { return; }; let uri = Url::from_file_path(path).unwrap(); let res = get_lexical_hierarchy(source.clone(), LexicalScopeKind::Symbol).and_then( |symbols| { self.pattern.as_ref().map(|pattern| { - filter_document_symbols(&symbols, pattern, &source, &uri, position_encoding) + filter_document_symbols( + &symbols, + pattern, + &source, + &uri, + ctx.position_encoding(), + ) }) }, ); diff --git a/crates/tinymist/src/actor/typst.rs b/crates/tinymist/src/actor/typst.rs index 6a3e23e7..bd3acf20 100644 --- a/crates/tinymist/src/actor/typst.rs +++ b/crates/tinymist/src/actor/typst.rs @@ -6,6 +6,7 @@ use std::{ sync::Arc, }; +use anyhow::anyhow; use log::{debug, error, info, trace, warn}; use once_cell::sync::OnceCell; use parking_lot::Mutex; @@ -25,7 +26,7 @@ use typst_preview::{CompilationHandle, CompilationHandleImpl, CompileStatus}; use typst_ts_compiler::{ service::{ CompileDriver as CompileDriverInner, CompileExporter, CompileMiddleware, Compiler, - WorkspaceProvider, WorldExporter, + EnvWorld, WorkspaceProvider, WorldExporter, }, vfs::notify::{FileChangeSet, MemoryEvent}, TypstSystemWorld, @@ -211,15 +212,7 @@ macro_rules! query_state { macro_rules! query_world { ($self:ident, $method:ident, $req:expr) => {{ - let enc = $self.position_encoding; - let res = $self.steal_world(move |w| $req.request(w, enc)); - res.map(CompilerQueryResponse::$method) - }}; -} - -macro_rules! query_world2 { - ($self:ident, $method:ident, $req:expr) => {{ - let res = $self.steal_world2(move |w| $req.request(w)); + let res = $self.steal_world(move |w| $req.request(w)); res.map(CompilerQueryResponse::$method) }}; } @@ -626,15 +619,15 @@ impl CompileActor { Ok(CompilerQueryResponse::OnSaveExport(())) } Hover(req) => query_state!(self, Hover, req), - GotoDefinition(req) => query_world2!(self, GotoDefinition, req), + GotoDefinition(req) => query_world!(self, GotoDefinition, req), GotoDeclaration(req) => query_world!(self, GotoDeclaration, req), - References(req) => query_world2!(self, References, req), + References(req) => query_world!(self, References, req), InlayHint(req) => query_world!(self, InlayHint, req), CodeLens(req) => query_world!(self, CodeLens, req), Completion(req) => query_state!(self, Completion, req), SignatureHelp(req) => query_world!(self, SignatureHelp, req), - Rename(req) => query_world2!(self, Rename, req), - PrepareRename(req) => query_world2!(self, PrepareRename, req), + Rename(req) => query_world!(self, Rename, req), + PrepareRename(req) => query_world!(self, PrepareRename, req), Symbol(req) => query_world!(self, Symbol, req), FoldingRange(..) | SelectionRange(..) @@ -679,25 +672,30 @@ impl CompileActor { } fn steal_world( - &self, - f: impl FnOnce(&TypstSystemWorld) -> T + Send + Sync + 'static, - ) -> anyhow::Result { - let fut = self.steal(move |compiler| f(compiler.compiler.world())); - - Ok(fut?) - } - - fn steal_world2( &self, f: impl FnOnce(&mut AnalysisContext) -> T + Send + Sync + 'static, ) -> anyhow::Result { let enc = self.position_encoding; - let fut = self.steal(move |compiler| { - // todo: record analysis - f(&mut AnalysisContext::new(compiler.compiler.world(), enc)) - }); - Ok(fut?) + self.steal(move |compiler| { + // todo: record analysis + let w = compiler.compiler.world_mut(); + + let Some(main) = w.main else { + log::error!("TypstActor: main file is not set"); + return Err(anyhow!("main file is not set")); + }; + w.source(main).map_err(|err| { + log::info!("TypstActor: failed to prepare main file: {:?}", err); + anyhow!("failed to get source: {err}") + })?; + w.prepare_env(&mut Default::default()).map_err(|err| { + log::error!("TypstActor: failed to prepare env: {:?}", err); + anyhow!("failed to prepare env") + })?; + + Ok(f(&mut AnalysisContext::new(compiler.compiler.world(), enc))) + })? } }