void _calculateCost()

in lib/src/line_splitting/solve_state.dart [313:422]


  void _calculateCost() {
    // Calculate the length of each line and apply the cost of any spans that
    // get split.
    var cost = 0;
    var length = _splitter.firstLineIndent;

    // The unbound rules in use by the current line. This will be null after
    // the first long line has completed.
    var foundOverflowRules = false;
    var start = 0;

    void endLine(int end) {
      // Track lines that went over the length. It is only rules contained in
      // long lines that we may want to split.
      if (length > _splitter.writer.pageWidth) {
        _overflowChars += length - _splitter.writer.pageWidth;

        // Only try rules that are in the first long line, since we know at
        // least one of them *will* be split.
        if (!foundOverflowRules) {
          for (var i = start; i < end; i++) {
            if (_addLiveRules(_splitter.chunks[i].rule)) {
              foundOverflowRules = true;
            }
          }
        }
      }

      start = end;
    }

    // The set of spans that contain chunks that ended up splitting. We store
    // these in a set so a span's cost doesn't get double-counted if more than
    // one split occurs in it.
    var splitSpans = <Span>{};

    // The nesting level of the chunk that ended the previous line.
    NestingLevel? previousNesting;

    for (var i = 0; i < _splitter.chunks.length; i++) {
      var chunk = _splitter.chunks[i];

      length += chunk.text.length;

      // Ignore the split after the last chunk.
      if (i == _splitter.chunks.length - 1) break;

      if (_splits.shouldSplitAt(i)) {
        endLine(i);

        splitSpans.addAll(chunk.spans);

        // Include the cost of the nested block.
        if (chunk.isBlock) {
          cost +=
              _splitter.writer.formatBlock(chunk, _splits.getColumn(i)).cost;
        }

        // Do not allow sequential lines to have the same indentation but for
        // different reasons. In other words, don't allow different expressions
        // to claim the same nesting level on subsequent lines.
        //
        // A contrived example would be:
        //
        //     function(inner(
        //         argument), second(
        //         another);
        //
        // For the most part, we prevent this by the constraints on splits.
        // For example, the above can't happen because the split before
        // "argument", forces the split before "second".
        //
        // But there are a couple of squirrely cases where it's hard to prevent
        // by construction. Instead, this outlaws it by penalizing it very
        // heavily if it happens to get this far.
        var totalIndent = chunk.nesting!.totalUsedIndent;
        if (previousNesting != null &&
            totalIndent != 0 &&
            totalIndent == previousNesting.totalUsedIndent &&
            !identical(chunk.nesting, previousNesting)) {
          _overflowChars += 10000;
        }

        previousNesting = chunk.nesting;

        // Start the new line.
        length = _splits.getColumn(i);
      } else {
        if (chunk.spaceWhenUnsplit) length++;

        // Include the nested block inline, if any.
        length += chunk.unsplitBlockLength;
      }
    }

    // Add the costs for the rules that have any splits.
    _ruleValues.forEach(_splitter.rules, (rule, value) {
      if (value != Rule.unsplit) cost += rule.cost;
    });

    // Add the costs for the spans containing splits.
    for (var span in splitSpans) {
      cost += span.cost;
    }

    // Finish the last line.
    endLine(_splitter.chunks.length);

    _splits.setCost(cost);
  }