summaryrefslogtreecommitdiff
path: root/src/plugins/texteditor
diff options
context:
space:
mode:
authorLeandro Melo <leandro.melo@nokia.com>2010-05-20 13:56:11 +0200
committerLeandro Melo <leandro.melo@nokia.com>2010-05-20 14:10:34 +0200
commit55b26868e61bdfc11cb7de23471ebd1dbc9973d3 (patch)
tree05ecd2ad062dd61734dd7c95cbfb7b093e773954 /src/plugins/texteditor
parent9b6c86bdc17f184937c36c5a101e6eead36d9e89 (diff)
downloadqt-creator-55b26868e61bdfc11cb7de23471ebd1dbc9973d3.tar.gz
Generic highlighter is now part of the text editor plugin.
Diffstat (limited to 'src/plugins/texteditor')
-rw-r--r--src/plugins/texteditor/generichighlighter/context.cpp156
-rw-r--r--src/plugins/texteditor/generichighlighter/context.h110
-rw-r--r--src/plugins/texteditor/generichighlighter/dynamicrule.cpp67
-rw-r--r--src/plugins/texteditor/generichighlighter/dynamicrule.h64
-rw-r--r--src/plugins/texteditor/generichighlighter/highlightdefinition.cpp167
-rw-r--r--src/plugins/texteditor/generichighlighter/highlightdefinition.h117
-rw-r--r--src/plugins/texteditor/generichighlighter/highlightdefinitionhandler.cpp461
-rw-r--r--src/plugins/texteditor/generichighlighter/highlightdefinitionhandler.h106
-rw-r--r--src/plugins/texteditor/generichighlighter/highlighter.cpp478
-rw-r--r--src/plugins/texteditor/generichighlighter/highlighter.h154
-rw-r--r--src/plugins/texteditor/generichighlighter/highlighterexception.h41
-rw-r--r--src/plugins/texteditor/generichighlighter/includerulesinstruction.cpp50
-rw-r--r--src/plugins/texteditor/generichighlighter/includerulesinstruction.h56
-rw-r--r--src/plugins/texteditor/generichighlighter/itemdata.cpp148
-rw-r--r--src/plugins/texteditor/generichighlighter/itemdata.h104
-rw-r--r--src/plugins/texteditor/generichighlighter/keywordlist.cpp61
-rw-r--r--src/plugins/texteditor/generichighlighter/keywordlist.h53
-rw-r--r--src/plugins/texteditor/generichighlighter/manager.cpp236
-rw-r--r--src/plugins/texteditor/generichighlighter/manager.h98
-rw-r--r--src/plugins/texteditor/generichighlighter/progressdata.cpp82
-rw-r--r--src/plugins/texteditor/generichighlighter/progressdata.h72
-rw-r--r--src/plugins/texteditor/generichighlighter/reuse.h100
-rw-r--r--src/plugins/texteditor/generichighlighter/rule.cpp292
-rw-r--r--src/plugins/texteditor/generichighlighter/rule.h160
-rw-r--r--src/plugins/texteditor/generichighlighter/specificrules.cpp467
-rw-r--r--src/plugins/texteditor/generichighlighter/specificrules.h288
-rw-r--r--src/plugins/texteditor/plaintexteditor.cpp67
-rw-r--r--src/plugins/texteditor/plaintexteditor.h14
-rw-r--r--src/plugins/texteditor/plaintexteditorfactory.cpp8
-rw-r--r--src/plugins/texteditor/plaintexteditorfactory.h1
-rw-r--r--src/plugins/texteditor/texteditor.pro34
-rw-r--r--src/plugins/texteditor/texteditorplugin.cpp4
-rw-r--r--src/plugins/texteditor/texteditorplugin.h1
33 files changed, 4310 insertions, 7 deletions
diff --git a/src/plugins/texteditor/generichighlighter/context.cpp b/src/plugins/texteditor/generichighlighter/context.cpp
new file mode 100644
index 0000000000..d9fea72fd5
--- /dev/null
+++ b/src/plugins/texteditor/generichighlighter/context.cpp
@@ -0,0 +1,156 @@
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** Commercial Usage
+**
+** Licensees holding valid Qt Commercial licenses may use this file in
+** accordance with the Qt Commercial License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Nokia.
+**
+** GNU Lesser General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://qt.nokia.com/contact.
+**
+**************************************************************************/
+
+#include "context.h"
+#include "rule.h"
+#include "reuse.h"
+#include "dynamicrule.h"
+#include "highlightdefinition.h"
+
+using namespace TextEditor;
+using namespace Internal;
+
+Context::Context() : m_fallthrough(false), m_dynamic(false)
+{}
+
+Context::Context(const Context &context) :
+ m_id(context.m_id), m_name(context.m_name), m_lineBeginContext(context.m_lineBeginContext),
+ m_lineEndContext(context.m_lineEndContext), m_fallthroughContext(context.m_fallthroughContext),
+ m_itemData(context.m_itemData), m_fallthrough(context.m_fallthrough),
+ m_dynamic(context.m_dynamic), m_instructions(context.m_instructions),
+ m_definition(context.m_definition)
+{
+ // Rules need to be deeply copied because of dynamic contexts.
+ foreach (const QSharedPointer<Rule> &rule, context.m_rules)
+ m_rules.append(QSharedPointer<Rule>(rule->clone()));
+}
+
+const Context &Context::operator=(Context copy)
+{
+ swap(copy);
+ return *this;
+}
+
+Context::~Context()
+{}
+
+void Context::swap(Context &context)
+{
+ qSwap(m_id, context.m_id);
+ qSwap(m_name, context.m_name);
+ qSwap(m_lineBeginContext, context.m_lineBeginContext);
+ qSwap(m_lineEndContext, context.m_lineEndContext);
+ qSwap(m_fallthroughContext, context.m_fallthroughContext);
+ qSwap(m_itemData, context.m_itemData);
+ qSwap(m_fallthrough, context.m_fallthrough);
+ qSwap(m_dynamic, context.m_dynamic);
+ qSwap(m_rules, context.m_rules);
+ qSwap(m_instructions, context.m_instructions);
+ qSwap(m_definition, context.m_definition);
+}
+
+void Context::configureId(const int unique)
+{ m_id.append(QString::number(unique)); }
+
+const QString &Context::id() const
+{ return m_id; }
+
+void Context::setName(const QString &name)
+{
+ m_name = name;
+ m_id = name;
+}
+
+const QString &Context::name() const
+{ return m_name; }
+
+void Context::setLineBeginContext(const QString &context)
+{ m_lineBeginContext = context; }
+
+const QString &Context::lineBeginContext() const
+{ return m_lineBeginContext; }
+
+void Context::setLineEndContext(const QString &context)
+{ m_lineEndContext = context; }
+
+const QString &Context::lineEndContext() const
+{ return m_lineEndContext; }
+
+void Context::setFallthroughContext(const QString &context)
+{ m_fallthroughContext = context; }
+
+const QString &Context::fallthroughContext() const
+{ return m_fallthroughContext; }
+
+void Context::setItemData(const QString &itemData)
+{ m_itemData = itemData; }
+
+const QString &Context::itemData() const
+{ return m_itemData; }
+
+void Context::setFallthrough(const QString &fallthrough)
+{ m_fallthrough = toBool(fallthrough); }
+
+bool Context::isFallthrough() const
+{ return m_fallthrough; }
+
+void Context::setDynamic(const QString &dynamic)
+{ m_dynamic = toBool(dynamic); }
+
+bool Context::isDynamic() const
+{ return m_dynamic; }
+
+void Context::updateDynamicRules(const QStringList &captures) const
+{
+ TextEditor::Internal::updateDynamicRules(m_rules, captures);
+}
+
+void Context::addRule(const QSharedPointer<Rule> &rule)
+{ m_rules.append(rule); }
+
+void Context::addRule(const QSharedPointer<Rule> &rule, int index)
+{ m_rules.insert(index, rule); }
+
+const QList<QSharedPointer<Rule> > & Context::rules() const
+{ return m_rules; }
+
+void Context::addIncludeRulesInstruction(const IncludeRulesInstruction &instruction)
+{ m_instructions.append(instruction); }
+
+const QList<IncludeRulesInstruction> &Context::includeRulesInstructions() const
+{ return m_instructions; }
+
+void Context::clearIncludeRulesInstructions()
+{ m_instructions.clear(); }
+
+void Context::setDefinition(const QSharedPointer<HighlightDefinition> &definition)
+{ m_definition = definition; }
+
+const QSharedPointer<HighlightDefinition> &Context::definition() const
+{ return m_definition; }
diff --git a/src/plugins/texteditor/generichighlighter/context.h b/src/plugins/texteditor/generichighlighter/context.h
new file mode 100644
index 0000000000..1d800ca2e5
--- /dev/null
+++ b/src/plugins/texteditor/generichighlighter/context.h
@@ -0,0 +1,110 @@
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** Commercial Usage
+**
+** Licensees holding valid Qt Commercial licenses may use this file in
+** accordance with the Qt Commercial License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Nokia.
+**
+** GNU Lesser General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://qt.nokia.com/contact.
+**
+**************************************************************************/
+
+#ifndef CONTEXT_H
+#define CONTEXT_H
+
+#include "includerulesinstruction.h"
+
+#include <QtCore/QString>
+#include <QtCore/QList>
+#include <QtCore/QSharedPointer>
+
+namespace TextEditor {
+namespace Internal {
+
+class Rule;
+class HighlightDefinition;
+
+class Context
+{
+public:
+ Context();
+ Context(const Context &context);
+ const Context &operator=(Context copy);
+ ~Context();
+
+ void configureId(const int unique);
+ const QString &id() const;
+
+ void setName(const QString &name);
+ const QString &name() const;
+
+ void setLineBeginContext(const QString &context);
+ const QString &lineBeginContext() const;
+
+ void setLineEndContext(const QString &context);
+ const QString &lineEndContext() const;
+
+ void setFallthroughContext(const QString &context);
+ const QString &fallthroughContext() const;
+
+ void setItemData(const QString &itemData);
+ const QString &itemData() const;
+
+ void setFallthrough(const QString &fallthrough);
+ bool isFallthrough() const;
+
+ void setDynamic(const QString &dynamic);
+ bool isDynamic() const;
+ void updateDynamicRules(const QStringList &captures) const;
+
+ void addRule(const QSharedPointer<Rule> &rule);
+ void addRule(const QSharedPointer<Rule> &rule, int index);
+ const QList<QSharedPointer<Rule> > &rules() const;
+
+ void addIncludeRulesInstruction(const IncludeRulesInstruction &instruction);
+ const QList<IncludeRulesInstruction> &includeRulesInstructions() const;
+ void clearIncludeRulesInstructions();
+
+ void setDefinition(const QSharedPointer<HighlightDefinition> &definition);
+ const QSharedPointer<HighlightDefinition> &definition() const;
+
+ void swap(Context &context);
+
+private:
+ QString m_id;
+ QString m_name;
+ QString m_lineBeginContext;
+ QString m_lineEndContext;
+ QString m_fallthroughContext;
+ QString m_itemData;
+ bool m_fallthrough;
+ bool m_dynamic;
+
+ QList<QSharedPointer<Rule> > m_rules;
+ QList<IncludeRulesInstruction> m_instructions;
+
+ QSharedPointer<HighlightDefinition> m_definition;
+};
+
+} // namespace Internal
+} // namespace TextEditor
+
+#endif // CONTEXT_H
diff --git a/src/plugins/texteditor/generichighlighter/dynamicrule.cpp b/src/plugins/texteditor/generichighlighter/dynamicrule.cpp
new file mode 100644
index 0000000000..24d7414dd7
--- /dev/null
+++ b/src/plugins/texteditor/generichighlighter/dynamicrule.cpp
@@ -0,0 +1,67 @@
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** Commercial Usage
+**
+** Licensees holding valid Qt Commercial licenses may use this file in
+** accordance with the Qt Commercial License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Nokia.
+**
+** GNU Lesser General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://qt.nokia.com/contact.
+**
+**************************************************************************/
+
+#include "dynamicrule.h"
+#include "reuse.h"
+
+using namespace TextEditor;
+using namespace Internal;
+
+DynamicRule::DynamicRule() : m_active(false)
+{}
+
+DynamicRule::~DynamicRule()
+{}
+
+void DynamicRule::setActive(const QString &active)
+{ m_active = toBool(active); }
+
+bool DynamicRule::isActive() const
+{ return m_active; }
+
+void DynamicRule::replaceExpressions(const QStringList &captures)
+{
+ doReplaceExpressions(captures);
+ updateDynamicRules(childs(), captures);
+}
+
+namespace TextEditor {
+namespace Internal {
+
+void updateDynamicRules(const QList<QSharedPointer<Rule> > &rules, const QStringList &captures)
+{
+ foreach (QSharedPointer<Rule> rule, rules) {
+ DynamicRule *dynamicRule = dynamic_cast<DynamicRule *>(rule.data());
+ if (dynamicRule && dynamicRule->isActive())
+ dynamicRule->replaceExpressions(captures);
+ }
+}
+
+} // namespace Internal
+} // namespace TextEditor
diff --git a/src/plugins/texteditor/generichighlighter/dynamicrule.h b/src/plugins/texteditor/generichighlighter/dynamicrule.h
new file mode 100644
index 0000000000..1e116d31bd
--- /dev/null
+++ b/src/plugins/texteditor/generichighlighter/dynamicrule.h
@@ -0,0 +1,64 @@
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** Commercial Usage
+**
+** Licensees holding valid Qt Commercial licenses may use this file in
+** accordance with the Qt Commercial License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Nokia.
+**
+** GNU Lesser General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://qt.nokia.com/contact.
+**
+**************************************************************************/
+
+#ifndef DYNAMICRULE_H
+#define DYNAMICRULE_H
+
+#include "rule.h"
+
+QT_BEGIN_NAMESPACE
+class QStringList;
+QT_END_NAMESPACE
+
+namespace TextEditor {
+namespace Internal {
+
+class DynamicRule : public Rule
+{
+public:
+ DynamicRule();
+ virtual ~DynamicRule();
+
+ void setActive(const QString &active);
+ bool isActive() const;
+
+ virtual void replaceExpressions(const QStringList &captures);
+
+private:
+ virtual void doReplaceExpressions(const QStringList &captures) = 0;
+
+ bool m_active;
+};
+
+void updateDynamicRules(const QList<QSharedPointer<Rule> > &rules, const QStringList &captures);
+
+} // namespace Internal
+} // namespace TextEditor
+
+#endif // DYNAMICRULE_H
diff --git a/src/plugins/texteditor/generichighlighter/highlightdefinition.cpp b/src/plugins/texteditor/generichighlighter/highlightdefinition.cpp
new file mode 100644
index 0000000000..7c723229d9
--- /dev/null
+++ b/src/plugins/texteditor/generichighlighter/highlightdefinition.cpp
@@ -0,0 +1,167 @@
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** Commercial Usage
+**
+** Licensees holding valid Qt Commercial licenses may use this file in
+** accordance with the Qt Commercial License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Nokia.
+**
+** GNU Lesser General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://qt.nokia.com/contact.
+**
+**************************************************************************/
+
+#include "highlightdefinition.h"
+#include "highlighterexception.h"
+#include "context.h"
+#include "keywordlist.h"
+#include "itemdata.h"
+#include "reuse.h"
+
+#include <QLatin1String>
+
+using namespace TextEditor;
+using namespace Internal;
+
+HighlightDefinition::HighlightDefinition() :
+ m_delimiters(QLatin1String(".():!+,-<=>%&/;?[]^{|}~\\*, \t")),
+ m_singleLineCommentAfterWhiteSpaces(false),
+ m_keywordCaseSensitivity(Qt::CaseSensitive)
+{}
+
+HighlightDefinition::~HighlightDefinition()
+{}
+
+template <class Element, class Container>
+const QSharedPointer<Element> &HighlightDefinition::
+GenericHelper::create(const QString &name, Container &container)
+{
+ if (name.isEmpty())
+ throw HighlighterException();
+
+ if (container.contains(name))
+ throw HighlighterException();
+
+ container.insert(name, QSharedPointer<Element>(new Element));
+ return *container.constFind(name);
+}
+
+template <class Element, class Container>
+const QSharedPointer<Element> &HighlightDefinition::
+GenericHelper::find(const QString &name, const Container &container) const
+{
+ typename Container::const_iterator it = container.find(name);
+ if (it == container.end())
+ throw HighlighterException();
+
+ return it.value();
+}
+
+const QSharedPointer<KeywordList> &HighlightDefinition::createKeywordList(const QString &list)
+{ return m_helper.create<KeywordList>(list, m_lists); }
+
+const QSharedPointer<KeywordList> &HighlightDefinition::keywordList(const QString &list)
+{ return m_helper.find<KeywordList>(list, m_lists); }
+
+const QSharedPointer<Context> &HighlightDefinition::createContext(const QString &context,
+ bool initial)
+{
+ if (initial)
+ m_initialContext = context;
+
+ return m_helper.create<Context>(context, m_contexts);
+}
+
+const QSharedPointer<Context> &HighlightDefinition::initialContext() const
+{ return m_helper.find<Context>(m_initialContext, m_contexts); }
+
+const QSharedPointer<Context> &HighlightDefinition::context(const QString &context) const
+{ return m_helper.find<Context>(context, m_contexts); }
+
+const QHash<QString, QSharedPointer<Context> > &HighlightDefinition::contexts() const
+{ return m_contexts; }
+
+const QSharedPointer<ItemData> &HighlightDefinition::createItemData(const QString &itemData)
+{ return m_helper.create<ItemData>(itemData, m_itemsData); }
+
+const QSharedPointer<ItemData> &HighlightDefinition::itemData(const QString &itemData) const
+{ return m_helper.find<ItemData>(itemData, m_itemsData); }
+
+void HighlightDefinition::setSingleLineComment(const QString &start)
+{ m_singleLineComment = start; }
+
+const QString &HighlightDefinition::singleLineComment() const
+{ return m_singleLineComment; }
+
+void HighlightDefinition::setCommentAfterWhitespaces(const QString &after)
+{
+ if (after == QLatin1String("afterwhitespace"))
+ m_singleLineCommentAfterWhiteSpaces = true;
+}
+
+bool HighlightDefinition::isCommentAfterWhiteSpaces() const
+{ return m_singleLineCommentAfterWhiteSpaces; }
+
+void HighlightDefinition::setMultiLineCommentStart(const QString &start)
+{ m_multiLineCommentStart = start; }
+
+const QString &HighlightDefinition::multiLineCommentStart() const
+{ return m_multiLineCommentStart; }
+
+void HighlightDefinition::setMultiLineCommentEnd(const QString &end)
+{ m_multiLineCommentEnd = end; }
+
+const QString &HighlightDefinition::multiLineCommentEnd() const
+{ return m_multiLineCommentEnd; }
+
+void HighlightDefinition::setMultiLineCommentRegion(const QString &region)
+{ m_multiLineCommentRegion = region; }
+
+const QString &HighlightDefinition::multiLineCommentRegion() const
+{ return m_multiLineCommentRegion; }
+
+void HighlightDefinition::removeDelimiters(const QString &characters)
+{
+ for (int i = 0; i < characters.length(); ++i)
+ m_delimiters.remove(characters.at(i));
+}
+
+void HighlightDefinition::addDelimiters(const QString &characters)
+{
+ for (int i = 0; i < characters.length(); ++i) {
+ if (!m_delimiters.contains(characters.at(i)))
+ m_delimiters.append(characters.at(i));
+ }
+}
+
+bool HighlightDefinition::isDelimiter(const QChar &character) const
+{
+ if (m_delimiters.contains(character))
+ return true;
+ return false;
+}
+
+void HighlightDefinition::setKeywordsSensitive(const QString &sensitivity)
+{
+ if (!sensitivity.isEmpty())
+ m_keywordCaseSensitivity = toCaseSensitivity(toBool(sensitivity));
+}
+
+Qt::CaseSensitivity HighlightDefinition::keywordsSensitive() const
+{ return m_keywordCaseSensitivity; }
diff --git a/src/plugins/texteditor/generichighlighter/highlightdefinition.h b/src/plugins/texteditor/generichighlighter/highlightdefinition.h
new file mode 100644
index 0000000000..2f48bc24c8
--- /dev/null
+++ b/src/plugins/texteditor/generichighlighter/highlightdefinition.h
@@ -0,0 +1,117 @@
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** Commercial Usage
+**
+** Licensees holding valid Qt Commercial licenses may use this file in
+** accordance with the Qt Commercial License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Nokia.
+**
+** GNU Lesser General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://qt.nokia.com/contact.
+**
+**************************************************************************/
+
+#ifndef HIGHLIGHTDEFINITION_H
+#define HIGHLIGHTDEFINITION_H
+
+#include <QtCore/QString>
+#include <QtCore/QHash>
+#include <QtCore/QSharedPointer>
+
+namespace TextEditor {
+namespace Internal {
+
+class KeywordList;
+class Context;
+class ItemData;
+
+class HighlightDefinition
+{
+public:
+ HighlightDefinition();
+ ~HighlightDefinition();
+
+ const QSharedPointer<KeywordList> &createKeywordList(const QString &list);
+ const QSharedPointer<KeywordList> &keywordList(const QString &list);
+
+ const QSharedPointer<Context> &createContext(const QString &context, bool initial);
+ const QSharedPointer<Context> &initialContext() const;
+ const QSharedPointer<Context> &context(const QString &context) const;
+ const QHash<QString, QSharedPointer<Context> > &contexts() const;
+
+ const QSharedPointer<ItemData> &createItemData(const QString &itemData);
+ const QSharedPointer<ItemData> &itemData(const QString &itemData) const;
+
+ void setKeywordsSensitive(const QString &sensitivity);
+ Qt::CaseSensitivity keywordsSensitive() const;
+
+ void addDelimiters(const QString &characters);
+ void removeDelimiters(const QString &characters);
+ bool isDelimiter(const QChar &character) const;
+
+ void setSingleLineComment(const QString &start);
+ const QString &singleLineComment() const;
+
+ void setCommentAfterWhitespaces(const QString &after);
+ bool isCommentAfterWhiteSpaces() const;
+
+ void setMultiLineCommentStart(const QString &start);
+ const QString &multiLineCommentStart() const;
+
+ void setMultiLineCommentEnd(const QString &end);
+ const QString &multiLineCommentEnd() const;
+
+ void setMultiLineCommentRegion(const QString &region);
+ const QString &multiLineCommentRegion() const;
+
+private:
+ Q_DISABLE_COPY(HighlightDefinition)
+
+ struct GenericHelper
+ {
+ template <class Element, class Container>
+ const QSharedPointer<Element> &create(const QString &name, Container &container);
+
+ template <class Element, class Container>
+ const QSharedPointer<Element> &find(const QString &name, const Container &container) const;
+ };
+ GenericHelper m_helper;
+
+ QHash<QString, QSharedPointer<KeywordList> > m_lists;
+ QHash<QString, QSharedPointer<Context> > m_contexts;
+ QHash<QString, QSharedPointer<ItemData> > m_itemsData;
+
+ QString m_initialContext;
+
+ QString m_delimiters;
+
+ QString m_singleLineComment;
+ bool m_singleLineCommentAfterWhiteSpaces;
+
+ QString m_multiLineCommentStart;
+ QString m_multiLineCommentEnd;
+ QString m_multiLineCommentRegion;
+
+ Qt::CaseSensitivity m_keywordCaseSensitivity;
+};
+
+} // namespace Internal
+} // namespace TextEditor
+
+#endif // HIGHLIGHTDEFINITION_H
diff --git a/src/plugins/texteditor/generichighlighter/highlightdefinitionhandler.cpp b/src/plugins/texteditor/generichighlighter/highlightdefinitionhandler.cpp
new file mode 100644
index 0000000000..f18d3de8f2
--- /dev/null
+++ b/src/plugins/texteditor/generichighlighter/highlightdefinitionhandler.cpp
@@ -0,0 +1,461 @@
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** Commercial Usage
+**
+** Licensees holding valid Qt Commercial licenses may use this file in
+** accordance with the Qt Commercial License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Nokia.
+**
+** GNU Lesser General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://qt.nokia.com/contact.
+**
+**************************************************************************/
+
+#include "highlightdefinitionhandler.h"
+#include "highlightdefinition.h"
+#include "specificrules.h"
+#include "itemdata.h"
+#include "keywordlist.h"
+#include "context.h"
+#include "reuse.h"
+#include "manager.h"
+#include "highlighterexception.h"
+
+#include <QLatin1String>
+
+using namespace TextEditor;
+using namespace Internal;
+
+namespace {
+ static const QLatin1String kName("name");
+ static const QLatin1String kList("list");
+ static const QLatin1String kItem("item");
+ static const QLatin1String kContext("context");
+ static const QLatin1String kAttribute("attribute");
+ static const QLatin1String kDynamic("dynamic");
+ static const QLatin1String kFallthrough("fallthrough");
+ static const QLatin1String kLineEndContext("lineEndContext");
+ static const QLatin1String kLineBeginContext("lineBeginContext");
+ static const QLatin1String kFallthroughContext("fallthroughContext");
+ static const QLatin1String kBeginRegion("beginRegion");
+ static const QLatin1String kEndRegion("endRegion");
+ static const QLatin1String kLookAhead("lookAhead");
+ static const QLatin1String kFirstNonSpace("firstNonSpace");
+ static const QLatin1String kColumn("column");
+ static const QLatin1String kItemData("itemData");
+ static const QLatin1String kDefStyleNum("defStyleNum");
+ static const QLatin1String kColor("color");
+ static const QLatin1String kSelColor("selColor");
+ static const QLatin1String kItalic("italic");
+ static const QLatin1String kBold("bold");
+ static const QLatin1String kUnderline("underline");
+ static const QLatin1String kStrikeout("strikeout");
+ static const QLatin1String kChar("char");
+ static const QLatin1String kChar1("char1");
+ static const QLatin1String kString("String");
+ static const QLatin1String kInsensitive("insensitive");
+ static const QLatin1String kMinimal("minimal");
+ static const QLatin1String kKeywords("keywords");
+ static const QLatin1String kCaseSensitive("casesensitive");
+ static const QLatin1String kWeakDeliminator("weakDeliminator");
+ static const QLatin1String kAdditionalDeliminator("additionalDeliminator");
+ static const QLatin1String kWordWrapDeliminator("wordWrapDeliminator");
+ static const QLatin1String kComment("comment");
+ static const QLatin1String kPosition("position");
+ static const QLatin1String kSingleLine("singleline");
+ static const QLatin1String kMultiLine("multiline");
+ static const QLatin1String kStart("start");
+ static const QLatin1String kEnd("end");
+ static const QLatin1String kRegion("region");
+ static const QLatin1String kDetectChar("DetectChar");
+ static const QLatin1String kDetect2Chars("Detect2Chars");
+ static const QLatin1String kAnyChar("AnyChar");
+ static const QLatin1String kStringDetect("StringDetect");
+ static const QLatin1String kRegExpr("RegExpr");
+ static const QLatin1String kKeyword("keyword");
+ static const QLatin1String kInt("Int");
+ static const QLatin1String kFloat("Float");
+ static const QLatin1String kHlCOct("HlCOct");
+ static const QLatin1String kHlCHex("HlCHex");
+ static const QLatin1String kHlCStringChar("HlCStringChar");
+ static const QLatin1String kHlCChar("HlCChar");
+ static const QLatin1String kRangeDetect("RangeDetect");
+ static const QLatin1String kLineContinue("LineContinue");
+ static const QLatin1String kIncludeRules("IncludeRules");
+ static const QLatin1String kDetectSpaces("DetectSpaces");
+ static const QLatin1String kDetectIdentifier("DetectIdentifier");
+ static const QLatin1String kLanguage("language");
+ static const QLatin1String kExtensions("extensions");
+ static const QLatin1String kIncludeAttrib("includeAttrib");
+ static const QLatin1String kHash("#");
+ static const QLatin1String kDoubleHash("##");
+}
+
+HighlightDefinitionHandler::
+HighlightDefinitionHandler(const QSharedPointer<HighlightDefinition> &definition) :
+ m_definition(definition),
+ m_processingKeyword(false),
+ m_initialContext(true)
+{}
+
+HighlightDefinitionHandler::~HighlightDefinitionHandler()
+{}
+
+bool HighlightDefinitionHandler::startDocument()
+{
+ return true;
+}
+
+bool HighlightDefinitionHandler::endDocument()
+{
+ processIncludeRules();
+ return true;
+}
+
+bool HighlightDefinitionHandler::startElement(const QString &,
+ const QString &,
+ const QString &qName,
+ const QXmlAttributes &atts)
+{
+ if (qName == kList) {
+ listElementStarted(atts);
+ } else if (qName == kItem) {
+ itemElementStarted();
+ } else if (qName == kContext) {
+ contextElementStarted(atts);
+ } else if (qName == kItemData) {
+ itemDataElementStarted(atts);
+ } else if (qName == kComment) {
+ commentElementStarted(atts);
+ } else if (qName == kKeywords) {
+ keywordsElementStarted(atts);
+ } else if (qName == kDetectChar) {
+ detectCharStarted(atts);
+ } else if (qName == kDetect2Chars) {
+ detect2CharsStarted(atts);
+ } else if (qName == kAnyChar) {
+ anyCharStarted(atts);
+ } else if (qName == kStringDetect) {
+ stringDetectedStarted(atts);
+ } else if (qName == kRegExpr) {
+ regExprStarted(atts);
+ } else if (qName == kKeyword) {
+ keywordStarted(atts);
+ } else if (qName == kInt) {
+ intStarted(atts);
+ } else if (qName == kFloat) {
+ floatStarted(atts);
+ } else if (qName == kHlCOct) {
+ hlCOctStarted(atts);
+ } else if (qName == kHlCHex) {
+ hlCHexStarted(atts);
+ } else if (qName == kHlCStringChar) {
+ hlCStringCharStarted(atts);
+ } else if (qName == kHlCChar) {
+ hlCCharStarted(atts);
+ } else if (qName == kRangeDetect) {
+ rangeDetectStarted(atts);
+ } else if (qName == kLineContinue) {
+ lineContinue(atts);
+ } else if (qName == kIncludeRules) {
+ includeRulesStarted(atts);
+ } else if (qName == kDetectSpaces) {
+ detectSpacesStarted(atts);
+ } else if (qName == kDetectIdentifier) {
+ detectIdentifier(atts);
+ }
+
+ return true;
+}
+
+bool HighlightDefinitionHandler::endElement(const QString &, const QString &, const QString &qName)
+{
+ if (qName == kItem) {
+ m_currentList->addKeyword(m_currentKeyword.trimmed());
+ m_processingKeyword = false;
+ } else if (qName == kDetectChar || qName == kDetect2Chars || qName == kAnyChar ||
+ qName == kStringDetect || qName == kRegExpr || qName == kKeyword || qName == kInt ||
+ qName == kFloat || qName == kHlCOct || qName == kHlCHex || qName == kHlCStringChar ||
+ qName == kHlCChar || qName == kRangeDetect || qName == kLineContinue ||
+ qName == kDetectSpaces || qName == kDetectIdentifier) {
+ m_currentRule.pop();
+ }
+
+ return true;
+}
+
+bool HighlightDefinitionHandler::characters(const QString& ch)
+{
+ // Character data of an element may be reported in more than one chunk.
+ if (m_processingKeyword)
+ m_currentKeyword.append(ch);
+
+ return true;
+}
+
+void HighlightDefinitionHandler::listElementStarted(const QXmlAttributes &atts)
+{
+ m_currentList = m_definition->createKeywordList(atts.value(kName));
+}
+
+void HighlightDefinitionHandler::itemElementStarted()
+{
+ m_currentKeyword.clear();
+ m_processingKeyword = true;
+}
+
+void HighlightDefinitionHandler::contextElementStarted(const QXmlAttributes &atts)
+{
+ m_currentContext = m_definition->createContext(atts.value(kName), m_initialContext);
+ m_currentContext->setDefinition(m_definition);
+ m_currentContext->setName(atts.value(kName));
+ m_currentContext->setItemData(atts.value(kAttribute));
+ m_currentContext->setDynamic(atts.value(kDynamic));
+ m_currentContext->setFallthrough(atts.value(kFallthrough));
+ m_currentContext->setFallthroughContext(atts.value(kFallthroughContext));
+ m_currentContext->setLineBeginContext(atts.value(kLineBeginContext));
+ m_currentContext->setLineEndContext(atts.value(kLineEndContext));
+
+ m_initialContext = false;
+}
+
+void HighlightDefinitionHandler::ruleElementStarted(const QXmlAttributes &atts,
+ const QSharedPointer<Rule> &rule)
+{
+ // The definition of a rule is not necessarily the same of its enclosing context because of
+ // externally included rules.
+ rule->setDefinition(m_definition);
+ rule->setItemData(atts.value(kAttribute));
+ rule->setContext(atts.value(kContext));
+ rule->setBeginRegion(atts.value(kBeginRegion));
+ rule->setEndRegion(atts.value(kEndRegion));
+ rule->setLookAhead(atts.value(kLookAhead));
+ rule->setFirstNonSpace(atts.value(kFirstNonSpace));
+ rule->setColumn(atts.value(kColumn));
+
+ if (m_currentRule.isEmpty())
+ m_currentContext->addRule(rule);
+ else
+ m_currentRule.top()->addChild(rule);
+
+ m_currentRule.push(rule);
+}
+
+void HighlightDefinitionHandler::itemDataElementStarted(const QXmlAttributes &atts) const
+{
+ QSharedPointer<ItemData> itemData = m_definition->createItemData(atts.value(kName));
+ itemData->setStyle(atts.value(kDefStyleNum));
+ itemData->setColor(atts.value(kColor));
+ itemData->setSelectionColor(atts.value(kSelColor));
+ itemData->setItalic(atts.value(kItalic));
+ itemData->setBold(atts.value(kBold));
+ itemData->setUnderlined(atts.value(kUnderline));
+ itemData->setStrikedOut(atts.value(kStrikeout));
+}
+
+void HighlightDefinitionHandler::commentElementStarted(const QXmlAttributes &atts) const
+{
+ const QString &commentType = atts.value(kName);
+ if (commentType.compare(kSingleLine, Qt::CaseInsensitive) == 0) {
+ m_definition->setSingleLineComment(atts.value(kStart));
+ m_definition->setCommentAfterWhitespaces(atts.value(kPosition));
+ } else if (commentType.compare(kMultiLine, Qt::CaseInsensitive) == 0) {
+ m_definition->setMultiLineCommentStart(atts.value(kStart));
+ m_definition->setMultiLineCommentEnd(atts.value(kEnd));
+ m_definition->setMultiLineCommentRegion(atts.value(kRegion));
+ }
+}
+
+void HighlightDefinitionHandler::keywordsElementStarted(const QXmlAttributes &atts) const
+{
+ // Global case sensitivity appears last in the document (required by dtd) and is set here.
+ m_definition->setKeywordsSensitive(atts.value(kCaseSensitive));
+ m_definition->removeDelimiters(atts.value(kWeakDeliminator));
+ m_definition->addDelimiters(atts.value(kAdditionalDeliminator));
+ //@todo: wordWrapDelimiters?
+}
+
+void HighlightDefinitionHandler::detectCharStarted(const QXmlAttributes &atts)
+{
+ DetectCharRule *rule = new DetectCharRule;
+ rule->setChar(atts.value(kChar));
+ rule->setActive(atts.value(kDynamic));
+ ruleElementStarted(atts, QSharedPointer<Rule>(rule));
+}
+
+void HighlightDefinitionHandler::detect2CharsStarted(const QXmlAttributes &atts)
+{
+ Detect2CharsRule *rule = new Detect2CharsRule;
+ rule->setChar(atts.value(kChar));
+ rule->setChar1(atts.value(kChar1));
+ rule->setActive(atts.value(kDynamic));
+ ruleElementStarted(atts, QSharedPointer<Rule>(rule));
+}
+
+void HighlightDefinitionHandler::anyCharStarted(const QXmlAttributes &atts)
+{
+ AnyCharRule *rule = new AnyCharRule;
+ rule->setCharacterSet(atts.value(kString));
+ ruleElementStarted(atts, QSharedPointer<Rule>(rule));
+}
+
+void HighlightDefinitionHandler::stringDetectedStarted(const QXmlAttributes &atts)
+{
+ StringDetectRule *rule = new StringDetectRule;
+ rule->setString(atts.value(kString));
+ rule->setInsensitive(atts.value(kInsensitive));
+ rule->setActive(atts.value(kDynamic));
+ ruleElementStarted(atts, QSharedPointer<Rule>(rule));
+}
+
+void HighlightDefinitionHandler::regExprStarted(const QXmlAttributes &atts)
+{
+ RegExprRule *rule = new RegExprRule;
+ rule->setPattern(atts.value(kString));
+ rule->setMinimal(atts.value(kMinimal));
+ rule->setInsensitive(atts.value(kInsensitive));
+ rule->setActive(atts.value(kDynamic));
+ ruleElementStarted(atts, QSharedPointer<Rule>(rule));
+}
+
+void HighlightDefinitionHandler::keywordStarted(const QXmlAttributes &atts)
+{
+ KeywordRule *rule = new KeywordRule(m_definition);
+ rule->setList(atts.value(kString));
+ rule->setInsensitive(atts.value(kInsensitive));
+ ruleElementStarted(atts, QSharedPointer<Rule>(rule));
+}
+
+void HighlightDefinitionHandler::intStarted(const QXmlAttributes &atts)
+{
+ ruleElementStarted(atts, QSharedPointer<Rule>(new IntRule));
+}
+
+void HighlightDefinitionHandler::floatStarted(const QXmlAttributes &atts)
+{
+ ruleElementStarted(atts, QSharedPointer<Rule>(new FloatRule));
+}
+
+void HighlightDefinitionHandler::hlCOctStarted(const QXmlAttributes &atts)
+{
+ ruleElementStarted(atts, QSharedPointer<Rule>(new HlCOctRule));
+}
+
+void HighlightDefinitionHandler::hlCHexStarted(const QXmlAttributes &atts)
+{
+ ruleElementStarted(atts, QSharedPointer<Rule>(new HlCHexRule));
+}
+
+void HighlightDefinitionHandler::hlCStringCharStarted(const QXmlAttributes &atts)
+{
+ ruleElementStarted(atts, QSharedPointer<Rule>(new HlCStringCharRule));
+}
+
+void HighlightDefinitionHandler::hlCCharStarted(const QXmlAttributes &atts)
+{
+ ruleElementStarted(atts, QSharedPointer<Rule>(new HlCCharRule));
+}
+
+void HighlightDefinitionHandler::rangeDetectStarted(const QXmlAttributes &atts)
+{
+ RangeDetectRule *rule = new RangeDetectRule;
+ rule->setChar(atts.value(kChar));
+ rule->setChar1(atts.value(kChar1));
+ ruleElementStarted(atts, QSharedPointer<Rule>(rule));
+}
+
+void HighlightDefinitionHandler::lineContinue(const QXmlAttributes &atts)
+{
+ ruleElementStarted(atts, QSharedPointer<Rule>(new LineContinueRule));
+}
+
+void HighlightDefinitionHandler::includeRulesStarted(const QXmlAttributes &atts)
+{
+ // Include rules are treated as instructions for latter processing.
+ IncludeRulesInstruction instruction(atts.value(kContext), m_currentContext->rules().size(),
+ atts.value(kIncludeAttrib));
+
+ // Include rules (as many others) are not allowed as a child.
+ m_currentContext->addIncludeRulesInstruction(instruction);
+}
+
+void HighlightDefinitionHandler::detectSpacesStarted(const QXmlAttributes &atts)
+{
+ ruleElementStarted(atts, QSharedPointer<Rule>(new DetectSpacesRule));
+}
+
+void HighlightDefinitionHandler::detectIdentifier(const QXmlAttributes &atts)
+{
+ ruleElementStarted(atts, QSharedPointer<Rule>(new DetectIdentifierRule));
+}
+
+void HighlightDefinitionHandler::processIncludeRules() const
+{
+ const QHash<QString, QSharedPointer<Context> > &allContexts = m_definition->contexts();
+ foreach (const QSharedPointer<Context> &context, allContexts)
+ processIncludeRules(context);
+}
+
+void HighlightDefinitionHandler::processIncludeRules(const QSharedPointer<Context> &context) const
+{
+ if (context->includeRulesInstructions().isEmpty())
+ return;
+
+ int rulesIncluded = 0;
+ const QList<IncludeRulesInstruction> &instructions = context->includeRulesInstructions();
+ foreach (const IncludeRulesInstruction &instruction, instructions) {
+
+ QSharedPointer<Context> sourceContext;
+ const QString &sourceName = instruction.sourceContext();
+ if (sourceName.startsWith(kDoubleHash)) {
+ // This refers to an external definition. The rules included are the ones from its
+ // initial context. Others contexts and rules from the external definition will work
+ // transparently to the highlighter. This is because contexts and rules know the
+ // definition they are from.
+ QString externalName = QString::fromRawData(sourceName.unicode() + 2,
+ sourceName.length() - 2);
+ const QString &id = Manager::instance()->definitionIdByName(externalName);
+
+ // If there is an incorrect circular dependency among definitions this is skipped.
+ if (Manager::instance()->isBuildingDefinition(id))
+ continue;
+
+ const QSharedPointer<HighlightDefinition> &externalDefinition =
+ Manager::instance()->definition(id);
+ sourceContext = externalDefinition->initialContext();
+ } else if (!sourceName.startsWith(kHash)) {
+ sourceContext = m_definition->context(sourceName);
+
+ // Recursion is done only for context direct rules. Child rules are not processed
+ // because they cannot be include rules.
+ processIncludeRules(sourceContext);
+ }
+
+ if (instruction.replaceItemData()) {
+ context->setItemData(sourceContext->itemData());
+ context->setDefinition(sourceContext->definition());
+ }
+
+ foreach (QSharedPointer<Rule> rule, sourceContext->rules()) {
+ context->addRule(rule, instruction.indexHint() + rulesIncluded);
+ ++rulesIncluded;
+ }
+ }
+ context->clearIncludeRulesInstructions();
+}
diff --git a/src/plugins/texteditor/generichighlighter/highlightdefinitionhandler.h b/src/plugins/texteditor/generichighlighter/highlightdefinitionhandler.h
new file mode 100644
index 0000000000..e08be97649
--- /dev/null
+++ b/src/plugins/texteditor/generichighlighter/highlightdefinitionhandler.h
@@ -0,0 +1,106 @@
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** Commercial Usage
+**
+** Licensees holding valid Qt Commercial licenses may use this file in
+** accordance with the Qt Commercial License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Nokia.
+**
+** GNU Lesser General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://qt.nokia.com/contact.
+**
+**************************************************************************/
+
+#ifndef HIGHLIGHTDEFINITIONHANDLER_H
+#define HIGHLIGHTDEFINITIONHANDLER_H
+
+#include <QtCore/QString>
+#include <QtCore/QList>
+#include <QtCore/QSharedPointer>
+#include <QtCore/QStack>
+
+#include <QtXml/QXmlDefaultHandler>
+
+namespace TextEditor {
+namespace Internal {
+
+class KeywordList;
+class Context;
+class Rule;
+class HighlightDefinition;
+
+class HighlightDefinitionHandler : public QXmlDefaultHandler
+{
+public:
+ HighlightDefinitionHandler(const QSharedPointer<HighlightDefinition> &definition);
+ ~HighlightDefinitionHandler();
+
+ bool startDocument();
+ bool endDocument();
+ bool startElement(const QString &namespaceURI, const QString &localName,
+ const QString &qName, const QXmlAttributes &atts);
+ bool endElement(const QString &namespaceURI, const QString &localName, const QString &qName);
+ bool characters(const QString &ch);
+
+private:
+ void listElementStarted(const QXmlAttributes &atts);
+ void itemElementStarted();
+ void contextElementStarted(const QXmlAttributes &atts);
+ void itemDataElementStarted(const QXmlAttributes &atts) const;
+ void commentElementStarted(const QXmlAttributes &atts) const;
+ void keywordsElementStarted(const QXmlAttributes &atts) const;
+ void ruleElementStarted(const QXmlAttributes &atts, const QSharedPointer<Rule> &rule);
+
+ // Specific rules.
+ void detectCharStarted(const QXmlAttributes &atts);
+ void detect2CharsStarted(const QXmlAttributes &atts);
+ void anyCharStarted(const QXmlAttributes &atts);
+ void stringDetectedStarted(const QXmlAttributes &atts);
+ void regExprStarted(const QXmlAttributes &atts);
+ void keywordStarted(const QXmlAttributes &atts);
+ void intStarted(const QXmlAttributes &atts);
+ void floatStarted(const QXmlAttributes &atts);
+ void hlCOctStarted(const QXmlAttributes &atts);
+ void hlCHexStarted(const QXmlAttributes &atts);
+ void hlCStringCharStarted(const QXmlAttributes &atts);
+ void hlCCharStarted(const QXmlAttributes &atts);
+ void rangeDetectStarted(const QXmlAttributes &atts);
+ void lineContinue(const QXmlAttributes &atts);
+ void includeRulesStarted(const QXmlAttributes &atts);
+ void detectSpacesStarted(const QXmlAttributes &atts);
+ void detectIdentifier(const QXmlAttributes &atts);
+
+ void processIncludeRules() const;
+ void processIncludeRules(const QSharedPointer<Context> &context) const;
+
+ QSharedPointer<HighlightDefinition> m_definition;
+
+ bool m_processingKeyword;
+ QString m_currentKeyword;
+ QSharedPointer<KeywordList> m_currentList;
+ QSharedPointer<Context> m_currentContext;
+ QStack<QSharedPointer<Rule> > m_currentRule;
+
+ bool m_initialContext;
+};
+
+} // namespace Internal
+} // namespace TextEditor
+
+#endif // HIGHLIGHTDEFINITIONHANDLER_H
diff --git a/src/plugins/texteditor/generichighlighter/highlighter.cpp b/src/plugins/texteditor/generichighlighter/highlighter.cpp
new file mode 100644
index 0000000000..27b0309795
--- /dev/null
+++ b/src/plugins/texteditor/generichighlighter/highlighter.cpp
@@ -0,0 +1,478 @@
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** Commercial Usage
+**
+** Licensees holding valid Qt Commercial licenses may use this file in
+** accordance with the Qt Commercial License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Nokia.
+**
+** GNU Lesser General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://qt.nokia.com/contact.
+**
+**************************************************************************/
+
+#include "highlighter.h"
+#include "highlightdefinition.h"
+#include "context.h"
+#include "rule.h"
+#include "itemdata.h"
+#include "highlighterexception.h"
+#include "progressdata.h"
+#include "reuse.h"
+#include "texteditorconstants.h"
+#include "fontsettings.h"
+
+#include <QtCore/QLatin1String>
+#include <QtCore/QLatin1Char>
+
+using namespace TextEditor;
+using namespace Internal;
+
+namespace {
+ static const QLatin1String kStay("#stay");
+ static const QLatin1String kPop("#pop");
+ static const QLatin1Char kBackSlash('\\');
+ static const QLatin1Char kHash('#');
+}
+
+Highlighter::Highlighter(const QSharedPointer<Context> &defaultContext,QTextDocument *parent) :
+ QSyntaxHighlighter(parent),
+ m_persistentStatesCounter(PersistentsStart),
+ m_dynamicContextsCounter(0),
+ m_isBroken(false),
+ m_defaultContext(defaultContext)
+{
+ m_persistentStates.insert(m_defaultContext->name(), Default);
+}
+
+Highlighter::~Highlighter()
+{}
+
+Highlighter::BlockData::BlockData()
+{}
+
+Highlighter::BlockData::~BlockData()
+{}
+
+void Highlighter::highlightBlock(const QString &text)
+{
+ if (m_isBroken)
+ return;
+
+ try {
+ setupDataForBlock(text);
+
+ handleContextChange(m_currentContext->lineBeginContext(), m_currentContext->definition());
+
+ ProgressData progress;
+ const int length = text.length();
+ while (progress.offset() < length) {
+
+ if (progress.offset() > 0 &&
+ progress.onlySpacesSoFar() &&
+ !text.at(progress.offset()).isSpace()) {
+ progress.setOnlySpacesSoFar(false);
+ }
+
+ iterateThroughRules(text, length, &progress, false, m_currentContext->rules());
+ }
+
+ handleContextChange(m_currentContext->lineEndContext(), m_currentContext->definition(),
+ false);
+ } catch (const HighlighterException &) {
+ m_isBroken = true;
+ return;
+ }
+
+ m_contexts.clear();
+ applyVisualWhitespaceFormat(text);
+}
+
+void Highlighter::setupDataForBlock(const QString &text)
+{
+ if (currentBlockState() == WillContinue)
+ analyseConsistencyOfWillContinueBlock(text);
+
+ if (previousBlockState() == Default || previousBlockState() == -1)
+ setupDefault();
+ else if (previousBlockState() == WillContinue)
+ setupFromWillContinue();
+ else if (previousBlockState() == Continued)
+ setupFromContinued();
+ else
+ setupFromPersistent();
+
+ setCurrentContext();
+}
+
+void Highlighter::setupDefault()
+{
+ m_contexts.push_back(m_defaultContext);
+
+ setCurrentBlockState(Default);
+}
+
+void Highlighter::setupFromWillContinue()
+{
+ BlockData *previousData = static_cast<BlockData *>(currentBlock().previous().userData());
+ m_contexts.push_back(previousData->m_contextToContinue);
+
+ if (!currentBlockUserData()) {
+ BlockData *data = initializeBlockData();
+ data->m_originalState = previousData->m_originalState;
+ }
+
+ if (currentBlockState() == Default || currentBlockState() == -1)
+ setCurrentBlockState(Continued);
+}
+
+void Highlighter::setupFromContinued()
+{
+ BlockData *previousData = static_cast<BlockData *>(currentBlock().previous().userData());
+
+ Q_ASSERT(previousData->m_originalState != WillContinue &&
+ previousData->m_originalState != Continued);
+
+ if (previousData->m_originalState == Default || previousData->m_originalState == -1)
+ m_contexts.push_back(m_defaultContext);
+ else
+ pushContextSequence(previousData->m_originalState);
+
+ setCurrentBlockState(previousData->m_originalState);
+}
+
+void Highlighter::setupFromPersistent()
+{
+ pushContextSequence(previousBlockState());
+
+ setCurrentBlockState(previousBlockState());
+}
+
+void Highlighter::iterateThroughRules(const QString &text,
+ const int length,
+ ProgressData *progress,
+ const bool childRule,
+ const QList<QSharedPointer<Rule> > &rules)
+{
+ typedef QList<QSharedPointer<Rule> >::const_iterator RuleIterator;
+
+ bool contextChanged = false;
+ bool atLeastOneMatch = false;
+
+ RuleIterator it = rules.begin();
+ RuleIterator endIt = rules.end();
+ while (it != endIt && progress->offset() < length) {
+ int startOffset = progress->offset();
+
+ const QSharedPointer<Rule> &rule = *it;
+ if (rule->matchSucceed(text, length, progress)) {
+ atLeastOneMatch = true;
+
+ if (progress->willContinueLine()) {
+ createWillContinueBlock();
+ progress->setWillContinueLine(false);
+ progress->setOffset(length);
+ } else {
+ if (rule->hasChild())
+ iterateThroughRules(text, length, progress, true, rule->childs());
+
+ if (!rule->context().isEmpty() && contextChangeRequired(rule->context())) {
+ m_currentCaptures = progress->captures();
+ changeContext(rule->context(), rule->definition());
+ contextChanged = true;
+ }
+ }
+
+ // Format is not applied to child rules directly (but relative to the offset of their
+ // parent) nor to look ahead rules.
+ if (!childRule && !rule->isLookAhead()) {
+ if (rule->itemData().isEmpty())
+ applyFormat(startOffset, progress->offset() - startOffset,
+ m_currentContext->itemData(), m_currentContext->definition());
+ else
+ applyFormat(startOffset, progress->offset() - startOffset, rule->itemData(),
+ rule->definition());
+ }
+
+ // When there is a match of one child rule the others should be skipped. Otherwise
+ // the highlighting would be incorret in a case like 9ULLLULLLUULLULLUL, for example.
+ if (contextChanged || childRule) {
+ break;
+ } else {
+ it = rules.begin();
+ continue;
+ }
+ }
+ ++it;
+ }
+
+ if (!childRule && !atLeastOneMatch) {
+ if (m_currentContext->isFallthrough()) {
+ handleContextChange(m_currentContext->fallthroughContext(),
+ m_currentContext->definition());
+ iterateThroughRules(text, length, progress, false, m_currentContext->rules());
+ } else {
+ applyFormat(progress->offset(), 1, m_currentContext->itemData(),
+ m_currentContext->definition());
+ progress->incrementOffset();
+ }
+ }
+}
+
+bool Highlighter::contextChangeRequired(const QString &contextName) const
+{
+ if (contextName == kStay)
+ return false;
+ return true;
+}
+
+void Highlighter::changeContext(const QString &contextName,
+ const QSharedPointer<HighlightDefinition> &definition,
+ const bool setCurrent)
+{
+ if (contextName.startsWith(kPop)) {
+ QStringList list = contextName.split(kHash, QString::SkipEmptyParts);
+ for (int i = 0; i < list.size(); ++i)
+ m_contexts.pop_back();
+
+ if (currentBlockState() >= PersistentsStart) {
+ // One or more persistent contexts were popped.
+ const QString &currentSequence = currentContextSequence();
+ if (m_persistentStates.contains(currentSequence))
+ setCurrentBlockState(m_persistentStates.value(currentContextSequence()));
+ else
+ setCurrentBlockState(m_leadingStates.value(currentContextSequence()));
+ }
+ } else {
+ const QSharedPointer<Context> &context = definition->context(contextName);
+
+ if (context->isDynamic())
+ pushDynamicContext(context);
+ else
+ m_contexts.push_back(context);
+
+ if (m_contexts.back()->lineEndContext() == kStay) {
+ // A persistent context was pushed.
+ const QString &currentSequence = currentContextSequence();
+ mapContextSequence(currentSequence);
+ setCurrentBlockState(m_persistentStates.value(currentSequence));
+ }
+ }
+
+ if (setCurrent)
+ setCurrentContext();
+}
+
+void Highlighter::handleContextChange(const QString &contextName,
+ const QSharedPointer<HighlightDefinition> &definition,
+ const bool setCurrent)
+{
+ if (!contextName.isEmpty() && contextChangeRequired(contextName))
+ changeContext(contextName, definition, setCurrent);
+}
+
+void Highlighter::applyFormat(int offset,
+ int count,
+ const QString &itemDataName,
+ const QSharedPointer<HighlightDefinition> &definition)
+{
+ if (count == 0)
+ return;
+
+ QSharedPointer<ItemData> itemData;
+ try {
+ itemData = definition->itemData(itemDataName);
+ } catch (const HighlighterException &) {
+ // There are some broken files. For instance, the Printf context in java.xml points to an
+ // inexistent Printf item data. These cases are considered to have normal text style.
+ return;
+ }
+
+ if (itemData->style() != ItemData::kDsNormal) {
+ QTextCharFormat format = m_genericFormats.value(itemData->style());
+
+ if (itemData->isCustomized()) {
+ // Please notice that the following are applied every time for item datas which have
+ // customizations. The configureFormats method could be used to provide a "one time"
+ // configuration, but it would probably require to traverse all item datas from all
+ // definitions available/loaded (either to set the values or for some "notifying"
+ // strategy). This is because the highlighter does not really know on which
+ // definition(s) it is working. Since not many item datas specify customizations I
+ // think this approach would fit better. If there are other ideas...
+ if (itemData->color().isValid())
+ format.setForeground(itemData->color());
+ if (itemData->isItalicSpecified())
+ format.setFontItalic(itemData->isItalic());
+ if (itemData->isBoldSpecified())
+ format.setFontWeight(toFontWeight(itemData->isBold()));
+ if (itemData->isUnderlinedSpecified())
+ format.setFontUnderline(itemData->isUnderlined());
+ if (itemData->isStrikedOutSpecified())
+ format.setFontStrikeOut(itemData->isStrikedOut());
+ }
+
+ setFormat(offset, count, format);
+ }
+}
+
+void Highlighter::applyVisualWhitespaceFormat(const QString &text)
+{
+ int offset = 0;
+ const int length = text.length();
+ while (offset < length) {
+ if (text.at(offset).isSpace()) {
+ int start = offset++;
+ while (offset < length && text.at(offset).isSpace())
+ ++offset;
+ setFormat(start, offset - start, m_visualWhitespaceFormat);
+ } else {
+ ++offset;
+ }
+ }
+}
+
+void Highlighter::createWillContinueBlock()
+{
+ if (!currentBlockUserData())
+ initializeBlockData();
+
+ BlockData *data = static_cast<BlockData *>(currentBlockUserData());
+ if (currentBlockState() == Continued) {
+ BlockData *previousData = static_cast<BlockData *>(currentBlock().previous().userData());
+ data->m_originalState = previousData->m_originalState;
+ } else if (currentBlockState() != WillContinue) {
+ data->m_originalState = currentBlockState();
+ }
+ data->m_contextToContinue = m_currentContext;
+
+ setCurrentBlockState(WillContinue);
+}
+
+void Highlighter::analyseConsistencyOfWillContinueBlock(const QString &text)
+{
+ if (currentBlock().next().isValid() && (
+ text.length() == 0 || text.at(text.length() - 1) != kBackSlash) &&
+ currentBlock().next().userState() != Continued) {
+ currentBlock().next().setUserState(Continued);
+ }
+
+ if (text.length() == 0 || text.at(text.length() - 1) != kBackSlash) {
+ BlockData *data = static_cast<BlockData *>(currentBlockUserData());
+ data->m_contextToContinue.clear();
+ setCurrentBlockState(data->m_originalState);
+ }
+}
+
+void Highlighter::mapContextSequence(const QString &contextSequence)
+{
+ if (currentBlockState() < PersistentsStart && !m_leadingStates.contains(contextSequence))
+ m_leadingStates.insert(contextSequence, currentBlockState());
+
+ if (!m_persistentStates.contains(contextSequence)) {
+ int newState = m_persistentStatesCounter;
+ m_persistentStates.insert(contextSequence, newState);
+ m_persistentContexts.insert(newState, m_contexts);
+ ++m_persistentStatesCounter;
+ }
+}
+
+void Highlighter::pushContextSequence(int state)
+{
+ const QVector<QSharedPointer<Context> > &contexts = m_persistentContexts.value(state);
+ for (int i = 0; i < contexts.size(); ++i)
+ m_contexts.push_back(contexts.at(i));
+}
+
+QString Highlighter::currentContextSequence() const
+{
+ QString sequence;
+ for (int i = 0; i < m_contexts.size(); ++i)
+ sequence.append(m_contexts.at(i)->id());
+
+ return sequence;
+}
+
+Highlighter::BlockData *Highlighter::initializeBlockData()
+{
+ BlockData *data = new BlockData;
+ setCurrentBlockUserData(data);
+ return data;
+}
+
+void Highlighter::pushDynamicContext(const QSharedPointer<Context> &baseContext)
+{
+ // A dynamic context is created from another context which serves as its basis. Then,
+ // its rules are updated according to the captures from the calling regular expression which
+ // triggered the push of the dynamic context.
+ QSharedPointer<Context> context(new Context(*baseContext));
+ context->configureId(m_dynamicContextsCounter);
+ context->updateDynamicRules(m_currentCaptures);
+ m_contexts.push_back(context);
+ ++m_dynamicContextsCounter;
+}
+
+void Highlighter::setCurrentContext()
+{
+ if (m_contexts.isEmpty()) {
+ // This is not supposed to happen. However, there are broken files (for example, php.xml)
+ // which will cause this behaviour. In such cases pushing the default context is enough to
+ // keep highlighter working.
+ m_contexts.push_back(m_defaultContext);
+ }
+ m_currentContext = m_contexts.back();
+}
+
+void Highlighter::configureFormats(const FontSettings & fs)
+{
+ m_visualWhitespaceFormat = fs.toTextCharFormat(
+ QLatin1String(TextEditor::Constants::C_VISUAL_WHITESPACE));
+
+ m_genericFormats[ItemData::kDsKeyword] = fs.toTextCharFormat(
+ QLatin1String(TextEditor::Constants::C_KEYWORD));
+ m_genericFormats[ItemData::kDsDataType] = fs.toTextCharFormat(
+ QLatin1String(TextEditor::Constants::C_TYPE));
+ // Currenlty using C_NUMBER for all kinds of numbers.
+ m_genericFormats[ItemData::kDsDecVal] = fs.toTextCharFormat(
+ QLatin1String(TextEditor::Constants::C_NUMBER));
+ m_genericFormats[ItemData::kDsBaseN] = fs.toTextCharFormat(
+ QLatin1String(TextEditor::Constants::C_NUMBER));
+ m_genericFormats[ItemData::kDsFloat] = fs.toTextCharFormat(
+ QLatin1String(TextEditor::Constants::C_NUMBER));
+ // Currently using C_STRING for strings and chars.
+ m_genericFormats[ItemData::kDsChar] = fs.toTextCharFormat(
+ QLatin1String(TextEditor::Constants::C_STRING));
+ m_genericFormats[ItemData::kDsString] = fs.toTextCharFormat(
+ QLatin1String(TextEditor::Constants::C_STRING));
+ m_genericFormats[ItemData::kDsComment] = fs.toTextCharFormat(
+ QLatin1String(TextEditor::Constants::C_COMMENT));
+
+ // Currently Creator does not have corresponding formats for the following items. We can
+ // implement them... Just for now I will leave hardcoded colors.
+ QTextCharFormat format;
+ format.setForeground(Qt::blue);
+ m_genericFormats[ItemData::kDsOthers] = format;
+ format.setForeground(Qt::red);
+ m_genericFormats[ItemData::kDsAlert] = format;
+ format.setForeground(Qt::darkBlue);
+ m_genericFormats[ItemData::kDsFunction] = format;
+ format.setForeground(Qt::darkGray);
+ m_genericFormats[ItemData::kDsRegionMarker] = format;
+ format.setForeground(Qt::darkRed);
+ m_genericFormats[ItemData::kDsError] = format;
+}
diff --git a/src/plugins/texteditor/generichighlighter/highlighter.h b/src/plugins/texteditor/generichighlighter/highlighter.h
new file mode 100644
index 0000000000..bbf7e76992
--- /dev/null
+++ b/src/plugins/texteditor/generichighlighter/highlighter.h
@@ -0,0 +1,154 @@
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** Commercial Usage
+**
+** Licensees holding valid Qt Commercial licenses may use this file in
+** accordance with the Qt Commercial License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Nokia.
+**
+** GNU Lesser General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://qt.nokia.com/contact.
+**
+**************************************************************************/
+
+#ifndef HIGHLIGHTER_H
+#define HIGHLIGHTER_H
+
+#include "basetextdocumentlayout.h"
+
+#include <QtCore/QString>
+#include <QtCore/QVector>
+#include <QtCore/QSharedPointer>
+#include <QtCore/QStringList>
+
+#include <QtGui/QSyntaxHighlighter>
+
+namespace TextEditor {
+class FontSettings;
+}
+
+namespace TextEditor {
+namespace Internal {
+
+class Rule;
+class Context;
+class HighlightDefinition;
+class ProgressData;
+
+class Highlighter : public QSyntaxHighlighter
+{
+public:
+ Highlighter(const QSharedPointer<Context> &defaultContext, QTextDocument *parent = 0);
+ virtual ~Highlighter();
+
+ void configureFormats(const FontSettings & fs);
+
+protected:
+ virtual void highlightBlock(const QString &text);
+
+private:
+
+ void setupDataForBlock(const QString &text);
+ void setupDefault();
+ void setupFromWillContinue();
+ void setupFromContinued();
+ void setupFromPersistent();
+
+ void iterateThroughRules(const QString &text,
+ const int length,
+ ProgressData *progress,
+ const bool childRule,
+ const QList<QSharedPointer<Rule> > &rules);
+
+ bool contextChangeRequired(const QString &contextName) const;
+ void handleContextChange(const QString &contextName,
+ const QSharedPointer<HighlightDefinition> &definition,
+ const bool setCurrent = true);
+ void changeContext(const QString &contextName,
+ const QSharedPointer<HighlightDefinition> &definition,
+ const bool setCurrent = true);
+
+ void applyFormat(int offset,
+ int count,
+ const QString &itemDataName,
+ const QSharedPointer<HighlightDefinition> &definition);
+ void applyVisualWhitespaceFormat(const QString &text);
+
+ QString currentContextSequence() const;
+ void mapContextSequence(const QString &contextSequence);
+ void pushContextSequence(int state);
+ void pushDynamicContext(const QSharedPointer<Context> &baseContext);
+
+ void setCurrentContext();
+
+ void createWillContinueBlock();
+ void analyseConsistencyOfWillContinueBlock(const QString &text);
+
+ struct BlockData : TextBlockUserData
+ {
+ BlockData();
+ virtual ~BlockData();
+
+ int m_originalState;
+ QSharedPointer<Context> m_contextToContinue;
+ };
+ BlockData *initializeBlockData();
+
+ // Block states
+ // - Default [0]: Nothing special.
+ // - WillContinue [1]: When there is match of the LineContinue rule (backslash as the last
+ // character).
+ // - Continued [2]: Blocks that happen after a WillContinue block and continued from their
+ // context until the next line end.
+ // - Persistent(s) [Anything >= 3]: Correspond to persistent contexts which last until a pop
+ // occurs due to a matching rule. Every sequence of persistent contexts seen so far is
+ // associated with a number (incremented by a unit each time).
+ enum BlockState {
+ Default = 0,
+ WillContinue,
+ Continued,
+ PersistentsStart
+ };
+ int m_persistentStatesCounter;
+ int m_dynamicContextsCounter;
+
+ bool m_isBroken;
+
+ QSharedPointer<Context> m_defaultContext;
+ QSharedPointer<Context> m_currentContext;
+ QVector<QSharedPointer<Context> > m_contexts;
+
+ // Mapping from context sequences to the persistent state they represent.
+ QHash<QString, int> m_persistentStates;
+ // Mapping from context sequences to the non-persistent state that led to them.
+ QHash<QString, int> m_leadingStates;
+ // Mapping from persistent states to context sequences (the actual "stack").
+ QHash<int, QVector<QSharedPointer<Context> > > m_persistentContexts;
+
+ // Captures used in dynamic rules.
+ QStringList m_currentCaptures;
+
+ QTextCharFormat m_visualWhitespaceFormat;
+ QHash<QString, QTextCharFormat> m_genericFormats;
+};
+
+} // namespace Internal
+} // namespace TextEditor
+
+#endif // HIGHLIGHTER_H
diff --git a/src/plugins/texteditor/generichighlighter/highlighterexception.h b/src/plugins/texteditor/generichighlighter/highlighterexception.h
new file mode 100644
index 0000000000..13310402fa
--- /dev/null
+++ b/src/plugins/texteditor/generichighlighter/highlighterexception.h
@@ -0,0 +1,41 @@
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** Commercial Usage
+**
+** Licensees holding valid Qt Commercial licenses may use this file in
+** accordance with the Qt Commercial License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Nokia.
+**
+** GNU Lesser General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://qt.nokia.com/contact.
+**
+**************************************************************************/
+
+#ifndef HIGHLIGHTEREXCEPTION_H
+#define HIGHLIGHTEREXCEPTION_H
+
+namespace TextEditor {
+namespace Internal {
+
+class HighlighterException {};
+
+} // namespace Internal
+} // namespace TextEditor
+
+#endif // HIGHLIGHTEREXCEPTION_H
diff --git a/src/plugins/texteditor/generichighlighter/includerulesinstruction.cpp b/src/plugins/texteditor/generichighlighter/includerulesinstruction.cpp
new file mode 100644
index 0000000000..8b04826633
--- /dev/null
+++ b/src/plugins/texteditor/generichighlighter/includerulesinstruction.cpp
@@ -0,0 +1,50 @@
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** Commercial Usage
+**
+** Licensees holding valid Qt Commercial licenses may use this file in
+** accordance with the Qt Commercial License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Nokia.
+**
+** GNU Lesser General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://qt.nokia.com/contact.
+**
+**************************************************************************/
+
+#include "includerulesinstruction.h"
+#include "reuse.h"
+
+using namespace TextEditor;
+using namespace Internal;
+
+IncludeRulesInstruction::IncludeRulesInstruction(const QString &context,
+ int hint,
+ const QString &replaceItemData) :
+ m_sourceContext(context), m_indexHint(hint), m_replaceItemData(toBool(replaceItemData))
+{
+}
+
+const QString &IncludeRulesInstruction::sourceContext() const
+{ return m_sourceContext; }
+
+int IncludeRulesInstruction::indexHint() const
+{ return m_indexHint; }
+
+bool IncludeRulesInstruction::replaceItemData() const
+{ return m_replaceItemData; }
diff --git a/src/plugins/texteditor/generichighlighter/includerulesinstruction.h b/src/plugins/texteditor/generichighlighter/includerulesinstruction.h
new file mode 100644
index 0000000000..c0f5d6e498
--- /dev/null
+++ b/src/plugins/texteditor/generichighlighter/includerulesinstruction.h
@@ -0,0 +1,56 @@
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** Commercial Usage
+**
+** Licensees holding valid Qt Commercial licenses may use this file in
+** accordance with the Qt Commercial License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Nokia.
+**
+** GNU Lesser General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://qt.nokia.com/contact.
+**
+**************************************************************************/
+
+#ifndef INCLUDERULESINSTRUCTION_H
+#define INCLUDERULESINSTRUCTION_H
+
+#include <QtCore/QString>
+
+namespace TextEditor {
+namespace Internal {
+
+class IncludeRulesInstruction
+{
+public:
+ IncludeRulesInstruction(const QString &context, int hint, const QString &replaceItemData);
+
+ const QString &sourceContext() const;
+ int indexHint() const;
+ bool replaceItemData() const;
+
+private:
+ QString m_sourceContext;
+ int m_indexHint;
+ bool m_replaceItemData;
+};
+
+} // namespace Internal
+} // namespace TextEditor
+
+#endif // INCLUDERULESINSTRUCTION_H
diff --git a/src/plugins/texteditor/generichighlighter/itemdata.cpp b/src/plugins/texteditor/generichighlighter/itemdata.cpp
new file mode 100644
index 0000000000..498d968e32
--- /dev/null
+++ b/src/plugins/texteditor/generichighlighter/itemdata.cpp
@@ -0,0 +1,148 @@
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** Commercial Usage
+**
+** Licensees holding valid Qt Commercial licenses may use this file in
+** accordance with the Qt Commercial License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Nokia.
+**
+** GNU Lesser General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://qt.nokia.com/contact.
+**
+**************************************************************************/
+
+#include "itemdata.h"
+#include "reuse.h"
+
+using namespace TextEditor;
+using namespace Internal;
+
+const QLatin1String ItemData::kDsNormal("dsNormal");
+const QLatin1String ItemData::kDsKeyword("dsKeyword");
+const QLatin1String ItemData::kDsDataType("dsDataType");
+const QLatin1String ItemData::kDsDecVal("dsDecVal");
+const QLatin1String ItemData::kDsBaseN("dsBaseN");
+const QLatin1String ItemData::kDsFloat("dsFloat");
+const QLatin1String ItemData::kDsChar("dsChar");
+const QLatin1String ItemData::kDsString("dsString");
+const QLatin1String ItemData::kDsComment("dsComment");
+const QLatin1String ItemData::kDsOthers("dsOthers");
+const QLatin1String ItemData::kDsAlert("dsAlert");
+const QLatin1String ItemData::kDsFunction("dsFunction");
+const QLatin1String ItemData::kDsRegionMarker("dsRegionMarker");
+const QLatin1String ItemData::kDsError("dsError");
+
+ItemData::ItemData() :
+ m_italicSpecified(false),
+ m_boldSpecified(false),
+ m_underlinedSpecified(false),
+ m_strikedOutSpecified(false),
+ m_isCustomized(false)
+{}
+
+void ItemData::setStyle(const QString &style)
+{ m_style = style; }
+
+const QString &ItemData::style() const
+{ return m_style; }
+
+void ItemData::setColor(const QString &color)
+{
+ if (!color.isEmpty()) {
+ m_color.setNamedColor(color);
+ m_isCustomized = true;
+ }
+}
+
+const QColor &ItemData::color() const
+{ return m_color; }
+
+void ItemData::setSelectionColor(const QString &color)
+{
+ if (!color.isEmpty()) {
+ m_selectionColor.setNamedColor(color);
+ m_isCustomized = true;
+ }
+}
+
+const QColor &ItemData::selectionColor() const
+{ return m_selectionColor; }
+
+void ItemData::setItalic(const QString &italic)
+{
+ if (!italic.isEmpty()) {
+ m_italic = toBool(italic);
+ m_italicSpecified = true;
+ m_isCustomized = true;
+ }
+}
+
+bool ItemData::isItalic() const
+{ return m_italic; }
+
+bool ItemData::isItalicSpecified() const
+{ return m_italicSpecified; }
+
+void ItemData::setBold(const QString &bold)
+{
+ if (!bold.isEmpty()) {
+ m_bold = toBool(bold);
+ m_boldSpecified = true;
+ m_isCustomized = true;
+ }
+}
+
+bool ItemData::isBold() const
+{ return m_bold; }
+
+bool ItemData::isBoldSpecified() const
+{ return m_boldSpecified; }
+
+void ItemData::setUnderlined(const QString &underlined)
+{
+ if (!underlined.isEmpty()) {
+ m_underlined = toBool(underlined);
+ m_underlinedSpecified = true;
+ m_isCustomized = true;
+ }
+}
+
+bool ItemData::isUnderlined() const
+{ return m_underlined; }
+
+bool ItemData::isUnderlinedSpecified() const
+{ return m_underlinedSpecified; }
+
+void ItemData::setStrikedOut(const QString &striked)
+{
+ if (!striked.isEmpty()) {
+ m_strikedOut = toBool(striked);
+ m_strikedOutSpecified = true;
+ m_isCustomized = true;
+ }
+}
+
+bool ItemData::isStrikedOut() const
+{ return m_strikedOut; }
+
+bool ItemData::isStrikedOutSpecified() const
+{ return m_strikedOutSpecified; }
+
+bool ItemData::isCustomized() const
+{ return m_isCustomized; }
diff --git a/src/plugins/texteditor/generichighlighter/itemdata.h b/src/plugins/texteditor/generichighlighter/itemdata.h
new file mode 100644
index 0000000000..c130239749
--- /dev/null
+++ b/src/plugins/texteditor/generichighlighter/itemdata.h
@@ -0,0 +1,104 @@
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** Commercial Usage
+**
+** Licensees holding valid Qt Commercial licenses may use this file in
+** accordance with the Qt Commercial License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Nokia.
+**
+** GNU Lesser General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://qt.nokia.com/contact.
+**
+**************************************************************************/
+
+#ifndef ITEMDATA_H
+#define ITEMDATA_H
+
+#include <QtCore/QString>
+#include <QtGui/QColor>
+
+namespace TextEditor {
+namespace Internal {
+
+class ItemData
+{
+public:
+ ItemData();
+
+ void setStyle(const QString &style);
+ const QString &style() const;
+
+ void setColor(const QString &color);
+ const QColor &color() const;
+
+ void setSelectionColor(const QString &color);
+ const QColor &selectionColor() const;
+
+ void setItalic(const QString &italic);
+ bool isItalic() const;
+ bool isItalicSpecified() const;
+
+ void setBold(const QString &bold);
+ bool isBold() const;
+ bool isBoldSpecified() const;
+
+ void setUnderlined(const QString &underlined);
+ bool isUnderlined() const;
+ bool isUnderlinedSpecified() const;
+
+ void setStrikedOut(const QString &striked);
+ bool isStrikedOut() const;
+ bool isStrikedOutSpecified() const;
+
+ bool isCustomized() const;
+
+ static const QLatin1String kDsNormal;
+ static const QLatin1String kDsKeyword;
+ static const QLatin1String kDsDataType;
+ static const QLatin1String kDsDecVal;
+ static const QLatin1String kDsBaseN;
+ static const QLatin1String kDsFloat;
+ static const QLatin1String kDsChar;
+ static const QLatin1String kDsString;
+ static const QLatin1String kDsComment;
+ static const QLatin1String kDsOthers;
+ static const QLatin1String kDsAlert;
+ static const QLatin1String kDsFunction;
+ static const QLatin1String kDsRegionMarker;
+ static const QLatin1String kDsError;
+
+private:
+ QString m_style;
+ QColor m_color;
+ QColor m_selectionColor;
+ bool m_italic;
+ bool m_italicSpecified;
+ bool m_bold;
+ bool m_boldSpecified;
+ bool m_underlined;
+ bool m_underlinedSpecified;
+ bool m_strikedOut;
+ bool m_strikedOutSpecified;
+ bool m_isCustomized;
+};
+
+} // namespace Internal
+} // namespace TextEditor
+
+#endif // ITEMDATA_H
diff --git a/src/plugins/texteditor/generichighlighter/keywordlist.cpp b/src/plugins/texteditor/generichighlighter/keywordlist.cpp
new file mode 100644
index 0000000000..48c9672915
--- /dev/null
+++ b/src/plugins/texteditor/generichighlighter/keywordlist.cpp
@@ -0,0 +1,61 @@
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** Commercial Usage
+**
+** Licensees holding valid Qt Commercial licenses may use this file in
+** accordance with the Qt Commercial License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Nokia.
+**
+** GNU Lesser General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://qt.nokia.com/contact.
+**
+**************************************************************************/
+
+#include "keywordlist.h"
+
+using namespace TextEditor;
+using namespace Internal;
+
+void KeywordList::addKeyword(const QString &keyword)
+{
+ if (keyword.isEmpty())
+ return;
+
+ m_keywords.insert(keyword);
+}
+
+bool KeywordList::isKeyword(const QString &keyword, Qt::CaseSensitivity sensitivity) const
+{
+ if (keyword.isEmpty())
+ return false;
+
+ // Case sensitivity could be implemented, for example, by converting all keywords to lower
+ // if the global sensitivity attribute is insensitive, then always checking for containment
+ // (with a conversion to lower in the necessary cases). But the code below is one alternative
+ // to support the existence of local sensitivity attributes (which override the global one -
+ // currently not documented).
+ if (sensitivity == Qt::CaseSensitive) {
+ return m_keywords.contains(keyword);
+ } else {
+ foreach (const QString &s, m_keywords)
+ if (keyword.compare(s, Qt::CaseInsensitive) == 0)
+ return true;
+ return false;
+ }
+}
diff --git a/src/plugins/texteditor/generichighlighter/keywordlist.h b/src/plugins/texteditor/generichighlighter/keywordlist.h
new file mode 100644
index 0000000000..82495ca220
--- /dev/null
+++ b/src/plugins/texteditor/generichighlighter/keywordlist.h
@@ -0,0 +1,53 @@
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** Commercial Usage
+**
+** Licensees holding valid Qt Commercial licenses may use this file in
+** accordance with the Qt Commercial License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Nokia.
+**
+** GNU Lesser General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://qt.nokia.com/contact.
+**
+**************************************************************************/
+
+#ifndef KEYWORDLIST_H
+#define KEYWORDLIST_H
+
+#include <QtCore/QString>
+#include <QtCore/QSet>
+
+namespace TextEditor {
+namespace Internal {
+
+class KeywordList
+{
+public:
+
+ void addKeyword(const QString &keyword);
+ bool isKeyword(const QString &keyword, Qt::CaseSensitivity sensitivity) const;
+
+private:
+ QSet<QString> m_keywords;
+};
+
+} // namespace Internal
+} // namespace TextEditor
+
+#endif // KEYWORDLIST_H
diff --git a/src/plugins/texteditor/generichighlighter/manager.cpp b/src/plugins/texteditor/generichighlighter/manager.cpp
new file mode 100644
index 0000000000..6080c4f764
--- /dev/null
+++ b/src/plugins/texteditor/generichighlighter/manager.cpp
@@ -0,0 +1,236 @@
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** Commercial Usage
+**
+** Licensees holding valid Qt Commercial licenses may use this file in
+** accordance with the Qt Commercial License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Nokia.
+**
+** GNU Lesser General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://qt.nokia.com/contact.
+**
+**************************************************************************/
+
+#include "manager.h"
+#include "highlightdefinition.h"
+#include "highlightdefinitionhandler.h"
+#include "highlighterexception.h"
+#include "texteditorplugin.h"
+#include "texteditorsettings.h"
+#include "plaintexteditorfactory.h"
+
+#include <coreplugin/icore.h>
+#include <utils/qtcassert.h>
+#include <qtconcurrent/QtConcurrentTools>
+
+#include <QtCore/QtAlgorithms>
+#include <QtCore/QtPlugin>
+#include <QtCore/QString>
+#include <QtCore/QLatin1Char>
+#include <QtCore/QLatin1String>
+#include <QtCore/QStringList>
+#include <QtCore/QFile>
+#include <QtCore/QFileInfo>
+#include <QtCore/QDir>
+#include <QtCore/QList>
+#include <QtCore/QRegExp>
+#include <QtCore/QFuture>
+#include <QtCore/QtConcurrentRun>
+#include <QtXml/QXmlSimpleReader>
+#include <QtXml/QXmlInputSource>
+#include <QtXml/QXmlStreamReader>
+#include <QtXml/QXmlStreamAttributes>
+
+using namespace TextEditor;
+using namespace Internal;
+
+Manager::Manager()
+{}
+
+Manager *Manager::instance()
+{
+ static Manager manager;
+ return &manager;
+}
+
+QString Manager::definitionIdByName(const QString &name) const
+{ return m_idByName.value(name); }
+
+QString Manager::definitionIdByMimeType(const QString &mimeType) const
+{
+ Q_ASSERT(!mimeType.isEmpty());
+
+ if (m_idByMimeType.count(mimeType) <= 1) {
+ return m_idByMimeType.value(mimeType);
+ } else {
+ QStringList candidateIds;
+ QMultiHash<QString, QString>::const_iterator it = m_idByMimeType.find(mimeType);
+ QMultiHash<QString, QString>::const_iterator endIt = m_idByMimeType.end();
+ for (; it != endIt && it.key() == mimeType; ++it)
+ candidateIds.append(it.value());
+
+ qSort(candidateIds.begin(), candidateIds.end(), m_priorityComp);
+ return candidateIds.last();
+ }
+}
+
+const QSharedPointer<HighlightDefinition> &Manager::definition(const QString &id)
+{
+ if (!m_definitions.contains(id)) {
+ m_isBuilding.insert(id);
+
+ QFile definitionFile(id);
+ if (!definitionFile.open(QIODevice::ReadOnly | QIODevice::Text))
+ throw HighlighterException();
+ QXmlInputSource source(&definitionFile);
+
+ QSharedPointer<HighlightDefinition> definition(new HighlightDefinition);
+ HighlightDefinitionHandler handler(definition);
+
+ QXmlSimpleReader reader;
+ reader.setContentHandler(&handler);
+ reader.parse(source);
+
+ m_definitions.insert(id, definition);
+ definitionFile.close();
+ m_isBuilding.remove(id);
+ }
+
+ return *m_definitions.constFind(id);
+}
+
+bool Manager::isBuildingDefinition(const QString &id) const
+{ return m_isBuilding.contains(id); }
+
+void Manager::registerMimeTypes()
+{
+ QFuture<Core::MimeType> future =
+ QtConcurrent::run(&Manager::gatherDefinitionsMimeTypes, this);
+ m_watcher.setFuture(future);
+
+ connect(&m_watcher, SIGNAL(resultReadyAt(int)), this, SLOT(registerMimeType(int)));
+}
+
+void Manager::gatherDefinitionsMimeTypes(QFutureInterface<Core::MimeType> &future)
+{
+ QDir definitionsDir(Core::ICore::instance()->resourcePath() +
+ QLatin1String("/generic-highlighter"));
+
+ QStringList filter(QLatin1String("*.xml"));
+ definitionsDir.setNameFilters(filter);
+
+ const QFileInfoList &filesInfo = definitionsDir.entryInfoList();
+ foreach (const QFileInfo &fileInfo, filesInfo) {
+ QString comment;
+ QStringList mimeTypes;
+ QStringList patterns;
+ parseDefinitionMetadata(fileInfo, &comment, &mimeTypes, &patterns);
+
+ // A definition can specify multiple MIME types and file extensions/patterns. However, each
+ // thing is done with a single string. Then, there is no direct way to tell which patterns
+ // belong to which MIME types nor whether a MIME type is just an alias for the other.
+ // Currently, I associate all expressions/patterns with all MIME types from a definition.
+
+ static const QStringList textPlain(QLatin1String("text/plain"));
+
+ QList<QRegExp> expressions;
+ foreach (const QString &type, mimeTypes) {
+ Core::MimeType mimeType = Core::ICore::instance()->mimeDatabase()->findByType(type);
+ if (mimeType.isNull()) {
+ if (expressions.isEmpty()) {
+ foreach (const QString &pattern, patterns)
+ expressions.append(QRegExp(pattern, Qt::CaseSensitive, QRegExp::Wildcard));
+ }
+
+ mimeType.setType(type);
+ mimeType.setSubClassesOf(textPlain);
+ mimeType.setComment(comment);
+ mimeType.setGlobPatterns(expressions);
+
+ future.reportResult(mimeType);
+ }
+ }
+ }
+}
+
+void Manager::registerMimeType(int index) const
+{
+ const Core::MimeType &mimeType = m_watcher.resultAt(index);
+ Core::ICore::instance()->mimeDatabase()->addMimeType(mimeType);
+ TextEditorPlugin::instance()->editorFactory()->addMimeType(mimeType.type());
+}
+
+void Manager::parseDefinitionMetadata(const QFileInfo &fileInfo,
+ QString *comment,
+ QStringList *mimeTypes,
+ QStringList *patterns)
+{
+ static const QLatin1Char kSemiColon(';');
+ static const QLatin1Char kSlash('/');
+ static const QLatin1String kLanguage("language");
+ static const QLatin1String kName("name");
+ static const QLatin1String kExtensions("extensions");
+ static const QLatin1String kMimeType("mimetype");
+ static const QLatin1String kPriority("priority");
+ static const QLatin1String kArtificial("artificial");
+
+ const QString &id = fileInfo.absoluteFilePath();
+
+ QFile definitionFile(id);
+ if (!definitionFile.open(QIODevice::ReadOnly | QIODevice::Text))
+ return;
+
+ QXmlStreamReader reader(&definitionFile);
+ while (!reader.atEnd() && !reader.hasError()) {
+ if (reader.readNext() == QXmlStreamReader::StartElement &&
+ reader.name() == kLanguage) {
+ const QXmlStreamAttributes &attr = reader.attributes();
+
+ *comment = attr.value(kName).toString();
+ m_idByName.insert(*comment, id);
+
+ *patterns = attr.value(kExtensions).toString().split(kSemiColon,
+ QString::SkipEmptyParts);
+
+ *mimeTypes = attr.value(kMimeType).toString().split(kSemiColon,
+ QString::SkipEmptyParts);
+ if (mimeTypes->isEmpty()) {
+ // There are definitions which do not specify a MIME type, but specify file
+ // patterns. Creating an artificial MIME type is a workaround.
+ QString artificialType(kArtificial);
+ artificialType.append(kSlash).append(*comment);
+ m_idByMimeType.insert(artificialType, id);
+ mimeTypes->append(artificialType);
+ } else {
+ foreach (const QString &type, *mimeTypes)
+ m_idByMimeType.insert(type, id);
+ }
+
+ // The priority below should not be confused with the priority used when matching files
+ // to MIME types. Kate uses this when there are definitions which share equal
+ // extensions/patterns. Here it is for choosing a highlight definition if there are
+ // multiple ones associated with the same MIME type (should not happen in general).
+ m_priorityComp.m_priorityById.insert(id, attr.value(kPriority).toString().toInt());
+
+ break;
+ }
+ }
+ reader.clear();
+ definitionFile.close();
+}
diff --git a/src/plugins/texteditor/generichighlighter/manager.h b/src/plugins/texteditor/generichighlighter/manager.h
new file mode 100644
index 0000000000..f5663dc411
--- /dev/null
+++ b/src/plugins/texteditor/generichighlighter/manager.h
@@ -0,0 +1,98 @@
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** Commercial Usage
+**
+** Licensees holding valid Qt Commercial licenses may use this file in
+** accordance with the Qt Commercial License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Nokia.
+**
+** GNU Lesser General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://qt.nokia.com/contact.
+**
+**************************************************************************/
+
+#ifndef MANAGER_H
+#define MANAGER_H
+
+#include <coreplugin/mimedatabase.h>
+
+#include <QtCore/QString>
+#include <QtCore/QHash>
+#include <QtCore/QMultiHash>
+#include <QtCore/QSet>
+#include <QtCore/QSharedPointer>
+#include <QtCore/QFutureWatcher>
+
+QT_BEGIN_NAMESPACE
+class QFileInfo;
+class QStringList;
+template <class> class QFutureInterface;
+QT_END_NAMESPACE
+
+namespace TextEditor {
+namespace Internal {
+
+class HighlightDefinition;
+
+class Manager : public QObject
+{
+ Q_OBJECT
+public:
+ static Manager *instance();
+
+ QString definitionIdByName(const QString &name) const;
+ QString definitionIdByMimeType(const QString &mimeType) const;
+ bool isBuildingDefinition(const QString &id) const;
+ const QSharedPointer<HighlightDefinition> &definition(const QString &id);
+
+private slots:
+ void registerMimeTypes();
+ void registerMimeType(int index) const;
+
+private:
+ Manager();
+ Q_DISABLE_COPY(Manager)
+
+ void gatherDefinitionsMimeTypes(QFutureInterface<Core::MimeType> &future);
+ void parseDefinitionMetadata(const QFileInfo &fileInfo,
+ QString *comment,
+ QStringList *mimeTypes,
+ QStringList *patterns);
+
+ struct PriorityCompare
+ {
+ bool operator()(const QString &a, const QString &b) const
+ { return m_priorityById.value(a) < m_priorityById.value(b); }
+
+ QHash<QString, int> m_priorityById;
+ };
+ PriorityCompare m_priorityComp;
+
+ QFutureWatcher<Core::MimeType> m_watcher;
+
+ QHash<QString, QString> m_idByName;
+ QMultiHash<QString, QString> m_idByMimeType;
+ QHash<QString, QSharedPointer<HighlightDefinition> > m_definitions;
+ QSet<QString> m_isBuilding;
+};
+
+} // namespace Internal
+} // namespace TextEditor
+
+#endif // MANAGER_H
diff --git a/src/plugins/texteditor/generichighlighter/progressdata.cpp b/src/plugins/texteditor/generichighlighter/progressdata.cpp
new file mode 100644
index 0000000000..12c76079d8
--- /dev/null
+++ b/src/plugins/texteditor/generichighlighter/progressdata.cpp
@@ -0,0 +1,82 @@
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** Commercial Usage
+**
+** Licensees holding valid Qt Commercial licenses may use this file in
+** accordance with the Qt Commercial License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Nokia.
+**
+** GNU Lesser General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://qt.nokia.com/contact.
+**
+**************************************************************************/
+
+#include "progressdata.h"
+
+#include <QtCore/QtGlobal>
+
+using namespace TextEditor;
+using namespace Internal;
+
+ProgressData::ProgressData() :
+ m_offset(0),
+ m_savedOffset(-1),
+ m_onlySpacesSoFar(true),
+ m_willContinueLine(false)
+{}
+
+void ProgressData::setOffset(const int offset)
+{ m_offset = offset; }
+
+int ProgressData::offset() const
+{ return m_offset; }
+
+void ProgressData::incrementOffset()
+{ ++m_offset; }
+
+void ProgressData::incrementOffset(const int increment)
+{ m_offset += increment; }
+
+void ProgressData::saveOffset()
+{ m_savedOffset = m_offset; }
+
+void ProgressData::restoreOffset()
+{
+ Q_ASSERT(m_savedOffset != -1);
+ m_offset = m_savedOffset;
+ m_savedOffset = -1;
+}
+
+void ProgressData::setOnlySpacesSoFar(const bool onlySpaces)
+{ m_onlySpacesSoFar = onlySpaces; }
+
+bool ProgressData::onlySpacesSoFar() const
+{ return m_onlySpacesSoFar; }
+
+void ProgressData::setWillContinueLine(const bool willContinue)
+{ m_willContinueLine = willContinue; }
+
+bool ProgressData::willContinueLine() const
+{ return m_willContinueLine; }
+
+void ProgressData::setCaptures(const QStringList &captures)
+{ m_captures = captures; }
+
+const QStringList &ProgressData::captures() const
+{ return m_captures; }
diff --git a/src/plugins/texteditor/generichighlighter/progressdata.h b/src/plugins/texteditor/generichighlighter/progressdata.h
new file mode 100644
index 0000000000..a621c15dc7
--- /dev/null
+++ b/src/plugins/texteditor/generichighlighter/progressdata.h
@@ -0,0 +1,72 @@
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** Commercial Usage
+**
+** Licensees holding valid Qt Commercial licenses may use this file in
+** accordance with the Qt Commercial License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Nokia.
+**
+** GNU Lesser General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://qt.nokia.com/contact.
+**
+**************************************************************************/
+
+#ifndef PROGRESSDATA_H
+#define PROGRESSDATA_H
+
+#include <QtCore/QStringList>
+
+namespace TextEditor {
+namespace Internal {
+
+class ProgressData
+{
+public:
+ ProgressData();
+
+ void setOffset(const int offset);
+ int offset() const;
+
+ void incrementOffset();
+ void incrementOffset(const int increment);
+
+ void saveOffset();
+ void restoreOffset();
+
+ void setOnlySpacesSoFar(const bool onlySpaces);
+ bool onlySpacesSoFar() const;
+
+ void setWillContinueLine(const bool willContinue);
+ bool willContinueLine() const;
+
+ void setCaptures(const QStringList &captures);
+ const QStringList &captures() const;
+
+private:
+ int m_offset;
+ int m_savedOffset;
+ bool m_onlySpacesSoFar;
+ bool m_willContinueLine;
+ QStringList m_captures;
+};
+
+} // namespace Internal
+} // namespace TextEditor
+
+#endif // PROGRESSDATA_H
diff --git a/src/plugins/texteditor/generichighlighter/reuse.h b/src/plugins/texteditor/generichighlighter/reuse.h
new file mode 100644
index 0000000000..197e3042d9
--- /dev/null
+++ b/src/plugins/texteditor/generichighlighter/reuse.h
@@ -0,0 +1,100 @@
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** Commercial Usage
+**
+** Licensees holding valid Qt Commercial licenses may use this file in
+** accordance with the Qt Commercial License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Nokia.
+**
+** GNU Lesser General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://qt.nokia.com/contact.
+**
+**************************************************************************/
+
+#ifndef REUSE_H
+#define REUSE_H
+
+#include <Qt>
+#include <QtCore/QString>
+#include <QtCore/QLatin1String>
+#include <QtCore/QChar>
+#include <QtGui/QFont>
+
+namespace TextEditor {
+namespace Internal {
+
+inline bool toBool(const QString &s)
+{
+ static const QLatin1String kTrue("true");
+ static const QLatin1String k1("1");
+
+ if (s.toLower() == kTrue || s == k1)
+ return true;
+ return false;
+}
+
+
+inline Qt::CaseSensitivity toCaseSensitivity(const bool sensitive)
+{
+ if (sensitive)
+ return Qt::CaseSensitive;
+ return Qt::CaseInsensitive;
+}
+
+inline QFont::Weight toFontWeight(const bool bold)
+{
+ if (bold)
+ return QFont::Bold;
+ else
+ return QFont::Normal;
+}
+
+inline bool isOctalDigit(const QChar &c)
+{
+ static const QLatin1Char k0('0');
+ static const QLatin1Char k7('7');
+
+ return c >= k0 && c <= k7;
+}
+
+inline bool isHexDigit(const QChar &c)
+{
+ static const QLatin1Char k0('0');
+ static const QLatin1Char k9('9');
+ static const QLatin1Char kA('A');
+ static const QLatin1Char kF('F');
+ static const QLatin1Char ka('a');
+ static const QLatin1Char kf('f');
+
+ if ((c >= k0 && c <= k9) || (c >= kA && c <= kF) || (c >= ka && c <= kf))
+ return true;
+
+ return false;
+}
+
+inline void setStartCharacter(QChar &c, const QString &character)
+{
+ if (!character.isEmpty())
+ c = character.at(0);
+}
+
+} // namespace Internal
+} // namespace TextEditor
+
+#endif // REUSE_H
diff --git a/src/plugins/texteditor/generichighlighter/rule.cpp b/src/plugins/texteditor/generichighlighter/rule.cpp
new file mode 100644
index 0000000000..1ca7349c6a
--- /dev/null
+++ b/src/plugins/texteditor/generichighlighter/rule.cpp
@@ -0,0 +1,292 @@
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** Commercial Usage
+**
+** Licensees holding valid Qt Commercial licenses may use this file in
+** accordance with the Qt Commercial License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Nokia.
+**
+** GNU Lesser General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://qt.nokia.com/contact.
+**
+**************************************************************************/
+
+#include "rule.h"
+#include "highlighterexception.h"
+#include "progressdata.h"
+#include "highlightdefinition.h"
+#include "reuse.h"
+
+#include <QtCore/QStringList>
+
+#include <functional>
+
+using namespace TextEditor;
+using namespace Internal;
+
+const QLatin1Char Rule::kBackSlash('\\');
+const QLatin1Char Rule::kUnderscore('_');
+const QLatin1Char Rule::kDot('.');
+const QLatin1Char Rule::kPlus('+');
+const QLatin1Char Rule::kMinus('-');
+const QLatin1Char Rule::kZero('0');
+const QLatin1Char Rule::kQuote('\"');
+const QLatin1Char Rule::kSingleQuote('\'');
+const QLatin1Char Rule::kQuestion('?');
+const QLatin1Char Rule::kX('x');
+const QLatin1Char Rule::kA('a');
+const QLatin1Char Rule::kB('b');
+const QLatin1Char Rule::kE('e');
+const QLatin1Char Rule::kF('f');
+const QLatin1Char Rule::kN('n');
+const QLatin1Char Rule::kR('r');
+const QLatin1Char Rule::kT('t');
+const QLatin1Char Rule::kV('v');
+
+Rule::Rule(bool consumesNonSpace) :
+ m_lookAhead(false), m_firstNonSpace(false), m_column(-1), m_consumesNonSpace(consumesNonSpace)
+{}
+
+Rule::~Rule()
+{}
+
+void Rule::setContext(const QString &context)
+{ m_context = context; }
+
+const QString &Rule::context() const
+{ return m_context; }
+
+void Rule::setItemData(const QString &itemData)
+{ m_itemData = itemData; }
+
+const QString &Rule::itemData() const
+{ return m_itemData; }
+
+void Rule::setBeginRegion(const QString &begin)
+{ m_beginRegion = begin; }
+
+const QString &Rule::beginRegion() const
+{ return m_beginRegion; }
+
+void Rule::setEndRegion(const QString &end)
+{ m_endRegion = end; }
+
+const QString &Rule::endRegion() const
+{ return m_endRegion; }
+
+void Rule::setLookAhead(const QString &lookAhead)
+{ m_lookAhead = toBool(lookAhead); }
+
+bool Rule::isLookAhead() const
+{ return m_lookAhead; }
+
+void Rule::setFirstNonSpace(const QString &firstNonSpace)
+{ m_firstNonSpace = toBool(firstNonSpace); }
+
+bool Rule::isFirstNonSpace() const
+{ return m_firstNonSpace; }
+
+void Rule::setColumn(const QString &column)
+{
+ bool ok;
+ m_column = column.toInt(&ok);
+ if (!ok)
+ m_column = -1;
+}
+
+int Rule::column() const
+{ return m_column; }
+
+void Rule::addChild(const QSharedPointer<Rule> &rule)
+{ m_childRules.append(rule); }
+
+bool Rule::hasChild() const
+{ return !m_childRules.isEmpty(); }
+
+const QList<QSharedPointer<Rule> > &Rule::childs() const
+{ return m_childRules; }
+
+void Rule::setDefinition(const QSharedPointer<HighlightDefinition> &definition)
+{ m_definition = definition; }
+
+const QSharedPointer<HighlightDefinition> &Rule::definition() const
+{ return m_definition; }
+
+template <class predicate_t>
+bool Rule::predicateMatchSucceed(const QString &text,
+ const int length,
+ ProgressData *progress,
+ const predicate_t &p) const
+{
+ int original = progress->offset();
+ while (progress->offset() < length && p(text.at(progress->offset())))
+ progress->incrementOffset();
+
+ if (original != progress->offset())
+ return true;
+
+ return false;
+}
+
+bool Rule::charPredicateMatchSucceed(const QString &text,
+ const int length,
+ ProgressData *progress,
+ bool (QChar::* predicate)() const) const
+{
+ return predicateMatchSucceed(text, length, progress, std::mem_fun_ref(predicate));
+}
+
+bool Rule::charPredicateMatchSucceed(const QString &text,
+ const int length,
+ ProgressData *progress,
+ bool (*predicate)(const QChar &)) const
+{
+ return predicateMatchSucceed(text, length, progress, std::ptr_fun(predicate));
+}
+
+bool Rule::matchSucceed(const QString &text, const int length, ProgressData *progress) const
+{
+ if (m_firstNonSpace && !progress->onlySpacesSoFar())
+ return false;
+
+ if (m_column != -1 && m_column != progress->offset())
+ return false;
+
+ int original = progress->offset();
+ if (doMatchSucceed(text, length, progress)) {
+ if (progress->onlySpacesSoFar() && !m_lookAhead && m_consumesNonSpace)
+ progress->setOnlySpacesSoFar(false);
+
+ if (m_lookAhead)
+ progress->setOffset(original);
+
+ return true;
+ }
+
+ return false;
+}
+
+Rule *Rule::clone() const
+{ return doClone(); }
+
+bool Rule::matchCharacter(const QString &text,
+ const int length,
+ ProgressData *progress,
+ const QChar &c,
+ bool saveRestoreOffset) const
+{
+ Q_UNUSED(length)
+ Q_ASSERT(progress->offset() < length);
+
+ if (text.at(progress->offset()) == c) {
+ if (saveRestoreOffset)
+ progress->saveOffset();
+ progress->incrementOffset();
+ return true;
+ }
+
+ return false;
+}
+
+bool Rule::matchEscapeSequence(const QString &text,
+ const int length,
+ ProgressData *progress,
+ bool saveRestoreOffset) const
+{
+ if (matchCharacter(text, length, progress, kBackSlash, saveRestoreOffset)) {
+
+ if (progress->offset() < length) {
+ const QChar &c = text.at(progress->offset());
+ if (c == kA || c == kB || c == kE || c == kF || c == kN || c == kR || c == kT ||
+ c == kV || c == kV || c == kQuestion || c == kSingleQuote || c == kQuote ||
+ c == kBackSlash) {
+ progress->incrementOffset();
+ return true;
+ } else if (saveRestoreOffset) {
+ progress->restoreOffset();
+ }
+ } else if (saveRestoreOffset) {
+ progress->restoreOffset();
+ }
+ }
+
+ return false;
+}
+
+bool Rule::matchOctalSequence(const QString &text,
+ const int length,
+ ProgressData *progress,
+ bool saveRestoreOffset) const
+{
+ // An octal sequence is identified as in the C++ Standard.
+ // octal-escape-sequence:
+ // \ octal-digit
+ // \ octal-digit octal-digit
+ // \ octal-digit octal-digit octal-digit
+
+ if (matchCharacter(text, length, progress, kBackSlash, saveRestoreOffset)) {
+
+ int count = 0;
+ while (progress->offset() < length &&
+ count < 3 &&
+ isOctalDigit(text.at(progress->offset()))) {
+ ++count;
+ progress->incrementOffset();
+ }
+
+ if (count > 0)
+ return true;
+ else if (saveRestoreOffset)
+ progress->restoreOffset();
+ }
+
+ return false;
+}
+
+bool Rule::matchHexSequence(const QString &text,
+ const int length,
+ ProgressData *progress,
+ bool saveRestoreOffset) const
+{
+ // An hex sequence is identified as in the C++ Standard.
+ // hexadecimal-escape-sequence:
+ // \x hexadecimal-digit
+ // hexadecimal-escape-sequence hexadecimal-digit
+
+ if (matchCharacter(text, length, progress, kBackSlash, saveRestoreOffset)) {
+
+ if (progress->offset() < length && matchCharacter(text, length, progress, kX, false)) {
+ bool found = false;
+ while (progress->offset() < length && isHexDigit(text.at(progress->offset()))) {
+ if (!found)
+ found = true;
+ progress->incrementOffset();
+ }
+
+ if (found)
+ return true;
+ else if (saveRestoreOffset)
+ progress->restoreOffset();
+ } else if (saveRestoreOffset) {
+ progress->restoreOffset();
+ }
+ }
+
+ return false;
+}
diff --git a/src/plugins/texteditor/generichighlighter/rule.h b/src/plugins/texteditor/generichighlighter/rule.h
new file mode 100644
index 0000000000..a53b2f8e5c
--- /dev/null
+++ b/src/plugins/texteditor/generichighlighter/rule.h
@@ -0,0 +1,160 @@
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** Commercial Usage
+**
+** Licensees holding valid Qt Commercial licenses may use this file in
+** accordance with the Qt Commercial License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Nokia.
+**
+** GNU Lesser General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://qt.nokia.com/contact.
+**
+**************************************************************************/
+
+#ifndef RULE_H
+#define RULE_H
+
+#include <QtCore/QString>
+#include <QtCore/QList>
+#include <QtCore/QSharedPointer>
+
+namespace TextEditor {
+namespace Internal {
+
+class ProgressData;
+class HighlightDefinition;
+
+class Rule
+{
+public:
+ Rule(bool consumesNonSpace = true);
+ virtual ~Rule();
+
+ void setContext(const QString &context);
+ const QString &context() const;
+
+ void setItemData(const QString &itemData);
+ const QString &itemData() const;
+
+ void setBeginRegion(const QString &begin);
+ const QString &beginRegion() const;
+
+ void setEndRegion(const QString &end);
+ const QString &endRegion() const;
+
+ void setLookAhead(const QString &lookAhead);
+ bool isLookAhead() const;
+
+ void setFirstNonSpace(const QString &firstNonSpace);
+ bool isFirstNonSpace() const;
+
+ void setColumn(const QString &column);
+ int column() const;
+
+ void addChild(const QSharedPointer<Rule> &rule);
+ const QList<QSharedPointer<Rule> > &childs() const;
+ bool hasChild() const;
+
+ void setDefinition(const QSharedPointer<HighlightDefinition> &definition);
+ const QSharedPointer<HighlightDefinition> &definition() const;
+
+ bool matchSucceed(const QString &text, const int length, ProgressData *progress) const;
+
+ Rule *clone() const;
+
+protected:
+ bool charPredicateMatchSucceed(const QString &text,
+ const int length,
+ ProgressData *progress,
+ bool (QChar::* predicate)() const) const;
+ bool charPredicateMatchSucceed(const QString &text,
+ const int length,
+ ProgressData *progress,
+ bool (*predicate)(const QChar &)) const;
+
+ bool matchCharacter(const QString &text,
+ const int length,
+ ProgressData *progress,
+ const QChar &c,
+ bool saveRestoreOffset = true) const;
+ bool matchEscapeSequence(const QString &text,
+ const int length,
+ ProgressData *progress,
+ bool saveRestoreOffset = true) const;
+ bool matchOctalSequence(const QString &text,
+ const int length,
+ ProgressData *progress,
+ bool saveRestoreOffset = true) const;
+ bool matchHexSequence(const QString &text,
+ const int length,
+ ProgressData *progress,
+ bool saveRestoreOffset = true) const;
+
+ static const QLatin1Char kBackSlash;
+ static const QLatin1Char kUnderscore;
+ static const QLatin1Char kDot;
+ static const QLatin1Char kPlus;
+ static const QLatin1Char kMinus;
+ static const QLatin1Char kZero;
+ static const QLatin1Char kQuote;
+ static const QLatin1Char kSingleQuote;
+ static const QLatin1Char kQuestion;
+ static const QLatin1Char kX;
+ static const QLatin1Char kA;
+ static const QLatin1Char kB;
+ static const QLatin1Char kE;
+ static const QLatin1Char kF;
+ static const QLatin1Char kN;
+ static const QLatin1Char kR;
+ static const QLatin1Char kT;
+ static const QLatin1Char kV;
+
+private:
+ virtual bool doMatchSucceed(const QString &text,
+ const int length,
+ ProgressData *progress) const = 0;
+
+ virtual Rule *doClone() const = 0;
+
+ template <class predicate_t>
+ bool predicateMatchSucceed(const QString &text,
+ const int length,
+ ProgressData *progress,
+ const predicate_t &p) const;
+
+ QString m_context;
+ QString m_itemData;
+ QString m_beginRegion;
+ QString m_endRegion;
+ bool m_lookAhead;
+ bool m_firstNonSpace;
+ int m_column;
+ bool m_consumesNonSpace;
+
+ QList<QSharedPointer<Rule> > m_childRules;
+
+ // Rules are represented within contexts. However, they have their own definition because
+ // of externally included rules.
+ QSharedPointer<HighlightDefinition> m_definition;
+};
+
+} // namespace Internal
+} // namespace TextEditor
+
+#endif // RULE_H
diff --git a/src/plugins/texteditor/generichighlighter/specificrules.cpp b/src/plugins/texteditor/generichighlighter/specificrules.cpp
new file mode 100644
index 0000000000..6fe4269367
--- /dev/null
+++ b/src/plugins/texteditor/generichighlighter/specificrules.cpp
@@ -0,0 +1,467 @@
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** Commercial Usage
+**
+** Licensees holding valid Qt Commercial licenses may use this file in
+** accordance with the Qt Commercial License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Nokia.
+**
+** GNU Lesser General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://qt.nokia.com/contact.
+**
+**************************************************************************/
+
+#include "specificrules.h"
+#include "highlightdefinition.h"
+#include "keywordlist.h"
+#include "progressdata.h"
+#include "reuse.h"
+
+#include <QLatin1Char>
+
+using namespace TextEditor;
+using namespace Internal;
+
+namespace {
+
+void replaceByCaptures(QChar *c, const QStringList &captures)
+{
+ int index = c->digitValue();
+ if (index > 0) {
+ const QString &capture = captures.at(index);
+ *c = capture.at(0);
+ }
+}
+
+void replaceByCaptures(QString *s, const QStringList &captures)
+{
+ static const QLatin1Char kPercent('%');
+
+ int index;
+ int from = 0;
+ while ((index = s->indexOf(kPercent, from)) != -1) {
+ from = index + 1;
+
+ QString accumulator;
+ while (from < s->length() && s->at(from).isDigit()) {
+ accumulator.append(s->at(from));
+ ++from;
+ }
+
+ bool ok;
+ int number = accumulator.toInt(&ok);
+ Q_ASSERT(ok);
+
+ s->replace(index, accumulator.length() + 1, captures.at(number));
+ index = from;
+ }
+}
+}
+
+// DetectChar
+void DetectCharRule::setChar(const QString &character)
+{ setStartCharacter(m_char, character); }
+
+void DetectCharRule::doReplaceExpressions(const QStringList &captures)
+{ replaceByCaptures(&m_char, captures); }
+
+bool DetectCharRule::doMatchSucceed(const QString &text,
+ const int length,
+ ProgressData *progress) const
+{
+ return matchCharacter(text, length, progress, m_char);
+}
+
+// Detect2Chars
+void Detect2CharsRule::setChar(const QString &character)
+{ setStartCharacter(m_char, character); }
+
+void Detect2CharsRule::setChar1(const QString &character)
+{ setStartCharacter(m_char1, character); }
+
+void Detect2CharsRule::doReplaceExpressions(const QStringList &captures)
+{
+ replaceByCaptures(&m_char, captures);
+ replaceByCaptures(&m_char1, captures);
+}
+
+bool Detect2CharsRule::doMatchSucceed(const QString &text,
+ const int length,
+ ProgressData *progress) const
+{
+ if (matchCharacter(text, length, progress, m_char)) {
+ if (progress->offset() < length && matchCharacter(text, length, progress, m_char1, false))
+ return true;
+ else
+ progress->restoreOffset();
+ }
+
+ return false;
+}
+
+// AnyChar
+void AnyCharRule::setCharacterSet(const QString &s)
+{ m_characterSet = s; }
+
+bool AnyCharRule::doMatchSucceed(const QString &text,
+ const int length,
+ ProgressData *progress) const
+{
+ Q_UNUSED(length)
+
+ if (m_characterSet.contains(text.at(progress->offset()))) {
+ progress->incrementOffset();
+ return true;
+ }
+
+ return false;
+}
+
+// StringDetect
+void StringDetectRule::setString(const QString &s)
+{
+ m_string = s;
+ m_length = m_string.length();
+}
+
+void StringDetectRule::setInsensitive(const QString &insensitive)
+{ m_caseSensitivity = toCaseSensitivity(!toBool(insensitive)); }
+
+void StringDetectRule::doReplaceExpressions(const QStringList &captures)
+{ replaceByCaptures(&m_string, captures); }
+
+bool StringDetectRule::doMatchSucceed(const QString &text,
+ const int length,
+ ProgressData *progress) const
+{
+ if (length - progress->offset() >= m_length) {
+ QString candidate = text.fromRawData(text.unicode() + progress->offset(), m_length);
+ if (candidate.compare(m_string, m_caseSensitivity) == 0) {
+ progress->incrementOffset(m_length);
+ return true;
+ }
+ }
+
+ return false;
+}
+
+// RegExpr
+void RegExprRule::setPattern(const QString &pattern)
+{ m_expression.setPattern(pattern); }
+
+void RegExprRule::setInsensitive(const QString &insensitive)
+{ m_expression.setCaseSensitivity(toCaseSensitivity(!toBool(insensitive))); }
+
+void RegExprRule::setMinimal(const QString &minimal)
+{ m_expression.setMinimal(toBool(minimal)); }
+
+void RegExprRule::doReplaceExpressions(const QStringList &captures)
+{
+ QString s = m_expression.pattern();
+ replaceByCaptures(&s, captures);
+ m_expression.setPattern(s);
+}
+
+bool RegExprRule::doMatchSucceed(const QString &text,
+ const int length,
+ ProgressData *progress) const
+{
+ Q_UNUSED(length)
+
+ // This is not documented but a regular expression match is considered valid if it starts
+ // at the current position and if the match length is not zero. Checked in Kate's source code
+ // after some unexpected problems.
+ const int offset = progress->offset();
+ if (m_expression.indexIn(text, offset, QRegExp::CaretAtZero) == offset) {
+ if (m_expression.matchedLength() == 0)
+ return false;
+ progress->incrementOffset(m_expression.matchedLength());
+ progress->setCaptures(m_expression.capturedTexts());
+ return true;
+ }
+
+ return false;
+}
+
+// Keyword
+KeywordRule::KeywordRule(const QSharedPointer<HighlightDefinition> &definition) :
+ m_overrideGlobal(false)
+{
+ setDefinition(definition);
+}
+
+KeywordRule::~KeywordRule()
+{}
+
+void KeywordRule::setInsensitive(const QString &insensitive)
+{
+ if (!insensitive.isEmpty()) {
+ m_overrideGlobal = true;
+ m_localCaseSensitivity = toCaseSensitivity(!toBool(insensitive));
+ }
+}
+
+void KeywordRule::setList(const QString &listName)
+{ m_list = definition()->keywordList(listName); }
+
+bool KeywordRule::doMatchSucceed(const QString &text,
+ const int length,
+ ProgressData *progress) const
+{
+ int current = progress->offset();
+
+ if (current > 0 && !definition()->isDelimiter(text.at(current - 1)))
+ return false;
+ if (definition()->isDelimiter(text.at(current)))
+ return false;
+
+ while (current < length && !definition()->isDelimiter(text.at(current)))
+ ++current;
+
+ QString candidate =
+ QString::fromRawData(text.unicode() + progress->offset(), current - progress->offset());
+ if ((m_overrideGlobal && m_list->isKeyword(candidate, m_localCaseSensitivity)) ||
+ (!m_overrideGlobal && m_list->isKeyword(candidate, definition()->keywordsSensitive()))) {
+ progress->setOffset(current);
+ return true;
+ }
+
+ return false;
+}
+
+// Int
+bool IntRule::doMatchSucceed(const QString &text,
+ const int length,
+ ProgressData *progress) const
+{
+ const int offset = progress->offset();
+
+ // This is necessary to correctly highlight an invalid octal like 09, for example.
+ if (offset > 0 && text.at(offset - 1).isDigit())
+ return false;
+
+ if (text.at(offset).isDigit() && text.at(offset) != kZero) {
+ progress->incrementOffset();
+ charPredicateMatchSucceed(text, length, progress, &QChar::isDigit);
+ return true;
+ }
+
+ return false;
+}
+
+// Float
+bool FloatRule::doMatchSucceed(const QString &text, const int length, ProgressData *progress) const
+{
+ progress->saveOffset();
+
+ bool integralPart = charPredicateMatchSucceed(text, length, progress, &QChar::isDigit);
+
+ bool decimalPoint = false;
+ if (progress->offset() < length && text.at(progress->offset()) == kDot) {
+ progress->incrementOffset();
+ decimalPoint = true;
+ }
+
+ bool fractionalPart = charPredicateMatchSucceed(text, length, progress, &QChar::isDigit);
+
+ bool exponentialPart = false;
+ int offset = progress->offset();
+ if (offset < length && (text.at(offset) == kE || text.at(offset).toLower() == kE)) {
+ progress->incrementOffset();
+
+ offset = progress->offset();
+ if (offset < length && (text.at(offset) == kPlus || text.at(offset) == kMinus))
+ progress->incrementOffset();
+
+ if (charPredicateMatchSucceed(text, length, progress, &QChar::isDigit)) {
+ exponentialPart = true;
+ } else {
+ progress->restoreOffset();
+ return false;
+ }
+ }
+
+ if ((integralPart || fractionalPart) && (decimalPoint || exponentialPart))
+ return true;
+
+ progress->restoreOffset();
+ return false;
+}
+
+// COctal
+bool HlCOctRule::doMatchSucceed(const QString &text,
+ const int length,
+ ProgressData *progress) const
+{
+ if (matchCharacter(text, length, progress, kZero)) {
+ // In the definition files the number matching rules which are more restrictive should
+ // appear before the rules which are least resctritive. Although this happens in general
+ // there is at least one case where this is not strictly followed for existent definition
+ // files (specifically, HlCHex comes before HlCOct). So the condition below.
+ const int offset = progress->offset();
+ if (offset < length && (text.at(offset) == kX || text.at(offset).toLower() == kX)) {
+ progress->restoreOffset();
+ return false;
+ }
+
+ charPredicateMatchSucceed(text, length, progress, &isOctalDigit);
+ return true;
+ }
+
+ return false;
+}
+
+// CHex
+bool HlCHexRule::doMatchSucceed(const QString &text,
+ const int length,
+ ProgressData *progress) const
+{
+ if (matchCharacter(text, length, progress, kZero)) {
+ const int offset = progress->offset();
+ if (offset < length && text.at(offset) != kX && text.at(offset).toLower() != kX) {
+ progress->restoreOffset();
+ return false;
+ }
+
+ progress->incrementOffset();
+ if (charPredicateMatchSucceed(text, length, progress, &isHexDigit))
+ return true;
+ else
+ progress->restoreOffset();
+ }
+
+ return false;
+}
+
+// CString
+bool HlCStringCharRule::doMatchSucceed(const QString &text,
+ const int length,
+ ProgressData *progress) const
+{
+ if (matchEscapeSequence(text, length, progress))
+ return true;
+
+ if (matchOctalSequence(text, length, progress))
+ return true;
+
+ if (matchHexSequence(text, length, progress))
+ return true;
+
+ return false;
+}
+
+// CChar
+bool HlCCharRule::doMatchSucceed(const QString &text,
+ const int length,
+ ProgressData *progress) const
+{
+ if (matchCharacter(text, length, progress, kSingleQuote)) {
+ if (progress->offset() < length) {
+ if (text.at(progress->offset()) != kBackSlash &&
+ text.at(progress->offset()) != kSingleQuote) {
+ progress->incrementOffset();
+ } else if (!matchEscapeSequence(text, length, progress, false)) {
+ progress->restoreOffset();
+ return false;
+ }
+
+ if (progress->offset() < length &&
+ matchCharacter(text, length, progress, kSingleQuote, false)) {
+ return true;
+ } else {
+ progress->restoreOffset();
+ }
+ } else {
+ progress->restoreOffset();
+ }
+ }
+
+ return false;
+}
+
+// RangeDetect
+void RangeDetectRule::setChar(const QString &character)
+{ setStartCharacter(m_char, character); }
+
+void RangeDetectRule::setChar1(const QString &character)
+{ setStartCharacter(m_char1, character); }
+
+bool RangeDetectRule::doMatchSucceed(const QString &text,
+ const int length,
+ ProgressData *progress) const
+{
+ if (matchCharacter(text, length, progress, m_char)) {
+ while (progress->offset() < length) {
+ if (matchCharacter(text, length, progress, m_char1, false))
+ return true;
+ progress->incrementOffset();
+ }
+ progress->restoreOffset();
+ }
+
+ return false;
+}
+
+// LineContinue
+bool LineContinueRule::doMatchSucceed(const QString &text,
+ const int length,
+ ProgressData *progress) const
+{
+ if (progress->offset() != length - 1)
+ return false;
+
+ if (text.at(progress->offset()) == kBackSlash) {
+ progress->setWillContinueLine(true);
+ return true;
+ }
+
+ return false;
+}
+
+// DetectSpaces
+DetectSpacesRule::DetectSpacesRule() : Rule(false)
+{}
+
+bool DetectSpacesRule::doMatchSucceed(const QString &text,
+ const int length,
+ ProgressData *progress) const
+{
+ return charPredicateMatchSucceed(text, length, progress, &QChar::isSpace);
+}
+
+// DetectIdentifier
+bool DetectIdentifierRule::doMatchSucceed(const QString &text,
+ const int length,
+ ProgressData *progress) const
+{
+ // Identifiers are characterized by a letter or underscore as the first character and then
+ // zero or more word characters (\w*).
+ if (text.at(progress->offset()).isLetter() || text.at(progress->offset()) == kUnderscore) {
+ progress->incrementOffset();
+ while (progress->offset() < length) {
+ const QChar &current = text.at(progress->offset());
+ if (current.isLetterOrNumber() || current.isMark() || current == kUnderscore)
+ progress->incrementOffset();
+ else
+ break;
+ }
+ return true;
+ }
+ return false;
+}
diff --git a/src/plugins/texteditor/generichighlighter/specificrules.h b/src/plugins/texteditor/generichighlighter/specificrules.h
new file mode 100644
index 0000000000..7ec2552dad
--- /dev/null
+++ b/src/plugins/texteditor/generichighlighter/specificrules.h
@@ -0,0 +1,288 @@
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** Commercial Usage
+**
+** Licensees holding valid Qt Commercial licenses may use this file in
+** accordance with the Qt Commercial License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Nokia.
+**
+** GNU Lesser General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://qt.nokia.com/contact.
+**
+**************************************************************************/
+
+#ifndef SPECIFICRULES_H
+#define SPECIFICRULES_H
+
+#include "rule.h"
+#include "dynamicrule.h"
+
+#include <QtCore/QChar>
+#include <QtCore/QString>
+#include <QtCore/QRegExp>
+#include <QtCore/QSharedPointer>
+
+namespace TextEditor {
+namespace Internal {
+
+class KeywordList;
+class HighlightDefinition;
+
+class DetectCharRule : public DynamicRule
+{
+public:
+ virtual ~DetectCharRule() {}
+
+ void setChar(const QString &character);
+
+private:
+ virtual bool doMatchSucceed(const QString &text,
+ const int length,
+ ProgressData *progress) const;
+ virtual DetectCharRule *doClone() const { return new DetectCharRule(*this); }
+ virtual void doReplaceExpressions(const QStringList &captures);
+
+ QChar m_char;
+};
+
+class Detect2CharsRule : public DynamicRule
+{
+public:
+ virtual ~Detect2CharsRule() {}
+
+ void setChar(const QString &character);
+ void setChar1(const QString &character);
+
+private:
+ virtual bool doMatchSucceed(const QString &text,
+ const int length,
+ ProgressData *progress) const;
+ virtual Detect2CharsRule *doClone() const { return new Detect2CharsRule(*this); }
+ virtual void doReplaceExpressions(const QStringList &captures);
+
+ QChar m_char;
+ QChar m_char1;
+};
+
+class AnyCharRule : public Rule
+{
+public:
+ virtual ~AnyCharRule() {}
+
+ void setCharacterSet(const QString &s);
+
+private:
+ virtual bool doMatchSucceed(const QString &text,
+ const int length,
+ ProgressData *progress) const;
+ virtual AnyCharRule *doClone() const { return new AnyCharRule(*this); }
+
+ QString m_characterSet;
+};
+
+class StringDetectRule : public DynamicRule
+{
+public:
+ virtual ~StringDetectRule() {}
+
+ void setString(const QString &s);
+ void setInsensitive(const QString &insensitive);
+
+private:
+ virtual bool doMatchSucceed(const QString &text,
+ const int length,
+ ProgressData *progress) const;
+ virtual StringDetectRule *doClone() const { return new StringDetectRule(*this); }
+ virtual void doReplaceExpressions(const QStringList &captures);
+
+ QString m_string;
+ int m_length;
+ Qt::CaseSensitivity m_caseSensitivity;
+};
+
+class RegExprRule : public DynamicRule
+{
+public:
+ virtual ~RegExprRule() {}
+
+ void setPattern(const QString &pattern);
+ void setInsensitive(const QString &insensitive);
+ void setMinimal(const QString &minimal);
+
+private:
+ virtual bool doMatchSucceed(const QString &text,
+ const int length,
+ ProgressData *progress) const;
+ virtual RegExprRule *doClone() const { return new RegExprRule(*this); }
+ virtual void doReplaceExpressions(const QStringList &captures);
+
+ QRegExp m_expression;
+};
+
+class KeywordRule : public Rule
+{
+public:
+ KeywordRule(const QSharedPointer<HighlightDefinition> &definition);
+ virtual ~KeywordRule();
+
+ void setInsensitive(const QString &insensitive);
+ void setList(const QString &listName);
+
+private:
+ virtual bool doMatchSucceed(const QString &text,
+ const int length,
+ ProgressData *progress) const;
+ virtual KeywordRule *doClone() const { return new KeywordRule(*this); }
+
+ bool m_overrideGlobal;
+ Qt::CaseSensitivity m_localCaseSensitivity;
+ QSharedPointer<KeywordList> m_list;
+};
+
+class IntRule : public Rule
+{
+public:
+ virtual ~IntRule() {}
+
+private:
+ virtual bool doMatchSucceed(const QString &text,
+ const int length,
+ ProgressData *progress) const;
+ virtual IntRule *doClone() const { return new IntRule(*this); }
+};
+
+class FloatRule : public Rule
+{
+public:
+ virtual ~FloatRule() {}
+
+private:
+ virtual bool doMatchSucceed(const QString &text,
+ const int length,
+ ProgressData *progress) const;
+ virtual FloatRule *doClone() const { return new FloatRule(*this); }
+};
+
+class HlCOctRule : public Rule
+{
+public:
+ virtual ~HlCOctRule() {}
+
+private:
+ virtual bool doMatchSucceed(const QString &text,
+ const int length,
+ ProgressData *progress) const;
+ virtual HlCOctRule *doClone() const { return new HlCOctRule(*this); }
+};
+
+class HlCHexRule : public Rule
+{
+public:
+ virtual ~HlCHexRule() {}
+
+private:
+ virtual bool doMatchSucceed(const QString &text,
+ const int length,
+ ProgressData *progress) const;
+ virtual HlCHexRule *doClone() const { return new HlCHexRule(*this); }
+};
+
+class HlCStringCharRule : public Rule
+{
+public:
+ virtual ~HlCStringCharRule() {}
+
+private:
+ virtual bool doMatchSucceed(const QString &text,
+ const int length,
+ ProgressData *progress) const;
+ virtual HlCStringCharRule *doClone() const { return new HlCStringCharRule(*this); }
+};
+
+class HlCCharRule : public Rule
+{
+public:
+ virtual ~HlCCharRule() {}
+
+private:
+ virtual bool doMatchSucceed(const QString &text,
+ const int length,
+ ProgressData *progress) const;
+ virtual HlCCharRule *doClone() const { return new HlCCharRule(*this); }
+};
+
+class RangeDetectRule : public Rule
+{
+public:
+ virtual ~RangeDetectRule() {}
+
+ void setChar(const QString &character);
+ void setChar1(const QString &character);
+
+private:
+ virtual bool doMatchSucceed(const QString &text,
+ const int length,
+ ProgressData *progress) const;
+ virtual RangeDetectRule *doClone() const { return new RangeDetectRule(*this); }
+
+ QChar m_char;
+ QChar m_char1;
+};
+
+class LineContinueRule : public Rule
+{
+public:
+ virtual ~LineContinueRule() {}
+
+private:
+ virtual bool doMatchSucceed(const QString &text,
+ const int length,
+ ProgressData *progress) const;
+ virtual LineContinueRule *doClone() const { return new LineContinueRule(*this); }
+};
+
+class DetectSpacesRule : public Rule
+{
+public:
+ DetectSpacesRule();
+ virtual ~DetectSpacesRule() {}
+
+private:
+ virtual bool doMatchSucceed(const QString &text,
+ const int length,
+ ProgressData *progress) const;
+ virtual DetectSpacesRule *doClone() const { return new DetectSpacesRule(*this); }
+};
+
+class DetectIdentifierRule : public Rule
+{
+public:
+ virtual ~DetectIdentifierRule() {}
+
+private:
+ virtual bool doMatchSucceed(const QString &text,
+ const int length,
+ ProgressData *progress) const;
+ virtual DetectIdentifierRule *doClone() const { return new DetectIdentifierRule(*this); }
+};
+
+} // namespace Internal
+} // namespace TextEditor
+
+#endif // SPECIFICRULES_H
diff --git a/src/plugins/texteditor/plaintexteditor.cpp b/src/plugins/texteditor/plaintexteditor.cpp
index 257280b0b3..2c748b0738 100644
--- a/src/plugins/texteditor/plaintexteditor.cpp
+++ b/src/plugins/texteditor/plaintexteditor.cpp
@@ -31,9 +31,20 @@
#include "tabsettings.h"
#include "texteditorconstants.h"
#include "texteditorplugin.h"
+#include "texteditorsettings.h"
+#include "basetextdocument.h"
+#include "highlightdefinition.h"
+#include "highlighter.h"
+#include "highlighterexception.h"
+#include "manager.h"
#include <coreplugin/coreconstants.h>
#include <coreplugin/uniqueidmanager.h>
+#include <coreplugin/icore.h>
+#include <coreplugin/mimedatabase.h>
+
+#include <QtCore/QSharedPointer>
+#include <QtCore/QFileInfo>
using namespace TextEditor;
using namespace TextEditor::Internal;
@@ -54,8 +65,11 @@ PlainTextEditor::PlainTextEditor(QWidget *parent)
setRequestMarkEnabled(false);
setLineSeparatorsAllowed(true);
- setMimeType(QLatin1String(TextEditor::Constants::C_TEXTEDITOR_MIMETYPE_TEXT));
setDisplayName(tr(Core::Constants::K_DEFAULT_TEXT_EDITOR_DISPLAY_NAME));
+
+ m_commentDefinition.clearCommentStyles();
+
+ connect(file(), SIGNAL(changed()), this, SLOT(configure()));
}
QList<int> PlainTextEditorEditable::context() const
@@ -76,7 +90,56 @@ QString PlainTextEditorEditable::id() const
return QLatin1String(Core::Constants::K_DEFAULT_TEXT_EDITOR_ID);
}
+void PlainTextEditor::unCommentSelection()
+{
+ Utils::unCommentSelection(this, m_commentDefinition);
+}
+
+void PlainTextEditor::setFontSettings(const TextEditor::FontSettings & fs)
+{
+ TextEditor::BaseTextEditor::setFontSettings(fs);
+
+ Highlighter *highlighter = static_cast<Highlighter *>(baseTextDocument()->syntaxHighlighter());
+ if (!highlighter)
+ return;
+
+ highlighter->configureFormats(fs);
+ highlighter->rehighlight();
+}
+
+void PlainTextEditor::configure()
+{
+ const QString &mimeType = Core::ICore::instance()->mimeDatabase()->findByFile(
+ QFileInfo(file()->fileName())).type();
+ baseTextDocument()->setMimeType(mimeType);
+
+ const QString &definitionId = Manager::instance()->definitionIdByMimeType(mimeType);
+ if (!definitionId.isEmpty()) {
+ try {
+ const QSharedPointer<HighlightDefinition> &definition =
+ Manager::instance()->definition(definitionId);
+
+ Highlighter *highlighter = new Highlighter(definition->initialContext());
+ highlighter->configureFormats(TextEditor::TextEditorSettings::instance()->fontSettings());
+
+ baseTextDocument()->setSyntaxHighlighter(highlighter);
+
+ m_commentDefinition.setAfterWhiteSpaces(definition->isCommentAfterWhiteSpaces());
+ m_commentDefinition.setSingleLine(definition->singleLineComment());
+ m_commentDefinition.setMultiLineStart(definition->multiLineCommentStart());
+ m_commentDefinition.setMultiLineEnd(definition->multiLineCommentEnd());
+ } catch (const HighlighterException &) {
+ }
+ }
+
+ // @todo: Indentation specification through the definition files is not really being
+ // used because Kate recommends to configure indentation through another feature.
+ // Maybe we should provide something similar in Creator? For now, only normal
+ // indentation is supported.
+ m_indenter.reset(new TextEditor::NormalIndenter);
+}
+
void PlainTextEditor::indentBlock(QTextDocument *doc, QTextBlock block, QChar typedChar)
{
- m_indenter.indentBlock(doc, block, typedChar, tabSettings());
+ m_indenter->indentBlock(doc, block, typedChar, tabSettings());
}
diff --git a/src/plugins/texteditor/plaintexteditor.h b/src/plugins/texteditor/plaintexteditor.h
index f2c5673fb0..fdc85423d2 100644
--- a/src/plugins/texteditor/plaintexteditor.h
+++ b/src/plugins/texteditor/plaintexteditor.h
@@ -33,7 +33,10 @@
#include "basetexteditor.h"
#include "normalindenter.h"
+#include <utils/uncommentselection.h>
+
#include <QtCore/QList>
+#include <QtCore/QScopedPointer>
namespace TextEditor {
@@ -61,13 +64,20 @@ class TEXTEDITOR_EXPORT PlainTextEditor : public BaseTextEditor
public:
PlainTextEditor(QWidget *parent);
+public slots:
+ virtual void unCommentSelection();
+ virtual void setFontSettings(const TextEditor::FontSettings &);
+
+private slots:
+ void configure();
+
protected:
virtual BaseTextEditorEditable *createEditableInterface() { return new PlainTextEditorEditable(this); }
virtual void indentBlock(QTextDocument *doc, QTextBlock block, QChar typedChar);
private:
- // Indent a text block based on previous line.
- NormalIndenter m_indenter;
+ Utils::CommentDefinition m_commentDefinition;
+ QScopedPointer<TextEditor::Indenter> m_indenter;
};
} // namespace TextEditor
diff --git a/src/plugins/texteditor/plaintexteditorfactory.cpp b/src/plugins/texteditor/plaintexteditorfactory.cpp
index 3a960bc180..7a21997395 100644
--- a/src/plugins/texteditor/plaintexteditorfactory.cpp
+++ b/src/plugins/texteditor/plaintexteditorfactory.cpp
@@ -44,7 +44,8 @@ PlainTextEditorFactory::PlainTextEditorFactory(QObject *parent)
{
m_actionHandler = new TextEditorActionHandler(
QLatin1String(TextEditor::Constants::C_TEXTEDITOR),
- TextEditorActionHandler::Format);
+ TextEditorActionHandler::Format |
+ TextEditorActionHandler::UnCommentSelection);
m_mimeTypes << QLatin1String(TextEditor::Constants::C_TEXTEDITOR_MIMETYPE_TEXT);
}
@@ -76,6 +77,11 @@ Core::IEditor *PlainTextEditorFactory::createEditor(QWidget *parent)
return rc->editableInterface();
}
+void PlainTextEditorFactory::addMimeType(const QString &type)
+{
+ m_mimeTypes.append(type);
+}
+
QStringList PlainTextEditorFactory::mimeTypes() const
{
return m_mimeTypes;
diff --git a/src/plugins/texteditor/plaintexteditorfactory.h b/src/plugins/texteditor/plaintexteditorfactory.h
index d55f4808af..a01a80f7f1 100644
--- a/src/plugins/texteditor/plaintexteditorfactory.h
+++ b/src/plugins/texteditor/plaintexteditorfactory.h
@@ -50,6 +50,7 @@ public:
PlainTextEditorFactory(QObject *parent = 0);
virtual ~PlainTextEditorFactory();
+ void addMimeType(const QString &type);
virtual QStringList mimeTypes() const;
//Core::IEditorFactory
QString id() const;
diff --git a/src/plugins/texteditor/texteditor.pro b/src/plugins/texteditor/texteditor.pro
index bf64eb51c1..4892ff2992 100644
--- a/src/plugins/texteditor/texteditor.pro
+++ b/src/plugins/texteditor/texteditor.pro
@@ -1,8 +1,11 @@
TEMPLATE = lib
TARGET = TextEditor
DEFINES += TEXTEDITOR_LIBRARY
+QT += xml
include(../../qtcreatorplugin.pri)
include(texteditor_dependencies.pri)
+INCLUDEPATH += generichighlighter
+DEPENDPATH += generichighlighter
SOURCES += texteditorplugin.cpp \
textfilewizard.cpp \
plaintexteditor.cpp \
@@ -37,7 +40,19 @@ SOURCES += texteditorplugin.cpp \
basetextdocumentlayout.cpp \
completionsettings.cpp \
normalindenter.cpp \
- indenter.cpp
+ indenter.cpp \
+ generichighlighter/itemdata.cpp \
+ generichighlighter/specificrules.cpp \
+ generichighlighter/rule.cpp \
+ generichighlighter/dynamicrule.cpp \
+ generichighlighter/context.cpp \
+ generichighlighter/includerulesinstruction.cpp \
+ generichighlighter/progressdata.cpp \
+ generichighlighter/keywordlist.cpp \
+ generichighlighter/highlightdefinition.cpp \
+ generichighlighter/highlighter.cpp \
+ generichighlighter/manager.cpp \
+ generichighlighter/highlightdefinitionhandler.cpp
HEADERS += texteditorplugin.h \
textfilewizard.h \
@@ -77,7 +92,22 @@ HEADERS += texteditorplugin.h \
basetextdocumentlayout.h \
completionsettings.h \
normalindenter.h \
- indenter.h
+ indenter.h \
+ generichighlighter/reuse.h \
+ generichighlighter/itemdata.h \
+ generichighlighter/specificrules.h \
+ generichighlighter/rule.h \
+ generichighlighter/reuse.h \
+ generichighlighter/dynamicrule.h \
+ generichighlighter/context.h \
+ generichighlighter/includerulesinstruction.h \
+ generichighlighter/progressdata.h \
+ generichighlighter/keywordlist.h \
+ generichighlighter/highlighterexception.h \
+ generichighlighter/highlightdefinition.h \
+ generichighlighter/highlighter.h \
+ generichighlighter/manager.h \
+ generichighlighter/highlightdefinitionhandler.h
FORMS += behaviorsettingspage.ui \
diff --git a/src/plugins/texteditor/texteditorplugin.cpp b/src/plugins/texteditor/texteditorplugin.cpp
index dca81bed5a..058fcd6350 100644
--- a/src/plugins/texteditor/texteditorplugin.cpp
+++ b/src/plugins/texteditor/texteditorplugin.cpp
@@ -39,6 +39,7 @@
#include "plaintexteditorfactory.h"
#include "plaintexteditor.h"
#include "storagesettings.h"
+#include "manager.h"
#include <coreplugin/icore.h>
#include <coreplugin/coreconstants.h>
@@ -70,6 +71,9 @@ TextEditorPlugin::TextEditorPlugin()
{
QTC_ASSERT(!m_instance, return);
m_instance = this;
+
+ connect(Core::ICore::instance(), SIGNAL(coreOpened()),
+ Manager::instance(), SLOT(registerMimeTypes()));
}
TextEditorPlugin::~TextEditorPlugin()
diff --git a/src/plugins/texteditor/texteditorplugin.h b/src/plugins/texteditor/texteditorplugin.h
index 1fc4c10be7..93f8870e1f 100644
--- a/src/plugins/texteditor/texteditorplugin.h
+++ b/src/plugins/texteditor/texteditorplugin.h
@@ -64,6 +64,7 @@ public:
void initializeEditor(PlainTextEditor *editor);
+ PlainTextEditorFactory *editorFactory() { return m_editorFactory; }
LineNumberFilter *lineNumberFilter() { return m_lineNumberFilter; }
private slots: