// intersperseComments consumes all comments that appear before the next token // tok and prints it together with the buffered whitespace (i.e., the whitespace // that needs to be written before the next token). A heuristic is used to mix // the comments and whitespace. The intersperseComments result indicates if a // newline was written or if a formfeed was dropped from the whitespace buffer. // func (p *printer) intersperseComments(next token.Position, tok token.Token) (wroteNewline, droppedFF bool) { var last *ast.Comment for p.commentBefore(next) { for _, c := range p.comment.List { p.writeCommentPrefix(p.posFor(c.Pos()), next, last, c, tok) p.writeComment(c) last = c } p.nextComment() } if last != nil { // if the last comment is a /*-style comment and the next item // follows on the same line but is not a comma, and not a "closing" // token immediately following its corresponding "opening" token, // add an extra blank for separation unless explicitly disabled if p.mode&noExtraBlank == 0 && last.Text[1] == '*' && p.lineFor(last.Pos()) == next.Line && tok != token.COMMA && (tok != token.RPAREN || p.prevOpen == token.LPAREN) && (tok != token.RBRACK || p.prevOpen == token.LBRACK) { p.writeByte(' ', 1) } // ensure that there is a line break after a //-style comment, // before a closing '}' unless explicitly disabled, or at eof needsLinebreak := last.Text[1] == '/' || tok == token.RBRACE && p.mode&noExtraLinebreak == 0 || tok == token.EOF return p.writeCommentSuffix(needsLinebreak) } // no comment was written - we should never reach here since // intersperseComments should not be called in that case p.internalError("intersperseComments called without pending comments") return }
func (p *printer) writeComment(comment *ast.Comment) { text := comment.Text pos := p.posFor(comment.Pos()) const linePrefix = "//line " if strings.HasPrefix(text, linePrefix) && (!pos.IsValid() || pos.Column == 1) { // possibly a line directive ldir := strings.TrimSpace(text[len(linePrefix):]) if i := strings.LastIndex(ldir, ":"); i >= 0 { if line, err := strconv.Atoi(ldir[i+1:]); err == nil && line > 0 { // The line directive we are about to print changed // the Filename and Line number used for subsequent // tokens. We have to update our AST-space position // accordingly and suspend indentation temporarily. indent := p.indent p.indent = 0 defer func() { p.pos.Filename = ldir[:i] p.pos.Line = line p.pos.Column = 1 p.indent = indent }() } } } // shortcut common case of //-style comments if text[1] == '/' { p.writeString(pos, trimRight(text), true) return } // for /*-style comments, print line by line and let the // write function take care of the proper indentation lines := strings.Split(text, "\n") // The comment started in the first column but is going // to be indented. For an idempotent result, add indentation // to all lines such that they look like they were indented // before - this will make sure the common prefix computation // is the same independent of how many times formatting is // applied (was issue 1835). if pos.IsValid() && pos.Column == 1 && p.indent > 0 { for i, line := range lines[1:] { lines[1+i] = " " + line } } stripCommonPrefix(lines) // write comment lines, separated by formfeed, // without a line break after the last line for i, line := range lines { if i > 0 { p.writeByte('\f', 1) pos = p.pos } if len(line) > 0 { p.writeString(pos, trimRight(line), true) } } }