From cf0f5ca814a1cf3a5ae8830bbcbabea1e3a045af Mon Sep 17 00:00:00 2001 From: Marcus Klaas Date: Mon, 19 Oct 2015 21:40:00 +0200 Subject: [PATCH] Implement CommentCodeSlices --- src/comment.rs | 83 ++++++++++++++++++++++++++++++++++++++++----- src/missed_spans.rs | 12 +++---- 2 files changed, 78 insertions(+), 17 deletions(-) diff --git a/src/comment.rs b/src/comment.rs index 86d1a9aeb14..d9b2d1e111e 100644 --- a/src/comment.rs +++ b/src/comment.rs @@ -162,7 +162,7 @@ pub fn contains_comment(text: &str) -> bool { CharClasses::new(text.chars()).any(|(kind, _)| kind == CodeCharKind::Comment) } -struct CharClasses +pub struct CharClasses where T: Iterator, T::Item: RichChar { @@ -170,7 +170,7 @@ struct CharClasses status: CharClassesStatus, } -trait RichChar { +pub trait RichChar { fn get_char(&self) -> char; } @@ -195,23 +195,23 @@ enum CharClassesStatus { LitCharEscape, // The u32 is the nesting deepness of the comment BlockComment(u32), - // Status when the '/' has been consumed, but not yet the '*', deepness is the new deepness - // (after the comment opening). + // Status when the '/' has been consumed, but not yet the '*', deepness is + // the new deepness (after the comment opening). BlockCommentOpening(u32), - // Status when the '*' has been consumed, but not yet the '/', deepness is the new deepness - // (after the comment closing). + // Status when the '*' has been consumed, but not yet the '/', deepness is + // the new deepness (after the comment closing). BlockCommentClosing(u32), LineComment, } #[derive(PartialEq, Eq, Debug, Clone, Copy)] -enum CodeCharKind { +pub enum CodeCharKind { Normal, Comment, } impl CharClasses where T: Iterator, T::Item: RichChar { - fn new(base: T) -> CharClasses { + pub fn new(base: T) -> CharClasses { CharClasses { base: base.peekable(), status: CharClassesStatus::Normal, @@ -298,11 +298,76 @@ impl Iterator for CharClasses where T: Iterator, T::Item: RichChar { } } +struct CommentCodeSlices<'a> { + slice: &'a str, + last_slice_type: CodeCharKind, + last_slice_end: usize, +} + +impl<'a> CommentCodeSlices<'a> { + fn new(slice: &'a str) -> CommentCodeSlices<'a> { + CommentCodeSlices { + slice: slice, + last_slice_type: CodeCharKind::Comment, + last_slice_end: 0, + } + } +} + +impl<'a> Iterator for CommentCodeSlices<'a> { + type Item = (CodeCharKind, &'a str); + + fn next(&mut self) -> Option { + if self.last_slice_end == self.slice.len() { + return None; + } + + let mut sub_slice_end = self.last_slice_end; + for (kind, (i, _)) in CharClasses::new(self.slice[self.last_slice_end..].char_indices()) { + if kind == self.last_slice_type { + sub_slice_end = self.last_slice_end + i; + break; + } + } + + let kind = match self.last_slice_type { + CodeCharKind::Comment => CodeCharKind::Normal, + CodeCharKind::Normal => CodeCharKind::Comment, + }; + self.last_slice_type = kind; + + // FIXME: be consistent in use of kind vs type. + if sub_slice_end == self.last_slice_end { + // This was the last subslice. + self.last_slice_end = self.slice.len(); + + Some((kind, &self.slice[sub_slice_end..])) + } else { + let res = &self.slice[self.last_slice_end..sub_slice_end]; + self.last_slice_end = sub_slice_end; + Some((kind, res)) + } + } +} + #[cfg(test)] mod test { - use super::{CharClasses, CodeCharKind, contains_comment, rewrite_comment, FindUncommented}; + use super::{CharClasses, CodeCharKind, contains_comment, rewrite_comment, FindUncommented, + CommentCodeSlices}; use Indent; + #[test] + fn comment_code_slices() { + let input = "code(); /* test */ 1 + 1"; + + let mut iter = CommentCodeSlices::new(input); + + assert_eq!((CodeCharKind::Normal, "code(); "), iter.next().unwrap()); + assert_eq!((CodeCharKind::Comment, "/* test */"), iter.next().unwrap()); + assert_eq!((CodeCharKind::Normal, " 1 + 1"), iter.next().unwrap()); + assert_eq!(None, iter.next()); + } + #[test] #[rustfmt_skip] fn format_comments() { diff --git a/src/missed_spans.rs b/src/missed_spans.rs index 57b63b56790..6cb4a88d160 100644 --- a/src/missed_spans.rs +++ b/src/missed_spans.rs @@ -10,7 +10,8 @@ use visitor::FmtVisitor; -use syntax::codemap::{self, BytePos}; +use syntax::codemap::{self, BytePos, Span}; +use comment::{CharClasses, CodeCharKind}; impl<'a> FmtVisitor<'a> { // TODO these format_missing methods are ugly. Refactor and add unit tests @@ -37,16 +38,12 @@ impl<'a> FmtVisitor<'a> { end: BytePos, process_last_snippet: F) { let start = self.last_pos; - debug!("format_missing_inner: {:?} to {:?}", - self.codemap.lookup_char_pos(start), - self.codemap.lookup_char_pos(end)); if start == end { // Do nothing if this is the beginning of the file. - if start == self.codemap.lookup_char_pos(start).file.start_pos { - return; + if start != self.codemap.lookup_char_pos(start).file.start_pos { + process_last_snippet(self, "", ""); } - process_last_snippet(self, "", ""); return; } @@ -57,7 +54,6 @@ impl<'a> FmtVisitor<'a> { self.last_pos = end; let span = codemap::mk_sp(start, end); - let snippet = self.snippet(span); self.write_snippet(&snippet, &process_last_snippet); }