97void Prettify( std::string& aSource, FORMAT_MODE aMode )
100 const char quoteChar =
'"';
101 const char indentChar =
'\t';
102 const int indentSize = 1;
106 const int xySpecialCaseColumnLimit = 99;
111 const int consecutiveTokenWrapThreshold = 72;
113 const bool textSpecialCase = aMode == FORMAT_MODE::COMPACT_TEXT_PROPERTIES;
114 const bool libSpecialCase = aMode == FORMAT_MODE::LIBRARY_TABLE;
116 std::string formatted;
117 formatted.reserve( aSource.length() );
119 auto cursor = aSource.begin();
124 char lastNonWhitespace = 0;
125 bool inQuote =
false;
126 bool hasInsertedSpace =
false;
127 bool inMultiLineList =
false;
129 bool inShortForm =
false;
130 bool inLibRow =
false;
131 int shortFormDepth = 0;
133 int backslashCount = 0;
135 auto isWhitespace = [](
const char aChar )
137 return ( aChar ==
' ' || aChar ==
'\t' || aChar ==
'\n' || aChar ==
'\r' );
140 auto nextNonWhitespace =
141 [&]( std::string::iterator aIt )
145 while( seek != aSource.end() && isWhitespace( *seek ) )
148 if( seek == aSource.end() )
155 [&]( std::string::iterator aIt )
159 if( ++seek == aSource.end() || *seek !=
'x' )
162 if( ++seek == aSource.end() || *seek !=
'y' )
165 if( ++seek == aSource.end() || *seek !=
' ' )
172 [&]( std::string::iterator aIt )
177 while( ++seek != aSource.end() && isalpha( *seek ) )
180 return token ==
"font" || token ==
"stroke" || token ==
"fill" || token ==
"teardrop"
181 || token ==
"offset" || token ==
"rotate" || token ==
"scale";
185 [&]( std::string::iterator aIt )
190 while( ++seek != aSource.end() && isalpha( *seek ) )
193 return token ==
"lib";
196 while(
cursor != aSource.end() )
200 if( isWhitespace( *
cursor ) && !inQuote )
202 if( !hasInsertedSpace
204 && lastNonWhitespace !=
'('
208 if( inXY || column < consecutiveTokenWrapThreshold )
212 formatted.push_back(
' ' );
215 else if( inShortForm || inLibRow )
217 formatted.push_back(
' ' );
221 formatted += fmt::format(
"\n{}",
222 std::string( listDepth * indentSize, indentChar ) );
223 column = listDepth * indentSize;
224 inMultiLineList =
true;
227 hasInsertedSpace =
true;
232 hasInsertedSpace =
false;
234 if( *
cursor ==
'(' && !inQuote )
236 bool currentIsXY = isXY(
cursor );
237 bool currentIsShortForm = textSpecialCase && isShortForm(
cursor );
238 bool currentIsLib = libSpecialCase && isLib(
cursor );
240 if( formatted.empty() )
242 formatted.push_back(
'(' );
245 else if( inXY && currentIsXY && column < xySpecialCaseColumnLimit )
251 else if( inShortForm || inLibRow )
258 formatted += fmt::format(
"\n{}(",
259 std::string( listDepth * indentSize, indentChar ) );
260 column = listDepth * indentSize + 1;
265 if( currentIsShortForm )
268 shortFormDepth = listDepth;
270 else if( currentIsLib )
273 libDepth = listDepth;
278 else if( *
cursor ==
')' && !inQuote )
285 formatted.push_back(
')' );
288 else if( inLibRow && listDepth == libDepth )
290 formatted.push_back(
')' );
293 else if( lastNonWhitespace ==
')' || inMultiLineList )
295 formatted += fmt::format(
"\n{})",
296 std::string( listDepth * indentSize, indentChar ) );
297 column = listDepth * indentSize + 1;
298 inMultiLineList =
false;
302 formatted.push_back(
')' );
306 if( shortFormDepth == listDepth )
319 else if( *
cursor == quoteChar && ( backslashCount & 1 ) == 0 )
325 formatted.push_back( *
cursor );
329 lastNonWhitespace = *
cursor;
338 aSource = std::move( formatted );