aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/plugins/cppeditor/cppautocompleter.cpp138
-rw-r--r--src/plugins/cppeditor/cppautocompleter.h59
-rw-r--r--src/plugins/cppeditor/cppeditor.cpp86
-rw-r--r--src/plugins/cppeditor/cppeditor.h11
-rw-r--r--src/plugins/cppeditor/cppeditor.pro6
-rw-r--r--src/plugins/qmljseditor/qmljsautocompleter.cpp279
-rw-r--r--src/plugins/qmljseditor/qmljsautocompleter.h59
-rw-r--r--src/plugins/qmljseditor/qmljseditor.cpp229
-rw-r--r--src/plugins/qmljseditor/qmljseditor.h7
-rw-r--r--src/plugins/qmljseditor/qmljseditor.pro6
-rw-r--r--src/plugins/texteditor/autocompleter.cpp106
-rw-r--r--src/plugins/texteditor/autocompleter.h78
-rw-r--r--src/plugins/texteditor/basetexteditor.cpp61
-rw-r--r--src/plugins/texteditor/basetexteditor.h15
-rw-r--r--src/plugins/texteditor/basetexteditor_p.h1
-rw-r--r--src/plugins/texteditor/texteditor.pro6
16 files changed, 759 insertions, 388 deletions
diff --git a/src/plugins/cppeditor/cppautocompleter.cpp b/src/plugins/cppeditor/cppautocompleter.cpp
new file mode 100644
index 00000000000..9f1088ada6b
--- /dev/null
+++ b/src/plugins/cppeditor/cppautocompleter.cpp
@@ -0,0 +1,138 @@
+/**************************************************************************
+**
+** 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 "cppautocompleter.h"
+
+#include <Token.h>
+
+#include <cplusplus/SimpleLexer.h>
+#include <cplusplus/MatchingText.h>
+#include <cplusplus/BackwardsScanner.h>
+
+#include <QtCore/QLatin1Char>
+#include <QtGui/QTextCursor>
+
+using namespace CppEditor;
+using namespace Internal;
+using namespace CPlusPlus;
+
+CppAutoCompleter::CppAutoCompleter()
+{}
+
+CppAutoCompleter::~CppAutoCompleter()
+{}
+
+bool CppAutoCompleter::doContextAllowsAutoParentheses(const QTextCursor &cursor,
+ const QString &textToInsert) const
+{
+ QChar ch;
+
+ if (! textToInsert.isEmpty())
+ ch = textToInsert.at(0);
+
+ if (! (MatchingText::shouldInsertMatchingText(cursor)
+ || ch == QLatin1Char('\'')
+ || ch == QLatin1Char('"')))
+ return false;
+ else if (isInComment(cursor))
+ return false;
+
+ return true;
+}
+
+bool CppAutoCompleter::doContextAllowsElectricCharacters(const QTextCursor &cursor) const
+{
+ const Token tk = SimpleLexer::tokenAt(cursor.block().text(), cursor.positionInBlock(),
+ BackwardsScanner::previousBlockState(cursor.block()));
+
+ // XXX Duplicated from CPPEditor::isInComment to avoid tokenizing twice
+ if (tk.isComment()) {
+ const unsigned pos = cursor.selectionEnd() - cursor.block().position();
+
+ if (pos == tk.end()) {
+ if (tk.is(T_CPP_COMMENT) || tk.is(T_CPP_DOXY_COMMENT))
+ return false;
+
+ const int state = cursor.block().userState() & 0xFF;
+ if (state > 0)
+ return false;
+ }
+
+ if (pos < tk.end())
+ return false;
+ }
+ else if (tk.is(T_STRING_LITERAL) || tk.is(T_WIDE_STRING_LITERAL)
+ || tk.is(T_CHAR_LITERAL) || tk.is(T_WIDE_CHAR_LITERAL)) {
+
+ const unsigned pos = cursor.selectionEnd() - cursor.block().position();
+ if (pos <= tk.end())
+ return false;
+ }
+
+ return true;
+}
+
+bool CppAutoCompleter::doIsInComment(const QTextCursor &cursor) const
+{
+ const Token tk = SimpleLexer::tokenAt(cursor.block().text(), cursor.positionInBlock(),
+ BackwardsScanner::previousBlockState(cursor.block()));
+
+ if (tk.isComment()) {
+ const unsigned pos = cursor.selectionEnd() - cursor.block().position();
+
+ if (pos == tk.end()) {
+ if (tk.is(T_CPP_COMMENT) || tk.is(T_CPP_DOXY_COMMENT))
+ return true;
+
+ const int state = cursor.block().userState() & 0xFF;
+ if (state > 0)
+ return true;
+ }
+
+ if (pos < tk.end())
+ return true;
+ }
+
+ return false;
+}
+
+QString CppAutoCompleter::doInsertMatchingBrace(const QTextCursor &cursor,
+ const QString &text,
+ QChar la,
+ int *skippedChars) const
+{
+ MatchingText m;
+ return m.insertMatchingBrace(cursor, text, la, skippedChars);
+}
+
+QString CppAutoCompleter::doInsertParagraphSeparator(const QTextCursor &cursor) const
+{
+ MatchingText m;
+ return m.insertParagraphSeparator(cursor);
+}
diff --git a/src/plugins/cppeditor/cppautocompleter.h b/src/plugins/cppeditor/cppautocompleter.h
new file mode 100644
index 00000000000..0a80679a9c5
--- /dev/null
+++ b/src/plugins/cppeditor/cppautocompleter.h
@@ -0,0 +1,59 @@
+/**************************************************************************
+**
+** 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 CPPAUTOCOMPLETER_H
+#define CPPAUTOCOMPLETER_H
+
+#include <texteditor/autocompleter.h>
+
+namespace CppEditor {
+namespace Internal {
+
+class CppAutoCompleter : public TextEditor::AutoCompleter
+{
+public:
+ CppAutoCompleter();
+ virtual ~CppAutoCompleter();
+
+private:
+ virtual bool doContextAllowsAutoParentheses(const QTextCursor &cursor,
+ const QString &textToInsert = QString()) const;
+ virtual bool doContextAllowsElectricCharacters(const QTextCursor &cursor) const;
+ virtual bool doIsInComment(const QTextCursor &cursor) const;
+ virtual QString doInsertMatchingBrace(const QTextCursor &cursor,
+ const QString &text,
+ QChar la,
+ int *skippedChars) const;
+ virtual QString doInsertParagraphSeparator(const QTextCursor &cursor) const;
+};
+
+} // Internal
+} // CppEditor
+
+#endif // CPPAUTOCOMPLETER_H
diff --git a/src/plugins/cppeditor/cppeditor.cpp b/src/plugins/cppeditor/cppeditor.cpp
index 74798b8b40a..ab3bc7b23a7 100644
--- a/src/plugins/cppeditor/cppeditor.cpp
+++ b/src/plugins/cppeditor/cppeditor.cpp
@@ -36,6 +36,7 @@
#include "cpplocalsymbols.h"
#include "cppquickfixcollector.h"
#include "cppqtstyleindenter.h"
+#include "cppautocompleter.h"
#include <AST.h>
#include <Control.h>
@@ -416,6 +417,7 @@ CPPEditor::CPPEditor(QWidget *parent)
setCodeFoldingSupported(true);
setCodeFoldingVisible(true);
setIndenter(new CppQtStyleIndenter);
+ setAutoCompleter(new CppAutoCompleter);
baseTextDocument()->setSyntaxHighlighter(new CppHighlighter);
m_modelManager = CppTools::CppModelManagerInterface::instance();
@@ -1407,90 +1409,6 @@ QModelIndex CPPEditor::outlineModelIndex()
return m_outlineModelIndex;
}
-QString CPPEditor::insertMatchingBrace(const QTextCursor &tc, const QString &text,
- QChar la, int *skippedChars) const
-{
- MatchingText m;
- return m.insertMatchingBrace(tc, text, la, skippedChars);
-}
-
-QString CPPEditor::insertParagraphSeparator(const QTextCursor &tc) const
-{
- MatchingText m;
- return m.insertParagraphSeparator(tc);
-}
-
-
-bool CPPEditor::contextAllowsAutoParentheses(const QTextCursor &cursor,
- const QString &textToInsert) const
-{
- QChar ch;
-
- if (! textToInsert.isEmpty())
- ch = textToInsert.at(0);
-
- if (! (MatchingText::shouldInsertMatchingText(cursor) || ch == QLatin1Char('\'') || ch == QLatin1Char('"')))
- return false;
- else if (isInComment(cursor))
- return false;
-
- return true;
-}
-
-bool CPPEditor::contextAllowsElectricCharacters(const QTextCursor &cursor) const
-{
- const Token tk = SimpleLexer::tokenAt(cursor.block().text(), cursor.positionInBlock(), BackwardsScanner::previousBlockState(cursor.block()));
-
- // XXX Duplicated from CPPEditor::isInComment to avoid tokenizing twice
- if (tk.isComment()) {
- const unsigned pos = cursor.selectionEnd() - cursor.block().position();
-
- if (pos == tk.end()) {
- if (tk.is(T_CPP_COMMENT) || tk.is(T_CPP_DOXY_COMMENT))
- return false;
-
- const int state = cursor.block().userState() & 0xFF;
- if (state > 0)
- return false;
- }
-
- if (pos < tk.end())
- return false;
- }
- else if (tk.is(T_STRING_LITERAL) || tk.is(T_WIDE_STRING_LITERAL)
- || tk.is(T_CHAR_LITERAL) || tk.is(T_WIDE_CHAR_LITERAL)) {
-
- const unsigned pos = cursor.selectionEnd() - cursor.block().position();
- if (pos <= tk.end())
- return false;
- }
-
- return true;
-}
-
-bool CPPEditor::isInComment(const QTextCursor &cursor) const
-{
- const Token tk = SimpleLexer::tokenAt(cursor.block().text(), cursor.positionInBlock(), BackwardsScanner::previousBlockState(cursor.block()));
-
- if (tk.isComment()) {
- const unsigned pos = cursor.selectionEnd() - cursor.block().position();
-
- if (pos == tk.end()) {
- if (tk.is(T_CPP_COMMENT) || tk.is(T_CPP_DOXY_COMMENT))
- return true;
-
- const int state = cursor.block().userState() & 0xFF;
- if (state > 0)
- return true;
- }
-
- if (pos < tk.end())
- return true;
- }
-
- return false;
-}
-
bool CPPEditor::event(QEvent *e)
{
switch (e->type()) {
diff --git a/src/plugins/cppeditor/cppeditor.h b/src/plugins/cppeditor/cppeditor.h
index 0989ee6c415..332fc1f0dce 100644
--- a/src/plugins/cppeditor/cppeditor.h
+++ b/src/plugins/cppeditor/cppeditor.h
@@ -207,17 +207,6 @@ protected:
TextEditor::BaseTextEditorEditable *createEditableInterface();
- virtual QString insertMatchingBrace(const QTextCursor &tc, const QString &text,
- QChar la, int *skippedChars) const;
-
- virtual QString insertParagraphSeparator(const QTextCursor &tc) const;
-
- virtual bool contextAllowsAutoParentheses(const QTextCursor &cursor,
- const QString &textToInsert = QString()) const;
- virtual bool contextAllowsElectricCharacters(const QTextCursor &cursor) const;
-
- virtual bool isInComment(const QTextCursor &cursor) const;
-
const CPlusPlus::Macro *findCanonicalMacro(const QTextCursor &cursor,
CPlusPlus::Document::Ptr doc) const;
diff --git a/src/plugins/cppeditor/cppeditor.pro b/src/plugins/cppeditor/cppeditor.pro
index 0883e69ed25..4ade5624bb6 100644
--- a/src/plugins/cppeditor/cppeditor.pro
+++ b/src/plugins/cppeditor/cppeditor.pro
@@ -23,7 +23,8 @@ HEADERS += cppplugin.h \
cpptypehierarchy.h \
cppelementevaluator.h \
cppquickfixcollector.h \
- cppqtstyleindenter.h
+ cppqtstyleindenter.h \
+ cppautocompleter.h
SOURCES += cppplugin.cpp \
cppeditor.cpp \
cpphighlighter.cpp \
@@ -40,6 +41,7 @@ SOURCES += cppplugin.cpp \
cpptypehierarchy.cpp \
cppelementevaluator.cpp \
cppquickfixcollector.cpp \
- cppqtstyleindenter.cpp
+ cppqtstyleindenter.cpp \
+ cppautocompleter.cpp
RESOURCES += cppeditor.qrc
OTHER_FILES += CppEditor.mimetypes.xml
diff --git a/src/plugins/qmljseditor/qmljsautocompleter.cpp b/src/plugins/qmljseditor/qmljsautocompleter.cpp
new file mode 100644
index 00000000000..fd9d686d9a7
--- /dev/null
+++ b/src/plugins/qmljseditor/qmljsautocompleter.cpp
@@ -0,0 +1,279 @@
+/**************************************************************************
+**
+** 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 "qmljsautocompleter.h"
+
+#include <qmljs/qmljsscanner.h>
+
+#include <QtCore/QChar>
+#include <QtCore/QLatin1Char>
+#include <QtGui/QTextDocument>
+#include <QtGui/QTextCursor>
+#include <QtGui/QTextBlock>
+
+using namespace QmlJSEditor;
+using namespace Internal;
+using namespace QmlJS;
+
+static int blockStartState(const QTextBlock &block)
+{
+ int state = block.userState();
+
+ if (state == -1)
+ return 0;
+ else
+ return state & 0xff;
+}
+
+static Token tokenUnderCursor(const QTextCursor &cursor)
+{
+ const QString blockText = cursor.block().text();
+ const int blockState = blockStartState(cursor.block());
+
+ Scanner tokenize;
+ const QList<Token> tokens = tokenize(blockText, blockState);
+ const int pos = cursor.positionInBlock();
+
+ int tokenIndex = 0;
+ for (; tokenIndex < tokens.size(); ++tokenIndex) {
+ const Token &token = tokens.at(tokenIndex);
+
+ if (token.is(Token::Comment) || token.is(Token::String)) {
+ if (pos > token.begin() && pos <= token.end())
+ break;
+ } else {
+ if (pos >= token.begin() && pos < token.end())
+ break;
+ }
+ }
+
+ if (tokenIndex != tokens.size())
+ return tokens.at(tokenIndex);
+
+ return Token();
+}
+
+static bool shouldInsertMatchingText(QChar lookAhead)
+{
+ switch (lookAhead.unicode()) {
+ case '{': case '}':
+ case ']': case ')':
+ case ';': case ',':
+ case '"': case '\'':
+ return true;
+
+ default:
+ if (lookAhead.isSpace())
+ return true;
+
+ return false;
+ } // switch
+}
+
+static bool shouldInsertMatchingText(const QTextCursor &tc)
+{
+ QTextDocument *doc = tc.document();
+ return shouldInsertMatchingText(doc->characterAt(tc.selectionEnd()));
+}
+
+static bool shouldInsertNewline(const QTextCursor &tc)
+{
+ QTextDocument *doc = tc.document();
+ int pos = tc.selectionEnd();
+
+ // count the number of empty lines.
+ int newlines = 0;
+ for (int e = doc->characterCount(); pos != e; ++pos) {
+ const QChar ch = doc->characterAt(pos);
+
+ if (! ch.isSpace())
+ break;
+ else if (ch == QChar::ParagraphSeparator)
+ ++newlines;
+ }
+
+ if (newlines <= 1 && doc->characterAt(pos) != QLatin1Char('}'))
+ return true;
+
+ return false;
+}
+
+static bool isCompleteStringLiteral(const QStringRef &text)
+{
+ if (text.length() < 2)
+ return false;
+
+ const QChar quote = text.at(0);
+
+ if (text.at(text.length() - 1) == quote)
+ return text.at(text.length() - 2) != QLatin1Char('\\'); // ### not exactly.
+
+ return false;
+}
+
+AutoCompleter::AutoCompleter()
+{}
+
+AutoCompleter::~AutoCompleter()
+{}
+
+bool AutoCompleter::doContextAllowsAutoParentheses(const QTextCursor &cursor,
+ const QString &textToInsert) const
+{
+ QChar ch;
+
+ if (! textToInsert.isEmpty())
+ ch = textToInsert.at(0);
+
+ switch (ch.unicode()) {
+ case '\'':
+ case '"':
+
+ case '(':
+ case '[':
+ case '{':
+
+ case ')':
+ case ']':
+ case '}':
+
+ case ';':
+ break;
+
+ default:
+ if (ch.isNull())
+ break;
+
+ return false;
+ } // end of switch
+
+ const Token token = tokenUnderCursor(cursor);
+ switch (token.kind) {
+ case Token::Comment:
+ return false;
+
+ case Token::String: {
+ const QString blockText = cursor.block().text();
+ const QStringRef tokenText = blockText.midRef(token.offset, token.length);
+ const QChar quote = tokenText.at(0);
+
+ if (ch != quote || isCompleteStringLiteral(tokenText))
+ break;
+
+ return false;
+ }
+
+ default:
+ break;
+ } // end of switch
+
+ return true;
+}
+
+bool AutoCompleter::doContextAllowsElectricCharacters(const QTextCursor &cursor) const
+{
+ Token token = tokenUnderCursor(cursor);
+ switch (token.kind) {
+ case Token::Comment:
+ case Token::String:
+ return false;
+ default:
+ return true;
+ }
+}
+
+bool AutoCompleter::doIsInComment(const QTextCursor &cursor) const
+{
+ return tokenUnderCursor(cursor).is(Token::Comment);
+}
+
+QString AutoCompleter::doInsertMatchingBrace(const QTextCursor &cursor,
+ const QString &text,
+ QChar,
+ int *skippedChars) const
+{
+ if (text.length() != 1)
+ return QString();
+
+ if (! shouldInsertMatchingText(cursor))
+ return QString();
+
+ const QChar la = cursor.document()->characterAt(cursor.position());
+
+ const QChar ch = text.at(0);
+ switch (ch.unicode()) {
+ case '\'':
+ if (la != ch)
+ return QString(ch);
+ ++*skippedChars;
+ break;
+
+ case '"':
+ if (la != ch)
+ return QString(ch);
+ ++*skippedChars;
+ break;
+
+ case '(':
+ return QString(QLatin1Char(')'));
+
+ case '[':
+ return QString(QLatin1Char(']'));
+
+ case '{':
+ return QString(); // nothing to do.
+
+ case ')':
+ case ']':
+ case '}':
+ case ';':
+ if (la == ch)
+ ++*skippedChars;
+ break;
+
+ default:
+ break;
+ } // end of switch
+
+ return QString();
+}
+
+QString AutoCompleter::doInsertParagraphSeparator(const QTextCursor &cursor) const
+{
+ if (shouldInsertNewline(cursor)) {
+ QTextCursor cursor = cursor;
+ cursor.movePosition(QTextCursor::EndOfBlock, QTextCursor::KeepAnchor);
+ if (! cursor.selectedText().trimmed().isEmpty())
+ return QString();
+
+ return QLatin1String("}\n");
+ }
+
+ return QLatin1String("}");
+}
diff --git a/src/plugins/qmljseditor/qmljsautocompleter.h b/src/plugins/qmljseditor/qmljsautocompleter.h
new file mode 100644
index 00000000000..7e6b2bab03f
--- /dev/null
+++ b/src/plugins/qmljseditor/qmljsautocompleter.h
@@ -0,0 +1,59 @@
+/**************************************************************************
+**
+** 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 QMLJSAUTOCOMPLETER_H
+#define QMLJSAUTOCOMPLETER_H
+
+#include <texteditor/autocompleter.h>
+
+namespace QmlJSEditor {
+namespace Internal {
+
+class AutoCompleter : public TextEditor::AutoCompleter
+{
+public:
+ AutoCompleter();
+ virtual ~AutoCompleter();
+
+private:
+ virtual bool doContextAllowsAutoParentheses(const QTextCursor &cursor,
+ const QString &textToInsert = QString()) const;
+ virtual bool doContextAllowsElectricCharacters(const QTextCursor &cursor) const;
+ virtual bool doIsInComment(const QTextCursor &cursor) const;
+ virtual QString doInsertMatchingBrace(const QTextCursor &tc,
+ const QString &text,
+ QChar la,
+ int *skippedChars) const;
+ virtual QString doInsertParagraphSeparator(const QTextCursor &tc) const;
+};
+
+} // Internal
+} // QmlJSEditor
+
+#endif // QMLJSAUTOCOMPLETER_H
diff --git a/src/plugins/qmljseditor/qmljseditor.cpp b/src/plugins/qmljseditor/qmljseditor.cpp
index f40858c3edc..c9a3afc3a58 100644
--- a/src/plugins/qmljseditor/qmljseditor.cpp
+++ b/src/plugins/qmljseditor/qmljseditor.cpp
@@ -39,6 +39,7 @@
#include "qmljsfindreferences.h"
#include "qmljssemantichighlighter.h"
#include "qmljsindenter.h"
+#include "qmljsautocompleter.h"
#include <qmljs/qmljsbind.h>
#include <qmljs/qmljsdocument.h>
@@ -91,39 +92,6 @@ using namespace QmlJS::AST;
using namespace QmlJSEditor;
using namespace QmlJSEditor::Internal;
-static int blockStartState(const QTextBlock &block)
-{
- int state = block.userState();
-
- if (state == -1)
- return 0;
- else
- return state & 0xff;
-}
-
-static bool shouldInsertMatchingText(QChar lookAhead)
-{
- switch (lookAhead.unicode()) {
- case '{': case '}':
- case ']': case ')':
- case ';': case ',':
- case '"': case '\'':
- return true;
-
- default:
- if (lookAhead.isSpace())
- return true;
-
- return false;
- } // switch
-}
-
-static bool shouldInsertMatchingText(const QTextCursor &tc)
-{
- QTextDocument *doc = tc.document();
- return shouldInsertMatchingText(doc->characterAt(tc.selectionEnd()));
-}
-
namespace {
class FindIdDeclarations: protected Visitor
@@ -647,6 +615,7 @@ QmlJSTextEditor::QmlJSTextEditor(QWidget *parent) :
setCodeFoldingSupported(true);
setCodeFoldingVisible(true);
setIndenter(new Indenter);
+ setAutoCompleter(new AutoCompleter);
m_updateDocumentTimer = new QTimer(this);
m_updateDocumentTimer->setInterval(UPDATE_DOCUMENT_DEFAULT_INTERVAL);
@@ -1504,200 +1473,6 @@ void QmlJSTextEditor::unCommentSelection()
Utils::unCommentSelection(this);
}
-static bool isCompleteStringLiteral(const QStringRef &text)
-{
- if (text.length() < 2)
- return false;
-
- const QChar quote = text.at(0);
-
- if (text.at(text.length() - 1) == quote)
- return text.at(text.length() - 2) != QLatin1Char('\\'); // ### not exactly.
-
- return false;
-}
-
-static Token tokenUnderCursor(const QTextCursor &cursor)
-{
- const QString blockText = cursor.block().text();
- const int blockState = blockStartState(cursor.block());
-
- Scanner tokenize;
- const QList<Token> tokens = tokenize(blockText, blockState);
- const int pos = cursor.positionInBlock();
-
- int tokenIndex = 0;
- for (; tokenIndex < tokens.size(); ++tokenIndex) {
- const Token &token = tokens.at(tokenIndex);
-
- if (token.is(Token::Comment) || token.is(Token::String)) {
- if (pos > token.begin() && pos <= token.end())
- break;
- } else {
- if (pos >= token.begin() && pos < token.end())
- break;
- }
- }
-
- if (tokenIndex != tokens.size())
- return tokens.at(tokenIndex);
-
- return Token();
-}
-
-bool QmlJSTextEditor::contextAllowsAutoParentheses(const QTextCursor &cursor, const QString &textToInsert) const
-{
- QChar ch;
-
- if (! textToInsert.isEmpty())
- ch = textToInsert.at(0);
-
- switch (ch.unicode()) {
- case '\'':
- case '"':
-
- case '(':
- case '[':
- case '{':
-
- case ')':
- case ']':
- case '}':
-
- case ';':
- break;
-
- default:
- if (ch.isNull())
- break;
-
- return false;
- } // end of switch
-
- const Token token = tokenUnderCursor(cursor);
- switch (token.kind) {
- case Token::Comment:
- return false;
-
- case Token::String: {
- const QString blockText = cursor.block().text();
- const QStringRef tokenText = blockText.midRef(token.offset, token.length);
- const QChar quote = tokenText.at(0);
-
- if (ch != quote || isCompleteStringLiteral(tokenText))
- break;
-
- return false;
- }
-
- default:
- break;
- } // end of switch
-
- return true;
-}
-
-bool QmlJSTextEditor::contextAllowsElectricCharacters(const QTextCursor &cursor) const
-{
- Token token = tokenUnderCursor(cursor);
- switch (token.kind) {
- case Token::Comment:
- case Token::String:
- return false;
- default:
- return true;
- }
-}
-
-bool QmlJSTextEditor::isInComment(const QTextCursor &cursor) const
-{
- return tokenUnderCursor(cursor).is(Token::Comment);
-}
-
-QString QmlJSTextEditor::insertMatchingBrace(const QTextCursor &tc, const QString &text, QChar, int *skippedChars) const
-{
- if (text.length() != 1)
- return QString();
-
- if (! shouldInsertMatchingText(tc))
- return QString();
-
- const QChar la = characterAt(tc.position());
-
- const QChar ch = text.at(0);
- switch (ch.unicode()) {
- case '\'':
- if (la != ch)
- return QString(ch);
- ++*skippedChars;
- break;
-
- case '"':
- if (la != ch)
- return QString(ch);
- ++*skippedChars;
- break;
-
- case '(':
- return QString(QLatin1Char(')'));
-
- case '[':
- return QString(QLatin1Char(']'));
-
- case '{':
- return QString(); // nothing to do.
-
- case ')':
- case ']':
- case '}':
- case ';':
- if (la == ch)
- ++*skippedChars;
- break;
-
- default:
- break;
- } // end of switch
-
- return QString();
-}
-
-static bool shouldInsertNewline(const QTextCursor &tc)
-{
- QTextDocument *doc = tc.document();
- int pos = tc.selectionEnd();
-
- // count the number of empty lines.
- int newlines = 0;
- for (int e = doc->characterCount(); pos != e; ++pos) {
- const QChar ch = doc->characterAt(pos);
-
- if (! ch.isSpace())
- break;
- else if (ch == QChar::ParagraphSeparator)
- ++newlines;
- }
-
- if (newlines <= 1 && doc->characterAt(pos) != QLatin1Char('}'))
- return true;
-
- return false;
-}
-
-QString QmlJSTextEditor::insertParagraphSeparator(const QTextCursor &tc) const
-{
- if (shouldInsertNewline(tc)) {
- QTextCursor cursor = tc;
- cursor.movePosition(QTextCursor::EndOfBlock, QTextCursor::KeepAnchor);
- if (! cursor.selectedText().trimmed().isEmpty())
- return QString();
-
- return QLatin1String("}\n");
- }
-
- return QLatin1String("}");
-}
-
void QmlJSTextEditor::forceSemanticRehighlight()
{
m_semanticHighlighter->rehighlight(currentSource(/* force = */ true));
diff --git a/src/plugins/qmljseditor/qmljseditor.h b/src/plugins/qmljseditor/qmljseditor.h
index ec7151a56aa..6392036444f 100644
--- a/src/plugins/qmljseditor/qmljseditor.h
+++ b/src/plugins/qmljseditor/qmljseditor.h
@@ -202,13 +202,6 @@ protected:
void createToolBar(Internal::QmlJSEditorEditable *editable);
TextEditor::BaseTextEditor::Link findLinkAt(const QTextCursor &cursor, bool resolveTarget = true);
- //// brace matching
- virtual bool contextAllowsAutoParentheses(const QTextCursor &cursor, const QString &textToInsert = QString()) const;
- virtual bool contextAllowsElectricCharacters(const QTextCursor &cursor) const;
- virtual bool isInComment(const QTextCursor &cursor) const;
- virtual QString insertMatchingBrace(const QTextCursor &tc, const QString &text, QChar la, int *skippedChars) const;
- virtual QString insertParagraphSeparator(const QTextCursor &tc) const;
-
private:
bool isClosingBrace(const QList<QmlJS::Token> &tokens) const;
diff --git a/src/plugins/qmljseditor/qmljseditor.pro b/src/plugins/qmljseditor/qmljseditor.pro
index 7093b3ec0eb..1d66b2f958c 100644
--- a/src/plugins/qmljseditor/qmljseditor.pro
+++ b/src/plugins/qmljseditor/qmljseditor.pro
@@ -35,7 +35,8 @@ HEADERS += \
qmljsfindreferences.h \
qmljseditoreditable.h \
qmljssemantichighlighter.h \
- qmljsindenter.h
+ qmljsindenter.h \
+ qmljsautocompleter.h
SOURCES += \
qmljscodecompletion.cpp \
@@ -64,7 +65,8 @@ SOURCES += \
qmljsfindreferences.cpp \
qmljseditoreditable.cpp \
qmljssemantichighlighter.cpp \
- qmljsindenter.cpp
+ qmljsindenter.cpp \
+ qmljsautocompleter.cpp
RESOURCES += qmljseditor.qrc
OTHER_FILES += QmlJSEditor.mimetypes.xml
diff --git a/src/plugins/texteditor/autocompleter.cpp b/src/plugins/texteditor/autocompleter.cpp
new file mode 100644
index 00000000000..92ce3161a40
--- /dev/null
+++ b/src/plugins/texteditor/autocompleter.cpp
@@ -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.
+**
+**************************************************************************/
+
+#include "autocompleter.h"
+
+#include <QtGui/QTextCursor>
+
+using namespace TextEditor;
+
+AutoCompleter::AutoCompleter()
+{}
+
+AutoCompleter::~AutoCompleter()
+{}
+
+bool AutoCompleter::contextAllowsAutoParentheses(const QTextCursor &cursor,
+ const QString &textToInsert) const
+{
+ return doContextAllowsAutoParentheses(cursor, textToInsert);
+}
+
+bool AutoCompleter::contextAllowsElectricCharacters(const QTextCursor &cursor) const
+{
+ return doContextAllowsElectricCharacters(cursor);
+}
+
+bool AutoCompleter::isInComment(const QTextCursor &cursor) const
+{
+ return doIsInComment(cursor);
+}
+
+QString AutoCompleter::insertMatchingBrace(const QTextCursor &cursor, const
+ QString &text,
+ QChar la,
+ int *skippedChars) const
+{
+ return doInsertMatchingBrace(cursor, text, la, skippedChars);
+}
+
+QString AutoCompleter::insertParagraphSeparator(const QTextCursor &cursor) const
+{
+ return doInsertParagraphSeparator(cursor);
+}
+
+bool AutoCompleter::doContextAllowsAutoParentheses(const QTextCursor &cursor,
+ const QString &textToInsert) const
+{
+ Q_UNUSED(cursor);
+ Q_UNUSED(textToInsert);
+ return false;
+}
+
+bool AutoCompleter::doContextAllowsElectricCharacters(const QTextCursor &cursor) const
+{
+ return doContextAllowsAutoParentheses(cursor);
+}
+
+bool AutoCompleter::doIsInComment(const QTextCursor &cursor) const
+{
+ Q_UNUSED(cursor);
+ return false;
+}
+
+QString AutoCompleter::doInsertMatchingBrace(const QTextCursor &cursor,
+ const QString &text,
+ QChar la,
+ int *skippedChars) const
+{
+ Q_UNUSED(cursor);
+ Q_UNUSED(text);
+ Q_UNUSED(la);
+ Q_UNUSED(skippedChars);
+ return QString();
+}
+
+QString AutoCompleter::doInsertParagraphSeparator(const QTextCursor &cursor) const
+{
+ Q_UNUSED(cursor);
+ return QString();
+}
diff --git a/src/plugins/texteditor/autocompleter.h b/src/plugins/texteditor/autocompleter.h
new file mode 100644
index 00000000000..3b49d499a4e
--- /dev/null
+++ b/src/plugins/texteditor/autocompleter.h
@@ -0,0 +1,78 @@
+/**************************************************************************
+**
+** 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 AUTOCOMPLETER_H
+#define AUTOCOMPLETER_H
+
+#include "texteditor_global.h"
+
+#include <QtCore/QChar>
+#include <QtCore/QString>
+
+QT_BEGIN_NAMESPACE
+class QTextCursor;
+QT_END_NAMESPACE
+
+namespace TextEditor {
+
+class TEXTEDITOR_EXPORT AutoCompleter
+{
+public:
+ AutoCompleter();
+ virtual ~AutoCompleter();
+
+ bool contextAllowsAutoParentheses(const QTextCursor &cursor,
+ const QString &textToInsert = QString()) const;
+ bool contextAllowsElectricCharacters(const QTextCursor &cursor) const;
+
+ // Returns true if the cursor is inside a comment.
+ bool isInComment(const QTextCursor &cursor) const;
+
+ QString insertMatchingBrace(const QTextCursor &cursor, const
+ QString &text,
+ QChar la,
+ int *skippedChars) const;
+ // Returns the text that needs to be inserted
+ QString insertParagraphSeparator(const QTextCursor &cursor) const;
+
+private:
+ virtual bool doContextAllowsAutoParentheses(const QTextCursor &cursor,
+ const QString &textToInsert = QString()) const;
+ virtual bool doContextAllowsElectricCharacters(const QTextCursor &cursor) const;
+ virtual bool doIsInComment(const QTextCursor &cursor) const;
+ virtual QString doInsertMatchingBrace(const QTextCursor &cursor,
+ const QString &text,
+ QChar la,
+ int *skippedChars) const;
+ virtual QString doInsertParagraphSeparator(const QTextCursor &cursor) const;
+};
+
+} // TextEditor
+
+#endif // AUTOCOMPLETER_H
diff --git a/src/plugins/texteditor/basetexteditor.cpp b/src/plugins/texteditor/basetexteditor.cpp
index 7457634afdf..f2fe088e6c5 100644
--- a/src/plugins/texteditor/basetexteditor.cpp
+++ b/src/plugins/texteditor/basetexteditor.cpp
@@ -43,6 +43,7 @@
#include "tooltip.h"
#include "tipcontents.h"
#include "indenter.h"
+#include "autocompleter.h"
#include <aggregation/aggregate.h>
#include <coreplugin/actionmanager/actionmanager.h>
@@ -1364,7 +1365,7 @@ void BaseTextEditor::keyPressEvent(QKeyEvent *e)
cursor.insertText(autoText);
cursor.setPosition(pos);
}
- if (!electricChar.isNull() && contextAllowsElectricCharacters(cursor))
+ if (!electricChar.isNull() && d->m_autoCompleter->contextAllowsElectricCharacters(cursor))
indent(document(), cursor, electricChar);
if (doEditBlock)
@@ -1889,6 +1890,16 @@ void BaseTextEditor::setIndenter(Indenter *indenter)
d->m_indenter.reset(indenter);
}
+void BaseTextEditor::setAutoCompleter(AutoCompleter *autoCompleter)
+{
+ d->m_autoCompleter.reset(autoCompleter);
+}
+
+AutoCompleter *BaseTextEditor::autoCompleter() const
+{
+ return d->m_autoCompleter.data();
+}
+
//--------- BaseTextEditorPrivate -----------
BaseTextEditorPrivate::BaseTextEditorPrivate()
@@ -1937,7 +1948,8 @@ BaseTextEditorPrivate::BaseTextEditorPrivate()
m_requestAutoCompletionRevision(0),
m_requestAutoCompletionPosition(0),
m_requestAutoCompletionTimer(0),
- m_cursorBlockNumber(-1)
+ m_cursorBlockNumber(-1),
+ m_autoCompleter(new AutoCompleter)
{
}
@@ -4051,41 +4063,6 @@ void BaseTextEditor::countBrackets(QTextCursor cursor, int from, int end, QChar
}
}
-bool BaseTextEditor::contextAllowsAutoParentheses(const QTextCursor &cursor,
- const QString &textToInsert) const
-{
- Q_UNUSED(cursor);
- Q_UNUSED(textToInsert);
- return false;
-}
-
-bool BaseTextEditor::contextAllowsElectricCharacters(const QTextCursor &cursor) const
-{
- return contextAllowsAutoParentheses(cursor);
-}
-
-bool BaseTextEditor::isInComment(const QTextCursor &cursor) const
-{
- Q_UNUSED(cursor);
- return false;
-}
-
-QString BaseTextEditor::insertMatchingBrace(const QTextCursor &tc, const QString &text,
- QChar la, int *skippedChars) const
-{
- Q_UNUSED(tc);
- Q_UNUSED(text);
- Q_UNUSED(la);
- Q_UNUSED(skippedChars);
- return QString();
-}
-
-QString BaseTextEditor::insertParagraphSeparator(const QTextCursor &tc) const
-{
- Q_UNUSED(tc);
- return QString();
-}
-
QString BaseTextEditor::autoComplete(QTextCursor &cursor, const QString &textToInsert) const
{
const bool checkBlockEnd = d->m_allowSkippingOfBlockEnd;
@@ -4094,7 +4071,7 @@ QString BaseTextEditor::autoComplete(QTextCursor &cursor, const QString &textToI
if (!d->m_autoParenthesesEnabled)
return QString();
- if (!contextAllowsAutoParentheses(cursor, textToInsert))
+ if (!d->m_autoCompleter->contextAllowsAutoParentheses(cursor, textToInsert))
return QString();
const QString text = textToInsert;
@@ -4128,7 +4105,7 @@ QString BaseTextEditor::autoComplete(QTextCursor &cursor, const QString &textToI
}
int skippedChars = 0;
- const QString autoText = insertMatchingBrace(cursor, text, lookAhead, &skippedChars);
+ const QString autoText = d->m_autoCompleter->insertMatchingBrace(cursor, text, lookAhead, &skippedChars);
if (checkBlockEnd && textToInsert.at(0) == QLatin1Char('}')) {
if (textToInsert.length() > 1)
@@ -4200,7 +4177,7 @@ bool BaseTextEditor::autoBackspace(QTextCursor &cursor)
&& lookFurtherBehind != QLatin1Char('\\'))
|| (lookBehind == QLatin1Char('\'') && lookAhead == QLatin1Char('\'')
&& lookFurtherBehind != QLatin1Char('\\'))) {
- if (! isInComment(c)) {
+ if (! d->m_autoCompleter->isInComment(c)) {
cursor.beginEditBlock();
cursor.deleteChar();
cursor.deletePreviousChar();
@@ -4219,7 +4196,7 @@ int BaseTextEditor::paragraphSeparatorAboutToBeInserted(QTextCursor &cursor)
if (characterAt(cursor.position() - 1) != QLatin1Char('{'))
return 0;
- if (!contextAllowsAutoParentheses(cursor))
+ if (!d->m_autoCompleter->contextAllowsAutoParentheses(cursor))
return 0;
// verify that we indeed do have an extra opening brace in the document
@@ -4253,7 +4230,7 @@ int BaseTextEditor::paragraphSeparatorAboutToBeInserted(QTextCursor &cursor)
int pos = cursor.position();
- const QString textToInsert = insertParagraphSeparator(cursor);
+ const QString textToInsert = d->m_autoCompleter->insertParagraphSeparator(cursor);
cursor.insertText(textToInsert);
cursor.setPosition(pos);
diff --git a/src/plugins/texteditor/basetexteditor.h b/src/plugins/texteditor/basetexteditor.h
index 77caa0ff1c3..ba2c4d1d4c4 100644
--- a/src/plugins/texteditor/basetexteditor.h
+++ b/src/plugins/texteditor/basetexteditor.h
@@ -69,6 +69,7 @@ class CompletionSettings;
class DisplaySettings;
class StorageSettings;
class Indenter;
+class AutoCompleter;
class TEXTEDITOR_EXPORT BaseTextEditorAnimator : public QObject
{
@@ -225,6 +226,9 @@ public:
void setIndenter(Indenter *indenter);
+ void setAutoCompleter(AutoCompleter *autoCompleter);
+ AutoCompleter *autoCompleter() const;
+
public slots:
void setDisplayName(const QString &title);
@@ -429,17 +433,6 @@ public:
// Reindent at cursor. Selection will be adjusted according to the indentation change of the first block
virtual void reindent(QTextDocument *doc, const QTextCursor &cursor);
- virtual bool contextAllowsAutoParentheses(const QTextCursor &cursor, const QString &textToInsert = QString()) const;
- virtual bool contextAllowsElectricCharacters(const QTextCursor &cursor) const;
-
- // Returns true if the cursor is inside a comment.
- virtual bool isInComment(const QTextCursor &cursor) const;
-
- virtual QString insertMatchingBrace(const QTextCursor &tc, const QString &text, QChar la, int *skippedChars) const;
-
- // Returns the text that needs to be inserted
- virtual QString insertParagraphSeparator(const QTextCursor &tc) const;
-
protected:
static void countBracket(QChar open, QChar close, QChar c, int *errors, int *stillopen);
diff --git a/src/plugins/texteditor/basetexteditor_p.h b/src/plugins/texteditor/basetexteditor_p.h
index bc6a3365eae..876e28a6aec 100644
--- a/src/plugins/texteditor/basetexteditor_p.h
+++ b/src/plugins/texteditor/basetexteditor_p.h
@@ -294,6 +294,7 @@ public:
QPointer<BaseTextEditorAnimator> m_animator;
int m_cursorBlockNumber;
+ QScopedPointer<AutoCompleter> m_autoCompleter;
QScopedPointer<Indenter> m_indenter;
};
diff --git a/src/plugins/texteditor/texteditor.pro b/src/plugins/texteditor/texteditor.pro
index 3b84f9c979c..43ba19013a8 100644
--- a/src/plugins/texteditor/texteditor.pro
+++ b/src/plugins/texteditor/texteditor.pro
@@ -70,7 +70,8 @@ SOURCES += texteditorplugin.cpp \
tooltip/tipfactory.cpp \
basehoverhandler.cpp \
helpitem.cpp \
- snippetsparser.cpp
+ snippetsparser.cpp \
+ autocompleter.cpp
HEADERS += texteditorplugin.h \
textfilewizard.h \
@@ -144,7 +145,8 @@ HEADERS += texteditorplugin.h \
tooltip/tipfactory.h \
basehoverhandler.h \
helpitem.h \
- snippetsparser.h
+ snippetsparser.h \
+ autocompleter.h
FORMS += behaviorsettingspage.ui \
displaysettingspage.ui \