forked from qt-creator/qt-creator
QmlJS highlighting: Use semantics for types and binding names.
This fixes some problems with highlighting like anchors {}, allows us
to only highlight correct types and to make the binding name formatting
customizable.
Change-Id: I7ab0c0ed384108b74a2998796d868d5ced4a5310
Reviewed-on: http://codereview.qt-project.org/4669
Reviewed-by: Thomas Hartmann <Thomas.Hartmann@nokia.com>
This commit is contained in:
@@ -166,54 +166,6 @@ void Highlighter::highlightBlock(const QString &text)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!spell.isEmpty() && spell.at(0).isUpper())
|
|
||||||
setFormat(token.offset, token.length, m_formats[TypeFormat]);
|
|
||||||
|
|
||||||
if (index + 1 < tokens.size()) {
|
|
||||||
bool maybeBinding = (index == 0 || checkStartOfBinding(tokens.at(index - 1)));
|
|
||||||
bool maybeOnBinding = false;
|
|
||||||
if (index > 0) {
|
|
||||||
const Token &previousToken = tokens.at(index - 1);
|
|
||||||
if (text.midRef(previousToken.offset, previousToken.length) == QLatin1String("on")) {
|
|
||||||
maybeOnBinding = true;
|
|
||||||
maybeBinding = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (maybeBinding || maybeOnBinding) {
|
|
||||||
Token::Kind expectedTerminator = Token::Colon;
|
|
||||||
if (maybeOnBinding)
|
|
||||||
expectedTerminator = Token::LeftBrace;
|
|
||||||
|
|
||||||
const int start = index;
|
|
||||||
|
|
||||||
// put index on last identifier not followed by .identifier
|
|
||||||
while (index + 2 < tokens.size() &&
|
|
||||||
tokens.at(index + 1).is(Token::Dot) &&
|
|
||||||
tokens.at(index + 2).is(Token::Identifier)) {
|
|
||||||
index += 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (index + 1 < tokens.size() && tokens.at(index + 1).is(expectedTerminator)) {
|
|
||||||
// it's a binding.
|
|
||||||
for (int i = start; i <= index; ++i) {
|
|
||||||
const Token &tok = tokens.at(i);
|
|
||||||
if (tok.kind == Token::Dot)
|
|
||||||
continue;
|
|
||||||
const QStringRef tokSpell = text.midRef(tok.offset, tok.length);
|
|
||||||
if (!tokSpell.isEmpty() && tokSpell.at(0).isUpper()) {
|
|
||||||
setFormat(tok.offset, tok.length, m_formats[TypeFormat]);
|
|
||||||
} else {
|
|
||||||
setFormat(tok.offset, tok.length, m_formats[FieldFormat]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
} else {
|
|
||||||
index = start;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
case Token::Delimiter:
|
case Token::Delimiter:
|
||||||
|
|||||||
@@ -40,6 +40,7 @@
|
|||||||
#include <qmljs/qmljsevaluate.h>
|
#include <qmljs/qmljsevaluate.h>
|
||||||
#include <qmljs/qmljscontext.h>
|
#include <qmljs/qmljscontext.h>
|
||||||
#include <qmljs/qmljsbind.h>
|
#include <qmljs/qmljsbind.h>
|
||||||
|
#include <qmljs/qmljscheck.h>
|
||||||
#include <qmljs/parser/qmljsast_p.h>
|
#include <qmljs/parser/qmljsast_p.h>
|
||||||
#include <qmljs/parser/qmljsastvisitor_p.h>
|
#include <qmljs/parser/qmljsastvisitor_p.h>
|
||||||
#include <texteditor/syntaxhighlighter.h>
|
#include <texteditor/syntaxhighlighter.h>
|
||||||
@@ -249,26 +250,57 @@ protected:
|
|||||||
addUse(location, type);
|
addUse(location, type);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void processTypeId(UiQualifiedId *typeId)
|
||||||
|
{
|
||||||
|
if (!typeId)
|
||||||
|
return;
|
||||||
|
if (m_scopeChain.context()->lookupType(m_scopeChain.document().data(), typeId))
|
||||||
|
addUse(fullLocationForQualifiedId(typeId), SemanticHighlighter::QmlTypeType);
|
||||||
|
}
|
||||||
|
|
||||||
|
void processBindingName(UiQualifiedId *localId)
|
||||||
|
{
|
||||||
|
if (!localId)
|
||||||
|
return;
|
||||||
|
addUse(fullLocationForQualifiedId(localId), SemanticHighlighter::BindingNameType);
|
||||||
|
}
|
||||||
|
|
||||||
bool visit(UiObjectDefinition *ast)
|
bool visit(UiObjectDefinition *ast)
|
||||||
{
|
{
|
||||||
|
if (m_scopeChain.document()->bind()->isGroupedPropertyBinding(ast)) {
|
||||||
|
processBindingName(ast->qualifiedTypeNameId);
|
||||||
|
} else {
|
||||||
|
processTypeId(ast->qualifiedTypeNameId);
|
||||||
|
}
|
||||||
scopedAccept(ast, ast->initializer);
|
scopedAccept(ast, ast->initializer);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool visit(UiObjectBinding *ast)
|
bool visit(UiObjectBinding *ast)
|
||||||
{
|
{
|
||||||
|
processTypeId(ast->qualifiedTypeNameId);
|
||||||
|
processBindingName(ast->qualifiedId);
|
||||||
scopedAccept(ast, ast->initializer);
|
scopedAccept(ast, ast->initializer);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool visit(UiScriptBinding *ast)
|
bool visit(UiScriptBinding *ast)
|
||||||
{
|
{
|
||||||
|
processBindingName(ast->qualifiedId);
|
||||||
scopedAccept(ast, ast->statement);
|
scopedAccept(ast, ast->statement);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool visit(UiArrayBinding *ast)
|
||||||
|
{
|
||||||
|
processBindingName(ast->qualifiedId);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
bool visit(UiPublicMember *ast)
|
bool visit(UiPublicMember *ast)
|
||||||
{
|
{
|
||||||
|
if (ast->identifierToken.isValid())
|
||||||
|
addUse(ast->identifierToken, SemanticHighlighter::BindingNameType);
|
||||||
scopedAccept(ast, ast->statement);
|
scopedAccept(ast, ast->statement);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -436,6 +468,8 @@ void SemanticHighlighter::updateFontSettings(const TextEditor::FontSettings &fon
|
|||||||
m_formats[JsImportType] = fontSettings.toTextCharFormat(QLatin1String(TextEditor::Constants::C_JS_IMPORT_VAR));
|
m_formats[JsImportType] = fontSettings.toTextCharFormat(QLatin1String(TextEditor::Constants::C_JS_IMPORT_VAR));
|
||||||
m_formats[JsGlobalType] = fontSettings.toTextCharFormat(QLatin1String(TextEditor::Constants::C_JS_GLOBAL_VAR));
|
m_formats[JsGlobalType] = fontSettings.toTextCharFormat(QLatin1String(TextEditor::Constants::C_JS_GLOBAL_VAR));
|
||||||
m_formats[LocalStateNameType] = fontSettings.toTextCharFormat(QLatin1String(TextEditor::Constants::C_QML_STATE_NAME));
|
m_formats[LocalStateNameType] = fontSettings.toTextCharFormat(QLatin1String(TextEditor::Constants::C_QML_STATE_NAME));
|
||||||
|
m_formats[BindingNameType] = fontSettings.toTextCharFormat(QLatin1String(TextEditor::Constants::C_BINDING));
|
||||||
|
m_formats[FieldType] = fontSettings.toTextCharFormat(QLatin1String(TextEditor::Constants::C_FIELD));
|
||||||
}
|
}
|
||||||
|
|
||||||
int SemanticHighlighter::startRevision() const
|
int SemanticHighlighter::startRevision() const
|
||||||
|
|||||||
@@ -69,7 +69,9 @@ public:
|
|||||||
JsScopeType, // var or function in local js scope
|
JsScopeType, // var or function in local js scope
|
||||||
JsImportType, // name of js import
|
JsImportType, // name of js import
|
||||||
JsGlobalType, // in global scope
|
JsGlobalType, // in global scope
|
||||||
LocalStateNameType // name of a state in the current file
|
LocalStateNameType, // name of a state in the current file
|
||||||
|
BindingNameType, // name on the left hand side of a binding
|
||||||
|
FieldType // member of an object
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef TextEditor::SemanticHighlighter::Result Use;
|
typedef TextEditor::SemanticHighlighter::Result Use;
|
||||||
|
|||||||
@@ -138,6 +138,7 @@ const char * const C_JS_SCOPE_VAR = "JsScopeVar";
|
|||||||
const char * const C_JS_IMPORT_VAR = "JsImportVar";
|
const char * const C_JS_IMPORT_VAR = "JsImportVar";
|
||||||
const char * const C_JS_GLOBAL_VAR = "JsGlobalVar";
|
const char * const C_JS_GLOBAL_VAR = "JsGlobalVar";
|
||||||
const char * const C_QML_STATE_NAME = "QmlStateName";
|
const char * const C_QML_STATE_NAME = "QmlStateName";
|
||||||
|
const char * const C_BINDING = "Binding";
|
||||||
|
|
||||||
|
|
||||||
const char * const C_DISABLED_CODE = "DisabledCode";
|
const char * const C_DISABLED_CODE = "DisabledCode";
|
||||||
|
|||||||
@@ -146,6 +146,8 @@ TextEditorSettings::TextEditorSettings(QObject *parent)
|
|||||||
virtualMethodFormatDescriptor.format().setItalic(true);
|
virtualMethodFormatDescriptor.format().setItalic(true);
|
||||||
formatDescriptions.append(virtualMethodFormatDescriptor);
|
formatDescriptions.append(virtualMethodFormatDescriptor);
|
||||||
|
|
||||||
|
formatDescriptions.append(FormatDescription(QLatin1String(C_BINDING), tr("QML Binding"), Qt::darkRed));
|
||||||
|
|
||||||
Format qmlLocalNameFormat;
|
Format qmlLocalNameFormat;
|
||||||
qmlLocalNameFormat.setItalic(true);
|
qmlLocalNameFormat.setItalic(true);
|
||||||
formatDescriptions.append(FormatDescription(QLatin1String(C_QML_LOCAL_ID), tr("QML Local Id"), qmlLocalNameFormat));
|
formatDescriptions.append(FormatDescription(QLatin1String(C_QML_LOCAL_ID), tr("QML Local Id"), qmlLocalNameFormat));
|
||||||
|
|||||||
Reference in New Issue
Block a user