111void Prettify( std::string& aSource, FORMAT_MODE aMode )
114 const char quoteChar =
'"';
115 const char indentChar =
'\t';
116 const int indentSize = 1;
120 const int xySpecialCaseColumnLimit = 99;
125 const int consecutiveTokenWrapThreshold = 72;
127 const bool textSpecialCase = aMode == FORMAT_MODE::COMPACT_TEXT_PROPERTIES;
128 const bool libSpecialCase = aMode == FORMAT_MODE::LIBRARY_TABLE;
130 std::string formatted;
131 formatted.reserve( aSource.length() );
133 auto cursor = aSource.begin();
138 char lastNonWhitespace = 0;
139 bool inQuote =
false;
140 bool hasInsertedSpace =
false;
141 bool inMultiLineList =
false;
143 bool inShortForm =
false;
144 bool inLibRow =
false;
145 int shortFormDepth = 0;
147 int backslashCount = 0;
149 auto isWhitespace = [](
const char aChar )
151 return ( aChar ==
' ' || aChar ==
'\t' || aChar ==
'\n' || aChar ==
'\r' );
154 auto nextNonWhitespace =
155 [&]( std::string::iterator aIt )
159 while( seek != aSource.end() && isWhitespace( *seek ) )
162 if( seek == aSource.end() )
169 [&]( std::string::iterator aIt )
173 if( ++seek == aSource.end() || *seek !=
'x' )
176 if( ++seek == aSource.end() || *seek !=
'y' )
179 if( ++seek == aSource.end() || *seek !=
' ' )
186 [&]( std::string::iterator aIt )
191 while( ++seek != aSource.end() && isalpha( *seek ) )
194 return token ==
"font" || token ==
"stroke" || token ==
"fill" || token ==
"teardrop"
195 || token ==
"offset" || token ==
"rotate" || token ==
"scale";
199 [&]( std::string::iterator aIt )
204 while( ++seek != aSource.end() && isalpha( *seek ) )
207 return token ==
"lib";
210 while(
cursor != aSource.end() )
214 if( isWhitespace( *
cursor ) && !inQuote )
216 if( !hasInsertedSpace
218 && lastNonWhitespace !=
'('
222 if( inXY || column < consecutiveTokenWrapThreshold )
226 formatted.push_back(
' ' );
229 else if( inShortForm || inLibRow )
231 formatted.push_back(
' ' );
235 formatted += fmt::format(
"\n{}",
236 std::string( listDepth * indentSize, indentChar ) );
237 column = listDepth * indentSize;
238 inMultiLineList =
true;
241 hasInsertedSpace =
true;
246 hasInsertedSpace =
false;
248 if( *
cursor ==
'(' && !inQuote )
250 bool currentIsXY = isXY(
cursor );
251 bool currentIsShortForm = textSpecialCase && isShortForm(
cursor );
252 bool currentIsLib = libSpecialCase && isLib(
cursor );
254 if( formatted.empty() )
256 formatted.push_back(
'(' );
259 else if( inXY && currentIsXY && column < xySpecialCaseColumnLimit )
265 else if( inShortForm || inLibRow )
272 formatted += fmt::format(
"\n{}(",
273 std::string( listDepth * indentSize, indentChar ) );
274 column = listDepth * indentSize + 1;
279 if( currentIsShortForm )
282 shortFormDepth = listDepth;
284 else if( currentIsLib )
287 libDepth = listDepth;
292 else if( *
cursor ==
')' && !inQuote )
299 formatted.push_back(
')' );
302 else if( inLibRow && listDepth == libDepth )
304 formatted.push_back(
')' );
307 else if( lastNonWhitespace ==
')' || inMultiLineList )
309 formatted += fmt::format(
"\n{})",
310 std::string( listDepth * indentSize, indentChar ) );
311 column = listDepth * indentSize + 1;
312 inMultiLineList =
false;
316 formatted.push_back(
')' );
320 if( shortFormDepth == listDepth )
333 else if( *
cursor == quoteChar && ( backslashCount & 1 ) == 0 )
339 formatted.push_back( *
cursor );
343 lastNonWhitespace = *
cursor;
352 aSource = std::move( formatted );