From 8467ba8cdb565d865e14e2115cde98cd7692719d Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Fri, 19 Jul 2019 20:29:59 +0300 Subject: flip syntax text to use internal iteration --- crates/ra_hir/src/ids.rs | 11 +++- crates/ra_ide_api/src/display/structure.rs | 6 +- crates/ra_syntax/src/syntax_node.rs | 1 - crates/ra_syntax/src/syntax_text.rs | 98 ++++++++++++++++++++---------- 4 files changed, 78 insertions(+), 38 deletions(-) (limited to 'crates') diff --git a/crates/ra_hir/src/ids.rs b/crates/ra_hir/src/ids.rs index 05a18eb56..ec756f2c3 100644 --- a/crates/ra_hir/src/ids.rs +++ b/crates/ra_hir/src/ids.rs @@ -362,7 +362,16 @@ impl MacroCallId { pub fn debug_dump(self, db: &impl AstDatabase) -> String { let loc = self.loc(db); let node = loc.ast_id.to_node(db); - let syntax_str = node.syntax().text().chunks().collect::>().join(" "); + let syntax_str = { + let mut res = String::new(); + node.syntax().text().for_each_chunk(|chunk| { + if !res.is_empty() { + res.push(' ') + } + res.push_str(chunk) + }); + res + }; // dump the file name let file_id: HirFileId = self.loc(db).ast_id.file_id(); diff --git a/crates/ra_ide_api/src/display/structure.rs b/crates/ra_ide_api/src/display/structure.rs index 2e183d2f6..0b1a8b6e6 100644 --- a/crates/ra_ide_api/src/display/structure.rs +++ b/crates/ra_ide_api/src/display/structure.rs @@ -83,12 +83,12 @@ fn structure_node(node: &SyntaxNode) -> Option { fn collapse_ws(node: &SyntaxNode, output: &mut String) { let mut can_insert_ws = false; - for chunk in node.text().chunks() { + node.text().for_each_chunk(|chunk| { for line in chunk.lines() { let line = line.trim(); if line.is_empty() { if can_insert_ws { - output.push_str(" "); + output.push(' '); can_insert_ws = false; } } else { @@ -96,7 +96,7 @@ fn structure_node(node: &SyntaxNode) -> Option { can_insert_ws = true; } } - } + }) } visitor() diff --git a/crates/ra_syntax/src/syntax_node.rs b/crates/ra_syntax/src/syntax_node.rs index 62e0967b7..8fe9e5b4e 100644 --- a/crates/ra_syntax/src/syntax_node.rs +++ b/crates/ra_syntax/src/syntax_node.rs @@ -297,7 +297,6 @@ fn to_green_element(element: SyntaxElement) -> rowan::GreenElement { #[derive(Clone, PartialEq, Eq, Hash)] pub struct SyntaxToken(pub(crate) rowan::cursor::SyntaxToken); -//FIXME: always output text impl fmt::Debug for SyntaxToken { fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { write!(fmt, "{:?}@{:?}", self.kind(), self.range())?; diff --git a/crates/ra_syntax/src/syntax_text.rs b/crates/ra_syntax/src/syntax_text.rs index 6902a04a2..6f15e3b35 100644 --- a/crates/ra_syntax/src/syntax_text.rs +++ b/crates/ra_syntax/src/syntax_text.rs @@ -16,26 +16,48 @@ impl<'a> SyntaxText<'a> { SyntaxText { node, range: node.range() } } - pub fn chunks(&self) -> impl Iterator { - let range = self.range; - self.node.descendants_with_tokens().filter_map(move |el| match el { - SyntaxElement::Token(t) => { - let text = t.text(); - let range = range.intersection(&t.range())?; - let res = if range == t.range() { - t.text().clone() - } else { - let range = range - t.range().start(); - text[range].into() - }; - Some(res) - } - SyntaxElement::Node(_) => None, + pub fn try_fold_chunks(&self, init: T, mut f: F) -> Result + where + F: FnMut(T, &str) -> Result, + { + self.node.descendants_with_tokens().try_fold(init, move |acc, element| { + let res = match element { + SyntaxElement::Token(token) => { + let range = match self.range.intersection(&token.range()) { + None => return Ok(acc), + Some(it) => it, + }; + let slice = if range == token.range() { + token.text() + } else { + let range = range - token.range().start(); + &token.text()[range] + }; + f(acc, slice)? + } + SyntaxElement::Node(_) => acc, + }; + Ok(res) }) } + pub fn try_for_each_chunk Result<(), E>, E>( + &self, + mut f: F, + ) -> Result<(), E> { + self.try_fold_chunks((), move |(), chunk| f(chunk)) + } + + pub fn for_each_chunk(&self, mut f: F) { + enum Void {} + match self.try_for_each_chunk(|chunk| Ok::<(), Void>(f(chunk))) { + Ok(()) => (), + Err(void) => match void {}, + } + } + pub fn push_to(&self, buf: &mut String) { - self.chunks().for_each(|it| buf.push_str(it.as_str())); + self.for_each_chunk(|chunk| buf.push_str(chunk)) } pub fn to_string(&self) -> String { @@ -49,19 +71,20 @@ impl<'a> SyntaxText<'a> { } pub fn contains(&self, c: char) -> bool { - self.chunks().any(|it| it.contains(c)) + self.try_for_each_chunk(|chunk| if chunk.contains(c) { Err(()) } else { Ok(()) }).is_err() } pub fn find(&self, c: char) -> Option { let mut acc: TextUnit = 0.into(); - for chunk in self.chunks() { + let res = self.try_for_each_chunk(|chunk| { if let Some(pos) = chunk.find(c) { let pos: TextUnit = (pos as u32).into(); - return Some(acc + pos); + return Err(acc + pos); } - acc += TextUnit::of_str(chunk.as_str()); - } - None + acc += TextUnit::of_str(chunk); + Ok(()) + }); + found(res) } pub fn len(&self) -> TextUnit { @@ -101,17 +124,25 @@ impl<'a> SyntaxText<'a> { } pub fn char_at(&self, offset: impl Into) -> Option { - let mut start: TextUnit = 0.into(); let offset = offset.into(); - for chunk in self.chunks() { - let end = start + TextUnit::of_str(chunk.as_str()); + let mut start: TextUnit = 0.into(); + let res = self.try_for_each_chunk(|chunk| { + 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()); + return Err(chunk[off..].chars().next().unwrap()); } start = end; - } - None + Ok(()) + }); + found(res) + } +} + +fn found(res: Result<(), T>) -> Option { + match res { + Ok(()) => None, + Err(it) => Some(it), } } @@ -135,13 +166,14 @@ impl From> for String { impl PartialEq for SyntaxText<'_> { fn eq(&self, mut rhs: &str) -> bool { - for chunk in self.chunks() { - if !rhs.starts_with(chunk.as_str()) { - return false; + self.try_for_each_chunk(|chunk| { + if !rhs.starts_with(chunk) { + return Err(()); } rhs = &rhs[chunk.len()..]; - } - rhs.is_empty() + Ok(()) + }) + .is_ok() } } -- cgit v1.2.3