Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(925)

Side by Side Diff: lib/src/line_writer.dart

Issue 1000513002: Tweak formatting rules. Fix #211. (Closed) Base URL: https://github.com/dart-lang/dart_style.git@master
Patch Set: Update changelog. Created 5 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « lib/src/chunk.dart ('k') | lib/src/multisplit.dart » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file
2 // for details. All rights reserved. Use of this source code is governed by a 2 // for details. All rights reserved. Use of this source code is governed by a
3 // BSD-style license that can be found in the LICENSE file. 3 // BSD-style license that can be found in the LICENSE file.
4 4
5 library dart_style.src.source_writer; 5 library dart_style.src.source_writer;
6 6
7 import 'dart_formatter.dart'; 7 import 'dart_formatter.dart';
8 import 'chunk.dart'; 8 import 'chunk.dart';
9 import 'debug.dart'; 9 import 'debug.dart';
10 import 'line_splitter.dart'; 10 import 'line_splitter.dart';
(...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after
67 /// 67 ///
68 /// Collections can also contain function expressions, which have blocks which 68 /// Collections can also contain function expressions, which have blocks which
69 /// in turn force a newline in the middle of the collection. When that 69 /// in turn force a newline in the middle of the collection. When that
70 /// happens, we need to force all surrounding collections to be multi-line. 70 /// happens, we need to force all surrounding collections to be multi-line.
71 /// This tracks them so we can do that. 71 /// This tracks them so we can do that.
72 final _multisplits = <Multisplit>[]; 72 final _multisplits = <Multisplit>[];
73 73
74 /// The nested stack of spans that are currently being written. 74 /// The nested stack of spans that are currently being written.
75 final _openSpans = <Span>[]; 75 final _openSpans = <Span>[];
76 76
77 /// All of the spans that have been created, open and closed. 77 /// All of the spans that have been created and closed.
78 final _spans = <Span>[]; 78 final _spans = <Span>[];
79 79
80 /// The current indentation and nesting levels. 80 /// The current indentation and nesting levels.
81 /// 81 ///
82 /// This is tracked as a stack of numbers. Each element in the stack 82 /// This is tracked as a stack of numbers. Each element in the stack
83 /// represents a level of statement indentation. The number of the element is 83 /// represents a level of statement indentation. The number of the element is
84 /// the current expression nesting depth for that statement. 84 /// the current expression nesting depth for that statement.
85 /// 85 ///
86 /// It's stored as a stack because expressions may contain statements which 86 /// It's stored as a stack because expressions may contain statements which
87 /// in turn contain other expressions. The nesting level of the inner 87 /// in turn contain other expressions. The nesting level of the inner
(...skipping 276 matching lines...) Expand 10 before | Expand all | Expand 10 after
364 /// Starts a new span with [cost]. 364 /// Starts a new span with [cost].
365 /// 365 ///
366 /// Each call to this needs a later matching call to [endSpan]. 366 /// Each call to this needs a later matching call to [endSpan].
367 void startSpan([int cost = Cost.normal]) { 367 void startSpan([int cost = Cost.normal]) {
368 _openSpans.add(new Span(_currentChunkIndex, cost)); 368 _openSpans.add(new Span(_currentChunkIndex, cost));
369 } 369 }
370 370
371 /// Ends the innermost span. 371 /// Ends the innermost span.
372 void endSpan() { 372 void endSpan() {
373 var span = _openSpans.removeLast(); 373 var span = _openSpans.removeLast();
374
375 // If the span was discarded while it was still open, just forget about it.
376 if (span == null) return;
377
374 span.close(_currentChunkIndex); 378 span.close(_currentChunkIndex);
375 379
376 // A span that just covers a single chunk can't be split anyway. 380 // A span that just covers a single chunk can't be split anyway.
377 if (span.start == span.end) return; 381 if (span.start == span.end) return;
378 _spans.add(span); 382 _spans.add(span);
379 } 383 }
380 384
381 /// Starts a new [Multisplit]. 385 /// Starts a new [Multisplit].
382 /// 386 ///
383 /// Returns the [SplitParam] for the multisplit. 387 /// Returns the [SplitParam] for the multisplit.
384 SplitParam startMultisplit({bool separable}) { 388 SplitParam startMultisplit({bool separable, int cost}) {
385 var multisplit = new Multisplit(_currentChunkIndex, separable: separable); 389 var multisplit = new Multisplit(_currentChunkIndex,
390 separable: separable, cost: cost);
386 _multisplits.add(multisplit); 391 _multisplits.add(multisplit);
387 392
388 return multisplit.param; 393 return multisplit.param;
389 } 394 }
390 395
391 /// Adds a new split point for the current innermost [Multisplit]. 396 /// Adds a new split point for the current innermost [Multisplit].
392 /// 397 ///
393 /// If [space] is `true`, the chunk will include a space when unsplit. If 398 /// If [space] is `true`, the chunk will include a space when unsplit. If
394 /// [nest] is `true`, then this split will take into account expression 399 /// [nest] is `true`, then this split will take into account expression
395 /// nesting. Otherwise, it will not. Collections do not follow expression 400 /// nesting. Otherwise, it will not. Collections do not follow expression
(...skipping 20 matching lines...) Expand all
416 /// Pre-emptively forces all of the multisplits to become hard splits. 421 /// Pre-emptively forces all of the multisplits to become hard splits.
417 /// 422 ///
418 /// This is called by [SourceVisitor] when it can determine that a multisplit 423 /// This is called by [SourceVisitor] when it can determine that a multisplit
419 /// will never be satisfied. Turning it into hard splits lets the writer 424 /// will never be satisfied. Turning it into hard splits lets the writer
420 /// break the output into smaller pieces for the line splitter, which helps 425 /// break the output into smaller pieces for the line splitter, which helps
421 /// performance and avoids failing on very large input. 426 /// performance and avoids failing on very large input.
422 /// 427 ///
423 /// In particular, it's easy for the visitor to know that collections with a 428 /// In particular, it's easy for the visitor to know that collections with a
424 /// large number of items must split. Doing that early avoids crashing the 429 /// large number of items must split. Doing that early avoids crashing the
425 /// splitter when it tries to recurse on huge collection literals. 430 /// splitter when it tries to recurse on huge collection literals.
426 void preemptMultisplits() => _splitMultisplits(); 431 void preemptMultisplits() => _handleHardSplit();
427 432
428 /// Increases the level of expression nesting. 433 /// Increases the level of expression nesting.
429 /// 434 ///
430 /// Expressions that are more nested will get increased indentation when split 435 /// Expressions that are more nested will get increased indentation when split
431 /// if the previous line has a lower level of nesting. 436 /// if the previous line has a lower level of nesting.
432 void nestExpression() { 437 void nestExpression() {
433 if (_pendingNesting != null) { 438 if (_pendingNesting != null) {
434 _pendingNesting++; 439 _pendingNesting++;
435 } else { 440 } else {
436 _pendingNesting = _nesting + 1; 441 _pendingNesting = _nesting + 1;
(...skipping 178 matching lines...) Expand 10 before | Expand all | Expand 10 after
615 } 620 }
616 621
617 /// Ends the current chunk (if any) with the given split information. 622 /// Ends the current chunk (if any) with the given split information.
618 void _writeSplit(int indent, int nesting, SplitParam param, 623 void _writeSplit(int indent, int nesting, SplitParam param,
619 {bool isDouble, bool spaceWhenUnsplit}) { 624 {bool isDouble, bool spaceWhenUnsplit}) {
620 if (_chunks.isEmpty) return; 625 if (_chunks.isEmpty) return;
621 626
622 _chunks.last.applySplit(indent, nesting, param, 627 _chunks.last.applySplit(indent, nesting, param,
623 isDouble: isDouble, spaceWhenUnsplit: spaceWhenUnsplit); 628 isDouble: isDouble, spaceWhenUnsplit: spaceWhenUnsplit);
624 629
625 if (_chunks.last.isHardSplit) _splitMultisplits(); 630 if (_chunks.last.isHardSplit) _handleHardSplit();
626 } 631 }
627 632
628 /// Writes [text] to either the current chunk or a new one if the current 633 /// Writes [text] to either the current chunk or a new one if the current
629 /// chunk is complete. 634 /// chunk is complete.
630 void _writeText(String text) { 635 void _writeText(String text) {
631 if (_chunks.isEmpty) { 636 if (_chunks.isEmpty) {
632 _chunks.add(new Chunk(text)); 637 _chunks.add(new Chunk(text));
633 } else if (_chunks.last.canAddText) { 638 } else if (_chunks.last.canAddText) {
634 _chunks.last.appendText(text); 639 _chunks.last.appendText(text);
635 } else { 640 } else {
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after
670 _beginningIndent = split.indent; 675 _beginningIndent = split.indent;
671 676
672 return true; 677 return true;
673 } 678 }
674 679
675 /// Hands off the first [length] chunks to the [LineSplitter] as a single 680 /// Hands off the first [length] chunks to the [LineSplitter] as a single
676 /// logical line to be split. 681 /// logical line to be split.
677 void _completeLine(int length) { 682 void _completeLine(int length) {
678 assert(_chunks.isNotEmpty); 683 assert(_chunks.isNotEmpty);
679 684
680 if (debugFormatter) {
681 dumpChunks(_chunks.take(length).toList());
682 print(_spans.join("\n"));
683 }
684
685 // Write the newlines required by the previous line. 685 // Write the newlines required by the previous line.
686 for (var i = 0; i < _bufferedNewlines; i++) { 686 for (var i = 0; i < _bufferedNewlines; i++) {
687 _buffer.write(_formatter.lineEnding); 687 _buffer.write(_formatter.lineEnding);
688 } 688 }
689 689
690 // If we aren't completing the entire set of chunks, get the subset that we 690 // If we aren't completing the entire set of chunks, get the subset that we
691 // are completing. 691 // are completing.
692 var chunks = _chunks; 692 var chunks = _chunks;
693 var spans = _spans; 693 var spans = _spans;
694 694
695 if (length < _chunks.length) { 695 if (length < _chunks.length) {
696 chunks = chunks.take(length).toList(); 696 chunks = chunks.take(length).toList();
697 spans = spans.where((span) => span.start <= length).toList(); 697 spans = spans.where((span) => span.start <= length).toList();
698 } 698 }
699 699
700 if (debugFormatter) {
701 dumpChunks(chunks);
702 print(spans.join("\n"));
703 }
704
700 var splitter = new LineSplitter(_formatter.lineEnding, _formatter.pageWidth, 705 var splitter = new LineSplitter(_formatter.lineEnding, _formatter.pageWidth,
701 chunks, spans, _beginningIndent); 706 chunks, spans, _beginningIndent);
702 var selection = splitter.apply(_buffer); 707 var selection = splitter.apply(_buffer);
703 708
704 if (selection[0] != null) _selectionStart = selection[0]; 709 if (selection[0] != null) _selectionStart = selection[0];
705 if (selection[1] != null) _selectionLength = selection[1] - _selectionStart; 710 if (selection[1] != null) _selectionLength = selection[1] - _selectionStart;
706 } 711 }
707 712
708 /// Handles multisplits when a hard line occurs. 713 /// Handles open multisplits and spans when a hard line occurs.
709 /// 714 ///
710 /// Any active separable multisplits will get split in two at this point. 715 /// Any active separable multisplits will get split in two at this point.
711 /// Other multisplits are forced into the "hard" state. All of their previous 716 /// Other multisplits are forced into the "hard" state. All of their previous
712 /// splits are turned into explicit hard splits and any new splits for that 717 /// splits are turned into explicit hard splits and any new splits for that
713 /// multisplit become hard splits too. 718 /// multisplit become hard splits too.
714 void _splitMultisplits() { 719 ///
720 /// All open spans get discarded since they will never be satisfied.
721 void _handleHardSplit() {
722 // Discard all open spans. We don't remove them from the stack so that we
723 // can still correctly count later calls to endSpan().
724 for (var i = 0; i < _openSpans.length; i++) {
725 _openSpans[i] = null;
726 }
727
715 if (_multisplits.isEmpty) return; 728 if (_multisplits.isEmpty) return;
716 729
717 var splitParams = new Set(); 730 var splitParams = new Set();
718 731
719 // Add [param] and the transitive closure of its implied params to 732 // Add [param] and the transitive closure of its implied params to
720 // [splitParams]. 733 // [splitParams].
721 traverseParams(param) { 734 traverseParams(param) {
722 splitParams.add(param); 735 splitParams.add(param);
723 736
724 // Traverse the tree of implied params. 737 // Traverse the tree of implied params.
(...skipping 22 matching lines...) Expand all
747 // the loop counter. 760 // the loop counter.
748 if (_checkForCompleteLine(i + 1)) i = -1; 761 if (_checkForCompleteLine(i + 1)) i = -1;
749 } else { 762 } else {
750 // If the chunk isn't hardened, but implies something that is, we can 763 // If the chunk isn't hardened, but implies something that is, we can
751 // discard the implication since it is always satisfied now. 764 // discard the implication since it is always satisfied now.
752 chunk.param.implies.removeWhere(splitParams.contains); 765 chunk.param.implies.removeWhere(splitParams.contains);
753 } 766 }
754 } 767 }
755 } 768 }
756 } 769 }
OLDNEW
« no previous file with comments | « lib/src/chunk.dart ('k') | lib/src/multisplit.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698