mirror of
https://github.com/Myriad-Dreamin/tinymist.git
synced 2025-11-23 12:46:43 +00:00
feat: support query of cross-module references (#42)
* feat: support cross-module references by wild-card import * feat: support cross-module references by ident import * feat: support cross-module references by alias import * docs: update readme * dev: remove two debug printing
This commit is contained in:
parent
fe25933d0e
commit
5fa4f8f94f
19 changed files with 360 additions and 136 deletions
|
|
@ -1,5 +1,3 @@
|
|||
use std::ops::Range;
|
||||
|
||||
use log::debug;
|
||||
|
||||
use crate::{
|
||||
|
|
@ -16,47 +14,31 @@ pub struct ReferencesRequest {
|
|||
impl ReferencesRequest {
|
||||
pub fn request(
|
||||
self,
|
||||
ctx: &TypstSystemWorld,
|
||||
ctx: &mut AnalysisContext,
|
||||
position_encoding: PositionEncoding,
|
||||
) -> Option<Vec<LspLocation>> {
|
||||
let mut ctx = AnalysisContext::new(ctx);
|
||||
|
||||
let world = ctx.world;
|
||||
let source = ctx.source_by_path(&self.path).ok()?;
|
||||
let offset = lsp_to_typst::position(self.position, position_encoding, &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 def_use = get_def_use(&mut ctx, source.clone())?;
|
||||
let ref_spans = find_declarations(w, def_use, deref_target)?;
|
||||
|
||||
let mut locations = 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 uri = Url::from_file_path(span_path).ok()?;
|
||||
|
||||
locations.push(LspLocation { uri, range });
|
||||
}
|
||||
let def_use = get_def_use(ctx, source.clone())?;
|
||||
let locations = find_references(ctx, def_use, deref_target, position_encoding)?;
|
||||
|
||||
debug!("references: {locations:?}");
|
||||
Some(locations)
|
||||
}
|
||||
}
|
||||
|
||||
fn find_declarations(
|
||||
_w: &dyn World,
|
||||
fn find_references(
|
||||
ctx: &mut AnalysisContext<'_>,
|
||||
def_use: Arc<crate::analysis::DefUseInfo>,
|
||||
deref_target: DerefTarget<'_>,
|
||||
) -> Option<Vec<Range<usize>>> {
|
||||
position_encoding: PositionEncoding,
|
||||
) -> Option<Vec<LspLocation>> {
|
||||
let node = match deref_target {
|
||||
DerefTarget::VarAccess(node) => node,
|
||||
DerefTarget::Callee(node) => node,
|
||||
|
|
@ -91,17 +73,74 @@ fn find_declarations(
|
|||
|
||||
// todo: if it is exported, find all the references in the workspace
|
||||
let ident_ref = IdentRef {
|
||||
name,
|
||||
name: name.clone(),
|
||||
range: ident.range(),
|
||||
};
|
||||
let def_fid = ident.span().id()?;
|
||||
|
||||
let (id, _) = def_use.get_def(ident.span().id()?, &ident_ref)?;
|
||||
Some(
|
||||
def_use
|
||||
.get_refs(id)
|
||||
.map(|r| r.range.clone())
|
||||
.collect::<Vec<_>>(),
|
||||
)
|
||||
let (id, _) = def_use.get_def(def_fid, &ident_ref)?;
|
||||
let def_source = ctx.source_by_id(def_fid).ok()?;
|
||||
|
||||
let def_path = ctx.world.path_for_id(def_fid).ok()?;
|
||||
let uri = Url::from_file_path(def_path).ok()?;
|
||||
|
||||
// todo: reuse uri, range to location
|
||||
let mut references = def_use
|
||||
.get_refs(id)
|
||||
.map(|r| {
|
||||
let range = typst_to_lsp::range(r.range.clone(), &def_source, position_encoding);
|
||||
|
||||
LspLocation {
|
||||
uri: uri.clone(),
|
||||
range,
|
||||
}
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
if def_use.is_exported(id) {
|
||||
// Find dependents
|
||||
let mut ctx = ctx.fork_for_search();
|
||||
ctx.push_dependents(def_fid);
|
||||
while let Some(ref_fid) = ctx.worklist.pop() {
|
||||
let ref_source = ctx.ctx.source_by_id(ref_fid).ok()?;
|
||||
let def_use = get_def_use(ctx.ctx, ref_source.clone())?;
|
||||
|
||||
let uri = ctx.ctx.world.path_for_id(ref_fid).ok()?;
|
||||
let uri = Url::from_file_path(uri).ok()?;
|
||||
|
||||
if let Some((id, _def)) = def_use.get_def(def_fid, &ident_ref) {
|
||||
references.extend(def_use.get_refs(id).map(|r| {
|
||||
let range =
|
||||
typst_to_lsp::range(r.range.clone(), &ref_source, position_encoding);
|
||||
|
||||
LspLocation {
|
||||
uri: uri.clone(),
|
||||
range,
|
||||
}
|
||||
}));
|
||||
};
|
||||
|
||||
references.extend(
|
||||
def_use
|
||||
.get_external_refs(def_fid, Some(name.clone()))
|
||||
.map(|r| {
|
||||
let range =
|
||||
typst_to_lsp::range(r.range.clone(), &ref_source, position_encoding);
|
||||
|
||||
LspLocation {
|
||||
uri: uri.clone(),
|
||||
range,
|
||||
}
|
||||
}),
|
||||
);
|
||||
|
||||
if def_use.is_exported(id) {
|
||||
ctx.push_dependents(ref_fid);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Some(references)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
|
@ -112,8 +151,8 @@ mod tests {
|
|||
#[test]
|
||||
fn test() {
|
||||
// goto_definition
|
||||
snapshot_testing("references", &|world, path| {
|
||||
let source = get_suitable_source_in_workspace(world, &path).unwrap();
|
||||
snapshot_testing2("references", &|world, path| {
|
||||
let source = world.source_by_path(&path).unwrap();
|
||||
|
||||
let request = ReferencesRequest {
|
||||
path: path.clone(),
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue