Skip to content

Commit c744a30

Browse files
committed
handle multiline class doc comments
1 parent ad62897 commit c744a30

1 file changed

Lines changed: 21 additions & 6 deletions

File tree

src/formatter.rs

Lines changed: 21 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
//! rules have too much performance overhead when applied through Topiary.
1515
use std::{collections::VecDeque, io::BufWriter};
1616

17-
use regex::{Regex, RegexBuilder};
17+
use regex::{Regex, RegexBuilder, Replacer};
1818
use topiary_core::{Language, Operation, TopiaryQuery, formatter_tree};
1919
use tree_sitter::{Parser, Point, Query, QueryCursor, StreamingIterator, Tree};
2020

@@ -165,15 +165,30 @@ impl Formatter {
165165
// - consists out of alphanumeric characters
166166
// - consists out of any characters (except new lines) between double quotes
167167
// - must contain at least one new line character between `extends_name` and optional doc comment
168-
// - may contain doc string that starts with `##` and ends with new line character
168+
// - may contain multiple doc comment lines that starts with `##` and ends with a new line character
169169
let re = RegexBuilder::new(
170-
r#"(?P<extends_line>^extends )(?P<extends_name>([a-zA-Z0-9]+|".*?"))\n+(^(?P<doc>##.*?)$)?"#,
170+
r#"(?P<extends_line>^extends )(?P<extends_name>([a-zA-Z0-9]+|".*?"))\n+(?P<doc>(?:^##.*\n)*)(?P<EOF>\z)?"#,
171171
)
172172
.multi_line(true)
173173
.build()
174174
.expect("regex should compile");
175175

176-
self.regex_replace_all_outside_strings(re, "$extends_line$extends_name\n$doc\n");
176+
self.regex_replace_all_outside_strings(re, |caps: &regex::Captures| {
177+
let extends_line = caps.name("extends_line").unwrap().as_str();
178+
let extends_name = caps.name("extends_name").unwrap().as_str();
179+
let doc = caps
180+
.name("doc")
181+
.map(|m| m.as_str())
182+
.unwrap_or_default()
183+
.trim_end(); // remove last new line from doc comment because we add a new line manually
184+
// insert new line only if we are not at the end of file
185+
let blank_new_line = if caps.name("EOF").is_some() { "" } else { "\n" };
186+
187+
format!(
188+
"{}{}\n{}{}",
189+
extends_line, extends_name, doc, blank_new_line
190+
)
191+
});
177192

178193
self
179194
}
@@ -237,7 +252,7 @@ impl Formatter {
237252
/// outside of strings (simple or multiline).
238253
/// Use this to make post-processing changes needed for formatting but that
239254
/// shouldn't affect strings in the source code.
240-
fn regex_replace_all_outside_strings(&mut self, re: Regex, rep: &str) {
255+
fn regex_replace_all_outside_strings<R: Replacer>(&mut self, re: Regex, mut rep: R) {
241256
let mut iter = re.captures_iter(&self.content).peekable();
242257
if iter.peek().is_none() {
243258
return;
@@ -264,7 +279,7 @@ impl Formatter {
264279
}
265280

266281
let mut replacement = String::new();
267-
capture.expand(rep, &mut replacement);
282+
rep.replace_append(&capture, &mut replacement);
268283

269284
let new_end_byte = start_byte + replacement.len();
270285

0 commit comments

Comments
 (0)