| // Copyright 2018 The Fuchsia Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #ifndef LIB_FOSTR_INDENT_H_ |
| #define LIB_FOSTR_INDENT_H_ |
| |
| #include <iomanip> |
| #include <ostream> |
| |
| namespace fostr { |
| |
| // Use these otuput manipulators to generate indented output: |
| // |
| // os << fostr::IdentBy(2); // Default is 4 spaces. |
| // os << "items:"; |
| // os << fostr::Indent; |
| // os << fostr::NewLine << "item 1"; |
| // os << fostr::NewLine << "item 2"; |
| // os << fostr::Indent; |
| // os << fostr::NewLine << "item 2A"; |
| // os << fostr::NewLine << "item 2B"; |
| // os << fostr::Outdent; |
| // os << fostr::NewLine << "item 3"; |
| // os << fostr::Outdent; |
| // |
| // This inserts: |
| // |
| // items:\n |
| // item 1\n |
| // item 2\n |
| // item 2A\n |
| // item 2B\n |
| // item 3 |
| // |
| // A useful pattern for nested output is for any given ostream operator<< |
| // overload to assume there is already text on the current line and to refrain |
| // from terminating the last line. In general, this means that fostr::NewLine |
| // prefixes text that needs to be on a new lines, and lines are not terminated. |
| |
| namespace internal { |
| |
| struct IndentLevel { |
| __attribute__((visibility("default"))) static long& Value(std::ostream& os); |
| IndentLevel(long level) : level_(level) {} |
| long level_; |
| }; |
| |
| struct IndentBy { |
| __attribute__((visibility("default"))) static long& Value(std::ostream& os); |
| IndentBy(long spaces) : spaces_(spaces) {} |
| long spaces_; |
| }; |
| |
| inline std::ostream& operator<<(std::ostream& os, const IndentLevel& value) { |
| IndentLevel::Value(os) = value.level_; |
| return os; |
| } |
| |
| inline std::ostream& operator<<(std::ostream& os, const IndentBy& value) { |
| IndentBy::Value(os) = value.spaces_; |
| return os; |
| } |
| |
| } // namespace internal |
| |
| // Inserts spaces to begin an indented line. The number of spaces inserted is |
| // the product of the indent level and the 'indent by' setting. |
| // e.g. os << fostr::BeginLine << "appears after indentation"; |
| inline std::ostream& BeginLine(std::ostream& os) { |
| return os << std::setw(internal::IndentLevel::Value(os) * |
| internal::IndentBy::Value(os)) |
| << std::setfill(' ') << "" << std::setw(0); |
| } |
| |
| // Inserts a newline and a BeginLine. |
| // e.g. os << fostr::NewLine << "appears on a new indented line"; |
| inline std::ostream& NewLine(std::ostream& os) { |
| return os << "\n" << BeginLine; |
| } |
| |
| // As an ostream manipulator, increments the indentation level. |
| // e.g. os << fostr::Indent; |
| inline std::ostream& Indent(std::ostream& os) { |
| ++internal::IndentLevel::Value(os); |
| return os; |
| } |
| |
| // As an ostream manipulator, decrements the indentation level. |
| // e.g. os << fostr::Outdent; |
| inline std::ostream& Outdent(std::ostream& os) { |
| --internal::IndentLevel::Value(os); |
| return os; |
| } |
| |
| // As an ostream manipulator, sets the indentation level. |
| // e.g. os << fostr::IdentLevel(3); |
| inline internal::IndentLevel IdentLevel(long level) { |
| return internal::IndentLevel(level); |
| } |
| |
| // Gets the current indentation level. |
| // e.g. long current_level = fostr::GetIdentLevel(os); |
| inline long GetIdentLevel(std::ostream& os) { |
| return internal::IndentLevel::Value(os); |
| } |
| |
| // As an ostream manipulator, sets the number of spaces to indent by for each |
| // indentation level. The default 'indent by' value is 4. |
| // e.g. os << fostr::IdentBy(2); |
| inline internal::IndentBy IdentBy(long spaces) { |
| return internal::IndentBy(spaces); |
| } |
| |
| } // namespace fostr |
| |
| #endif // LIB_FOSTR_INDENT_H_ |