message: Wrap: Support for token-level wrapping and hanging indentation
diff: @@ -634,15 +634,20 @@ class LayoutFunctionFactory {
  // Joins layouts horizontally and wraps them into multiple lines to stay under
  // column limit. Kind of like a words in a paragraph.
  - LayoutFunction Wrap(std::initializer_list<LayoutFunction> lfs) const {
  - return Wrap(lfs.begin(), lfs.end());
  + LayoutFunction Wrap(std::initializer_list<LayoutFunction> lfs,
  + bool use_tokens_break_penalty = false,
  + int hanging_indentation = 0) const {
  + return Wrap(lfs.begin(), lfs.end(), use_tokens_break_penalty,
  + hanging_indentation);
  }
  // See Wrap(std::initializer_list<LayoutFunction> lfs).
  //
  // Iterator: iterator type that dereferences to LayoutFunction.
  template <class Iterator>
  - LayoutFunction Wrap(const Iterator begin, const Iterator end) const {
  + LayoutFunction Wrap(const Iterator begin, const Iterator end,
  + bool use_tokens_break_penalty = false,
  + int hanging_indentation = 0) const {
  static_assert(IsIteratorDereferencingTo<Iterator, LayoutFunction>,
  "Iterator's value type must be LayoutFunction.");
  @@ -653,23 +658,41 @@ class LayoutFunctionFactory {
  absl::FixedArray<LayoutFunction> results(lfs.size());
  - int size = lfs.size();
  + const int size = lfs.size();
  for (int i = size - 1; i >= 0; --i) {
  absl::FixedArray<LayoutFunction> results_i(size - i);
  LayoutFunction incremental = lfs[i];
  for (int j = i; j < size - 1; ++j) {
  results_i[j - i] = Stack({
  incremental,
  - results[j + 1],
  + (i == 0) ? Indent(results[j + 1], hanging_indentation)
  + : results[j + 1],
  });
  const auto& next_element = lfs[j + 1];
  + if (use_tokens_break_penalty) {
  + // Deprioritize token-level wrapping
  + // TODO(mglb): Find a better way to do this. This ratio has been
  + // chosen using only a few test cases.
  + const int wrapping_penalty = style_.over_column_limit_penalty;
  + const auto& second_layout = results[j + 1].front().layout;
  + const auto& first_line = second_layout.LeftmostDescendant()->Value();
  + const auto& first_token = first_line.TokensRange().front();
  + const int token_break_penalty = first_token.before.break_penalty;
  +
  + for (auto& segment : results_i[j - i])
  + segment.intercept += wrapping_penalty + token_break_penalty;
  + }
  - const auto layout_functions = {std::move(incremental), next_element};
  if (next_element.MustWrap())
  - incremental = Stack(layout_functions);
  + incremental = Stack({
  + std::move(incremental),
  + Indent(next_element, hanging_indentation),
  + });
  else
  - incremental = Juxtaposition(layout_functions);
  + // TODO(mglb): use Stack for invervals where lfs[j] is multiline (i.e.
  + // has any stack sublayouts)
  + incremental = Juxtaposition({std::move(incremental), next_element});
  }
  results_i.back() = std::move(incremental);
  