blob: 3f39513e2e484f99dc2148b2e8b2c9e35d21d3b0 [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.
#ifndef VERIBLE_COMMON_FORMATTING_UNWRAPPED_LINE_H_
#define VERIBLE_COMMON_FORMATTING_UNWRAPPED_LINE_H_
#include <iosfwd>
#include <string>
#include <vector>
#include "common/formatting/format_token.h"
#include "common/text/symbol.h"
namespace verible {
// Enumeration of partitioning choices at each node in the UnwrappedLine
// token range partition tree.
// TODO(fangism): It is forseeable that each language's formatter may have a
// different set of policies, this this might eventually have to move into
// language-specific implementation code.
enum class PartitionPolicyEnum {
// Denotes that no partition policy has been set.
kUninitialized,
// This partition exists solely just for grouping purposes.
// Always view subpartitions of node tagged with this, rather than whole range
// spanned by the subpartitions.
kAlwaysExpand,
// Collapse into one line if it doesn't exceed column limit.
kFitOnLineElseExpand,
// There's no kNeverExpand, because one would just not create the partition in
// the first place.
// This is where future formatting configuration policies could go:
// e.g. kOneItemPerLine, kCompactItems
// With this policy, coordinate the spacing of subpartitions like auto-sized
// columns that use space-padding to achieve vertical alignment.
kTabularAlignment,
// Signal that this unwrapped line (a direct child of a partition marked with
// kTabularAlignment) has been successfully aligned with spacing padded.
// In this case, do NOT bother to call SearchLineWraps or perform any other
// spacing/wrapping optimization.
// Reserved for setting only from align.cc.
kSuccessfullyAligned,
// Treats subpartitions as units, and appends them to the same line as
// long as they fit, else wrap them aligned to the position of the first
// element It uses first subpartition length to compute indentation spaces or
// FormatStyle.wrap_spaces when wrapping.
kAppendFittingSubPartitions,
};
std::ostream& operator<<(std::ostream&, PartitionPolicyEnum);
// An UnwrappedLine represents a partition of the input token stream that
// is an independent unit of work for other phases of formatting, such as
// line wrap optimization. It consists of a lightweight const_iterator range
// that can be easily grown without any copy-overhead.
class UnwrappedLine {
typedef FormatTokenRange::const_iterator token_iterator;
public:
enum {
kIndentationMarker = '>' // for readable debug printing
};
// Parameter d is the indentation level, and iterator b points to the first
// PreFormatToken spanned by this range, which is initially empty.
UnwrappedLine(int d, token_iterator b,
PartitionPolicyEnum p = PartitionPolicyEnum::kUninitialized)
: indentation_spaces_(d), tokens_(b, b), partition_policy_(p) {}
// Allow default construction for use in resize-able containers.
UnwrappedLine() = default;
UnwrappedLine(const UnwrappedLine&) = default;
UnwrappedLine(UnwrappedLine&&) = default;
UnwrappedLine& operator=(const UnwrappedLine&) = default;
UnwrappedLine& operator=(UnwrappedLine&&) = default;
// Extends PreFormatToken range spanned by this UnwrappedLine by one token at
// the back.
void SpanNextToken() { tokens_.extend_back(); }
// Extends PreFormatToken range spanned by this UnwrappedLine by one token at
// the front.
void SpanPrevToken() { tokens_.extend_front(); }
// Extends PreFormatToken range's lower bound to the given token (inclusive).
void SpanBackToToken(token_iterator iter) { tokens_.set_begin(iter); }
// Extends PreFormatToken range's upper bound up to the given token
// (exclusive).
void SpanUpToToken(token_iterator iter) { tokens_.set_end(iter); }
int IndentationSpaces() const { return indentation_spaces_; }
void SetIndentationSpaces(int spaces);
PartitionPolicyEnum PartitionPolicy() const { return partition_policy_; }
void SetPartitionPolicy(PartitionPolicyEnum policy) {
partition_policy_ = policy;
}
const Symbol* Origin() const { return origin_; }
void SetOrigin(const Symbol* origin) { origin_ = origin; }
// Returns the range of PreFormatTokens spanned by this UnwrappedLine.
// Note that this is a *copy*, and not a reference to the underlying range.
FormatTokenRange TokensRange() const { return tokens_; }
// Returns the number of tokens in this UnwrappedLine
size_t Size() const { return tokens_.size(); }
// Returns true if the UnwrappedLine is empty, if it has no tokens
bool IsEmpty() const { return tokens_.empty(); }
// Currently for debugging, prints the UnwrappedLine as Code
std::ostream* AsCode(std::ostream*, bool verbose = false) const;
private:
// Data members:
// indentation_spaces_ is the number of spaces to indent from the left.
int indentation_spaces_;
// The range of sequential PreFormatTokens spanned by this UnwrappedLine.
// These represent the tokens that will be formatted independently.
// The memory for these must be owned elsewhere.
FormatTokenRange tokens_;
// This determines under what conditions this UnwrappedLine should be
// further partitioned for formatting.
PartitionPolicyEnum partition_policy_ = PartitionPolicyEnum::kUninitialized;
// Hint about the origin of this partition, e.g. a particular syntax
// tree node/leaf.
const Symbol* origin_ = nullptr;
};
std::ostream& operator<<(std::ostream&, const UnwrappedLine&);
// FormattedExcerpt is the result of formatting a slice of code represented
// as an UnwrappedLine. In this representation, wrapping and spacing decisions
// are considered bound.
// TODO(fangism): move this class to its own file.
class FormattedExcerpt {
public:
FormattedExcerpt() = default;
explicit FormattedExcerpt(const UnwrappedLine&);
// Returns the number of spaces to indent.
int IndentationSpaces() const { return indentation_spaces_; }
const std::vector<FormattedToken>& Tokens() const { return tokens_; }
// Note: The mutable variant is only intended for use in StateNode.
std::vector<FormattedToken>& MutableTokens() { return tokens_; }
// Prints formatted text. If indent is true, include the spacing
// that is to the left of the first token.
std::ostream& FormattedText(std::ostream&, bool indent) const;
// Returns formatted code as a string.
std::string Render() const;
// Signal to the consumer that the analysis use to construct this
// formatted excerpt did not run to completion, and that the result
// may be unoptimal.
void MarkIncomplete() { completed_formatting_ = false; }
// Returns true if this result represents optimal formatting.
bool CompletedFormatting() const { return completed_formatting_; }
private:
// Number of spaces to indent this line from the left.
int indentation_spaces_ = 0;
// Sequence of formatted tokens.
std::vector<FormattedToken> tokens_;
// If true, this result can be interpreted as formatting-optimal.
// if false, this is the result of incomplete optimization.
bool completed_formatting_ = true;
};
std::ostream& operator<<(std::ostream&, const FormattedExcerpt&);
} // namespace verible
#endif // VERIBLE_COMMON_FORMATTING_UNWRAPPED_LINE_H_