in lib/src/source_visitor.dart [3803:3885]
bool writePrecedingCommentsAndNewlines(Token token) {
Token? comment = token.precedingComments;
// For performance, avoid calculating newlines between tokens unless
// actually needed.
if (comment == null) {
if (builder.needsToPreserveNewlines) {
builder.preserveNewlines(_startLine(token) - _endLine(token.previous!));
}
return false;
}
// If the token's comments are being moved by a fix, do not write them here.
if (_suppressPrecedingCommentsAndNewLines.contains(token)) return false;
var previousLine = _endLine(token.previous!);
var tokenLine = _startLine(token);
// Edge case: The analyzer includes the "\n" in the script tag's lexeme,
// which confuses some of these calculations. We don't want to allow a
// blank line between the script tag and a following comment anyway, so
// just override the script tag's line.
if (token.previous!.type == TokenType.SCRIPT_TAG) previousLine = tokenLine;
var comments = <SourceComment>[];
while (comment != null) {
var commentLine = _startLine(comment);
// Don't preserve newlines at the top of the file.
if (comment == token.precedingComments &&
token.previous!.type == TokenType.EOF) {
previousLine = commentLine;
}
var text = comment.lexeme.trim();
var linesBefore = commentLine - previousLine;
var flushLeft = _startColumn(comment) == 1;
if (text.startsWith('///') && !text.startsWith('////')) {
// Line doc comments are always indented even if they were flush left.
flushLeft = false;
// Always add a blank line (if possible) before a doc comment block.
if (comment == token.precedingComments) linesBefore = 2;
}
var type = CommentType.block;
if (text.startsWith('///') && !text.startsWith('////') ||
text.startsWith('/**')) {
type = CommentType.doc;
} else if (comment.type == TokenType.SINGLE_LINE_COMMENT) {
type = CommentType.line;
} else if (commentLine == previousLine || commentLine == tokenLine) {
type = CommentType.inlineBlock;
}
var sourceComment =
SourceComment(text, type, linesBefore, flushLeft: flushLeft);
// If this comment contains either of the selection endpoints, mark them
// in the comment.
var start = _getSelectionStartWithin(comment.offset, comment.length);
if (start != null) sourceComment.startSelection(start);
var end = _getSelectionEndWithin(comment.offset, comment.length);
if (end != null) sourceComment.endSelection(end);
comments.add(sourceComment);
previousLine = _endLine(comment);
comment = comment.next;
}
builder.writeComments(comments, tokenLine - previousLine, token.lexeme);
// TODO(rnystrom): This is wrong. Consider:
//
// [/* inline comment */
// // line comment
// element];
return comments.first.linesBefore > 0;
}