1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
7 #include "base/command_line.h"
8 #include "base/files/file_util.h"
9 #include "base/strings/string_split.h"
10 #include "tools/gn/commands.h"
11 #include "tools/gn/filesystem_utils.h"
12 #include "tools/gn/input_file.h"
13 #include "tools/gn/parser.h"
14 #include "tools/gn/scheduler.h"
15 #include "tools/gn/setup.h"
16 #include "tools/gn/source_file.h"
17 #include "tools/gn/tokenizer.h"
21 const char kSwitchDryRun
[] = "dry-run";
22 const char kSwitchDumpTree
[] = "dump-tree";
23 const char kSwitchInPlace
[] = "in-place";
24 const char kSwitchStdin
[] = "stdin";
26 const char kFormat
[] = "format";
27 const char kFormat_HelpShort
[] =
28 "format: Format .gn file.";
29 const char kFormat_Help
[] =
30 "gn format [--dump-tree] [--in-place] [--stdin] BUILD.gn\n"
32 " Formats .gn file to a standard format.\n"
36 " Does not change or output anything, but sets the process exit code\n"
37 " based on whether output would be different than what's on disk.\n"
38 " This is useful for presubmit/lint-type checks.\n"
39 " - Exit code 0: successful format, matches on disk.\n"
40 " - Exit code 1: general failure (parse error, etc.)\n"
41 " - Exit code 2: successful format, but differs from on disk.\n"
44 " For debugging only, dumps the parse tree.\n"
47 " Instead of writing the formatted file to stdout, replace the input\n"
48 " file with the formatted output. If no reformatting is required,\n"
49 " the input file will not be touched, and nothing printed.\n"
52 " Read input from stdin (and write to stdout). Not compatible with\n"
53 " --in-place of course.\n"
56 " gn format //some/BUILD.gn\n"
57 " gn format some\\BUILD.gn\n"
58 " gn format /abspath/some/BUILD.gn\n"
59 " gn format --stdin\n";
63 const int kIndentSize
= 2;
64 const int kMaximumWidth
= 80;
66 const int kPenaltyLineBreak
= 500;
67 const int kPenaltyHorizontalSeparation
= 100;
68 const int kPenaltyExcess
= 10000;
69 const int kPenaltyBrokenLineOnOneLiner
= 5000;
82 int CountLines(const std::string
& str
) {
83 return static_cast<int>(base::SplitStringPiece(
84 str
, "\n", base::KEEP_WHITESPACE
, base::SPLIT_WANT_ALL
).size());
92 void Block(const ParseNode
* file
);
94 std::string
String() const { return output_
; }
97 // Format a list of values using the given style.
101 kSequenceStyleBracedBlock
,
105 Metrics() : first_length(-1), longest_length(-1), multiline(false) {}
112 void Print(base::StringPiece str
);
114 // Add the current margin (as spaces) to the output.
117 void TrimAndPrintToken(const Token
& token
);
119 // End the current line, flushing end of line comments.
122 // Remove trailing spaces from the current line.
125 // Whether there's a blank separator line at the current position.
126 bool HaveBlankLine();
128 // Flag assignments to sources, deps, etc. to make their RHSs multiline.
129 void AnnotatePreferredMultilineAssignment(const BinaryOpNode
* binop
);
131 // Alphabetically a list on the RHS if the LHS is 'sources'.
132 void SortIfSources(const BinaryOpNode
* binop
);
134 // Heuristics to decide if there should be a blank line added between two
135 // items. For various "small" items, it doesn't look nice if there's too much
136 // vertical whitespace added.
137 bool ShouldAddBlankLineInBetween(const ParseNode
* a
, const ParseNode
* b
);
139 // Get the 0-based x position on the current line.
140 int CurrentColumn() const;
142 // Get the current line in the output;
143 int CurrentLine() const;
145 // Adds an opening ( if prec is less than the outers (to maintain evalution
146 // order for a subexpression). If an opening paren is emitted, *parenthesized
147 // will be set so it can be closed at the end of the expression.
148 void AddParen(int prec
, int outer_prec
, bool* parenthesized
);
150 // Print the expression to the output buffer. Returns the type of element
151 // added to the output. The value of outer_prec gives the precedence of the
152 // operator outside this Expr. If that operator binds tighter than root's,
153 // Expr must introduce parentheses.
154 int Expr(const ParseNode
* root
, int outer_prec
, const std::string
& suffix
);
156 // Generic penalties for exceeding maximum width, adding more lines, etc.
157 int AssessPenalty(const std::string
& output
);
159 // Tests if any lines exceed the maximum width.
160 bool ExceedsMaximumWidth(const std::string
& output
);
162 // Format a list of values using the given style.
163 // |end| holds any trailing comments to be printed just before the closing
165 template <class PARSENODE
> // Just for const covariance.
166 void Sequence(SequenceStyle style
,
167 const std::vector
<PARSENODE
*>& list
,
168 const ParseNode
* end
,
169 bool force_multiline
);
171 // Returns the penalty.
172 int FunctionCall(const FunctionCallNode
* func_call
,
173 const std::string
& suffix
);
175 // Create a clone of this Printer in a similar state (other than the output,
176 // but including margins, etc.) to be used for dry run measurements.
177 void InitializeSub(Printer
* sub
);
179 template <class PARSENODE
>
180 bool ListWillBeMultiline(const std::vector
<PARSENODE
*>& list
,
181 const ParseNode
* end
);
183 std::string output_
; // Output buffer.
184 std::vector
<Token
> comments_
; // Pending end-of-line comments.
185 int margin() const { return stack_
.back().margin
; }
188 int GetPenaltyForLineBreak() const {
189 return penalty_depth_
* kPenaltyLineBreak
;
195 continuation_requires_indent(false),
196 parent_is_boolean_or(false) {}
197 IndentState(int margin
,
198 bool continuation_requires_indent
,
199 bool parent_is_boolean_or
)
201 continuation_requires_indent(continuation_requires_indent
),
202 parent_is_boolean_or(parent_is_boolean_or
) {}
204 // The left margin (number of spaces).
207 bool continuation_requires_indent
;
209 bool parent_is_boolean_or
;
211 // Stack used to track
212 std::vector
<IndentState
> stack_
;
214 // Gives the precedence for operators in a BinaryOpNode.
215 std::map
<base::StringPiece
, Precedence
> precedence_
;
217 DISALLOW_COPY_AND_ASSIGN(Printer
);
220 Printer::Printer() : penalty_depth_(0) {
221 output_
.reserve(100 << 10);
222 precedence_
["="] = kPrecedenceAssign
;
223 precedence_
["+="] = kPrecedenceAssign
;
224 precedence_
["-="] = kPrecedenceAssign
;
225 precedence_
["||"] = kPrecedenceOr
;
226 precedence_
["&&"] = kPrecedenceAnd
;
227 precedence_
["<"] = kPrecedenceCompare
;
228 precedence_
[">"] = kPrecedenceCompare
;
229 precedence_
["=="] = kPrecedenceCompare
;
230 precedence_
["!="] = kPrecedenceCompare
;
231 precedence_
["<="] = kPrecedenceCompare
;
232 precedence_
[">="] = kPrecedenceCompare
;
233 precedence_
["+"] = kPrecedenceAdd
;
234 precedence_
["-"] = kPrecedenceAdd
;
235 precedence_
["!"] = kPrecedenceUnary
;
236 stack_
.push_back(IndentState());
239 Printer::~Printer() {
242 void Printer::Print(base::StringPiece str
) {
243 str
.AppendToString(&output_
);
246 void Printer::PrintMargin() {
247 output_
+= std::string(margin(), ' ');
250 void Printer::TrimAndPrintToken(const Token
& token
) {
252 TrimWhitespaceASCII(token
.value().as_string(), base::TRIM_ALL
, &trimmed
);
256 void Printer::Newline() {
257 if (!comments_
.empty()) {
259 // Save the margin, and temporarily set it to where the first comment
260 // starts so that multiple suffix comments are vertically aligned. This
261 // will need to be fancier once we enforce 80 col.
262 stack_
.push_back(IndentState(CurrentColumn(), false, false));
264 for (const auto& c
: comments_
) {
270 TrimAndPrintToken(c
);
281 void Printer::Trim() {
282 size_t n
= output_
.size();
283 while (n
> 0 && output_
[n
- 1] == ' ')
288 bool Printer::HaveBlankLine() {
289 size_t n
= output_
.size();
290 while (n
> 0 && output_
[n
- 1] == ' ')
292 return n
> 2 && output_
[n
- 1] == '\n' && output_
[n
- 2] == '\n';
295 void Printer::AnnotatePreferredMultilineAssignment(const BinaryOpNode
* binop
) {
296 const IdentifierNode
* ident
= binop
->left()->AsIdentifier();
297 const ListNode
* list
= binop
->right()->AsList();
298 // This is somewhat arbitrary, but we include the 'deps'- and 'sources'-like
299 // things, but not flags things.
300 if (binop
->op().value() == "=" && ident
&& list
) {
301 const base::StringPiece lhs
= ident
->value().value();
302 if (lhs
== "data" || lhs
== "datadeps" || lhs
== "data_deps" ||
303 lhs
== "deps" || lhs
== "inputs" || lhs
== "outputs" ||
304 lhs
== "public" || lhs
== "public_deps" || lhs
== "sources") {
305 const_cast<ListNode
*>(list
)->set_prefer_multiline(true);
310 void Printer::SortIfSources(const BinaryOpNode
* binop
) {
311 const IdentifierNode
* ident
= binop
->left()->AsIdentifier();
312 const ListNode
* list
= binop
->right()->AsList();
313 // TODO(scottmg): Sort more than 'sources'?
314 if ((binop
->op().value() == "=" || binop
->op().value() == "+=" ||
315 binop
->op().value() == "-=") &&
317 const base::StringPiece lhs
= ident
->value().value();
318 if (lhs
== "sources")
319 const_cast<ListNode
*>(list
)->SortAsStringsList();
324 bool Printer::ShouldAddBlankLineInBetween(const ParseNode
* a
,
325 const ParseNode
* b
) {
326 LocationRange a_range
= a
->GetRange();
327 LocationRange b_range
= b
->GetRange();
328 // If they're already separated by 1 or more lines, then we want to keep a
330 return (b_range
.begin().line_number() > a_range
.end().line_number() + 1) ||
331 // Always put a blank line before a block comment.
335 int Printer::CurrentColumn() const {
337 while (n
< static_cast<int>(output_
.size()) &&
338 output_
[output_
.size() - 1 - n
] != '\n') {
344 int Printer::CurrentLine() const {
346 for (const char* p
= output_
.c_str(); (p
= strchr(p
, '\n')) != nullptr;) {
353 void Printer::Block(const ParseNode
* root
) {
354 const BlockNode
* block
= root
->AsBlock();
356 if (block
->comments()) {
357 for (const auto& c
: block
->comments()->before()) {
358 TrimAndPrintToken(c
);
364 for (const auto& stmt
: block
->statements()) {
365 Expr(stmt
, kPrecedenceLowest
, std::string());
367 if (stmt
->comments()) {
368 // Why are before() not printed here too? before() are handled inside
369 // Expr(), as are suffix() which are queued to the next Newline().
370 // However, because it's a general expression handler, it doesn't insert
371 // the newline itself, which only happens between block statements. So,
372 // the after are handled explicitly here.
373 for (const auto& c
: stmt
->comments()->after()) {
374 TrimAndPrintToken(c
);
378 if (i
< block
->statements().size() - 1 &&
379 (ShouldAddBlankLineInBetween(block
->statements()[i
],
380 block
->statements()[i
+ 1]))) {
386 if (block
->comments()) {
387 for (const auto& c
: block
->comments()->after()) {
388 TrimAndPrintToken(c
);
394 int Printer::AssessPenalty(const std::string
& output
) {
396 std::vector
<std::string
> lines
= base::SplitString(
397 output
, "\n", base::KEEP_WHITESPACE
, base::SPLIT_WANT_ALL
);
398 penalty
+= static_cast<int>(lines
.size() - 1) * GetPenaltyForLineBreak();
399 for (const auto& line
: lines
) {
400 if (line
.size() > kMaximumWidth
)
401 penalty
+= static_cast<int>(line
.size() - kMaximumWidth
) * kPenaltyExcess
;
406 bool Printer::ExceedsMaximumWidth(const std::string
& output
) {
407 for (const auto& line
: base::SplitString(
408 output
, "\n", base::KEEP_WHITESPACE
, base::SPLIT_WANT_ALL
)) {
409 if (line
.size() > kMaximumWidth
)
415 void Printer::AddParen(int prec
, int outer_prec
, bool* parenthesized
) {
416 if (prec
< outer_prec
) {
418 *parenthesized
= true;
422 int Printer::Expr(const ParseNode
* root
,
424 const std::string
& suffix
) {
425 std::string at_end
= suffix
;
429 if (root
->comments()) {
430 if (!root
->comments()->before().empty()) {
432 // If there's already other text on the line, start a new line.
433 if (CurrentColumn() > 0)
435 // We're printing a line comment, so we need to be at the current margin.
437 for (const auto& c
: root
->comments()->before()) {
438 TrimAndPrintToken(c
);
444 bool parenthesized
= false;
446 if (const AccessorNode
* accessor
= root
->AsAccessor()) {
447 AddParen(kPrecedenceSuffix
, outer_prec
, &parenthesized
);
448 Print(accessor
->base().value());
449 if (accessor
->member()) {
451 Expr(accessor
->member(), kPrecedenceLowest
, std::string());
453 CHECK(accessor
->index());
455 Expr(accessor
->index(), kPrecedenceLowest
, "]");
457 } else if (const BinaryOpNode
* binop
= root
->AsBinaryOp()) {
458 CHECK(precedence_
.find(binop
->op().value()) != precedence_
.end());
459 AnnotatePreferredMultilineAssignment(binop
);
461 SortIfSources(binop
);
463 Precedence prec
= precedence_
[binop
->op().value()];
465 // Since binary operators format left-to-right, it is ok for the left side
466 // use the same operator without parentheses, so the left uses prec. For the
467 // same reason, the right side cannot reuse the same operator, or else "x +
468 // (y + z)" would format as "x + y + z" which means "(x + y) + z". So, treat
469 // the right expression as appearing one precedence level higher.
470 // However, because the source parens are not in the parse tree, as a
471 // special case for && and || we insert strictly-redundant-but-helpful-for-
472 // human-readers parentheses.
473 int prec_left
= prec
;
474 int prec_right
= prec
+ 1;
475 if (binop
->op().value() == "&&" && stack_
.back().parent_is_boolean_or
) {
477 parenthesized
= true;
479 AddParen(prec_left
, outer_prec
, &parenthesized
);
482 int start_line
= CurrentLine();
483 int start_column
= CurrentColumn();
484 bool is_assignment
= binop
->op().value() == "=" ||
485 binop
->op().value() == "+=" ||
486 binop
->op().value() == "-=";
487 // A sort of funny special case for the long lists that are common in .gn
488 // files, don't indent them + 4, even though they're just continuations when
489 // they're simple lists like "x = [ a, b, c, ... ]"
490 const ListNode
* right_as_list
= binop
->right()->AsList();
493 (!right_as_list
|| (!right_as_list
->prefer_multiline() &&
494 !ListWillBeMultiline(right_as_list
->contents(),
495 right_as_list
->End()))))
496 ? margin() + kIndentSize
* 2
498 if (stack_
.back().continuation_requires_indent
)
499 indent_column
+= kIndentSize
* 2;
501 stack_
.push_back(IndentState(indent_column
,
502 stack_
.back().continuation_requires_indent
,
503 binop
->op().value() == "||"));
505 InitializeSub(&sub_left
);
506 sub_left
.Expr(binop
->left(),
508 std::string(" ") + binop
->op().value().as_string());
509 bool left_is_multiline
= CountLines(sub_left
.String()) > 1;
510 // Avoid walking the whole left redundantly times (see timing of Format.046)
511 // so pull the output and comments from subprinter.
512 Print(sub_left
.String().substr(start_column
));
513 std::copy(sub_left
.comments_
.begin(),
514 sub_left
.comments_
.end(),
515 std::back_inserter(comments_
));
519 InitializeSub(&sub1
);
521 int penalty_current_line
=
522 sub1
.Expr(binop
->right(), prec_right
, std::string());
524 penalty_current_line
+= AssessPenalty(sub1
.String());
525 if (!is_assignment
&& left_is_multiline
) {
526 // In e.g. xxx + yyy, if xxx is already multiline, then we want a penalty
527 // for trying to continue as if this were one line.
528 penalty_current_line
+=
529 (CountLines(sub1
.String()) - 1) * kPenaltyBrokenLineOnOneLiner
;
532 // Break after operator.
534 InitializeSub(&sub2
);
536 int penalty_next_line
=
537 sub2
.Expr(binop
->right(), prec_right
, std::string());
539 penalty_next_line
+= AssessPenalty(sub2
.String());
541 // If in both cases it was forced past 80col, then we don't break to avoid
542 // breaking after '=' in the case of:
543 // variable = "... very long string ..."
544 // as breaking and indenting doesn't make things much more readable, even
545 // though there's less characters past the maximum width.
546 bool exceeds_maximum_either_way
= ExceedsMaximumWidth(sub1
.String()) &&
547 ExceedsMaximumWidth(sub2
.String());
549 if (penalty_current_line
< penalty_next_line
||
550 exceeds_maximum_either_way
) {
552 Expr(binop
->right(), prec_right
, std::string());
554 // Otherwise, put first argument and op, and indent next.
556 penalty
+= std::abs(CurrentColumn() - start_column
) *
557 kPenaltyHorizontalSeparation
;
558 Expr(binop
->right(), prec_right
, std::string());
561 penalty
+= (CurrentLine() - start_line
) * GetPenaltyForLineBreak();
562 } else if (const BlockNode
* block
= root
->AsBlock()) {
564 kSequenceStyleBracedBlock
, block
->statements(), block
->End(), false);
565 } else if (const ConditionNode
* condition
= root
->AsConditionNode()) {
567 // TODO(scottmg): The { needs to be included in the suffix here.
568 Expr(condition
->condition(), kPrecedenceLowest
, ") ");
569 Sequence(kSequenceStyleBracedBlock
,
570 condition
->if_true()->statements(),
571 condition
->if_true()->End(),
573 if (condition
->if_false()) {
575 // If it's a block it's a bare 'else', otherwise it's an 'else if'. See
576 // ConditionNode::Execute.
577 bool is_else_if
= condition
->if_false()->AsBlock() == nullptr;
579 Expr(condition
->if_false(), kPrecedenceLowest
, std::string());
581 Sequence(kSequenceStyleBracedBlock
,
582 condition
->if_false()->AsBlock()->statements(),
583 condition
->if_false()->AsBlock()->End(),
587 } else if (const FunctionCallNode
* func_call
= root
->AsFunctionCall()) {
588 penalty
+= FunctionCall(func_call
, at_end
);
590 } else if (const IdentifierNode
* identifier
= root
->AsIdentifier()) {
591 Print(identifier
->value().value());
592 } else if (const ListNode
* list
= root
->AsList()) {
593 bool force_multiline
=
594 list
->prefer_multiline() && !list
->contents().empty();
596 kSequenceStyleList
, list
->contents(), list
->End(), force_multiline
);
597 } else if (const LiteralNode
* literal
= root
->AsLiteral()) {
598 Print(literal
->value().value());
599 } else if (const UnaryOpNode
* unaryop
= root
->AsUnaryOp()) {
600 Print(unaryop
->op().value());
601 Expr(unaryop
->operand(), kPrecedenceUnary
, std::string());
602 } else if (const BlockCommentNode
* block_comment
= root
->AsBlockComment()) {
603 Print(block_comment
->comment().value());
604 } else if (const EndNode
* end
= root
->AsEnd()) {
605 Print(end
->value().value());
607 CHECK(false) << "Unhandled case in Expr.";
613 // Defer any end of line comment until we reach the newline.
614 if (root
->comments() && !root
->comments()->suffix().empty()) {
615 std::copy(root
->comments()->suffix().begin(),
616 root
->comments()->suffix().end(),
617 std::back_inserter(comments_
));
626 template <class PARSENODE
>
627 void Printer::Sequence(SequenceStyle style
,
628 const std::vector
<PARSENODE
*>& list
,
629 const ParseNode
* end
,
630 bool force_multiline
) {
631 if (style
== kSequenceStyleList
)
633 else if (style
== kSequenceStyleBracedBlock
)
636 if (style
== kSequenceStyleBlock
|| style
== kSequenceStyleBracedBlock
)
637 force_multiline
= true;
639 force_multiline
|= ListWillBeMultiline(list
, end
);
641 if (list
.size() == 0 && !force_multiline
) {
642 // No elements, and not forcing newlines, print nothing.
643 } else if (list
.size() == 1 && !force_multiline
) {
645 Expr(list
[0], kPrecedenceLowest
, std::string());
646 CHECK(!list
[0]->comments() || list
[0]->comments()->after().empty());
649 stack_
.push_back(IndentState(margin() + kIndentSize
,
650 style
== kSequenceStyleList
,
653 for (const auto& x
: list
) {
656 // - we're going to output some comments, and;
657 // - we haven't just started this multiline list, and;
658 // - there isn't already a blank line here;
660 if (i
!= 0 && x
->comments() && !x
->comments()->before().empty() &&
664 bool body_of_list
= i
< list
.size() - 1 || style
== kSequenceStyleList
;
666 body_of_list
&& (style
== kSequenceStyleList
&& !x
->AsBlockComment());
667 Expr(x
, kPrecedenceLowest
, want_comma
? "," : std::string());
668 CHECK(!x
->comments() || x
->comments()->after().empty());
670 if (i
< list
.size() - 1 &&
671 ShouldAddBlankLineInBetween(list
[i
], list
[i
+ 1]))
677 // Trailing comments.
678 if (end
->comments() && !end
->comments()->before().empty()) {
679 if (list
.size() >= 2)
681 for (const auto& c
: end
->comments()->before()) {
683 TrimAndPrintToken(c
);
690 // Defer any end of line comment until we reach the newline.
691 if (end
->comments() && !end
->comments()->suffix().empty()) {
692 std::copy(end
->comments()->suffix().begin(),
693 end
->comments()->suffix().end(),
694 std::back_inserter(comments_
));
698 if (style
== kSequenceStyleList
)
700 else if (style
== kSequenceStyleBracedBlock
)
704 int Printer::FunctionCall(const FunctionCallNode
* func_call
,
705 const std::string
& suffix
) {
706 int start_line
= CurrentLine();
707 int start_column
= CurrentColumn();
708 Print(func_call
->function().value());
711 bool have_block
= func_call
->block() != nullptr;
712 bool force_multiline
= false;
714 const std::vector
<const ParseNode
*>& list
= func_call
->args()->contents();
715 const ParseNode
* end
= func_call
->args()->End();
717 if (end
&& end
->comments() && !end
->comments()->before().empty())
718 force_multiline
= true;
720 // If there's before line comments, make sure we have a place to put them.
721 for (const auto& i
: list
) {
722 if (i
->comments() && !i
->comments()->before().empty())
723 force_multiline
= true;
726 // Calculate the penalties for 3 possible layouts:
727 // 1. all on same line;
728 // 2. starting on same line, broken at each comma but paren aligned;
729 // 3. broken to next line + 4, broken at each comma.
730 std::string terminator
= ")";
733 terminator
+= suffix
;
735 // Special case to make function calls of one arg taking a long list of
736 // boolean operators not indent.
737 bool continuation_requires_indent
=
738 list
.size() != 1 || !list
[0]->AsBinaryOp();
742 InitializeSub(&sub1
);
743 sub1
.stack_
.push_back(
744 IndentState(CurrentColumn(), continuation_requires_indent
, false));
745 int penalty_one_line
= 0;
746 for (size_t i
= 0; i
< list
.size(); ++i
) {
747 penalty_one_line
+= sub1
.Expr(list
[i
], kPrecedenceLowest
,
748 i
< list
.size() - 1 ? ", " : std::string());
750 sub1
.Print(terminator
);
751 penalty_one_line
+= AssessPenalty(sub1
.String());
752 // This extra penalty prevents a short second argument from being squeezed in
753 // after a first argument that went multiline (and instead preferring a
756 (CountLines(sub1
.String()) - 1) * kPenaltyBrokenLineOnOneLiner
;
758 // 2: Starting on same line, broken at commas.
760 InitializeSub(&sub2
);
761 sub2
.stack_
.push_back(
762 IndentState(CurrentColumn(), continuation_requires_indent
, false));
763 int penalty_multiline_start_same_line
= 0;
764 for (size_t i
= 0; i
< list
.size(); ++i
) {
765 penalty_multiline_start_same_line
+= sub2
.Expr(
766 list
[i
], kPrecedenceLowest
, i
< list
.size() - 1 ? "," : std::string());
767 if (i
< list
.size() - 1) {
771 sub2
.Print(terminator
);
772 penalty_multiline_start_same_line
+= AssessPenalty(sub2
.String());
774 // 3: Starting on next line, broken at commas.
776 InitializeSub(&sub3
);
777 sub3
.stack_
.push_back(IndentState(margin() + kIndentSize
* 2,
778 continuation_requires_indent
, false));
780 int penalty_multiline_start_next_line
= 0;
781 for (size_t i
= 0; i
< list
.size(); ++i
) {
783 penalty_multiline_start_next_line
+=
784 std::abs(sub3
.CurrentColumn() - start_column
) *
785 kPenaltyHorizontalSeparation
;
787 penalty_multiline_start_next_line
+= sub3
.Expr(
788 list
[i
], kPrecedenceLowest
, i
< list
.size() - 1 ? "," : std::string());
789 if (i
< list
.size() - 1) {
793 sub3
.Print(terminator
);
794 penalty_multiline_start_next_line
+= AssessPenalty(sub3
.String());
796 int penalty
= penalty_multiline_start_next_line
;
797 bool fits_on_current_line
= false;
798 if (penalty_one_line
< penalty_multiline_start_next_line
||
799 penalty_multiline_start_same_line
< penalty_multiline_start_next_line
) {
800 fits_on_current_line
= true;
801 penalty
= penalty_one_line
;
802 if (penalty_multiline_start_same_line
< penalty_one_line
) {
803 penalty
= penalty_multiline_start_same_line
;
804 force_multiline
= true;
807 force_multiline
= true;
810 if (list
.size() == 0 && !force_multiline
) {
811 // No elements, and not forcing newlines, print nothing.
813 if (penalty_multiline_start_next_line
< penalty_multiline_start_same_line
) {
814 stack_
.push_back(IndentState(margin() + kIndentSize
* 2,
815 continuation_requires_indent
,
820 IndentState(CurrentColumn(), continuation_requires_indent
, false));
823 for (size_t i
= 0; i
< list
.size(); ++i
) {
824 const auto& x
= list
[i
];
826 if (fits_on_current_line
&& !force_multiline
)
831 bool want_comma
= i
< list
.size() - 1 && !x
->AsBlockComment();
832 Expr(x
, kPrecedenceLowest
, want_comma
? "," : std::string());
833 CHECK(!x
->comments() || x
->comments()->after().empty());
834 if (i
< list
.size() - 1) {
840 // Trailing comments.
841 if (end
->comments() && !end
->comments()->before().empty()) {
844 for (const auto& c
: end
->comments()->before()) {
846 TrimAndPrintToken(c
);
853 // Defer any end of line comment until we reach the newline.
854 if (end
->comments() && !end
->comments()->suffix().empty()) {
855 std::copy(end
->comments()->suffix().begin(),
856 end
->comments()->suffix().end(), std::back_inserter(comments_
));
864 Sequence(kSequenceStyleBracedBlock
,
865 func_call
->block()->statements(),
866 func_call
->block()->End(),
869 return penalty
+ (CurrentLine() - start_line
) * GetPenaltyForLineBreak();
872 void Printer::InitializeSub(Printer
* sub
) {
873 sub
->stack_
= stack_
;
874 sub
->comments_
= comments_
;
875 sub
->penalty_depth_
= penalty_depth_
;
876 sub
->Print(std::string(CurrentColumn(), 'x'));
879 template <class PARSENODE
>
880 bool Printer::ListWillBeMultiline(const std::vector
<PARSENODE
*>& list
,
881 const ParseNode
* end
) {
885 if (end
&& end
->comments() && !end
->comments()->before().empty())
888 // If there's before line comments, make sure we have a place to put them.
889 for (const auto& i
: list
) {
890 if (i
->comments() && !i
->comments()->before().empty())
897 void DoFormat(const ParseNode
* root
, bool dump_tree
, std::string
* output
) {
899 std::ostringstream os
;
901 printf("----------------------\n");
902 printf("-- PARSE TREE --------\n");
903 printf("----------------------\n");
904 printf("%s", os
.str().c_str());
905 printf("----------------------\n");
909 *output
= pr
.String();
912 std::string
ReadStdin() {
913 static const int kBufferSize
= 256;
914 char buffer
[kBufferSize
];
917 char* input
= nullptr;
918 input
= fgets(buffer
, kBufferSize
, stdin
);
919 if (input
== nullptr && feof(stdin
))
921 int length
= static_cast<int>(strlen(buffer
));
925 result
+= std::string(buffer
, length
);
931 bool FormatFileToString(Setup
* setup
,
932 const SourceFile
& file
,
934 std::string
* output
) {
936 const ParseNode
* parse_node
=
937 setup
->scheduler().input_file_manager()->SyncLoadFile(
938 LocationRange(), &setup
->build_settings(), file
, &err
);
939 if (err
.has_error()) {
943 DoFormat(parse_node
, dump_tree
, output
);
947 bool FormatStringToString(const std::string
& input
,
949 std::string
* output
) {
950 SourceFile source_file
;
951 InputFile
file(source_file
);
952 file
.SetContents(input
);
955 std::vector
<Token
> tokens
= Tokenizer::Tokenize(&file
, &err
);
956 if (err
.has_error()) {
962 scoped_ptr
<ParseNode
> parse_node
= Parser::Parse(tokens
, &err
);
963 if (err
.has_error()) {
968 DoFormat(parse_node
.get(), dump_tree
, output
);
972 int RunFormat(const std::vector
<std::string
>& args
) {
974 base::CommandLine::ForCurrentProcess()->HasSwitch(kSwitchDryRun
);
976 base::CommandLine::ForCurrentProcess()->HasSwitch(kSwitchDumpTree
);
978 base::CommandLine::ForCurrentProcess()->HasSwitch(kSwitchStdin
);
980 base::CommandLine::ForCurrentProcess()->HasSwitch(kSwitchInPlace
);
983 // --dry-run only works with an actual file to compare to.
989 if (args
.size() != 0) {
990 Err(Location(), "Expecting no arguments when reading from stdin.\n")
994 std::string input
= ReadStdin();
996 if (!FormatStringToString(input
, dump_tree
, &output
))
998 printf("%s", output
.c_str());
1002 // TODO(scottmg): Eventually, this should be a list/spec of files, and they
1003 // should all be done in parallel.
1004 if (args
.size() != 1) {
1005 Err(Location(), "Expecting exactly one argument, see `gn help format`.\n")
1011 SourceDir source_dir
=
1012 SourceDirForCurrentDirectory(setup
.build_settings().root_path());
1015 SourceFile file
= source_dir
.ResolveRelativeFile(Value(nullptr, args
[0]),
1017 if (err
.has_error()) {
1018 err
.PrintToStdout();
1022 std::string output_string
;
1023 if (FormatFileToString(&setup
, file
, dump_tree
, &output_string
)) {
1025 base::FilePath to_write
= setup
.build_settings().GetFullPath(file
);
1026 std::string original_contents
;
1027 if (!base::ReadFileToString(to_write
, &original_contents
)) {
1028 Err(Location(), std::string("Couldn't read \"") +
1029 to_write
.AsUTF8Unsafe() +
1030 std::string("\" for comparison.")).PrintToStdout();
1034 return original_contents
== output_string
? 0 : 2;
1035 if (original_contents
!= output_string
) {
1036 if (base::WriteFile(to_write
,
1037 output_string
.data(),
1038 static_cast<int>(output_string
.size())) == -1) {
1040 std::string("Failed to write formatted output back to \"") +
1041 to_write
.AsUTF8Unsafe() + std::string("\".")).PrintToStdout();
1044 printf("Wrote formatted to '%s'.\n", to_write
.AsUTF8Unsafe().c_str());
1047 printf("%s", output_string
.c_str());
1054 } // namespace commands