File indexing completed on 2025-09-17 08:53:29
0001
0002
0003
0004
0005
0006
0007
0008 #ifndef CATCH_TEXTFLOW_HPP_INCLUDED
0009 #define CATCH_TEXTFLOW_HPP_INCLUDED
0010
0011 #include <catch2/internal/catch_console_width.hpp>
0012 #include <catch2/internal/catch_move_and_forward.hpp>
0013
0014 #include <cassert>
0015 #include <string>
0016 #include <vector>
0017
0018 namespace Catch {
0019 namespace TextFlow {
0020
0021 class Columns;
0022
0023
0024
0025
0026
0027
0028
0029
0030
0031
0032
0033
0034
0035 class AnsiSkippingString {
0036 std::string m_string;
0037 std::size_t m_size = 0;
0038
0039
0040 void preprocessString();
0041
0042 public:
0043 class const_iterator;
0044 using iterator = const_iterator;
0045
0046
0047 static constexpr char sentinel = static_cast<char>( 0xffu );
0048
0049 explicit AnsiSkippingString( std::string const& text );
0050 explicit AnsiSkippingString( std::string&& text );
0051
0052 const_iterator begin() const;
0053 const_iterator end() const;
0054
0055 size_t size() const { return m_size; }
0056
0057 std::string substring( const_iterator begin,
0058 const_iterator end ) const;
0059 };
0060
0061 class AnsiSkippingString::const_iterator {
0062 friend AnsiSkippingString;
0063 struct EndTag {};
0064
0065 const std::string* m_string;
0066 std::string::const_iterator m_it;
0067
0068 explicit const_iterator( const std::string& string, EndTag ):
0069 m_string( &string ), m_it( string.end() ) {}
0070
0071 void tryParseAnsiEscapes();
0072 void advance();
0073 void unadvance();
0074
0075 public:
0076 using difference_type = std::ptrdiff_t;
0077 using value_type = char;
0078 using pointer = value_type*;
0079 using reference = value_type&;
0080 using iterator_category = std::bidirectional_iterator_tag;
0081
0082 explicit const_iterator( const std::string& string ):
0083 m_string( &string ), m_it( string.begin() ) {
0084 tryParseAnsiEscapes();
0085 }
0086
0087 char operator*() const { return *m_it; }
0088
0089 const_iterator& operator++() {
0090 advance();
0091 return *this;
0092 }
0093 const_iterator operator++( int ) {
0094 iterator prev( *this );
0095 operator++();
0096 return prev;
0097 }
0098 const_iterator& operator--() {
0099 unadvance();
0100 return *this;
0101 }
0102 const_iterator operator--( int ) {
0103 iterator prev( *this );
0104 operator--();
0105 return prev;
0106 }
0107
0108 bool operator==( const_iterator const& other ) const {
0109 return m_it == other.m_it;
0110 }
0111 bool operator!=( const_iterator const& other ) const {
0112 return !operator==( other );
0113 }
0114 bool operator<=( const_iterator const& other ) const {
0115 return m_it <= other.m_it;
0116 }
0117
0118 const_iterator oneBefore() const {
0119 auto it = *this;
0120 return --it;
0121 }
0122 };
0123
0124
0125
0126
0127
0128
0129
0130
0131 class Column {
0132
0133 AnsiSkippingString m_string;
0134
0135 size_t m_width = CATCH_CONFIG_CONSOLE_WIDTH - 1;
0136
0137
0138 size_t m_indent = 0;
0139
0140 size_t m_initialIndent = std::string::npos;
0141
0142 public:
0143
0144
0145
0146 class const_iterator {
0147 friend Column;
0148 struct EndTag {};
0149
0150 Column const& m_column;
0151
0152 AnsiSkippingString::const_iterator m_lineStart;
0153
0154 AnsiSkippingString::const_iterator m_lineEnd;
0155
0156 AnsiSkippingString::const_iterator m_parsedTo;
0157
0158 bool m_addHyphen = false;
0159
0160 const_iterator( Column const& column, EndTag ):
0161 m_column( column ),
0162 m_lineStart( m_column.m_string.end() ),
0163 m_lineEnd( column.m_string.end() ),
0164 m_parsedTo( column.m_string.end() ) {}
0165
0166
0167 void calcLength();
0168
0169
0170 size_t indentSize() const;
0171
0172
0173
0174 std::string addIndentAndSuffix(
0175 AnsiSkippingString::const_iterator start,
0176 AnsiSkippingString::const_iterator end ) const;
0177
0178 public:
0179 using difference_type = std::ptrdiff_t;
0180 using value_type = std::string;
0181 using pointer = value_type*;
0182 using reference = value_type&;
0183 using iterator_category = std::forward_iterator_tag;
0184
0185 explicit const_iterator( Column const& column );
0186
0187 std::string operator*() const;
0188
0189 const_iterator& operator++();
0190 const_iterator operator++( int );
0191
0192 bool operator==( const_iterator const& other ) const {
0193 return m_lineStart == other.m_lineStart &&
0194 &m_column == &other.m_column;
0195 }
0196 bool operator!=( const_iterator const& other ) const {
0197 return !operator==( other );
0198 }
0199 };
0200 using iterator = const_iterator;
0201
0202 explicit Column( std::string const& text ): m_string( text ) {}
0203 explicit Column( std::string&& text ):
0204 m_string( CATCH_MOVE( text ) ) {}
0205
0206 Column& width( size_t newWidth ) & {
0207 assert( newWidth > 0 );
0208 m_width = newWidth;
0209 return *this;
0210 }
0211 Column&& width( size_t newWidth ) && {
0212 assert( newWidth > 0 );
0213 m_width = newWidth;
0214 return CATCH_MOVE( *this );
0215 }
0216 Column& indent( size_t newIndent ) & {
0217 m_indent = newIndent;
0218 return *this;
0219 }
0220 Column&& indent( size_t newIndent ) && {
0221 m_indent = newIndent;
0222 return CATCH_MOVE( *this );
0223 }
0224 Column& initialIndent( size_t newIndent ) & {
0225 m_initialIndent = newIndent;
0226 return *this;
0227 }
0228 Column&& initialIndent( size_t newIndent ) && {
0229 m_initialIndent = newIndent;
0230 return CATCH_MOVE( *this );
0231 }
0232
0233 size_t width() const { return m_width; }
0234 const_iterator begin() const { return const_iterator( *this ); }
0235 const_iterator end() const {
0236 return { *this, const_iterator::EndTag{} };
0237 }
0238
0239 friend std::ostream& operator<<( std::ostream& os,
0240 Column const& col );
0241
0242 friend Columns operator+( Column const& lhs, Column const& rhs );
0243 friend Columns operator+( Column&& lhs, Column&& rhs );
0244 };
0245
0246
0247 Column Spacer( size_t spaceWidth );
0248
0249 class Columns {
0250 std::vector<Column> m_columns;
0251
0252 public:
0253 class iterator {
0254 friend Columns;
0255 struct EndTag {};
0256
0257 std::vector<Column> const& m_columns;
0258 std::vector<Column::const_iterator> m_iterators;
0259 size_t m_activeIterators;
0260
0261 iterator( Columns const& columns, EndTag );
0262
0263 public:
0264 using difference_type = std::ptrdiff_t;
0265 using value_type = std::string;
0266 using pointer = value_type*;
0267 using reference = value_type&;
0268 using iterator_category = std::forward_iterator_tag;
0269
0270 explicit iterator( Columns const& columns );
0271
0272 auto operator==( iterator const& other ) const -> bool {
0273 return m_iterators == other.m_iterators;
0274 }
0275 auto operator!=( iterator const& other ) const -> bool {
0276 return m_iterators != other.m_iterators;
0277 }
0278 std::string operator*() const;
0279 iterator& operator++();
0280 iterator operator++( int );
0281 };
0282 using const_iterator = iterator;
0283
0284 iterator begin() const { return iterator( *this ); }
0285 iterator end() const { return { *this, iterator::EndTag() }; }
0286
0287 friend Columns& operator+=( Columns& lhs, Column const& rhs );
0288 friend Columns& operator+=( Columns& lhs, Column&& rhs );
0289 friend Columns operator+( Columns const& lhs, Column const& rhs );
0290 friend Columns operator+( Columns&& lhs, Column&& rhs );
0291
0292 friend std::ostream& operator<<( std::ostream& os,
0293 Columns const& cols );
0294 };
0295
0296 }
0297 }
0298 #endif