diff --git a/src/plugins/qmleditor/qmleditor.cpp b/src/plugins/qmleditor/qmleditor.cpp index 2819b87f68fb3fe365cc6148c993363dfef52a9d..539726b3661c7ae5f98eeeec4526a64023479091 100644 --- a/src/plugins/qmleditor/qmleditor.cpp +++ b/src/plugins/qmleditor/qmleditor.cpp @@ -70,6 +70,7 @@ enum { using namespace QmlJS; using namespace QmlJS::AST; +using namespace SharedTools; namespace QmlEditor { namespace Internal { @@ -634,49 +635,81 @@ bool ScriptEditor::isElectricCharacter(const QChar &ch) const return false; } -void ScriptEditor::indentBlock(QTextDocument *, QTextBlock block, QChar typedChar) +bool ScriptEditor::isClosingBrace(const QList<QScriptIncrementalScanner::Token> &tokens) const { - TextEditor::TabSettings ts = tabSettings(); - if (typedChar == QLatin1Char('}') || typedChar == QLatin1Char(']') - || (typedChar == QChar::Null - && (block.text().trimmed() == "}" || block.text().trimmed() == "]"))) { + if (tokens.size() == 1) { + const QScriptIncrementalScanner::Token firstToken = tokens.first(); - QTextCursor tc(block); + return firstToken.is(QScriptIncrementalScanner::Token::RightBrace) || firstToken.is(QScriptIncrementalScanner::Token::RightBracket); + } - if (typedChar == QLatin1Char('}') || typedChar == QLatin1Char(']')) - tc = textCursor(); + return false; +} - if (TextEditor::TextBlockUserData::findPreviousBlockOpenParenthesis(&tc)) { - const QString text = tc.block().text(); - int indent = ts.columnAt(text, ts.firstNonSpace(text)); - ts.indentLine(block, indent); - return; - } - } +static int blockBraceDepth(const QTextBlock &block) +{ + int state = block.userState(); + if (state == -1) + return 0; + + return (state >> 8) & 0xFF; +} - int indent = 0; - int extraIndent = 0; +static int blockStartState(const QTextBlock &block) +{ + int state = block.userState(); - if (block.previous().isValid()) { - const int braceDepth = qMax(0, block.previous().userState() >> 8); - const int previousBraceDepth = qMax(0, block.previous().previous().userState() >> 8); + if (state == -1) + return 0; + else + return state & 0xff; +} - if (braceDepth > previousBraceDepth) - extraIndent = ts.m_indentSize * (braceDepth - previousBraceDepth); +void ScriptEditor::indentBlock(QTextDocument *, QTextBlock block, QChar typedChar) +{ + TextEditor::TabSettings ts = tabSettings(); + + QTextCursor tc(block); + + const QString blockText = block.text(); + int startState = blockStartState(block.previous()); + + QScriptIncrementalScanner scanner; + const QList<QScriptIncrementalScanner::Token> tokens = scanner(blockText, startState); + + if (! tokens.isEmpty()) { + const QScriptIncrementalScanner::Token tk = tokens.first(); + + if (tk.is(QScriptIncrementalScanner::Token::RightBrace) + || tk.is(QScriptIncrementalScanner::Token::RightBracket)) { + if (TextEditor::TextBlockUserData::findPreviousBlockOpenParenthesis(&tc)) { + const QString text = tc.block().text(); + int indent = ts.columnAt(text, ts.firstNonSpace(text)); + ts.indentLine(block, indent); + return; + } + } } + int initialIndent = 0; QTextBlock it = block.previous(); for (; it.isValid(); it = it.previous()) { const QString text = it.text(); if (! text.isEmpty()) { - indent = ts.columnAt(text, ts.firstNonSpace(text)); + initialIndent = ts.columnAt(text, ts.firstNonSpace(text)); break; } } - ts.indentLine(block, extraIndent + indent); + // default indent is initialIndent .. + + const int braceDepth = blockBraceDepth(block.previous()); + const int previousBraceDepth = blockBraceDepth(block.previous().previous()); + const int delta = qMax(0, braceDepth - previousBraceDepth); + int indent = initialIndent + (delta * ts.m_indentSize); + ts.indentLine(block, indent); } TextEditor::BaseTextEditorEditable *ScriptEditor::createEditableInterface() diff --git a/src/plugins/qmleditor/qmleditor.h b/src/plugins/qmleditor/qmleditor.h index ac4692bc4de8557be1c85c9ac6c1da03fc7f6d3a..7afd46008d263a66f8ea9746def2f82dfbedec3a 100644 --- a/src/plugins/qmleditor/qmleditor.h +++ b/src/plugins/qmleditor/qmleditor.h @@ -35,6 +35,7 @@ #include "qmljsastfwd_p.h" #include "qmljsengine_p.h" #include "qmldocument.h" +#include "qscriptincrementalscanner.h" QT_BEGIN_NAMESPACE class QComboBox; @@ -134,6 +135,7 @@ protected: private: virtual bool isElectricCharacter(const QChar &ch) const; virtual void indentBlock(QTextDocument *doc, QTextBlock block, QChar typedChar); + bool isClosingBrace(const QList<SharedTools::QScriptIncrementalScanner::Token> &tokens) const; QString wordUnderCursor() const; diff --git a/src/shared/qscripthighlighter/qscripthighlighter.cpp b/src/shared/qscripthighlighter/qscripthighlighter.cpp index a028ac4d7bad18534bbd3ed709dace737ddcf34f..f871aeb45ffa49ed99b9d2a4d43825e5bfc43cdc 100644 --- a/src/shared/qscripthighlighter/qscripthighlighter.cpp +++ b/src/shared/qscripthighlighter/qscripthighlighter.cpp @@ -58,7 +58,7 @@ bool QScriptHighlighter::isDuiEnabled() const void QScriptHighlighter::highlightBlock(const QString &text) { - m_scanner(onBlockStart(), text); + m_scanner(text, onBlockStart()); QTextCharFormat emptyFormat; int lastEnd = 0; diff --git a/src/shared/qscripthighlighter/qscriptincrementalscanner.cpp b/src/shared/qscripthighlighter/qscriptincrementalscanner.cpp index 851110f6004fa8cdd26c39693f3dd257a391ce38..9ea05fa2f227f7de32e029e8c5ff33be5867fb64 100644 --- a/src/shared/qscripthighlighter/qscriptincrementalscanner.cpp +++ b/src/shared/qscripthighlighter/qscriptincrementalscanner.cpp @@ -19,7 +19,7 @@ void QScriptIncrementalScanner::reset() m_tokens.clear(); } -void QScriptIncrementalScanner::operator()(int startState, const QString &text) +QList<QScriptIncrementalScanner::Token> QScriptIncrementalScanner::operator()(const QString &text, int startState) { reset(); @@ -78,7 +78,7 @@ void QScriptIncrementalScanner::operator()(int startState, const QString &text) int state = startState; if (text.isEmpty()) { blockEnd(state, 0); - return; + return m_tokens; } int input = -1; @@ -268,6 +268,8 @@ void QScriptIncrementalScanner::operator()(int startState, const QString &text) } blockEnd(state, firstNonSpace); + + return m_tokens; } void QScriptIncrementalScanner::insertToken(int start, int length, Token::Kind kind, bool forceNewToken) diff --git a/src/shared/qscripthighlighter/qscriptincrementalscanner.h b/src/shared/qscripthighlighter/qscriptincrementalscanner.h index 531a37464eeb11a2a84d598f4068ec88879aaf4d..253417d5214a8d19ec5da00a40c12dc5905570d9 100644 --- a/src/shared/qscripthighlighter/qscriptincrementalscanner.h +++ b/src/shared/qscripthighlighter/qscriptincrementalscanner.h @@ -35,6 +35,8 @@ public: inline Token(int o, int l, Kind k): offset(o), length(l), kind(k) {} inline int end() const { return offset + length; } + inline bool is(int k) const { return k == kind; } + inline bool isNot(int k) const { return k != kind; } }; public: @@ -46,7 +48,7 @@ public: void reset(); - void operator()(int startState, const QString &text); + QList<QScriptIncrementalScanner::Token> operator()(const QString &text, int startState = 0); int endState() const { return m_endState; }