Skip to main content

oak_navigation/
lib.rs

1#![feature(new_range_api)]
2#![warn(missing_docs)]
3//! Navigation support for the Oak language framework.
4//!
5//! This crate provides traits and structures for code navigation features
6//! like "Go to Definition" and "Find All References".
7use core::range::Range;
8use oak_core::{Language, TokenType, language::UniversalTokenRole, tree::RedNode, visitor::Visitor};
9
10/// Represents a location in a source file.
11#[derive(Debug, Clone, PartialEq, Eq, Hash, serde::Serialize, serde::Deserialize)]
12pub struct Location {
13    /// The URI of the resource.
14    #[serde(with = "oak_core::serde_arc_str")]
15    pub uri: oak_core::Arc<str>,
16    /// The byte range within the resource.
17    #[serde(with = "oak_core::serde_range")]
18    pub range: Range<usize>,
19}
20
21/// Trait for languages that support jumping to definition.
22pub trait DefinitionProvider<L: Language> {
23    /// Returns the definition(s) of the symbol at the given offset.
24    fn definition(&self, root: &RedNode<L>, offset: usize) -> Vec<Location>;
25}
26
27/// Trait for languages that support finding references.
28pub trait ReferencesProvider<L: Language> {
29    /// Returns the references to the symbol at the given offset.
30    fn references(&self, root: &RedNode<L>, offset: usize, include_declaration: bool) -> Vec<Location>;
31}
32
33/// A helper to find all references of a name in a tree.
34pub struct SimpleReferenceFinder<'a, L: Language> {
35    /// The name of the symbol to find references for.
36    name: &'a str,
37    /// The full source text.
38    source: &'a str,
39    /// The URI of the source file.
40    uri: oak_core::Arc<str>,
41    /// The list of locations where the name was found.
42    references: Vec<Location>,
43    /// Phantom data for the language type.
44    _phantom: std::marker::PhantomData<L>,
45}
46
47impl<'a, L: Language> SimpleReferenceFinder<'a, L> {
48    /// Finds all references of the given name in the tree.
49    ///
50    /// # Arguments
51    /// * `root` - The root node of the syntax tree.
52    /// * `name` - The name of the symbol to find.
53    /// * `source` - The source text.
54    /// * `uri` - The URI of the source file.
55    pub fn find(root: &RedNode<'a, L>, name: &'a str, source: &'a str, uri: impl Into<oak_core::Arc<str>>) -> Vec<Location> {
56        let mut finder = Self { name, source, uri: uri.into(), references: Vec::new(), _phantom: std::marker::PhantomData };
57        finder.visit_node(*root);
58        finder.references
59    }
60}
61
62impl<'a, L: Language> Visitor<'a, L> for SimpleReferenceFinder<'a, L> {
63    fn visit_node(&mut self, node: RedNode<'a, L>) {
64        self.walk_node(node);
65    }
66
67    fn visit_token(&mut self, token: oak_core::tree::RedLeaf<L>) {
68        if token.kind.is_universal(UniversalTokenRole::Name) {
69            let text = &self.source[token.span.clone()];
70            if text == self.name {
71                self.references.push(Location { uri: self.uri.clone(), range: token.span });
72            }
73        }
74    }
75}