diff --git a/crates/tinymist-query/src/analysis.rs b/crates/tinymist-query/src/analysis.rs index e3a33bb1..4f01f87a 100644 --- a/crates/tinymist-query/src/analysis.rs +++ b/crates/tinymist-query/src/analysis.rs @@ -97,6 +97,7 @@ mod post_type_check_tests { use insta::with_settings; use typst::syntax::LinkedNode; + use typst_shim::syntax::LinkedNodeExt; use crate::analysis::ty; use crate::tests::*; @@ -110,7 +111,7 @@ mod post_type_check_tests { .to_typst_pos(find_test_position(&source), &source) .unwrap(); let root = LinkedNode::new(source.root()); - let node = root.leaf_at(pos + 1).unwrap(); + let node = root.leaf_at_compat(pos + 1).unwrap(); let text = node.get().clone().into_text(); let result = ty::type_check(ctx, source.clone()); @@ -132,6 +133,7 @@ mod type_describe_tests { use insta::with_settings; use typst::syntax::LinkedNode; + use typst_shim::syntax::LinkedNodeExt; use crate::analysis::ty; use crate::tests::*; @@ -145,7 +147,7 @@ mod type_describe_tests { .to_typst_pos(find_test_position(&source), &source) .unwrap(); let root = LinkedNode::new(source.root()); - let node = root.leaf_at(pos + 1).unwrap(); + let node = root.leaf_at_compat(pos + 1).unwrap(); let text = node.get().clone().into_text(); let result = ty::type_check(ctx, source.clone()); @@ -220,6 +222,7 @@ mod module_tests { mod matcher_tests { use typst::syntax::LinkedNode; + use typst_shim::syntax::LinkedNodeExt; use crate::{syntax::get_def_target, tests::*}; @@ -233,7 +236,7 @@ mod matcher_tests { .unwrap(); let root = LinkedNode::new(source.root()); - let node = root.leaf_at(pos).unwrap(); + let node = root.leaf_at_compat(pos).unwrap(); let result = get_def_target(node).map(|e| format!("{:?}", e.node().range())); let result = result.as_deref().unwrap_or(""); @@ -382,6 +385,7 @@ mod signature_tests { use typst::foundations::Repr; use typst::syntax::LinkedNode; + use typst_shim::syntax::LinkedNodeExt; use crate::analysis::{analyze_signature, Signature, SignatureTarget}; use crate::syntax::get_deref_target; @@ -397,7 +401,7 @@ mod signature_tests { .unwrap(); let root = LinkedNode::new(source.root()); - let callee_node = root.leaf_at(pos).unwrap(); + let callee_node = root.leaf_at_compat(pos).unwrap(); let callee_node = get_deref_target(callee_node, pos).unwrap(); let callee_node = callee_node.node(); @@ -463,6 +467,7 @@ mod call_info_tests { use core::fmt; use typst::syntax::{LinkedNode, SyntaxKind}; + use typst_shim::syntax::LinkedNodeExt; use crate::analysis::analyze_call; use crate::tests::*; @@ -479,7 +484,7 @@ mod call_info_tests { .unwrap(); let root = LinkedNode::new(source.root()); - let mut call_node = root.leaf_at(pos + 1).unwrap(); + let mut call_node = root.leaf_at_compat(pos + 1).unwrap(); while let Some(parent) = call_node.parent() { if call_node.kind() == SyntaxKind::FuncCall { diff --git a/crates/tinymist-query/src/analysis/global.rs b/crates/tinymist-query/src/analysis/global.rs index effafcac..d69fe171 100644 --- a/crates/tinymist-query/src/analysis/global.rs +++ b/crates/tinymist-query/src/analysis/global.rs @@ -23,6 +23,7 @@ use typst::{ }; use typst::{foundations::Value, model::Document, syntax::ast, text::Font}; use typst::{layout::Position, syntax::FileId as TypstFileId}; +use typst_shim::syntax::LinkedNodeExt; use super::{ analyze_bib, analyze_expr_, analyze_import_, post_type_check, BibInfo, DefUseInfo, @@ -367,7 +368,7 @@ impl<'w> AnalysisContext<'w> { let offset = self.to_typst_pos(position, source)?; let cursor = ceil_char_boundary(source.text(), offset + shift); - let node = LinkedNode::new(source.root()).leaf_at(cursor)?; + let node = LinkedNode::new(source.root()).leaf_at_compat(cursor)?; Some((cursor, get_deref_target(node, cursor))) } diff --git a/crates/tinymist-query/src/analysis/import.rs b/crates/tinymist-query/src/analysis/import.rs index 8824599f..9ddae554 100644 --- a/crates/tinymist-query/src/analysis/import.rs +++ b/crates/tinymist-query/src/analysis/import.rs @@ -6,6 +6,7 @@ use typst::{ syntax::{LinkedNode, SyntaxKind}, World, }; +use typst_shim::syntax::LinkedNodeExt; use crate::{analysis::analyze_import_, syntax::resolve_id_by_path}; @@ -91,7 +92,7 @@ impl<'a, 'w> ImportCollector<'a, 'w> { LexicalKind::Mod(LexicalModKind::Module(p)) => { let id = match p { ModSrc::Expr(exp) => { - let exp = find_import_expr(self.root.leaf_at(exp.range.end)); + let exp = find_import_expr(self.root.leaf_at_compat(exp.range.end)); let val = exp .as_ref() .and_then(|exp| analyze_import_(self.ctx.deref(), exp)); diff --git a/crates/tinymist-query/src/analysis/linked_def.rs b/crates/tinymist-query/src/analysis/linked_def.rs index 4436a1e6..2bd0c315 100644 --- a/crates/tinymist-query/src/analysis/linked_def.rs +++ b/crates/tinymist-query/src/analysis/linked_def.rs @@ -8,6 +8,7 @@ use typst::foundations::{IntoValue, Label, Selector, Type}; use typst::model::BibliographyElem; use typst::syntax::FileId as TypstFileId; use typst::{foundations::Value, syntax::Span}; +use typst_shim::syntax::LinkedNodeExt; use super::{prelude::*, BibInfo}; use crate::{ @@ -208,7 +209,7 @@ pub fn find_definition( LexicalKind::Var(LexicalVarKind::Function) => { let def_source = ctx.source_by_id(def_fid).ok()?; let root = LinkedNode::new(def_source.root()); - let def_name = root.leaf_at(def.range.start + 1)?; + let def_name = root.leaf_at_compat(def.range.start + 1)?; log::info!("def_name for function: {def_name:?}", def_name = def_name); let values = ctx.analyze_expr(&def_name); let func = values.into_iter().find(|v| matches!(v.0, Value::Func(..))); diff --git a/crates/tinymist-query/src/analysis/signature.rs b/crates/tinymist-query/src/analysis/signature.rs index 96d14ee7..381de6e9 100644 --- a/crates/tinymist-query/src/analysis/signature.rs +++ b/crates/tinymist-query/src/analysis/signature.rs @@ -13,6 +13,7 @@ use typst::{ LinkedNode, Span, SyntaxKind, }, }; +use typst_shim::syntax::LinkedNodeExt; use typst_shim::utils::LazyHash; use crate::adt::interner::Interned; @@ -260,7 +261,7 @@ pub(crate) fn analyze_signature( // }; // let root = LinkedNode::new(def_source.root()); -// let def_node = root.leaf_at(def_at.1.start + 1)?; +// let def_node = root.leaf_at_compat(def_at.1.start + 1)?; // let def_node = get_def_target(def_node)?; // let def_node = match def_node { // DefTarget::Let(node) => node, @@ -304,7 +305,7 @@ fn resolve_callee_v2( let _t = ctx.type_check(source)?; let root = LinkedNode::new(def_source.root()); - let def_node = root.leaf_at(def_at.1.start + 1)?; + let def_node = root.leaf_at_compat(def_at.1.start + 1)?; let def_node = get_def_target(def_node)?; let _def_node = match def_node { DefTarget::Let(node) => node, diff --git a/crates/tinymist-query/src/code_action.rs b/crates/tinymist-query/src/code_action.rs index cad33f64..5ac82912 100644 --- a/crates/tinymist-query/src/code_action.rs +++ b/crates/tinymist-query/src/code_action.rs @@ -1,6 +1,7 @@ use lsp_types::TextEdit; use once_cell::sync::{Lazy, OnceCell}; use regex::Regex; +use typst_shim::syntax::LinkedNodeExt; use crate::{prelude::*, SemanticRequest}; @@ -269,7 +270,7 @@ impl<'a, 'w> CodeActionWorker<'a, 'w> { } fn work(&mut self, root: LinkedNode, cursor: usize) -> Option<()> { - let node = root.leaf_at(cursor)?; + let node = root.leaf_at_compat(cursor)?; let mut node = &node; let mut heading_resolved = false; diff --git a/crates/tinymist-query/src/code_context.rs b/crates/tinymist-query/src/code_context.rs index 6adc705f..2c58989d 100644 --- a/crates/tinymist-query/src/code_context.rs +++ b/crates/tinymist-query/src/code_context.rs @@ -1,4 +1,5 @@ use serde::{Deserialize, Serialize}; +use typst_shim::syntax::LinkedNodeExt; use crate::{ prelude::*, @@ -75,7 +76,7 @@ impl InteractCodeContextRequest { // Get mode let root = LinkedNode::new(source.root()); - let leaf = root.leaf_at(pos); + let leaf = root.leaf_at_compat(pos); let mut leaf = leaf.as_ref(); Some(loop { log::debug!("leaf for context: {leaf:?}"); diff --git a/crates/tinymist-query/src/document_highlight.rs b/crates/tinymist-query/src/document_highlight.rs index 80f23198..22eb2c97 100644 --- a/crates/tinymist-query/src/document_highlight.rs +++ b/crates/tinymist-query/src/document_highlight.rs @@ -1,3 +1,5 @@ +use typst_shim::syntax::LinkedNodeExt; + use crate::{prelude::*, SemanticRequest}; /// The [`textDocument/documentHighlight`] request @@ -19,7 +21,7 @@ impl SemanticRequest for DocumentHighlightRequest { let cursor = ctx.to_typst_pos(self.position, &source)?; let root = LinkedNode::new(source.root()); - let mut node = &root.leaf_at(cursor)?; + let mut node = &root.leaf_at_compat(cursor)?; loop { match node.kind() { diff --git a/crates/tinymist-query/src/hover.rs b/crates/tinymist-query/src/hover.rs index b8dcffb7..6c8d1f56 100644 --- a/crates/tinymist-query/src/hover.rs +++ b/crates/tinymist-query/src/hover.rs @@ -1,5 +1,7 @@ use core::fmt; +use typst_shim::syntax::LinkedNodeExt; + use crate::{ analysis::{analyze_dyn_signature, find_definition, DefinitionLink, Signature}, jump_from_cursor, @@ -48,7 +50,7 @@ impl StatefulRequest for HoverRequest { )) })?; - let ast_node = LinkedNode::new(source.root()).leaf_at(cursor)?; + let ast_node = LinkedNode::new(source.root()).leaf_at_compat(cursor)?; let range = ctx.to_lsp_range(ast_node.range(), &source); // Neovim shows ugly hover if the hover content is in array, so we join them @@ -120,7 +122,7 @@ fn star_tooltip( source: &Source, cursor: usize, ) -> Option { - let leaf = LinkedNode::new(source.root()).leaf_at(cursor)?; + let leaf = LinkedNode::new(source.root()).leaf_at_compat(cursor)?; if !matches!(leaf.kind(), SyntaxKind::Star) { return None; @@ -174,7 +176,7 @@ fn def_tooltip( document: Option<&VersionedDocument>, cursor: usize, ) -> Option { - let leaf = LinkedNode::new(source.root()).leaf_at(cursor)?; + let leaf = LinkedNode::new(source.root()).leaf_at_compat(cursor)?; let deref_target = get_deref_target(leaf.clone(), cursor)?; diff --git a/crates/tinymist-query/src/jump.rs b/crates/tinymist-query/src/jump.rs index 516dc1c2..5695dee9 100644 --- a/crates/tinymist-query/src/jump.rs +++ b/crates/tinymist-query/src/jump.rs @@ -9,10 +9,11 @@ use typst::{ layout::{Frame, FrameItem, Point, Position}, syntax::{LinkedNode, Source, Span, SyntaxKind}, }; +use typst_shim::syntax::LinkedNodeExt; /// Find the output location in the document for a cursor position. pub fn jump_from_cursor(document: &Document, source: &Source, cursor: usize) -> Option { - let node = LinkedNode::new(source.root()).leaf_at(cursor)?; + let node = LinkedNode::new(source.root()).leaf_at_compat(cursor)?; if node.kind() != SyntaxKind::Text { return None; } diff --git a/crates/tinymist-query/src/on_enter.rs b/crates/tinymist-query/src/on_enter.rs index 408326f5..04f9d2db 100644 --- a/crates/tinymist-query/src/on_enter.rs +++ b/crates/tinymist-query/src/on_enter.rs @@ -1,5 +1,7 @@ //! +use typst_shim::syntax::LinkedNodeExt; + use crate::{prelude::*, SyntaxRequest}; /// The [`experimental/onEnter`] request is sent from client to server to handle @@ -32,7 +34,7 @@ impl SyntaxRequest for OnEnterRequest { ) -> Option { let root = LinkedNode::new(source.root()); let cursor = lsp_to_typst::position(self.position, position_encoding, source)?; - let leaf = root.leaf_at(cursor)?; + let leaf = root.leaf_at_compat(cursor)?; let worker = OnEnterWorker { source, diff --git a/crates/tinymist-query/src/selection_range.rs b/crates/tinymist-query/src/selection_range.rs index 3bb00d63..a1f9c1ac 100644 --- a/crates/tinymist-query/src/selection_range.rs +++ b/crates/tinymist-query/src/selection_range.rs @@ -1,3 +1,5 @@ +use typst_shim::syntax::LinkedNodeExt; + use crate::{prelude::*, SyntaxRequest}; /// The [`textDocument/selectionRange`] request is sent from the client to the @@ -34,7 +36,7 @@ impl SyntaxRequest for SelectionRangeRequest { for position in self.positions { let typst_offset = lsp_to_typst::position(position, position_encoding, source)?; let tree = LinkedNode::new(source.root()); - let leaf = tree.leaf_at(typst_offset + 1)?; + let leaf = tree.leaf_at_compat(typst_offset + 1)?; ranges.push(range_for_node(source, position_encoding, &leaf)); } diff --git a/crates/tinymist-query/src/signature_help.rs b/crates/tinymist-query/src/signature_help.rs index 7c45c6b4..3e12a699 100644 --- a/crates/tinymist-query/src/signature_help.rs +++ b/crates/tinymist-query/src/signature_help.rs @@ -1,4 +1,5 @@ use once_cell::sync::OnceCell; +use typst_shim::syntax::LinkedNodeExt; use crate::{ adt::interner::Interned, @@ -27,7 +28,7 @@ impl SemanticRequest for SignatureHelpRequest { let source = ctx.source_by_path(&self.path).ok()?; let cursor = ctx.to_typst_pos(self.position, &source)? + 1; - let ast_node = LinkedNode::new(source.root()).leaf_at(cursor)?; + let ast_node = LinkedNode::new(source.root()).leaf_at_compat(cursor)?; let CheckTarget::Param { callee, target, diff --git a/crates/tinymist-query/src/syntax/comment.rs b/crates/tinymist-query/src/syntax/comment.rs index 64d0328a..1c7da769 100644 --- a/crates/tinymist-query/src/syntax/comment.rs +++ b/crates/tinymist-query/src/syntax/comment.rs @@ -1,5 +1,7 @@ use std::ops::Range; +use typst_shim::syntax::LinkedNodeExt; + use crate::prelude::*; use crate::syntax::get_def_target; @@ -89,7 +91,7 @@ pub fn find_docs_before(src: &Source, cursor: usize) -> Option { log::debug!("finding docs at: {id:?}, {cursor}", id = src.id()); let root = LinkedNode::new(src.root()); - let leaf = root.leaf_at(cursor)?; + let leaf = root.leaf_at_compat(cursor)?; let def_target = get_def_target(leaf.clone())?; log::debug!("found docs target: {:?}", def_target.node().kind()); // todo: import node diff --git a/crates/tinymist-query/src/syntax/matcher.rs b/crates/tinymist-query/src/syntax/matcher.rs index b251edc6..c0a1c95f 100644 --- a/crates/tinymist-query/src/syntax/matcher.rs +++ b/crates/tinymist-query/src/syntax/matcher.rs @@ -590,6 +590,7 @@ mod tests { use super::*; use insta::assert_snapshot; use typst::syntax::{is_newline, Source}; + use typst_shim::syntax::LinkedNodeExt; fn map_base(source: &str, mapper: impl Fn(&LinkedNode, usize) -> char) -> String { let source = Source::detached(source.to_owned()); @@ -617,7 +618,7 @@ mod tests { fn map_deref(source: &str) -> String { map_base(source, |root, cursor| { - let node = root.leaf_at(cursor); + let node = root.leaf_at_compat(cursor); let kind = node.and_then(|node| get_deref_target(node, cursor)); match kind { Some(DerefTarget::VarAccess(..)) => 'v', @@ -634,7 +635,7 @@ mod tests { fn map_check(source: &str) -> String { map_base(source, |root, cursor| { - let node = root.leaf_at(cursor); + let node = root.leaf_at_compat(cursor); let kind = node.and_then(|node| get_check_target(node)); match kind { Some(CheckTarget::Param { .. }) => 'p', diff --git a/crates/tinymist-query/src/tests.rs b/crates/tinymist-query/src/tests.rs index 6414d73a..0d5c5d71 100644 --- a/crates/tinymist-query/src/tests.rs +++ b/crates/tinymist-query/src/tests.rs @@ -24,6 +24,7 @@ pub use insta::assert_snapshot; pub use reflexo_typst::TypstSystemWorld; pub use serde::Serialize; pub use serde_json::json; +use typst_shim::syntax::LinkedNodeExt; use crate::{ analysis::{Analysis, AnalysisResources}, @@ -245,7 +246,7 @@ pub fn find_test_position_(s: &Source, offset: usize) -> LspPosition { .unwrap(); let n = LinkedNode::new(s.root()); - let mut n = n.leaf_at(re + 1).unwrap(); + let mut n = n.leaf_at_compat(re + 1).unwrap(); let match_prev = match &m { MatchAny { prev } => *prev, diff --git a/crates/tinymist-query/src/upstream/complete.rs b/crates/tinymist-query/src/upstream/complete.rs index 20bc76d6..2be5c397 100644 --- a/crates/tinymist-query/src/upstream/complete.rs +++ b/crates/tinymist-query/src/upstream/complete.rs @@ -11,6 +11,7 @@ use typst::syntax::ast::AstNode; use typst::syntax::package::PackageSpec; use typst::syntax::{ast, is_id_continue, is_id_start, is_ident, LinkedNode, Source, SyntaxKind}; use typst::text::RawElem; +use typst_shim::syntax::LinkedNodeExt; use unscanny::Scanner; use super::{plain_docs_sentence, summarize_font_family}; @@ -969,7 +970,7 @@ impl<'a, 'w> CompletionContext<'a, 'w> { ) -> Option { let text = source.text(); let root = LinkedNode::new(source.root()); - let leaf = root.leaf_at(cursor)?; + let leaf = root.leaf_at_compat(cursor)?; Some(Self { ctx, document, diff --git a/crates/tinymist-query/src/upstream/tooltip.rs b/crates/tinymist-query/src/upstream/tooltip.rs index d7424a0b..2006f51d 100644 --- a/crates/tinymist-query/src/upstream/tooltip.rs +++ b/crates/tinymist-query/src/upstream/tooltip.rs @@ -8,6 +8,7 @@ use typst::layout::Length; use typst::model::Document; use typst::syntax::{ast, LinkedNode, Source, SyntaxKind}; use typst::World; +use typst_shim::syntax::LinkedNodeExt; use typst_shim::utils::{round_2, Numeric}; use super::{plain_docs_sentence, summarize_font_family, truncated_repr}; @@ -24,7 +25,7 @@ pub fn tooltip_( source: &Source, cursor: usize, ) -> Option { - let leaf = LinkedNode::new(source.root()).leaf_at(cursor)?; + let leaf = LinkedNode::new(source.root()).leaf_at_compat(cursor)?; if leaf.kind().is_trivia() { return None; } diff --git a/crates/tinymist/src/tool/preview.rs b/crates/tinymist/src/tool/preview.rs index 3a29030a..8381b8aa 100644 --- a/crates/tinymist/src/tool/preview.rs +++ b/crates/tinymist/src/tool/preview.rs @@ -27,6 +27,7 @@ use typst_preview::{ ControlPlaneTx, DocToSrcJumpInfo, EditorServer, Location, MemoryFiles, MemoryFilesShort, PreviewArgs, PreviewBuilder, PreviewMode, Previewer, SourceFileServer, WsMessage, }; +use typst_shim::syntax::LinkedNodeExt; use crate::world::{LspCompilerFeat, LspWorld}; use crate::*; @@ -47,7 +48,7 @@ impl CompileHandler { let source = world.source(source_id).ok()?; let cursor = source.line_column_to_byte(loc.pos.line, loc.pos.column)?; - let node = LinkedNode::new(source.root()).leaf_at(cursor)?; + let node = LinkedNode::new(source.root()).leaf_at_compat(cursor)?; if node.kind() != SyntaxKind::Text { return None; } @@ -676,7 +677,7 @@ impl Notification for NotifDocumentOutline { /// Find the output location in the document for a cursor position. fn jump_from_cursor(document: &TypstDocument, source: &Source, cursor: usize) -> Option { - let node = LinkedNode::new(source.root()).leaf_at(cursor)?; + let node = LinkedNode::new(source.root()).leaf_at_compat(cursor)?; if node.kind() != SyntaxKind::Text { return None; } diff --git a/crates/typst-shim/src/nightly/mod.rs b/crates/typst-shim/src/nightly/mod.rs index b5614dd8..970ea68b 100644 --- a/crates/typst-shim/src/nightly/mod.rs +++ b/crates/typst-shim/src/nightly/mod.rs @@ -1 +1,2 @@ +pub mod syntax; pub mod utils; diff --git a/crates/typst-shim/src/nightly/syntax.rs b/crates/typst-shim/src/nightly/syntax.rs new file mode 100644 index 00000000..f125286d --- /dev/null +++ b/crates/typst-shim/src/nightly/syntax.rs @@ -0,0 +1,14 @@ +//! Typst Syntax +use typst::syntax::LinkedNode; +use typst::syntax::Side; + +/// The `LinkedNodeExt` trait is designed for compatibility between new and old versions of `typst`. +pub trait LinkedNodeExt: Sized { + fn leaf_at_compat(&self, cursor: usize) -> Option; +} + +impl LinkedNodeExt for LinkedNode { + fn leaf_at_compat(&self, cursor: usize) -> Option { + self.leaf_at(cursor, Side::Before) + } +} diff --git a/crates/typst-shim/src/stable/mod.rs b/crates/typst-shim/src/stable/mod.rs index b5614dd8..970ea68b 100644 --- a/crates/typst-shim/src/stable/mod.rs +++ b/crates/typst-shim/src/stable/mod.rs @@ -1 +1,2 @@ +pub mod syntax; pub mod utils; diff --git a/crates/typst-shim/src/stable/syntax.rs b/crates/typst-shim/src/stable/syntax.rs new file mode 100644 index 00000000..7e0c8bca --- /dev/null +++ b/crates/typst-shim/src/stable/syntax.rs @@ -0,0 +1,14 @@ +//! Typst Syntax +use typst_syntax::LinkedNode; + +/// The `LinkedNodeExt` trait is designed for compatibility between new and old versions of `typst`. +pub trait LinkedNodeExt: Sized { + /// Get the leaf at the specified byte offset. + fn leaf_at_compat(&self, cursor: usize) -> Option; +} + +impl<'a> LinkedNodeExt for LinkedNode<'a> { + fn leaf_at_compat(&self, cursor: usize) -> Option { + self.leaf_at(cursor) + } +}