blob: f87b6f19da03dbde0ef0732f9a816d086906e0ce [file] [log] [blame]
// Copyright 2017-2020 The Verible Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "common/formatting/unwrapped_line.h"
#include <algorithm>
#include <iostream>
#include <iterator>
#include <map>
#include <sstream>
#include <string>
#include <vector>
#include "absl/strings/str_cat.h"
#include "absl/strings/str_join.h"
#include "common/formatting/format_token.h"
#include "common/strings/display_utils.h"
#include "common/text/tree_utils.h"
#include "common/util/container_iterator_range.h"
#include "common/util/spacer.h"
namespace verible {
std::ostream& operator<<(std::ostream& stream, PartitionPolicyEnum p) {
switch (p) {
case PartitionPolicyEnum::kUninitialized:
return stream << "uninitialized";
case PartitionPolicyEnum::kAlwaysExpand:
return stream << "always-expand";
case PartitionPolicyEnum::kFitOnLineElseExpand:
return stream << "fit-else-expand";
case PartitionPolicyEnum::kTabularAlignment:
return stream << "tabular-alignment";
case PartitionPolicyEnum::kAlreadyFormatted:
return stream << "already-formatted";
case PartitionPolicyEnum::kInline:
return stream << "inline";
case PartitionPolicyEnum::kAppendFittingSubPartitions:
return stream << "append-fitting-sub-partitions";
case PartitionPolicyEnum::kJuxtaposition:
return stream << "juxtaposition";
case PartitionPolicyEnum::kStack:
return stream << "stack";
case PartitionPolicyEnum::kWrap:
return stream << "wrap";
case PartitionPolicyEnum::kJuxtapositionOrIndentedStack:
return stream << "juxtaposition-or-indented-stack";
}
LOG(FATAL) << "Unknown partition policy " << int(p);
}
static void TokenFormatter(std::string* out, const PreFormatToken& token,
bool verbose) {
if (verbose) {
std::ostringstream oss;
token.before.CompactNotation(oss);
absl::StrAppend(out, oss.str());
}
absl::StrAppend(out, token.Text());
}
void UnwrappedLine::SetIndentationSpaces(int spaces) {
CHECK_GE(spaces, 0);
indentation_spaces_ = spaces;
}
void UnwrappedLine::DefaultOriginPrinter(std::ostream& stream,
const verible::Symbol* symbol) {
static constexpr int kContextLimit = 25;
stream << '"' << AutoTruncate{StringSpanOfSymbol(*symbol), kContextLimit}
<< '"';
}
std::ostream* UnwrappedLine::AsCode(
std::ostream* stream, bool verbose,
const OriginPrinterFunction& origin_printer) const {
*stream << Spacer(indentation_spaces_, kIndentationMarker) << '['
<< absl::StrJoin(tokens_, " ",
[=](std::string* out, const PreFormatToken& token) {
TokenFormatter(out, token, verbose);
})
<< "], policy: " << partition_policy_;
if (origin_ != nullptr) {
*stream << ", (origin: ";
origin_printer(*stream, origin_);
*stream << ")";
}
return stream;
}
std::ostream& operator<<(std::ostream& stream, const UnwrappedLine& line) {
return *line.AsCode(&stream);
}
FormattedExcerpt::FormattedExcerpt(const UnwrappedLine& uwline)
: indentation_spaces_(uwline.IndentationSpaces()) {
tokens_.reserve(uwline.Size());
// Convert working PreFormatTokens (computed from wrap optimization) into
// decision-bound representation.
const auto range = uwline.TokensRange();
std::transform(range.begin(), range.end(), std::back_inserter(tokens_),
[](const PreFormatToken& t) { return FormattedToken(t); });
}
std::ostream& FormattedExcerpt::FormattedText(
std::ostream& stream, bool indent,
const std::function<bool(const TokenInfo&)>& include_token_p) const {
if (tokens_.empty()) return stream;
// Let caller print the preceding/trailing newline.
if (indent) {
if (tokens_.front().before.action != SpacingDecision::Preserve) {
stream << Spacer(IndentationSpaces());
}
}
// We do not want the indentation before the first token, if it was
// already handled separately.
const auto& front = tokens_.front();
if (include_token_p(*front.token)) {
VLOG(2) << "action: " << front.before.action;
switch (front.before.action) {
case SpacingDecision::Align:
// When aligning tokens, the first token might be further indented.
stream << Spacer(front.before.spaces) << front.token->text();
break;
default:
stream << front.token->text();
}
}
for (const auto& ftoken :
verible::make_range(tokens_.begin() + 1, tokens_.end())) {
if (include_token_p(*ftoken.token)) stream << ftoken;
}
return stream;
}
std::ostream& operator<<(std::ostream& stream,
const FormattedExcerpt& excerpt) {
return excerpt.FormattedText(stream, true);
}
std::string FormattedExcerpt::Render() const {
std::ostringstream stream;
FormattedText(stream, true);
return stream.str();
}
} // namespace verible