From b5021411a84822cb3f1e3aeffad9550dd15bdeb6 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Sun, 16 Sep 2018 12:54:24 +0300 Subject: rename all things --- crates/ra_syntax/src/yellow/syntax_text.rs | 122 +++++++++++++++++++++++++++++ 1 file changed, 122 insertions(+) create mode 100644 crates/ra_syntax/src/yellow/syntax_text.rs (limited to 'crates/ra_syntax/src/yellow/syntax_text.rs') diff --git a/crates/ra_syntax/src/yellow/syntax_text.rs b/crates/ra_syntax/src/yellow/syntax_text.rs new file mode 100644 index 000000000..280bedd78 --- /dev/null +++ b/crates/ra_syntax/src/yellow/syntax_text.rs @@ -0,0 +1,122 @@ +use std::{ + fmt, ops, +}; + +use { + SyntaxNodeRef, TextRange, TextUnit, + algo::walk::preorder, + text_utils::{intersect, contains_offset_nonstrict}, +}; + +#[derive(Clone)] +pub struct SyntaxText<'a> { + node: SyntaxNodeRef<'a>, + range: TextRange, +} + +impl<'a> SyntaxText<'a> { + pub(crate) fn new(node: SyntaxNodeRef<'a>) -> SyntaxText<'a> { + SyntaxText { + node, + range: node.range() + } + } + pub fn chunks(&self) -> impl Iterator { + let range = self.range; + preorder(self.node) + .filter_map(move |node| { + let text = node.leaf_text_ref()?; + let range = intersect(range, node.range())?; + let range = range - node.range().start(); + Some(&text[range]) + }) + } + pub fn push_to(&self, buf: &mut String) { + self.chunks().for_each(|it| buf.push_str(it)); + } + pub fn to_string(&self) -> String { + self.chunks().collect() + } + pub fn contains(&self, c: char) -> bool { + self.chunks().any(|it| it.contains(c)) + } + pub fn find(&self, c: char) -> Option { + let mut acc: TextUnit = 0.into(); + for chunk in self.chunks() { + if let Some(pos) = chunk.find(c) { + let pos: TextUnit = (pos as u32).into(); + return Some(acc + pos); + } + acc += TextUnit::of_str(chunk); + } + None + } + pub fn len(&self) -> TextUnit { + self.range.len() + } + pub fn slice(&self, range: impl SyntaxTextSlice) -> SyntaxText<'a> { + let range = range.restrict(self.range) + .unwrap_or_else(|| { + panic!("invalid slice, range: {:?}, slice: {:?}", self.range, range) + }); + SyntaxText { node: self.node, range } + } + pub fn char_at(&self, offset: TextUnit) -> Option { + let mut start: TextUnit = 0.into(); + for chunk in self.chunks() { + let end = start + TextUnit::of_str(chunk); + if start <= offset && offset < end { + let off: usize = u32::from(offset - start) as usize; + return Some(chunk[off..].chars().next().unwrap()); + } + start = end; + } + None + } +} + +impl<'a> fmt::Debug for SyntaxText<'a> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fmt::Debug::fmt(&self.to_string(), f) + } +} + +impl<'a> fmt::Display for SyntaxText<'a> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fmt::Display::fmt(&self.to_string(), f) + } +} + +pub trait SyntaxTextSlice: fmt::Debug { + fn restrict(&self, range: TextRange) -> Option; +} + +impl SyntaxTextSlice for TextRange { + fn restrict(&self, range: TextRange) -> Option { + intersect(*self, range) + } +} + +impl SyntaxTextSlice for ops::RangeTo { + fn restrict(&self, range: TextRange) -> Option { + if !contains_offset_nonstrict(range, self.end) { + return None; + } + Some(TextRange::from_to(range.start(), self.end)) + } +} + +impl SyntaxTextSlice for ops::RangeFrom { + fn restrict(&self, range: TextRange) -> Option { + if !contains_offset_nonstrict(range, self.start) { + return None; + } + Some(TextRange::from_to(self.start, range.end())) + } +} + +impl SyntaxTextSlice for ops::Range { + fn restrict(&self, range: TextRange) -> Option { + TextRange::from_to(self.start, self.end).restrict(range) + } +} -- cgit v1.2.3