Attach comments smartly

This commit is contained in:
Aleksey Kladov 2018-10-08 17:33:13 +03:00
parent b642e6c645
commit a05e09e9c5
4 changed files with 97 additions and 24 deletions

View file

@ -153,6 +153,22 @@ impl S {
);
}
#[test]
fn test_extend_selection_doc_comments() {
do_check(
r#"
struct A;
/// bla
/// bla
struct B {
<|>
}
"#,
&["\n \n", "{\n \n}", "/// bla\n/// bla\nstruct B {\n \n}"]
)
}
#[test]
fn test_extend_selection_comments() {
do_check(

View file

@ -12,7 +12,7 @@ use {
TextUnit, TextRange, SmolStr,
lexer::Token,
parser_impl::Sink,
SyntaxKind::{self, TOMBSTONE},
SyntaxKind::{self, *},
};
@ -104,7 +104,6 @@ impl<'a, S: Sink> EventProcessor<'a, S> {
fn tombstone() -> Event {
Event::Start { kind: TOMBSTONE, forward_parent: None }
}
let mut depth = 0;
let mut forward_parents = Vec::new();
for i in 0..self.events.len() {
@ -131,25 +130,14 @@ impl<'a, S: Sink> EventProcessor<'a, S> {
};
}
for kind in forward_parents.drain(..).rev() {
if depth > 0 {
self.eat_ws();
}
depth += 1;
self.sink.start_internal(kind);
self.start(kind);
}
}
Event::Finish => {
depth -= 1;
if depth == 0 {
self.eat_ws();
}
self.sink.finish_internal();
}
Event::Token {
kind,
n_raw_tokens,
} => {
let last = i == self.events.len() - 1;
self.finish(last);
},
Event::Token { kind, n_raw_tokens } => {
self.eat_ws();
let n_raw_tokens = n_raw_tokens as usize;
let len = self.tokens[self.token_pos..self.token_pos + n_raw_tokens]
@ -164,6 +152,43 @@ impl<'a, S: Sink> EventProcessor<'a, S> {
self.sink
}
fn start(&mut self, kind: SyntaxKind) {
if kind == ROOT {
self.sink.start_internal(kind);
return;
}
let n_trivias = self.tokens[self.token_pos..]
.iter()
.take_while(|it| it.kind.is_trivia())
.count();
let leading_trivias = &self.tokens[self.token_pos..self.token_pos + n_trivias];
let mut trivia_end = self.text_pos + leading_trivias
.iter()
.map(|it| it.len)
.sum::<TextUnit>();
let n_attached_trivias = {
let leading_trivias = leading_trivias.iter().rev()
.map(|it| {
let next_end = trivia_end - it.len;
let range = TextRange::from_to(next_end, trivia_end);
trivia_end = next_end;
(it.kind, &self.text[range])
});
n_attached_trivias(kind, leading_trivias)
};
self.eat_n_trivias(n_trivias - n_attached_trivias);
self.sink.start_internal(kind);
self.eat_n_trivias(n_attached_trivias);
}
fn finish(&mut self, last: bool) {
if last {
self.eat_ws()
}
self.sink.finish_internal();
}
fn eat_ws(&mut self) {
while let Some(&token) = self.tokens.get(self.token_pos) {
if !token.kind.is_trivia() {
@ -173,6 +198,14 @@ impl<'a, S: Sink> EventProcessor<'a, S> {
}
}
fn eat_n_trivias(&mut self, n: usize) {
for _ in 0..n {
let token = self.tokens[self.token_pos];
assert!(token.kind.is_trivia());
self.leaf(token.kind, token.len, 1);
}
}
fn leaf(&mut self, kind: SyntaxKind, len: TextUnit, n_tokens: usize) {
let range = TextRange::offset_len(self.text_pos, len);
let text: SmolStr = self.text[range].into();
@ -181,3 +214,27 @@ impl<'a, S: Sink> EventProcessor<'a, S> {
self.sink.leaf(kind, text);
}
}
fn n_attached_trivias<'a>(kind: SyntaxKind, trivias: impl Iterator<Item=(SyntaxKind, &'a str)>) -> usize {
match kind {
STRUCT_DEF | ENUM_DEF | FN_DEF | TRAIT_DEF | MODULE => {
let mut res = 0;
for (i, (kind, text)) in trivias.enumerate() {
match kind {
WHITESPACE => {
if text.contains("\n\n") {
break;
}
}
COMMENT => {
res = i + 1;
}
_ => (),
}
}
res
}
_ => 0,
}
}

View file

@ -137,9 +137,9 @@ ROOT@[0; 575)
BLOCK@[306; 459)
L_CURLY@[306; 307)
WHITESPACE@[307; 316)
COMMENT@[316; 329)
WHITESPACE@[329; 338)
ENUM_DEF@[338; 453)
ENUM_DEF@[316; 453)
COMMENT@[316; 329)
WHITESPACE@[329; 338)
ENUM_KW@[338; 342)
WHITESPACE@[342; 343)
NAME@[343; 348)

View file

@ -1,7 +1,7 @@
ROOT@[0; 506)
COMMENT@[0; 33)
WHITESPACE@[33; 34)
FN_DEF@[34; 505)
FN_DEF@[0; 505)
COMMENT@[0; 33)
WHITESPACE@[33; 34)
FN_KW@[34; 36)
WHITESPACE@[36; 37)
NAME@[37; 41)