aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLeandro Melo <leandro.melo@nokia.com>2010-09-24 20:16:34 +0200
committerLeandro Melo <leandro.melo@nokia.com>2010-09-24 20:22:03 +0200
commitcafcce0c3738264d48795f60b85472c06d587079 (patch)
treea7e1a60562a6e235a7043d66732f9d3472b08038
parentf64cf427f2a0cd37789b9feb782cd1b4e26563ec (diff)
Add support for C++ snippets.
-rw-r--r--share/qtcreator/snippets/cpp.xml9
-rw-r--r--src/plugins/cpptools/cppcodecompletion.cpp30
-rw-r--r--src/plugins/cpptools/cppcodecompletion.h4
-rw-r--r--src/plugins/qmljseditor/qmljscodecompletion.cpp104
-rw-r--r--src/plugins/qmljseditor/qmljscodecompletion.h8
-rw-r--r--src/plugins/texteditor/icompletioncollector.h4
-rw-r--r--src/plugins/texteditor/images/snippet.pngbin0 -> 367 bytes
-rw-r--r--src/plugins/texteditor/snippetsparser.cpp139
-rw-r--r--src/plugins/texteditor/snippetsparser.h60
-rw-r--r--src/plugins/texteditor/texteditor.pro6
-rw-r--r--src/plugins/texteditor/texteditor.qrc1
11 files changed, 247 insertions, 118 deletions
diff --git a/share/qtcreator/snippets/cpp.xml b/share/qtcreator/snippets/cpp.xml
new file mode 100644
index 0000000000..6a8037be30
--- /dev/null
+++ b/share/qtcreator/snippets/cpp.xml
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="utf-8"?>
+<snippets>
+<snippet>for (int <tab>var</tab> = 0; <tab>var</tab> &lt; <tab>total</tab>; ++<tab>var</tab>) {
+}
+</snippet>
+<snippet>for (<tab>var</tab>; <tab>var</tab> &lt; <tab>total</tab>; ++<tab>var</tab>) {
+}
+</snippet>
+</snippets>
diff --git a/src/plugins/cpptools/cppcodecompletion.cpp b/src/plugins/cpptools/cppcodecompletion.cpp
index 32a51d7f2c..4426cb64a7 100644
--- a/src/plugins/cpptools/cppcodecompletion.cpp
+++ b/src/plugins/cpptools/cppcodecompletion.cpp
@@ -75,6 +75,7 @@
#include <QtGui/QTextDocument> // Qt::escape()
#include <QtGui/QToolButton>
#include <QtGui/QVBoxLayout>
+#include <QtAlgorithms>
namespace {
const bool debug = ! qgetenv("CPLUSPLUS_DEBUG").isEmpty();
@@ -460,7 +461,8 @@ CppCodeCompletion::CppCodeCompletion(CppModelManager *manager)
m_shouldRestartCompletion(false),
m_automaticCompletion(false),
m_completionOperator(T_EOF_SYMBOL),
- m_objcEnabled(true)
+ m_objcEnabled(true),
+ m_snippetsParser(Core::ICore::instance()->resourcePath() + QLatin1String("/snippets/cpp.xml"))
{
}
@@ -1123,7 +1125,10 @@ void CppCodeCompletion::globalCompletion(Scope *currentScope)
foreach (ClassOrNamespace *b, usingBindings)
completeNamespace(b);
+ addSnippets();
addKeywords();
+ qStableSort(m_completions.begin(), m_completions.end(), completionItemLessThan);
+
addMacros(QLatin1String("<configuration>"), context.snapshot());
addMacros(context.thisDocument()->fileName(), context.snapshot());
}
@@ -1759,18 +1764,19 @@ void CppCodeCompletion::completions(QList<TextEditor::CompletionItem> *completio
QList<TextEditor::CompletionItem> CppCodeCompletion::removeDuplicates(const QList<TextEditor::CompletionItem> &items)
{
- // Remove duplicates
+ // Duplicates are kept only if they are snippets.
QList<TextEditor::CompletionItem> uniquelist;
QSet<QString> processed;
-
foreach (const TextEditor::CompletionItem &item, items) {
- if (! processed.contains(item.text)) {
- processed.insert(item.text);
+ if (!processed.contains(item.text) || item.isSnippet) {
uniquelist.append(item);
- if (Symbol *symbol = qvariant_cast<Symbol *>(item.data)) {
- if (Function *funTy = symbol->type()->asFunctionType()) {
- if (funTy->hasArguments())
- ++uniquelist.back().duplicateCount;
+ if (!item.isSnippet) {
+ processed.insert(item.text);
+ if (Symbol *symbol = qvariant_cast<Symbol *>(item.data)) {
+ if (Function *funTy = symbol->type()->asFunctionType()) {
+ if (funTy->hasArguments())
+ ++uniquelist.back().duplicateCount;
+ }
}
}
}
@@ -2018,4 +2024,10 @@ bool CppCodeCompletion::objcKeywordsWanted() const
return mdb->findByFile(fileName).type() == CppTools::Constants::OBJECTIVE_CPP_SOURCE_MIMETYPE;
}
+void CppCodeCompletion::addSnippets()
+{
+ static const QIcon icon(QLatin1String(":/texteditor/images/snippet.png"));
+ m_completions.append(m_snippetsParser.execute(this, icon));
+}
+
#include "cppcodecompletion.moc"
diff --git a/src/plugins/cpptools/cppcodecompletion.h b/src/plugins/cpptools/cppcodecompletion.h
index 89753ce72e..49317eb096 100644
--- a/src/plugins/cpptools/cppcodecompletion.h
+++ b/src/plugins/cpptools/cppcodecompletion.h
@@ -37,6 +37,7 @@
#include <cplusplus/TypeOfExpression.h>
#include <texteditor/icompletioncollector.h>
+#include <texteditor/snippetsparser.h>
#include <QtCore/QObject>
#include <QtCore/QPointer>
@@ -87,6 +88,7 @@ public:
QIcon iconForSymbol(CPlusPlus::Symbol *symbol) const;
private:
+ void addSnippets();
void addKeywords();
void addMacros(const QString &fileName, const CPlusPlus::Snapshot &snapshot);
void addMacros_helper(const CPlusPlus::Snapshot &snapshot,
@@ -151,6 +153,8 @@ private:
unsigned m_completionOperator;
bool m_objcEnabled;
+ TextEditor::SnippetsParser m_snippetsParser;
+
CPlusPlus::Icons m_icons;
CPlusPlus::Overview overview;
CPlusPlus::TypeOfExpression typeOfExpression;
diff --git a/src/plugins/qmljseditor/qmljscodecompletion.cpp b/src/plugins/qmljseditor/qmljscodecompletion.cpp
index 4219b3b302..cde1a659e6 100644
--- a/src/plugins/qmljseditor/qmljscodecompletion.cpp
+++ b/src/plugins/qmljseditor/qmljscodecompletion.cpp
@@ -50,7 +50,6 @@
#include <QtCore/QFile>
#include <QtCore/QFileInfo>
#include <QtCore/QDir>
-#include <QtCore/QXmlStreamReader>
#include <QtCore/QDebug>
#include <QtGui/QApplication>
@@ -485,7 +484,8 @@ CodeCompletion::CodeCompletion(ModelManagerInterface *modelManager, QObject *par
m_modelManager(modelManager),
m_editor(0),
m_startPosition(0),
- m_restartCompletion(false)
+ m_restartCompletion(false),
+ m_snippetsParser(Core::ICore::instance()->resourcePath() + QLatin1String("/snippets/qml.xml"))
{
Q_ASSERT(modelManager);
}
@@ -860,8 +860,7 @@ int CodeCompletion::startCompletion(TextEditor::ITextEditable *editor)
}
if (isQmlFile && (completionOperator.isNull() || completionOperator.isSpace() || isDelimiter(completionOperator))) {
- updateSnippets();
- m_completions.append(m_snippets);
+ m_completions.append(m_snippetsParser.execute(this, iconForColor(Qt::red), SnippetOrder));
}
if (! m_completions.isEmpty())
@@ -960,103 +959,6 @@ void CodeCompletion::cleanup()
m_completions.clear();
}
-
-void CodeCompletion::updateSnippets()
-{
- QString qmlsnippets = Core::ICore::instance()->resourcePath() + QLatin1String("/snippets/qml.xml");
- if (!QFile::exists(qmlsnippets))
- return;
-
- QDateTime lastModified = QFileInfo(qmlsnippets).lastModified();
- if (!m_snippetFileLastModified.isNull() && lastModified == m_snippetFileLastModified)
- return;
-
- const QIcon icon = iconForColor(Qt::red);
-
- m_snippetFileLastModified = lastModified;
- QFile file(qmlsnippets);
- file.open(QIODevice::ReadOnly);
- QXmlStreamReader xml(&file);
- if (xml.readNextStartElement()) {
- if (xml.name() == QLatin1String("snippets")) {
- while (xml.readNextStartElement()) {
- if (xml.name() == QLatin1String("snippet")) {
- TextEditor::CompletionItem item(this);
- QString title, data;
- QString description = xml.attributes().value("description").toString();
-
- while (!xml.atEnd()) {
- xml.readNext();
- if (xml.isEndElement()) {
- int i = 0;
- while (i < data.size() && data.at(i).isLetterOrNumber())
- ++i;
- title = data.left(i);
- item.text = title;
- if (!description.isEmpty()) {
- item.text += QLatin1Char(' ');
- item.text += description;
- }
- item.data = QVariant::fromValue(data);
-
-
- QString infotip = data;
- while (infotip.size() && infotip.at(infotip.size()-1).isSpace())
- infotip.chop(1);
- infotip.replace(QLatin1Char('\n'), QLatin1String("<br>"));
- infotip.replace(QLatin1Char(' '), QLatin1String("&nbsp;"));
- {
- QString s = QLatin1String("<nobr>");
- int count = 0;
- for (int i = 0; i < infotip.count(); ++i) {
- if (infotip.at(i) != QChar::ObjectReplacementCharacter) {
- s += infotip.at(i);
- continue;
- }
- if (++count % 2) {
- s += QLatin1String("<b>");
- } else {
- if (infotip.at(i-1) == QChar::ObjectReplacementCharacter)
- s += QLatin1String("...");
- s += QLatin1String("</b>");
- }
- }
- infotip = s;
- }
-
- item.details = infotip;
-
- item.icon = icon;
- item.order = SnippetOrder;
- m_snippets.append(item);
- break;
- }
-
- if (xml.isCharacters())
- data += xml.text();
- else if (xml.isStartElement()) {
- if (xml.name() != QLatin1String("tab"))
- xml.raiseError(QLatin1String("invalid snippets file"));
- else {
- data += QChar::ObjectReplacementCharacter;
- data += xml.readElementText();
- data += QChar::ObjectReplacementCharacter;
- }
- }
- }
- } else {
- xml.skipCurrentElement();
- }
- }
- } else {
- xml.skipCurrentElement();
- }
- }
- if (xml.hasError())
- qWarning() << qmlsnippets << xml.errorString() << xml.lineNumber() << xml.columnNumber();
- file.close();
-}
-
static bool qmlCompletionItemLessThan(const TextEditor::CompletionItem &l, const TextEditor::CompletionItem &r)
{
if (l.order != r.order)
diff --git a/src/plugins/qmljseditor/qmljscodecompletion.h b/src/plugins/qmljseditor/qmljscodecompletion.h
index a2e2284c19..586d30e498 100644
--- a/src/plugins/qmljseditor/qmljscodecompletion.h
+++ b/src/plugins/qmljseditor/qmljscodecompletion.h
@@ -32,6 +32,7 @@
#include <qmljs/qmljsdocument.h>
#include <texteditor/icompletioncollector.h>
+#include <texteditor/snippetsparser.h>
#include <QtCore/QDateTime>
#include <QtCore/QPointer>
@@ -76,7 +77,6 @@ public:
virtual void cleanup();
private:
- void updateSnippets();
bool maybeTriggersCompletion(TextEditor::ITextEditable *editor);
bool isDelimiter(QChar ch) const;
@@ -92,12 +92,10 @@ private:
QmlJS::ModelManagerInterface *m_modelManager;
TextEditor::ITextEditable *m_editor;
int m_startPosition;
+ bool m_restartCompletion;
+ TextEditor::SnippetsParser m_snippetsParser;
QList<TextEditor::CompletionItem> m_completions;
-
- QList<TextEditor::CompletionItem> m_snippets;
- QDateTime m_snippetFileLastModified;
QPointer<FunctionArgumentWidget> m_functionArgumentWidget;
- bool m_restartCompletion;
};
diff --git a/src/plugins/texteditor/icompletioncollector.h b/src/plugins/texteditor/icompletioncollector.h
index 5ec3574326..5f24893785 100644
--- a/src/plugins/texteditor/icompletioncollector.h
+++ b/src/plugins/texteditor/icompletioncollector.h
@@ -54,7 +54,8 @@ public:
duplicateCount(0),
order(0),
originalIndex(0),
- collector(collector)
+ collector(collector),
+ isSnippet(false)
{ }
bool isValid() const
@@ -69,6 +70,7 @@ public:
int order;
int originalIndex;
ICompletionCollector *collector;
+ bool isSnippet;
};
/* Defines the interface to completion collectors. A completion collector tells
diff --git a/src/plugins/texteditor/images/snippet.png b/src/plugins/texteditor/images/snippet.png
new file mode 100644
index 0000000000..929ac6b922
--- /dev/null
+++ b/src/plugins/texteditor/images/snippet.png
Binary files differ
diff --git a/src/plugins/texteditor/snippetsparser.cpp b/src/plugins/texteditor/snippetsparser.cpp
new file mode 100644
index 0000000000..63ddc93aee
--- /dev/null
+++ b/src/plugins/texteditor/snippetsparser.cpp
@@ -0,0 +1,139 @@
+/**************************************************************************
+**
+** 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 "snippetsparser.h"
+
+#include <QtCore/QFile>
+#include <QtCore/QFileInfo>
+#include <QtCore/QLatin1String>
+#include <QtCore/QLatin1Char>
+#include <QtCore/QVariant>
+#include <QtCore/QXmlStreamReader>
+#include <QtCore/QDebug>
+
+using namespace TextEditor;
+
+SnippetsParser::SnippetsParser(const QString &fileName) : m_fileName(fileName)
+{}
+
+const QList<CompletionItem> &SnippetsParser::execute(ICompletionCollector *collector,
+ const QIcon &icon,
+ int order)
+{
+ const QDateTime &lastModified = QFileInfo(m_fileName).lastModified();
+ if (m_lastTrackedFileChange.isNull() || m_lastTrackedFileChange != lastModified) {
+ m_snippets.clear();
+
+ QFile file(m_fileName);
+ file.open(QIODevice::ReadOnly);
+ QXmlStreamReader xml(&file);
+ if (xml.readNextStartElement()) {
+ if (xml.name() == QLatin1String("snippets")) {
+ while (xml.readNextStartElement()) {
+ if (xml.name() == QLatin1String("snippet")) {
+ TextEditor::CompletionItem item(collector);
+ QString title;
+ QString data;
+ QString description = xml.attributes().value("description").toString();
+
+ while (!xml.atEnd()) {
+ xml.readNext();
+ if (xml.isEndElement()) {
+ int i = 0;
+ while (i < data.size() && data.at(i).isLetterOrNumber())
+ ++i;
+ title = data.left(i);
+ item.text = title;
+ if (!description.isEmpty()) {
+ item.text += QLatin1Char(' ');
+ item.text += description;
+ }
+ item.data = QVariant::fromValue(data);
+
+ QString infotip = data;
+ while (infotip.size() && infotip.at(infotip.size()-1).isSpace())
+ infotip.chop(1);
+ infotip.replace(QLatin1Char('\n'), QLatin1String("<br>"));
+ infotip.replace(QLatin1Char(' '), QLatin1String("&nbsp;"));
+ {
+ QString s = QLatin1String("<nobr>");
+ int count = 0;
+ for (int i = 0; i < infotip.count(); ++i) {
+ if (infotip.at(i) != QChar::ObjectReplacementCharacter) {
+ s += infotip.at(i);
+ continue;
+ }
+ if (++count % 2) {
+ s += QLatin1String("<b>");
+ } else {
+ if (infotip.at(i-1) == QChar::ObjectReplacementCharacter)
+ s += QLatin1String("...");
+ s += QLatin1String("</b>");
+ }
+ }
+ infotip = s;
+ }
+ item.details = infotip;
+
+ item.icon = icon;
+ item.order = order;
+ item.isSnippet = true;
+ m_snippets.append(item);
+ break;
+ }
+
+ if (xml.isCharacters())
+ data += xml.text();
+ else if (xml.isStartElement()) {
+ if (xml.name() != QLatin1String("tab"))
+ xml.raiseError(QLatin1String("invalid snippets file"));
+ else {
+ data += QChar::ObjectReplacementCharacter;
+ data += xml.readElementText();
+ data += QChar::ObjectReplacementCharacter;
+ }
+ }
+ }
+ } else {
+ xml.skipCurrentElement();
+ }
+ }
+ } else {
+ xml.skipCurrentElement();
+ }
+ }
+ if (xml.hasError())
+ qWarning() << m_fileName << xml.errorString() << xml.lineNumber() << xml.columnNumber();
+ file.close();
+
+ m_lastTrackedFileChange = lastModified;
+ }
+
+ return m_snippets;
+}
diff --git a/src/plugins/texteditor/snippetsparser.h b/src/plugins/texteditor/snippetsparser.h
new file mode 100644
index 0000000000..90cb6c18cf
--- /dev/null
+++ b/src/plugins/texteditor/snippetsparser.h
@@ -0,0 +1,60 @@
+/**************************************************************************
+**
+** 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 SNIPPETSPARSER_H
+#define SNIPPETSPARSER_H
+
+#include "texteditor_global.h"
+#include "icompletioncollector.h"
+
+#include <QtCore/QString>
+#include <QtCore/QList>
+#include <QtCore/QDateTime>
+#include <QtGui/QIcon>
+
+namespace TextEditor {
+
+class TEXTEDITOR_EXPORT SnippetsParser
+{
+public:
+ SnippetsParser(const QString &fileName);
+
+ const QList<CompletionItem> &execute(ICompletionCollector *collector,
+ const QIcon &icon,
+ int order = 0);
+
+private:
+ QString m_fileName;
+ QDateTime m_lastTrackedFileChange;
+ QList<CompletionItem> m_snippets;
+};
+
+} // namespace TextEditor
+
+#endif // SNIPPETSPARSER_H
diff --git a/src/plugins/texteditor/texteditor.pro b/src/plugins/texteditor/texteditor.pro
index e917e279e7..21a4ba9952 100644
--- a/src/plugins/texteditor/texteditor.pro
+++ b/src/plugins/texteditor/texteditor.pro
@@ -69,7 +69,8 @@ SOURCES += texteditorplugin.cpp \
tooltip/tipcontents.cpp \
tooltip/tipfactory.cpp \
basehoverhandler.cpp \
- helpitem.cpp
+ helpitem.cpp \
+ snippetsparser.cpp
HEADERS += texteditorplugin.h \
textfilewizard.h \
@@ -142,7 +143,8 @@ HEADERS += texteditorplugin.h \
tooltip/effects.h \
tooltip/tipfactory.h \
basehoverhandler.h \
- helpitem.h
+ helpitem.h \
+ snippetsparser.h
FORMS += behaviorsettingspage.ui \
displaysettingspage.ui \
diff --git a/src/plugins/texteditor/texteditor.qrc b/src/plugins/texteditor/texteditor.qrc
index 0d131c4f3b..86fa6638cb 100644
--- a/src/plugins/texteditor/texteditor.qrc
+++ b/src/plugins/texteditor/texteditor.qrc
@@ -4,5 +4,6 @@
<file>images/finddirectory.png</file>
<file>TextEditor.mimetypes.xml</file>
<file>images/refactormarker.png</file>
+ <file>images/snippet.png</file>
</qresource>
</RCC>