1 | // Copyright (C) 2022 The Qt Company Ltd. |
2 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only |
3 | |
4 | #include "qqmldomcodeformatter_p.h" |
5 | |
6 | #include <QLoggingCategory> |
7 | #include <QMetaEnum> |
8 | |
9 | static Q_LOGGING_CATEGORY(formatterLog, "qt.qmldom.formatter" , QtWarningMsg); |
10 | |
11 | QT_BEGIN_NAMESPACE |
12 | namespace QQmlJS { |
13 | namespace Dom { |
14 | |
15 | using StateType = FormatTextStatus::StateType; |
16 | using State = FormatTextStatus::State; |
17 | |
18 | State FormatTextStatus::state(int belowTop) const |
19 | { |
20 | if (belowTop < states.size()) |
21 | return states.at(i: states.size() - 1 - belowTop); |
22 | else |
23 | return State(); |
24 | } |
25 | |
26 | QString FormatTextStatus::stateToString(StateType type) |
27 | { |
28 | const QMetaEnum &metaEnum = |
29 | staticMetaObject.enumerator(index: staticMetaObject.indexOfEnumerator(name: "StateType" )); |
30 | return QString::fromUtf8(utf8: metaEnum.valueToKey(value: int(type))); |
31 | } |
32 | |
33 | void FormatPartialStatus::enterState(StateType newState) |
34 | { |
35 | int savedIndentDepth = currentIndent; |
36 | defaultOnEnter(newState, indentDepth: ¤tIndent, savedIndentDepth: &savedIndentDepth); |
37 | currentStatus.pushState(type: newState, savedIndentDepth); |
38 | qCDebug(formatterLog) << "enter state" << FormatTextStatus::stateToString(type: newState); |
39 | |
40 | if (newState == StateType::BracketOpen) |
41 | enterState(newState: StateType::BracketElementStart); |
42 | } |
43 | |
44 | void FormatPartialStatus::leaveState(bool statementDone) |
45 | { |
46 | Q_ASSERT(currentStatus.size() > 1); |
47 | if (currentStatus.state().type == StateType::TopmostIntro) |
48 | return; |
49 | |
50 | // restore indent depth |
51 | State poppedState = currentStatus.popState(); |
52 | currentIndent = poppedState.savedIndentDepth; |
53 | |
54 | StateType topState = currentStatus.state().type; |
55 | |
56 | qCDebug(formatterLog) << "left state" << FormatTextStatus::stateToString(type: poppedState.type) |
57 | << ", now in state" << FormatTextStatus::stateToString(type: topState); |
58 | |
59 | // if statement is done, may need to leave recursively |
60 | if (statementDone) { |
61 | if (topState == StateType::IfStatement) { |
62 | if (poppedState.type != StateType::MaybeElse) |
63 | enterState(newState: StateType::MaybeElse); |
64 | else |
65 | leaveState(statementDone: true); |
66 | } else if (topState == StateType::ElseClause) { |
67 | // leave the else *and* the surrounding if, to prevent another else |
68 | leaveState(statementDone: false); |
69 | leaveState(statementDone: true); |
70 | } else if (topState == StateType::TryStatement) { |
71 | if (poppedState.type != StateType::MaybeCatchOrFinally |
72 | && poppedState.type != StateType::FinallyStatement) { |
73 | enterState(newState: StateType::MaybeCatchOrFinally); |
74 | } else { |
75 | leaveState(statementDone: true); |
76 | } |
77 | } else if (!FormatTextStatus::isExpressionEndState(type: topState)) { |
78 | leaveState(statementDone: true); |
79 | } |
80 | } |
81 | } |
82 | |
83 | void FormatPartialStatus::turnIntoState(StateType newState) |
84 | { |
85 | leaveState(statementDone: false); |
86 | enterState(newState); |
87 | } |
88 | |
89 | const Token &FormatPartialStatus::tokenAt(int idx) const |
90 | { |
91 | static const Token empty; |
92 | if (idx < 0 || idx >= lineTokens.size()) |
93 | return empty; |
94 | else |
95 | return lineTokens.at(i: idx); |
96 | } |
97 | |
98 | int FormatPartialStatus::column(int index) const |
99 | { |
100 | if (index > line.size()) |
101 | index = line.size(); |
102 | IndentInfo indent(QStringView(line).mid(pos: 0, n: index), options.tabSize, indentOffset); |
103 | return indent.column; |
104 | } |
105 | |
106 | QStringView FormatPartialStatus::tokenText(const Token &token) const |
107 | { |
108 | return line.mid(pos: token.begin(), n: token.length); |
109 | } |
110 | |
111 | bool FormatPartialStatus::tryInsideExpression(bool alsoExpression) |
112 | { |
113 | StateType newState = StateType::Invalid; |
114 | const int kind = tokenAt(idx: tokenIndex).lexKind; |
115 | switch (kind) { |
116 | case QQmlJSGrammar::T_LPAREN: |
117 | newState = StateType::ParenOpen; |
118 | break; |
119 | case QQmlJSGrammar::T_LBRACKET: |
120 | newState = StateType::BracketOpen; |
121 | break; |
122 | case QQmlJSGrammar::T_LBRACE: |
123 | newState = StateType::ObjectliteralOpen; |
124 | break; |
125 | case QQmlJSGrammar::T_FUNCTION: |
126 | newState = StateType::FunctionStart; |
127 | break; |
128 | case QQmlJSGrammar::T_QUESTION: |
129 | newState = StateType::TernaryOp; |
130 | break; |
131 | } |
132 | |
133 | if (newState != StateType::Invalid) { |
134 | if (alsoExpression) |
135 | enterState(newState: StateType::Expression); |
136 | enterState(newState); |
137 | return true; |
138 | } |
139 | |
140 | return false; |
141 | } |
142 | |
143 | bool FormatPartialStatus::tryStatement() |
144 | { |
145 | Token t = tokenAt(idx: tokenIndex); |
146 | const int kind = t.lexKind; |
147 | switch (kind) { |
148 | case QQmlJSGrammar::T_AUTOMATIC_SEMICOLON: |
149 | case QQmlJSGrammar::T_COMPATIBILITY_SEMICOLON: |
150 | case QQmlJSGrammar::T_SEMICOLON: |
151 | enterState(newState: StateType::EmptyStatement); |
152 | leaveState(statementDone: true); |
153 | return true; |
154 | case QQmlJSGrammar::T_BREAK: |
155 | case QQmlJSGrammar::T_CONTINUE: |
156 | enterState(newState: StateType::BreakcontinueStatement); |
157 | return true; |
158 | case QQmlJSGrammar::T_THROW: |
159 | enterState(newState: StateType::ThrowStatement); |
160 | enterState(newState: StateType::Expression); |
161 | return true; |
162 | case QQmlJSGrammar::T_RETURN: |
163 | enterState(newState: StateType::ReturnStatement); |
164 | enterState(newState: StateType::Expression); |
165 | return true; |
166 | case QQmlJSGrammar::T_WHILE: |
167 | case QQmlJSGrammar::T_FOR: |
168 | case QQmlJSGrammar::T_CATCH: |
169 | enterState(newState: StateType::StatementWithCondition); |
170 | return true; |
171 | case QQmlJSGrammar::T_SWITCH: |
172 | enterState(newState: StateType::SwitchStatement); |
173 | return true; |
174 | case QQmlJSGrammar::T_IF: |
175 | enterState(newState: StateType::IfStatement); |
176 | return true; |
177 | case QQmlJSGrammar::T_DO: |
178 | enterState(newState: StateType::DoStatement); |
179 | enterState(newState: StateType::Substatement); |
180 | return true; |
181 | case QQmlJSGrammar::T_CASE: |
182 | case QQmlJSGrammar::T_DEFAULT: |
183 | enterState(newState: StateType::CaseStart); |
184 | return true; |
185 | case QQmlJSGrammar::T_TRY: |
186 | enterState(newState: StateType::TryStatement); |
187 | return true; |
188 | case QQmlJSGrammar::T_LBRACE: |
189 | enterState(newState: StateType::JsblockOpen); |
190 | return true; |
191 | case QQmlJSGrammar::T_VAR: |
192 | case QQmlJSGrammar::T_PLUS_PLUS: |
193 | case QQmlJSGrammar::T_MINUS_MINUS: |
194 | case QQmlJSGrammar::T_IMPORT: |
195 | case QQmlJSGrammar::T_SIGNAL: |
196 | case QQmlJSGrammar::T_ON: |
197 | case QQmlJSGrammar::T_AS: |
198 | case QQmlJSGrammar::T_PROPERTY: |
199 | case QQmlJSGrammar::T_REQUIRED: |
200 | case QQmlJSGrammar::T_READONLY: |
201 | case QQmlJSGrammar::T_FUNCTION: |
202 | case QQmlJSGrammar::T_NUMERIC_LITERAL: |
203 | case QQmlJSGrammar::T_LPAREN: |
204 | enterState(newState: StateType::Expression); |
205 | // look at the token again |
206 | tokenIndex -= 1; |
207 | return true; |
208 | default: |
209 | if (Token::lexKindIsIdentifier(kind)) { |
210 | enterState(newState: StateType::ExpressionOrLabel); |
211 | return true; |
212 | } else if (Token::lexKindIsDelimiter(kind) || Token::lexKindIsStringType(kind)) { |
213 | enterState(newState: StateType::Expression); |
214 | // look at the token again |
215 | tokenIndex -= 1; |
216 | return true; |
217 | } |
218 | } |
219 | return false; |
220 | } |
221 | |
222 | void FormatPartialStatus::dump() const |
223 | { |
224 | qCDebug(formatterLog) << "Current token index" << tokenIndex; |
225 | qCDebug(formatterLog) << "Current state:" ; |
226 | for (const State &s : currentStatus.states) |
227 | qCDebug(formatterLog) << FormatTextStatus::stateToString(type: s.type) << s.savedIndentDepth; |
228 | qCDebug(formatterLog) << "Current lexerState:" << currentStatus.lexerState.state; |
229 | qCDebug(formatterLog) << "Current indent:" << currentIndent; |
230 | } |
231 | |
232 | void FormatPartialStatus::handleTokens() |
233 | { |
234 | auto enter = [this](StateType newState) { this->enterState(newState); }; |
235 | |
236 | auto leave = [this](bool statementDone = false) { this->leaveState(statementDone); }; |
237 | |
238 | auto turnInto = [this](StateType newState) { this->turnIntoState(newState); }; |
239 | |
240 | qCDebug(formatterLog) << "Starting to look at " << line; |
241 | |
242 | for (; tokenIndex < lineTokens.size();) { |
243 | Token currentToken = tokenAt(idx: tokenIndex); |
244 | const int kind = currentToken.lexKind; |
245 | |
246 | qCDebug(formatterLog) << "Token: " << tokenText(token: currentToken); |
247 | |
248 | if (Token::lexKindIsComment(kind) |
249 | && currentStatus.state().type != StateType::MultilineCommentCont |
250 | && currentStatus.state().type != StateType::MultilineCommentStart) { |
251 | tokenIndex += 1; |
252 | continue; |
253 | } |
254 | |
255 | switch (currentStatus.state().type) { |
256 | case StateType::TopmostIntro: |
257 | switch (kind) { |
258 | case QQmlJSGrammar::T_IDENTIFIER: |
259 | enter(StateType::ObjectdefinitionOrJs); |
260 | continue; |
261 | case QQmlJSGrammar::T_IMPORT: |
262 | enter(StateType::TopQml); |
263 | continue; |
264 | case QQmlJSGrammar::T_LBRACE: |
265 | enter(StateType::TopJs); |
266 | enter(StateType::Expression); |
267 | continue; // if a file starts with {, it's likely json |
268 | default: |
269 | enter(StateType::TopJs); |
270 | continue; |
271 | } |
272 | break; |
273 | |
274 | case StateType::TopQml: |
275 | switch (kind) { |
276 | case QQmlJSGrammar::T_IMPORT: |
277 | enter(StateType::ImportStart); |
278 | break; |
279 | case QQmlJSGrammar::T_IDENTIFIER: |
280 | enter(StateType::BindingOrObjectdefinition); |
281 | break; |
282 | default: |
283 | if (Token::lexKindIsIdentifier(kind)) |
284 | enter(StateType::BindingOrObjectdefinition); |
285 | break; |
286 | } |
287 | break; |
288 | |
289 | case StateType::TopJs: |
290 | tryStatement(); |
291 | break; |
292 | |
293 | case StateType::ObjectdefinitionOrJs: |
294 | switch (kind) { |
295 | case QQmlJSGrammar::T_DOT: |
296 | break; |
297 | case QQmlJSGrammar::T_LBRACE: |
298 | turnInto(StateType::BindingOrObjectdefinition); |
299 | continue; |
300 | default: |
301 | if (!Token::lexKindIsIdentifier(kind) || !line.at(n: currentToken.begin()).isUpper()) { |
302 | turnInto(StateType::TopJs); |
303 | continue; |
304 | } |
305 | } |
306 | break; |
307 | |
308 | case StateType::ImportStart: |
309 | enter(StateType::ImportMaybeDotOrVersionOrAs); |
310 | break; |
311 | |
312 | case StateType::ImportMaybeDotOrVersionOrAs: |
313 | switch (kind) { |
314 | case QQmlJSGrammar::T_DOT: |
315 | turnInto(StateType::ImportDot); |
316 | break; |
317 | case QQmlJSGrammar::T_AS: |
318 | turnInto(StateType::ImportAs); |
319 | break; |
320 | case QQmlJSGrammar::T_NUMERIC_LITERAL: |
321 | case QQmlJSGrammar::T_VERSION_NUMBER: |
322 | turnInto(StateType::ImportMaybeAs); |
323 | break; |
324 | default: |
325 | leave(); |
326 | leave(); |
327 | continue; |
328 | } |
329 | break; |
330 | |
331 | case StateType::ImportMaybeAs: |
332 | switch (kind) { |
333 | case QQmlJSGrammar::T_AS: |
334 | turnInto(StateType::ImportAs); |
335 | break; |
336 | default: |
337 | leave(); |
338 | leave(); |
339 | continue; |
340 | } |
341 | break; |
342 | |
343 | case StateType::ImportDot: |
344 | if (Token::lexKindIsIdentifier(kind)) { |
345 | turnInto(StateType::ImportMaybeDotOrVersionOrAs); |
346 | } else { |
347 | leave(); |
348 | leave(); |
349 | continue; |
350 | } |
351 | break; |
352 | |
353 | case StateType::ImportAs: |
354 | if (Token::lexKindIsIdentifier(kind)) { |
355 | leave(); |
356 | leave(); |
357 | } |
358 | break; |
359 | |
360 | case StateType::BindingOrObjectdefinition: |
361 | switch (kind) { |
362 | case QQmlJSGrammar::T_COLON: |
363 | enter(StateType::BindingAssignment); |
364 | break; |
365 | case QQmlJSGrammar::T_LBRACE: |
366 | enter(StateType::ObjectdefinitionOpen); |
367 | break; |
368 | } |
369 | break; |
370 | |
371 | case StateType::BindingAssignment: |
372 | switch (kind) { |
373 | case QQmlJSGrammar::T_AUTOMATIC_SEMICOLON: |
374 | case QQmlJSGrammar::T_COMPATIBILITY_SEMICOLON: |
375 | case QQmlJSGrammar::T_SEMICOLON: |
376 | leave(true); |
377 | break; |
378 | case QQmlJSGrammar::T_IF: |
379 | enter(StateType::IfStatement); |
380 | break; |
381 | case QQmlJSGrammar::T_WITH: |
382 | enter(StateType::StatementWithCondition); |
383 | break; |
384 | case QQmlJSGrammar::T_TRY: |
385 | enter(StateType::TryStatement); |
386 | break; |
387 | case QQmlJSGrammar::T_SWITCH: |
388 | enter(StateType::SwitchStatement); |
389 | break; |
390 | case QQmlJSGrammar::T_LBRACE: |
391 | enter(StateType::JsblockOpen); |
392 | break; |
393 | case QQmlJSGrammar::T_ON: |
394 | case QQmlJSGrammar::T_AS: |
395 | case QQmlJSGrammar::T_IMPORT: |
396 | case QQmlJSGrammar::T_SIGNAL: |
397 | case QQmlJSGrammar::T_PROPERTY: |
398 | case QQmlJSGrammar::T_REQUIRED: |
399 | case QQmlJSGrammar::T_READONLY: |
400 | case QQmlJSGrammar::T_IDENTIFIER: |
401 | enter(StateType::ExpressionOrObjectdefinition); |
402 | break; |
403 | |
404 | // error recovery |
405 | case QQmlJSGrammar::T_RBRACKET: |
406 | case QQmlJSGrammar::T_RPAREN: |
407 | leave(true); |
408 | break; |
409 | |
410 | default: |
411 | enter(StateType::Expression); |
412 | continue; |
413 | } |
414 | break; |
415 | |
416 | case StateType::ObjectdefinitionOpen: |
417 | switch (kind) { |
418 | case QQmlJSGrammar::T_RBRACE: |
419 | leave(true); |
420 | break; |
421 | case QQmlJSGrammar::T_DEFAULT: |
422 | case QQmlJSGrammar::T_READONLY: |
423 | enter(StateType::PropertyModifiers); |
424 | break; |
425 | case QQmlJSGrammar::T_PROPERTY: |
426 | enter(StateType::PropertyStart); |
427 | break; |
428 | case QQmlJSGrammar::T_REQUIRED: |
429 | enter(StateType::RequiredProperty); |
430 | break; |
431 | case QQmlJSGrammar::T_COMPONENT: |
432 | enter(StateType::ComponentStart); |
433 | break; |
434 | case QQmlJSGrammar::T_FUNCTION: |
435 | enter(StateType::FunctionStart); |
436 | break; |
437 | case QQmlJSGrammar::T_SIGNAL: |
438 | enter(StateType::SignalStart); |
439 | break; |
440 | case QQmlJSGrammar::T_ENUM: |
441 | enter(StateType::EnumStart); |
442 | break; |
443 | case QQmlJSGrammar::T_ON: |
444 | case QQmlJSGrammar::T_AS: |
445 | case QQmlJSGrammar::T_IMPORT: |
446 | enter(StateType::BindingOrObjectdefinition); |
447 | break; |
448 | default: |
449 | if (Token::lexKindIsIdentifier(kind)) |
450 | enter(StateType::BindingOrObjectdefinition); |
451 | break; |
452 | } |
453 | break; |
454 | |
455 | case StateType::PropertyModifiers: |
456 | switch (kind) { |
457 | case QQmlJSGrammar::T_PROPERTY: |
458 | turnInto(StateType::PropertyStart); |
459 | break; |
460 | case QQmlJSGrammar::T_DEFAULT: |
461 | case QQmlJSGrammar::T_READONLY: |
462 | break; |
463 | case QQmlJSGrammar::T_REQUIRED: |
464 | turnInto(StateType::RequiredProperty); |
465 | break; |
466 | default: |
467 | leave(true); |
468 | break; |
469 | } |
470 | break; |
471 | |
472 | case StateType::PropertyStart: |
473 | switch (kind) { |
474 | case QQmlJSGrammar::T_COLON: |
475 | enter(StateType::BindingAssignment); |
476 | break; // oops, was a binding |
477 | case QQmlJSGrammar::T_VAR: |
478 | case QQmlJSGrammar::T_IDENTIFIER: |
479 | enter(StateType::PropertyName); |
480 | break; |
481 | default: |
482 | if (Token::lexKindIsIdentifier(kind) && tokenText(token: currentToken) == u"list" ) { |
483 | enter(StateType::PropertyListOpen); |
484 | } else { |
485 | leave(true); |
486 | continue; |
487 | } |
488 | } |
489 | break; |
490 | |
491 | case StateType::RequiredProperty: |
492 | switch (kind) { |
493 | case QQmlJSGrammar::T_PROPERTY: |
494 | turnInto(StateType::PropertyStart); |
495 | break; |
496 | case QQmlJSGrammar::T_DEFAULT: |
497 | case QQmlJSGrammar::T_READONLY: |
498 | turnInto(StateType::PropertyModifiers); |
499 | break; |
500 | case QQmlJSGrammar::T_IDENTIFIER: |
501 | leave(true); |
502 | break; |
503 | default: |
504 | leave(true); |
505 | continue; |
506 | } |
507 | break; |
508 | |
509 | case StateType::ComponentStart: |
510 | switch (kind) { |
511 | case QQmlJSGrammar::T_IDENTIFIER: |
512 | turnInto(StateType::ComponentName); |
513 | break; |
514 | default: |
515 | leave(true); |
516 | continue; |
517 | } |
518 | break; |
519 | |
520 | case StateType::ComponentName: |
521 | switch (kind) { |
522 | case QQmlJSGrammar::T_COLON: |
523 | enter(StateType::BindingAssignment); |
524 | break; |
525 | default: |
526 | leave(true); |
527 | continue; |
528 | } |
529 | break; |
530 | |
531 | case StateType::PropertyName: |
532 | turnInto(StateType::PropertyMaybeInitializer); |
533 | break; |
534 | |
535 | case StateType::PropertyListOpen: { |
536 | const QStringView tok = tokenText(token: currentToken); |
537 | if (tok == u">" ) |
538 | turnInto(StateType::PropertyName); |
539 | break; |
540 | } |
541 | case StateType::PropertyMaybeInitializer: |
542 | switch (kind) { |
543 | case QQmlJSGrammar::T_COLON: |
544 | turnInto(StateType::BindingAssignment); |
545 | break; |
546 | default: |
547 | leave(true); |
548 | continue; |
549 | } |
550 | break; |
551 | |
552 | case StateType::EnumStart: |
553 | switch (kind) { |
554 | case QQmlJSGrammar::T_LBRACE: |
555 | enter(StateType::ObjectliteralOpen); |
556 | break; |
557 | } |
558 | break; |
559 | |
560 | case StateType::SignalStart: |
561 | switch (kind) { |
562 | case QQmlJSGrammar::T_COLON: |
563 | enter(StateType::BindingAssignment); |
564 | break; // oops, was a binding |
565 | default: |
566 | enter(StateType::SignalMaybeArglist); |
567 | break; |
568 | } |
569 | break; |
570 | |
571 | case StateType::SignalMaybeArglist: |
572 | switch (kind) { |
573 | case QQmlJSGrammar::T_LPAREN: |
574 | turnInto(StateType::SignalArglistOpen); |
575 | break; |
576 | default: |
577 | leave(true); |
578 | continue; |
579 | } |
580 | break; |
581 | |
582 | case StateType::SignalArglistOpen: |
583 | switch (kind) { |
584 | case QQmlJSGrammar::T_RPAREN: |
585 | leave(true); |
586 | break; |
587 | } |
588 | break; |
589 | |
590 | case StateType::FunctionStart: |
591 | switch (kind) { |
592 | case QQmlJSGrammar::T_LPAREN: |
593 | enter(StateType::FunctionArglistOpen); |
594 | break; |
595 | } |
596 | break; |
597 | |
598 | case StateType::FunctionArglistOpen: |
599 | switch (kind) { |
600 | case QQmlJSGrammar::T_COLON: |
601 | enter(StateType::TypeAnnotation); |
602 | break; |
603 | case QQmlJSGrammar::T_RPAREN: |
604 | turnInto(StateType::FunctionArglistClosed); |
605 | break; |
606 | } |
607 | break; |
608 | |
609 | case StateType::FunctionArglistClosed: |
610 | switch (kind) { |
611 | case QQmlJSGrammar::T_COLON: |
612 | enter(StateType::TypeAnnotation); |
613 | break; |
614 | case QQmlJSGrammar::T_LBRACE: |
615 | turnInto(StateType::JsblockOpen); |
616 | break; |
617 | default: |
618 | leave(true); |
619 | continue; // error recovery |
620 | } |
621 | break; |
622 | |
623 | case StateType::TypeAnnotation: |
624 | switch (kind) { |
625 | case QQmlJSGrammar::T_IDENTIFIER: |
626 | case QQmlJSGrammar::T_DOT: |
627 | break; |
628 | case QQmlJSGrammar::T_LT: |
629 | turnInto(StateType::TypeParameter); |
630 | break; |
631 | default: |
632 | leave(); |
633 | continue; // error recovery |
634 | } |
635 | break; |
636 | |
637 | case StateType::TypeParameter: |
638 | switch (kind) { |
639 | case QQmlJSGrammar::T_LT: |
640 | enter(StateType::TypeParameter); |
641 | break; |
642 | case QQmlJSGrammar::T_GT: |
643 | leave(); |
644 | break; |
645 | } |
646 | break; |
647 | |
648 | case StateType::ExpressionOrObjectdefinition: |
649 | switch (kind) { |
650 | case QQmlJSGrammar::T_DOT: |
651 | break; // need to become an objectdefinition_open in cases like "width: Qt.Foo |
652 | // {" |
653 | case QQmlJSGrammar::T_LBRACE: |
654 | turnInto(StateType::ObjectdefinitionOpen); |
655 | break; |
656 | |
657 | // propagate 'leave' from expression state |
658 | case QQmlJSGrammar::T_RBRACKET: |
659 | case QQmlJSGrammar::T_RPAREN: |
660 | leave(); |
661 | continue; |
662 | |
663 | default: |
664 | if (Token::lexKindIsIdentifier(kind)) |
665 | break; // need to become an objectdefinition_open in cases like "width: |
666 | // Qt.Foo |
667 | enter(StateType::Expression); |
668 | continue; // really? identifier and more tokens might already be gone |
669 | } |
670 | break; |
671 | |
672 | case StateType::ExpressionOrLabel: |
673 | switch (kind) { |
674 | case QQmlJSGrammar::T_COLON: |
675 | turnInto(StateType::LabelledStatement); |
676 | break; |
677 | |
678 | // propagate 'leave' from expression state |
679 | case QQmlJSGrammar::T_RBRACKET: |
680 | case QQmlJSGrammar::T_RPAREN: |
681 | leave(); |
682 | continue; |
683 | |
684 | default: |
685 | enter(StateType::Expression); |
686 | continue; |
687 | } |
688 | break; |
689 | |
690 | case StateType::TernaryOp: |
691 | if (kind == QQmlJSGrammar::T_COLON) { |
692 | enter(StateType::TernaryOpAfterColon); |
693 | enter(StateType::ExpressionContinuation); |
694 | break; |
695 | } |
696 | Q_FALLTHROUGH(); |
697 | case StateType::TernaryOpAfterColon: |
698 | case StateType::Expression: |
699 | if (tryInsideExpression(alsoExpression: false)) |
700 | break; |
701 | switch (kind) { |
702 | case QQmlJSGrammar::T_COMMA: |
703 | leave(true); |
704 | break; |
705 | case QQmlJSGrammar::T_RBRACKET: |
706 | case QQmlJSGrammar::T_RPAREN: |
707 | leave(); |
708 | continue; |
709 | case QQmlJSGrammar::T_RBRACE: |
710 | leave(true); |
711 | continue; |
712 | case QQmlJSGrammar::T_AUTOMATIC_SEMICOLON: |
713 | case QQmlJSGrammar::T_COMPATIBILITY_SEMICOLON: |
714 | case QQmlJSGrammar::T_SEMICOLON: |
715 | leave(true); |
716 | break; |
717 | default: |
718 | if (Token::lexKindIsDelimiter(kind)) |
719 | enter(StateType::ExpressionContinuation); |
720 | break; |
721 | } |
722 | break; |
723 | |
724 | case StateType::ExpressionContinuation: |
725 | leave(); |
726 | continue; |
727 | |
728 | case StateType::ExpressionMaybeContinuation: |
729 | switch (kind) { |
730 | case QQmlJSGrammar::T_QUESTION: |
731 | case QQmlJSGrammar::T_LBRACKET: |
732 | case QQmlJSGrammar::T_LPAREN: |
733 | case QQmlJSGrammar::T_LBRACE: |
734 | leave(); |
735 | continue; |
736 | default: |
737 | leave(!Token::lexKindIsDelimiter(kind)); |
738 | continue; |
739 | } |
740 | break; |
741 | |
742 | case StateType::ParenOpen: |
743 | if (tryInsideExpression(alsoExpression: false)) |
744 | break; |
745 | switch (kind) { |
746 | case QQmlJSGrammar::T_RPAREN: |
747 | leave(); |
748 | break; |
749 | } |
750 | break; |
751 | |
752 | case StateType::BracketOpen: |
753 | if (tryInsideExpression(alsoExpression: false)) |
754 | break; |
755 | switch (kind) { |
756 | case QQmlJSGrammar::T_COMMA: |
757 | enter(StateType::BracketElementStart); |
758 | break; |
759 | case QQmlJSGrammar::T_RBRACKET: |
760 | leave(); |
761 | break; |
762 | } |
763 | break; |
764 | |
765 | case StateType::ObjectliteralOpen: |
766 | if (tryInsideExpression(alsoExpression: false)) |
767 | break; |
768 | switch (kind) { |
769 | case QQmlJSGrammar::T_COLON: |
770 | enter(StateType::ObjectliteralAssignment); |
771 | break; |
772 | case QQmlJSGrammar::T_RBRACKET: |
773 | case QQmlJSGrammar::T_RPAREN: |
774 | leave(); |
775 | continue; // error recovery |
776 | case QQmlJSGrammar::T_RBRACE: |
777 | leave(true); |
778 | break; |
779 | } |
780 | break; |
781 | |
782 | // pretty much like expression, but ends with , or } |
783 | case StateType::ObjectliteralAssignment: |
784 | if (tryInsideExpression(alsoExpression: false)) |
785 | break; |
786 | switch (kind) { |
787 | case QQmlJSGrammar::T_COMMA: |
788 | leave(); |
789 | break; |
790 | case QQmlJSGrammar::T_RBRACKET: |
791 | case QQmlJSGrammar::T_RPAREN: |
792 | leave(); |
793 | continue; // error recovery |
794 | case QQmlJSGrammar::T_RBRACE: |
795 | leave(); |
796 | continue; // so we also leave objectliteral_open |
797 | default: |
798 | if (Token::lexKindIsDelimiter(kind)) |
799 | enter(StateType::ExpressionContinuation); |
800 | break; |
801 | } |
802 | break; |
803 | |
804 | case StateType::BracketElementStart: |
805 | if (Token::lexKindIsIdentifier(kind)) { |
806 | turnInto(StateType::BracketElementMaybeObjectdefinition); |
807 | } else { |
808 | leave(); |
809 | continue; |
810 | } |
811 | break; |
812 | |
813 | case StateType::BracketElementMaybeObjectdefinition: |
814 | switch (kind) { |
815 | case QQmlJSGrammar::T_LBRACE: |
816 | turnInto(StateType::ObjectdefinitionOpen); |
817 | break; |
818 | default: |
819 | leave(); |
820 | continue; |
821 | } |
822 | break; |
823 | |
824 | case StateType::JsblockOpen: |
825 | case StateType::SubstatementOpen: |
826 | if (tryStatement()) |
827 | break; |
828 | switch (kind) { |
829 | case QQmlJSGrammar::T_RBRACE: |
830 | leave(true); |
831 | break; |
832 | } |
833 | break; |
834 | |
835 | case StateType::LabelledStatement: |
836 | if (tryStatement()) |
837 | break; |
838 | leave(true); // error recovery |
839 | break; |
840 | |
841 | case StateType::Substatement: |
842 | // prefer substatement_open over block_open |
843 | if (kind != QQmlJSGrammar::T_LBRACE) { |
844 | if (tryStatement()) |
845 | break; |
846 | } |
847 | switch (kind) { |
848 | case QQmlJSGrammar::T_LBRACE: |
849 | turnInto(StateType::SubstatementOpen); |
850 | break; |
851 | } |
852 | break; |
853 | |
854 | case StateType::IfStatement: |
855 | switch (kind) { |
856 | case QQmlJSGrammar::T_LPAREN: |
857 | enter(StateType::ConditionOpen); |
858 | break; |
859 | default: |
860 | leave(true); |
861 | break; // error recovery |
862 | } |
863 | break; |
864 | |
865 | case StateType::MaybeElse: |
866 | switch (kind) { |
867 | case QQmlJSGrammar::T_ELSE: |
868 | turnInto(StateType::ElseClause); |
869 | enter(StateType::Substatement); |
870 | break; |
871 | default: |
872 | leave(true); |
873 | continue; |
874 | } |
875 | break; |
876 | |
877 | case StateType::MaybeCatchOrFinally: |
878 | switch (kind) { |
879 | case QQmlJSGrammar::T_CATCH: |
880 | turnInto(StateType::CatchStatement); |
881 | break; |
882 | case QQmlJSGrammar::T_FINALLY: |
883 | turnInto(StateType::FinallyStatement); |
884 | break; |
885 | default: |
886 | leave(true); |
887 | continue; |
888 | } |
889 | break; |
890 | |
891 | case StateType::ElseClause: |
892 | // ### shouldn't happen |
893 | dump(); |
894 | Q_ASSERT(false); |
895 | leave(true); |
896 | break; |
897 | |
898 | case StateType::ConditionOpen: |
899 | if (tryInsideExpression(alsoExpression: false)) |
900 | break; |
901 | switch (kind) { |
902 | case QQmlJSGrammar::T_RPAREN: |
903 | turnInto(StateType::Substatement); |
904 | break; |
905 | } |
906 | break; |
907 | |
908 | case StateType::SwitchStatement: |
909 | case StateType::CatchStatement: |
910 | case StateType::StatementWithCondition: |
911 | switch (kind) { |
912 | case QQmlJSGrammar::T_LPAREN: |
913 | enter(StateType::StatementWithConditionParenOpen); |
914 | break; |
915 | default: |
916 | leave(true); |
917 | } |
918 | break; |
919 | |
920 | case StateType::StatementWithConditionParenOpen: |
921 | if (tryInsideExpression(alsoExpression: false)) |
922 | break; |
923 | switch (kind) { |
924 | case QQmlJSGrammar::T_RPAREN: |
925 | turnInto(StateType::Substatement); |
926 | break; |
927 | } |
928 | break; |
929 | |
930 | case StateType::TryStatement: |
931 | case StateType::FinallyStatement: |
932 | switch (kind) { |
933 | case QQmlJSGrammar::T_LBRACE: |
934 | enter(StateType::JsblockOpen); |
935 | break; |
936 | default: |
937 | leave(true); |
938 | break; |
939 | } |
940 | break; |
941 | |
942 | case StateType::DoStatement: |
943 | switch (kind) { |
944 | case QQmlJSGrammar::T_WHILE: |
945 | break; |
946 | case QQmlJSGrammar::T_LPAREN: |
947 | enter(StateType::DoStatementWhileParenOpen); |
948 | break; |
949 | default: |
950 | leave(true); |
951 | continue; // error recovery |
952 | } |
953 | break; |
954 | |
955 | case StateType::DoStatementWhileParenOpen: |
956 | if (tryInsideExpression(alsoExpression: false)) |
957 | break; |
958 | switch (kind) { |
959 | case QQmlJSGrammar::T_RPAREN: |
960 | leave(); |
961 | leave(true); |
962 | break; |
963 | } |
964 | break; |
965 | |
966 | case StateType::BreakcontinueStatement: |
967 | if (Token ::lexKindIsIdentifier(kind)) { |
968 | leave(true); |
969 | } else { |
970 | leave(true); |
971 | continue; // try again |
972 | } |
973 | break; |
974 | |
975 | case StateType::CaseStart: |
976 | switch (kind) { |
977 | case QQmlJSGrammar::T_COLON: |
978 | turnInto(StateType::CaseCont); |
979 | break; |
980 | } |
981 | break; |
982 | |
983 | case StateType::CaseCont: |
984 | if (kind != QQmlJSGrammar::T_CASE && kind != QQmlJSGrammar::T_DEFAULT && tryStatement()) |
985 | break; |
986 | switch (kind) { |
987 | case QQmlJSGrammar::T_RBRACE: |
988 | leave(); |
989 | continue; |
990 | case QQmlJSGrammar::T_DEFAULT: |
991 | case QQmlJSGrammar::T_CASE: |
992 | leave(); |
993 | continue; |
994 | } |
995 | break; |
996 | |
997 | case StateType::MultilineCommentStart: |
998 | case StateType::MultilineCommentCont: |
999 | if (!Token::lexKindIsComment(kind)) { |
1000 | leave(); |
1001 | continue; |
1002 | } else if (tokenIndex == lineTokens.size() - 1 |
1003 | && !currentStatus.lexerState.isMultiline()) { |
1004 | leave(); |
1005 | } else if (tokenIndex == 0) { |
1006 | // to allow enter/leave to update the indentDepth |
1007 | turnInto(StateType::MultilineCommentCont); |
1008 | } |
1009 | break; |
1010 | |
1011 | default: |
1012 | qWarning() << "Unhandled state" << currentStatus.state().typeStr(); |
1013 | break; |
1014 | } // end of state switch |
1015 | |
1016 | ++tokenIndex; |
1017 | } |
1018 | |
1019 | StateType topState = currentStatus.state().type; |
1020 | |
1021 | // if there's no colon on the same line, it's not a label |
1022 | if (topState == StateType::ExpressionOrLabel) |
1023 | enterState(newState: StateType::Expression); |
1024 | // if not followed by an identifier on the same line, it's done |
1025 | else if (topState == StateType::BreakcontinueStatement) |
1026 | leaveState(statementDone: true); |
1027 | |
1028 | topState = currentStatus.state().type; |
1029 | |
1030 | // some states might be continued on the next line |
1031 | if (topState == StateType::Expression || topState == StateType::ExpressionOrObjectdefinition |
1032 | || topState == StateType::ObjectliteralAssignment |
1033 | || topState == StateType::TernaryOpAfterColon) { |
1034 | enterState(newState: StateType::ExpressionMaybeContinuation); |
1035 | } |
1036 | // multi-line comment start? |
1037 | if (topState != StateType::MultilineCommentStart && topState != StateType::MultilineCommentCont |
1038 | && currentStatus.lexerState.state.tokenKind == QQmlJSGrammar::T_PARTIAL_COMMENT) { |
1039 | enterState(newState: StateType::MultilineCommentStart); |
1040 | } |
1041 | currentStatus.finalIndent = currentIndent; |
1042 | } |
1043 | |
1044 | // adjusts the indentation of the current line based on the status of the previous one, and what |
1045 | // it starts with |
1046 | int indentForLineStartingWithToken(const FormatTextStatus &oldStatus, const FormatOptions &, |
1047 | int tokenKind) |
1048 | { |
1049 | State topState = oldStatus.state(); |
1050 | State previousState = oldStatus.state(belowTop: 1); |
1051 | int indentDepth = oldStatus.finalIndent; |
1052 | |
1053 | // keep user-adjusted indent in multiline comments |
1054 | if (topState.type == StateType::MultilineCommentStart |
1055 | || topState.type == StateType::MultilineCommentCont) { |
1056 | if (!Token::lexKindIsInvalid(kind: tokenKind)) |
1057 | return -1; |
1058 | } |
1059 | // don't touch multi-line strings at all |
1060 | if (oldStatus.lexerState.state.tokenKind == QQmlJSGrammar::T_PARTIAL_DOUBLE_QUOTE_STRING_LITERAL |
1061 | || oldStatus.lexerState.state.tokenKind == QQmlJSGrammar::T_PARTIAL_SINGLE_QUOTE_STRING_LITERAL |
1062 | || oldStatus.lexerState.state.tokenKind == QQmlJSGrammar::T_PARTIAL_TEMPLATE_HEAD |
1063 | || oldStatus.lexerState.state.tokenKind == QQmlJSGrammar::T_PARTIAL_TEMPLATE_MIDDLE) { |
1064 | return -1; |
1065 | } |
1066 | |
1067 | switch (tokenKind) { |
1068 | case QQmlJSGrammar::T_LBRACE: |
1069 | if (topState.type == StateType::Substatement |
1070 | || topState.type == StateType::BindingAssignment |
1071 | || topState.type == StateType::CaseCont) { |
1072 | return topState.savedIndentDepth; |
1073 | } |
1074 | break; |
1075 | case QQmlJSGrammar::T_RBRACE: { |
1076 | if (topState.type == StateType::JsblockOpen && previousState.type == StateType::CaseCont) { |
1077 | return previousState.savedIndentDepth; |
1078 | } |
1079 | for (int i = 0; oldStatus.state(belowTop: i).type != StateType::TopmostIntro; ++i) { |
1080 | const StateType type = oldStatus.state(belowTop: i).type; |
1081 | if (type == StateType::ObjectdefinitionOpen || type == StateType::JsblockOpen |
1082 | || type == StateType::SubstatementOpen || type == StateType::ObjectliteralOpen) { |
1083 | return oldStatus.state(belowTop: i).savedIndentDepth; |
1084 | } |
1085 | } |
1086 | break; |
1087 | } |
1088 | case QQmlJSGrammar::T_RBRACKET: |
1089 | for (int i = 0; oldStatus.state(belowTop: i).type != StateType::TopmostIntro; ++i) { |
1090 | const StateType type = oldStatus.state(belowTop: i).type; |
1091 | if (type == StateType::BracketOpen) { |
1092 | return oldStatus.state(belowTop: i).savedIndentDepth; |
1093 | } |
1094 | } |
1095 | break; |
1096 | case QQmlJSGrammar::T_LBRACKET: |
1097 | case QQmlJSGrammar::T_LPAREN: |
1098 | if (topState.type == StateType::ExpressionMaybeContinuation) |
1099 | return topState.savedIndentDepth; |
1100 | break; |
1101 | case QQmlJSGrammar::T_ELSE: |
1102 | if (topState.type == StateType::MaybeElse) { |
1103 | return oldStatus.state(belowTop: 1).savedIndentDepth; |
1104 | } else if (topState.type == StateType::ExpressionMaybeContinuation) { |
1105 | bool hasElse = false; |
1106 | for (int i = 1; oldStatus.state(belowTop: i).type != StateType::TopmostIntro; ++i) { |
1107 | const StateType type = oldStatus.state(belowTop: i).type; |
1108 | if (type == StateType::ElseClause) |
1109 | hasElse = true; |
1110 | if (type == StateType::IfStatement) { |
1111 | if (hasElse) { |
1112 | hasElse = false; |
1113 | } else { |
1114 | return oldStatus.state(belowTop: i).savedIndentDepth; |
1115 | } |
1116 | } |
1117 | } |
1118 | } |
1119 | break; |
1120 | case QQmlJSGrammar::T_CATCH: |
1121 | case QQmlJSGrammar::T_FINALLY: |
1122 | if (topState.type == StateType::MaybeCatchOrFinally) |
1123 | return oldStatus.state(belowTop: 1).savedIndentDepth; |
1124 | break; |
1125 | case QQmlJSGrammar::T_COLON: |
1126 | if (topState.type == StateType::TernaryOp) |
1127 | return indentDepth - 2; |
1128 | break; |
1129 | case QQmlJSGrammar::T_QUESTION: |
1130 | if (topState.type == StateType::ExpressionMaybeContinuation) |
1131 | return topState.savedIndentDepth; |
1132 | break; |
1133 | |
1134 | case QQmlJSGrammar::T_DEFAULT: |
1135 | case QQmlJSGrammar::T_CASE: |
1136 | for (int i = 0; oldStatus.state(belowTop: i).type != StateType::TopmostIntro; ++i) { |
1137 | const StateType type = oldStatus.state(belowTop: i).type; |
1138 | if (type == StateType::SwitchStatement || type == StateType::CaseCont) { |
1139 | return oldStatus.state(belowTop: i).savedIndentDepth; |
1140 | } else if (type == StateType::TopmostIntro) { |
1141 | break; |
1142 | } |
1143 | } |
1144 | break; |
1145 | default: |
1146 | if (Token::lexKindIsDelimiter(kind: tokenKind) |
1147 | && topState.type == StateType::ExpressionMaybeContinuation) |
1148 | return topState.savedIndentDepth; |
1149 | |
1150 | break; |
1151 | } |
1152 | return indentDepth; |
1153 | } |
1154 | |
1155 | // sets currentIndent to the correct indent for the current line |
1156 | int FormatPartialStatus::indentLine() |
1157 | { |
1158 | Q_ASSERT(currentStatus.size() >= 1); |
1159 | int firstToken = (lineTokens.isEmpty() ? QQmlJSGrammar::T_NONE : tokenAt(0).lexKind); |
1160 | int indent = indentForLineStartingWithToken(initialStatus, options, firstToken); |
1161 | recalculateWithIndent(indent); |
1162 | return indent; |
1163 | } |
1164 | |
1165 | int FormatPartialStatus::indentForNewLineAfter() const |
1166 | { |
1167 | // should be just currentIndent? |
1168 | int indent = indentForLineStartingWithToken(currentStatus, options, QQmlJSGrammar::T_NONE); |
1169 | if (indent < 0) |
1170 | return currentIndent; |
1171 | return indent; |
1172 | } |
1173 | |
1174 | void FormatPartialStatus::recalculateWithIndent(int indent) |
1175 | { |
1176 | if (indent >= 0) { |
1177 | indentOffset = 0; |
1178 | int i = 0; |
1179 | while (i < line.size() && line.at(n: i).isSpace()) |
1180 | ++i; |
1181 | indentOffset = indent - column(index: i); |
1182 | } |
1183 | currentIndent = initialStatus.finalIndent; |
1184 | auto lexerState = currentStatus.lexerState; |
1185 | currentStatus = initialStatus; |
1186 | currentStatus.lexerState = lexerState; |
1187 | tokenIndex = 0; |
1188 | handleTokens(); |
1189 | } |
1190 | |
1191 | FormatPartialStatus formatCodeLine(QStringView line, const FormatOptions &options, |
1192 | const FormatTextStatus &initialStatus) |
1193 | { |
1194 | FormatPartialStatus status(line, options, initialStatus); |
1195 | |
1196 | status.handleTokens(); |
1197 | |
1198 | return status; |
1199 | } |
1200 | |
1201 | void FormatPartialStatus::defaultOnEnter(StateType newState, int *indentDepth, |
1202 | int *savedIndentDepth) const |
1203 | { |
1204 | const State &parentState = currentStatus.state(); |
1205 | const Token &tk = tokenAt(idx: tokenIndex); |
1206 | const int tokenPosition = column(index: tk.begin()); |
1207 | const bool firstToken = (tokenIndex == 0); |
1208 | const bool lastToken = (tokenIndex == lineTokens.size() - 1); |
1209 | |
1210 | switch (newState) { |
1211 | case StateType::ObjectdefinitionOpen: { |
1212 | // special case for things like "gradient: Gradient {" |
1213 | if (parentState.type == StateType::BindingAssignment) |
1214 | *savedIndentDepth = currentStatus.state(belowTop: 1).savedIndentDepth; |
1215 | |
1216 | if (firstToken) |
1217 | *savedIndentDepth = tokenPosition; |
1218 | |
1219 | *indentDepth = *savedIndentDepth + options.indentSize; |
1220 | break; |
1221 | } |
1222 | |
1223 | case StateType::BindingOrObjectdefinition: |
1224 | if (firstToken) |
1225 | *indentDepth = *savedIndentDepth = tokenPosition; |
1226 | break; |
1227 | |
1228 | case StateType::BindingAssignment: |
1229 | case StateType::ObjectliteralAssignment: |
1230 | if (lastToken) |
1231 | *indentDepth = *savedIndentDepth + options.indentSize; |
1232 | else |
1233 | *indentDepth = column(index: tokenAt(idx: tokenIndex + 1).begin()); |
1234 | break; |
1235 | |
1236 | case StateType::ExpressionOrObjectdefinition: |
1237 | *indentDepth = tokenPosition; |
1238 | break; |
1239 | |
1240 | case StateType::ExpressionOrLabel: |
1241 | if (*indentDepth == tokenPosition) |
1242 | *indentDepth += 2 * options.indentSize; |
1243 | else |
1244 | *indentDepth = tokenPosition; |
1245 | break; |
1246 | |
1247 | case StateType::Expression: |
1248 | if (*indentDepth == tokenPosition) { |
1249 | // expression_or_objectdefinition doesn't want the indent |
1250 | // expression_or_label already has it |
1251 | if (parentState.type != StateType::ExpressionOrObjectdefinition |
1252 | && parentState.type != StateType::ExpressionOrLabel |
1253 | && parentState.type != StateType::BindingAssignment) { |
1254 | *indentDepth += 2 * options.indentSize; |
1255 | } |
1256 | } |
1257 | // expression_or_objectdefinition and expression_or_label have already consumed the |
1258 | // first token |
1259 | else if (parentState.type != StateType::ExpressionOrObjectdefinition |
1260 | && parentState.type != StateType::ExpressionOrLabel) { |
1261 | *indentDepth = tokenPosition; |
1262 | } |
1263 | break; |
1264 | |
1265 | case StateType::ExpressionMaybeContinuation: |
1266 | // set indent depth to indent we'd get if the expression ended here |
1267 | for (int i = 1; currentStatus.state(belowTop: i).type != StateType::TopmostIntro; ++i) { |
1268 | const StateType type = currentStatus.state(belowTop: i).type; |
1269 | if (FormatTextStatus::isExpressionEndState(type) |
1270 | && !FormatTextStatus::isBracelessState(type)) { |
1271 | *indentDepth = currentStatus.state(belowTop: i - 1).savedIndentDepth; |
1272 | break; |
1273 | } |
1274 | } |
1275 | break; |
1276 | |
1277 | case StateType::BracketOpen: |
1278 | if (parentState.type == StateType::Expression |
1279 | && currentStatus.state(belowTop: 1).type == StateType::BindingAssignment) { |
1280 | *savedIndentDepth = currentStatus.state(belowTop: 2).savedIndentDepth; |
1281 | *indentDepth = *savedIndentDepth + options.indentSize; |
1282 | } else if (parentState.type == StateType::ObjectliteralAssignment) { |
1283 | *savedIndentDepth = parentState.savedIndentDepth; |
1284 | *indentDepth = *savedIndentDepth + options.indentSize; |
1285 | } else if (!lastToken) { |
1286 | *indentDepth = tokenPosition + 1; |
1287 | } else { |
1288 | *indentDepth = *savedIndentDepth + options.indentSize; |
1289 | } |
1290 | break; |
1291 | |
1292 | case StateType::FunctionStart: |
1293 | // align to the beginning of the line |
1294 | *savedIndentDepth = *indentDepth = column(index: tokenAt(idx: 0).begin()); |
1295 | break; |
1296 | |
1297 | case StateType::DoStatementWhileParenOpen: |
1298 | case StateType::StatementWithConditionParenOpen: |
1299 | case StateType::SignalArglistOpen: |
1300 | case StateType::FunctionArglistOpen: |
1301 | case StateType::ParenOpen: |
1302 | if (!lastToken) |
1303 | *indentDepth = tokenPosition + 1; |
1304 | else |
1305 | *indentDepth += options.indentSize; |
1306 | break; |
1307 | |
1308 | case StateType::TernaryOp: |
1309 | if (!lastToken) |
1310 | *indentDepth = tokenPosition + tk.length + 1; |
1311 | else |
1312 | *indentDepth += options.indentSize; |
1313 | break; |
1314 | |
1315 | case StateType::JsblockOpen: |
1316 | // closing brace should be aligned to case |
1317 | if (parentState.type == StateType::CaseCont) { |
1318 | *savedIndentDepth = parentState.savedIndentDepth; |
1319 | break; |
1320 | } |
1321 | Q_FALLTHROUGH(); |
1322 | case StateType::SubstatementOpen: |
1323 | // special case for "foo: {" and "property int foo: {" |
1324 | if (parentState.type == StateType::BindingAssignment) |
1325 | *savedIndentDepth = currentStatus.state(belowTop: 1).savedIndentDepth; |
1326 | *indentDepth = *savedIndentDepth + options.indentSize; |
1327 | break; |
1328 | |
1329 | case StateType::Substatement: |
1330 | *indentDepth += options.indentSize; |
1331 | break; |
1332 | |
1333 | case StateType::ObjectliteralOpen: |
1334 | if (parentState.type == StateType::Expression |
1335 | || parentState.type == StateType::ObjectliteralAssignment) { |
1336 | // undo the continuation indent of the expression |
1337 | if (currentStatus.state(belowTop: 1).type == StateType::ExpressionOrLabel) |
1338 | *indentDepth = currentStatus.state(belowTop: 1).savedIndentDepth; |
1339 | else |
1340 | *indentDepth = parentState.savedIndentDepth; |
1341 | *savedIndentDepth = *indentDepth; |
1342 | } |
1343 | *indentDepth += options.indentSize; |
1344 | break; |
1345 | |
1346 | case StateType::StatementWithCondition: |
1347 | case StateType::TryStatement: |
1348 | case StateType::CatchStatement: |
1349 | case StateType::FinallyStatement: |
1350 | case StateType::IfStatement: |
1351 | case StateType::DoStatement: |
1352 | case StateType::SwitchStatement: |
1353 | if (firstToken || parentState.type == StateType::BindingAssignment) |
1354 | *savedIndentDepth = tokenPosition; |
1355 | // ### continuation |
1356 | *indentDepth = *savedIndentDepth; // + 2*options.indentSize; |
1357 | // special case for 'else if' |
1358 | if (!firstToken && newState == StateType::IfStatement |
1359 | && parentState.type == StateType::Substatement |
1360 | && currentStatus.state(belowTop: 1).type == StateType::ElseClause) { |
1361 | *indentDepth = currentStatus.state(belowTop: 1).savedIndentDepth; |
1362 | *savedIndentDepth = *indentDepth; |
1363 | } |
1364 | break; |
1365 | |
1366 | case StateType::MaybeElse: |
1367 | case StateType::MaybeCatchOrFinally: { |
1368 | // set indent to where leave(true) would put it |
1369 | int lastNonEndState = 0; |
1370 | while (!FormatTextStatus::isExpressionEndState( |
1371 | type: currentStatus.state(belowTop: lastNonEndState + 1).type)) |
1372 | ++lastNonEndState; |
1373 | *indentDepth = currentStatus.state(belowTop: lastNonEndState).savedIndentDepth; |
1374 | break; |
1375 | } |
1376 | |
1377 | case StateType::ConditionOpen: |
1378 | // fixed extra indent when continuing 'if (', but not for 'else if (' |
1379 | if (tokenPosition <= *indentDepth + options.indentSize) |
1380 | *indentDepth += 2 * options.indentSize; |
1381 | else |
1382 | *indentDepth = tokenPosition + 1; |
1383 | break; |
1384 | |
1385 | case StateType::CaseStart: |
1386 | *savedIndentDepth = tokenPosition; |
1387 | break; |
1388 | |
1389 | case StateType::CaseCont: |
1390 | *indentDepth += options.indentSize; |
1391 | break; |
1392 | |
1393 | case StateType::MultilineCommentStart: |
1394 | *indentDepth = tokenPosition + 2; |
1395 | break; |
1396 | |
1397 | case StateType::MultilineCommentCont: |
1398 | *indentDepth = tokenPosition; |
1399 | break; |
1400 | default: |
1401 | break; |
1402 | } |
1403 | } |
1404 | |
1405 | } // namespace Dom |
1406 | } // namespace QQmlJS |
1407 | QT_END_NAMESPACE |
1408 | |