Unnamed repository; edit this file 'description' to name the repository.
Diffstat (limited to 'crates/span/src/map.rs')
-rw-r--r--crates/span/src/map.rs59
1 files changed, 45 insertions, 14 deletions
diff --git a/crates/span/src/map.rs b/crates/span/src/map.rs
index 9f8101c816..1f396a1e97 100644
--- a/crates/span/src/map.rs
+++ b/crates/span/src/map.rs
@@ -1,23 +1,26 @@
//! A map that maps a span to every position in a file. Usually maps a span to some range of positions.
//! Allows bidirectional lookup.
-use std::hash::Hash;
+use std::{fmt, hash::Hash};
use stdx::{always, itertools::Itertools};
use syntax::{TextRange, TextSize};
use vfs::FileId;
-use crate::{ErasedFileAstId, Span, SpanAnchor, SyntaxContextId, ROOT_ERASED_FILE_AST_ID};
+use crate::{
+ ErasedFileAstId, Span, SpanAnchor, SpanData, SyntaxContextId, ROOT_ERASED_FILE_AST_ID,
+};
/// Maps absolute text ranges for the corresponding file to the relevant span data.
#[derive(Debug, PartialEq, Eq, Clone, Hash)]
pub struct SpanMap<S> {
- spans: Vec<(TextSize, S)>,
- // FIXME: Should be
- // spans: Vec<(TextSize, crate::SyntaxContextId)>,
+ spans: Vec<(TextSize, SpanData<S>)>,
}
-impl<S: Copy> SpanMap<S> {
+impl<S> SpanMap<S>
+where
+ SpanData<S>: Copy,
+{
/// Creates a new empty [`SpanMap`].
pub fn empty() -> Self {
Self { spans: Vec::new() }
@@ -34,7 +37,7 @@ impl<S: Copy> SpanMap<S> {
}
/// Pushes a new span onto the [`SpanMap`].
- pub fn push(&mut self, offset: TextSize, span: S) {
+ pub fn push(&mut self, offset: TextSize, span: SpanData<S>) {
if cfg!(debug_assertions) {
if let Some(&(last_offset, _)) = self.spans.last() {
assert!(
@@ -49,13 +52,31 @@ impl<S: Copy> SpanMap<S> {
/// Returns all [`TextRange`]s that correspond to the given span.
///
/// Note this does a linear search through the entire backing vector.
- pub fn ranges_with_span(&self, span: S) -> impl Iterator<Item = TextRange> + '_
+ pub fn ranges_with_span_exact(&self, span: SpanData<S>) -> impl Iterator<Item = TextRange> + '_
where
- S: Eq,
+ S: Copy,
{
- // FIXME: This should ignore the syntax context!
self.spans.iter().enumerate().filter_map(move |(idx, &(end, s))| {
- if s != span {
+ if !s.eq_ignoring_ctx(span) {
+ return None;
+ }
+ let start = idx.checked_sub(1).map_or(TextSize::new(0), |prev| self.spans[prev].0);
+ Some(TextRange::new(start, end))
+ })
+ }
+
+ /// Returns all [`TextRange`]s whose spans contain the given span.
+ ///
+ /// Note this does a linear search through the entire backing vector.
+ pub fn ranges_with_span(&self, span: SpanData<S>) -> impl Iterator<Item = TextRange> + '_
+ where
+ S: Copy,
+ {
+ self.spans.iter().enumerate().filter_map(move |(idx, &(end, s))| {
+ if s.anchor != span.anchor {
+ return None;
+ }
+ if !s.range.contains_range(span.range) {
return None;
}
let start = idx.checked_sub(1).map_or(TextSize::new(0), |prev| self.spans[prev].0);
@@ -64,21 +85,21 @@ impl<S: Copy> SpanMap<S> {
}
/// Returns the span at the given position.
- pub fn span_at(&self, offset: TextSize) -> S {
+ pub fn span_at(&self, offset: TextSize) -> SpanData<S> {
let entry = self.spans.partition_point(|&(it, _)| it <= offset);
self.spans[entry].1
}
/// Returns the spans associated with the given range.
/// In other words, this will return all spans that correspond to all offsets within the given range.
- pub fn spans_for_range(&self, range: TextRange) -> impl Iterator<Item = S> + '_ {
+ pub fn spans_for_range(&self, range: TextRange) -> impl Iterator<Item = SpanData<S>> + '_ {
let (start, end) = (range.start(), range.end());
let start_entry = self.spans.partition_point(|&(it, _)| it <= start);
let end_entry = self.spans[start_entry..].partition_point(|&(it, _)| it <= end); // FIXME: this might be wrong?
self.spans[start_entry..][..end_entry].iter().map(|&(_, s)| s)
}
- pub fn iter(&self) -> impl Iterator<Item = (TextSize, S)> + '_ {
+ pub fn iter(&self) -> impl Iterator<Item = (TextSize, SpanData<S>)> + '_ {
self.spans.iter().copied()
}
}
@@ -92,6 +113,16 @@ pub struct RealSpanMap {
end: TextSize,
}
+impl fmt::Display for RealSpanMap {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ writeln!(f, "RealSpanMap({:?}):", self.file_id)?;
+ for span in self.pairs.iter() {
+ writeln!(f, "{}: {}", u32::from(span.0), span.1.into_raw().into_u32())?;
+ }
+ Ok(())
+ }
+}
+
impl RealSpanMap {
/// Creates a real file span map that returns absolute ranges (relative ranges to the root ast id).
pub fn absolute(file_id: FileId) -> Self {