Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions crates/common/src/comments/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -235,9 +235,9 @@ impl<'ast> CommentGatherer<'ast> {
let line_begin_pos = (line_begin_in_file - self.start_bpos).to_usize();
let mut col = CharPos(self.text[line_begin_pos..self.pos].chars().count());

// To preserve alignment in non-doc comments, normalize the block based on its
// least-indented line.
if !is_doc {
// To preserve alignment in multi-line non-doc comments, normalize the block based
// on its least-indented line.
if !is_doc && token_text.contains('\n') {
col = token_text.lines().skip(1).fold(col, |min, line| {
if line.is_empty() {
return min;
Expand Down
91 changes: 59 additions & 32 deletions crates/fmt/src/state/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -584,52 +584,79 @@ impl<'sess> State<'sess, '_> {
return;
}

let post_break_prefix = |prefix: &'static str, line_len: usize| -> &'static str {
fn post_break_prefix(prefix: &'static str, has_content: bool) -> &'static str {
if !has_content {
return prefix;
}
match prefix {
"///" if line_len > 3 => "/// ",
"//" if line_len > 2 => "// ",
"/*" if line_len > 2 => "/* ",
" *" if line_len > 2 => " * ",
"///" => "/// ",
"//" => "// ",
"/*" => "/* ",
" *" => " * ",
_ => prefix,
}
};
}

self.ibox(0);
let (prefix, content) = if is_doc {
// Doc comments preserve leading whitespaces (right after the prefix).
self.word(prefix);
let content = &line[prefix.len()..];
let (leading_ws, rest) =
content.split_at(content.chars().take_while(|&c| c.is_whitespace()).count());
self.word(prefix);

let content = &line[prefix.len()..];
let content = if is_doc {
// Doc comments preserve leading whitespaces (right after the prefix) as nbps.
let ws_len = content.chars().take_while(|&c| c.is_whitespace()).count();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is char count instead of byte count

let (leading_ws, rest) = content.split_at(ws_len);
if !leading_ws.is_empty() {
self.word(leading_ws.to_owned());
}
let prefix = post_break_prefix(prefix, rest.len());
(prefix, rest)
rest
} else {
let content = line[prefix.len()..].trim();
let prefix = post_break_prefix(prefix, content.len());
self.word(prefix);
(prefix, content)
};

// Split the rest of the content into words.
let mut words = content.split_whitespace().peekable();
while let Some(word) = words.next() {
self.word(word.to_owned());
if let Some(next_word) = words.peek() {
if *next_word == "*/" {
// Non-doc comments: replace first whitespace with nbsp, rest of content continues
if let Some(first_char) = content.chars().next() {
if first_char.is_whitespace() {
self.nbsp();
&content[first_char.len_utf8()..]
} else {
self.s.scan_break(BreakToken {
offset: break_offset,
blank_space: 1,
post_break: if matches!(prefix, "/* ") { None } else { Some(prefix) },
..Default::default()
});
content
}
} else {
""
}
};

let post_break = post_break_prefix(prefix, !content.is_empty());

// Process content character by character to preserve consecutive whitespaces
let (mut chars, mut current_word) = (content.chars().peekable(), String::new());
while let Some(ch) = chars.next() {
if ch.is_whitespace() {
// Print current word
if !current_word.is_empty() {
self.word(std::mem::take(&mut current_word));
}

// Preserve multiple spaces while adding a single break
let mut ws_count = 1;
while chars.peek().is_some_and(|c| c.is_whitespace()) {
ws_count += 1;
chars.next();
}
self.s.scan_break(BreakToken {
offset: break_offset,
blank_space: ws_count,
post_break: if post_break.starts_with("/*") { None } else { Some(post_break) },
..Default::default()
});
continue;
}

current_word.push(ch);
}

// Print final word
if !current_word.is_empty() {
self.word(current_word);
}

self.end();
}

Expand Down
8 changes: 8 additions & 0 deletions crates/fmt/testdata/SimpleComments/fmt.sol
Original file line number Diff line number Diff line change
@@ -1,6 +1,14 @@
contract SimpleComments {
//´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:
// VARIABLES
//.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•

mapping(address /* asset */ => address /* router */) public router;

/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* FUNCTIONS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

constructor() {
// TODO: do this and that

Expand Down
7 changes: 7 additions & 0 deletions crates/fmt/testdata/SimpleComments/original.sol
Original file line number Diff line number Diff line change
@@ -1,6 +1,13 @@
contract SimpleComments {
//´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:
// VARIABLES
//.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•

mapping(address /* asset */ => address /* router */) public router;

/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* FUNCTIONS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

constructor() {
// TODO: do this and that
Expand Down
9 changes: 9 additions & 0 deletions crates/fmt/testdata/SimpleComments/wrap-comments.fmt.sol
Original file line number Diff line number Diff line change
@@ -1,9 +1,18 @@
// config: line_length = 60
// config: wrap_comments = true
contract SimpleComments {
//´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:
// VARIABLES
//.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•

mapping(address /* asset */ => address /* router */)
public router;

/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* FUNCTIONS
*/
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

constructor() {
// TODO: do this and that

Expand Down
Loading