summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorThorbjørn Lindeijer <thorbjorn.lindeijer@nokia.com>2010-07-09 15:12:44 +0200
committerThorbjørn Lindeijer <thorbjorn.lindeijer@nokia.com>2010-07-09 15:52:09 +0200
commitb4cecd6ec8a39c10913887fd9a99293a260e6482 (patch)
treee6a57036feaba57f9e6f1f1d02a1ea69d564444b /src
parent6ee1027eaa796008612a78ffa62339963d597b3a (diff)
downloadqt-creator-b4cecd6ec8a39c10913887fd9a99293a260e6482.tar.gz
Allow certain characters to also trigger the completion
Now you can type characters like ., ( and : to complete the selected item, depending on the type of the completion item. Task-number: QTCREATORBUG-271 Reviewed-by: Roberto Raggi
Diffstat (limited to 'src')
-rw-r--r--src/plugins/cpptools/cppcodecompletion.cpp70
-rw-r--r--src/plugins/cpptools/cppcodecompletion.h3
-rw-r--r--src/plugins/qmljseditor/qmljscodecompletion.cpp17
-rw-r--r--src/plugins/qmljseditor/qmljscodecompletion.h3
-rw-r--r--src/plugins/texteditor/completionsupport.cpp2
-rw-r--r--src/plugins/texteditor/completionwidget.cpp15
-rw-r--r--src/plugins/texteditor/completionwidget.h3
-rw-r--r--src/plugins/texteditor/icompletioncollector.h25
-rw-r--r--src/plugins/texteditor/quickfix.cpp2
-rw-r--r--src/plugins/texteditor/quickfix.h2
10 files changed, 125 insertions, 17 deletions
diff --git a/src/plugins/cpptools/cppcodecompletion.cpp b/src/plugins/cpptools/cppcodecompletion.cpp
index 733671fa51..9ea8d987dc 100644
--- a/src/plugins/cpptools/cppcodecompletion.cpp
+++ b/src/plugins/cpptools/cppcodecompletion.cpp
@@ -1723,7 +1723,33 @@ QList<TextEditor::CompletionItem> CppCodeCompletion::getCompletions()
return completionItems;
}
-void CppCodeCompletion::complete(const TextEditor::CompletionItem &item)
+bool CppCodeCompletion::typedCharCompletes(const TextEditor::CompletionItem &item, QChar typedChar)
+{
+ if (item.data.canConvert<QString>()) // snippet
+ return false;
+
+ if (m_completionOperator == T_SIGNAL || m_completionOperator == T_SLOT)
+ return typedChar == QLatin1Char('(')
+ || typedChar == QLatin1Char(',');
+
+ if (m_completionOperator == T_STRING_LITERAL || m_completionOperator == T_ANGLE_STRING_LITERAL)
+ return typedChar == QLatin1Char('/')
+ && item.text.endsWith(QLatin1Char('/'));
+
+ if (item.data.value<Symbol *>())
+ return typedChar == QLatin1Char(':')
+ || typedChar == QLatin1Char(';')
+ || typedChar == QLatin1Char('.')
+ || typedChar == QLatin1Char(',')
+ || typedChar == QLatin1Char('(');
+
+ if (item.data.canConvert<CompleteFunctionDeclaration>())
+ return typedChar == QLatin1Char('(');
+
+ return false;
+}
+
+void CppCodeCompletion::complete(const TextEditor::CompletionItem &item, QChar typedChar)
{
Symbol *symbol = 0;
@@ -1749,10 +1775,15 @@ void CppCodeCompletion::complete(const TextEditor::CompletionItem &item)
if (m_completionOperator == T_SIGNAL || m_completionOperator == T_SLOT) {
toInsert = item.text;
extraChars += QLatin1Char(')');
+
+ if (typedChar == QLatin1Char('(')) // Eat the opening parenthesis
+ typedChar = QChar();
} else if (m_completionOperator == T_STRING_LITERAL || m_completionOperator == T_ANGLE_STRING_LITERAL) {
toInsert = item.text;
if (!toInsert.endsWith(QLatin1Char('/')))
extraChars += QLatin1Char((m_completionOperator == T_ANGLE_STRING_LITERAL) ? '>' : '"');
+ else if (typedChar == QLatin1Char('/')) // Eat the slash
+ typedChar = QChar();
} else {
toInsert = item.text;
@@ -1768,7 +1799,7 @@ void CppCodeCompletion::complete(const TextEditor::CompletionItem &item)
if (! function->hasReturnType() && (function->identity() && !function->identity()->isDestructorNameId())) {
// Don't insert any magic, since the user might have just wanted to select the class
- } else if (function->templateParameterCount() != 0) {
+ } else if (function->templateParameterCount() != 0 && typedChar != QLatin1Char('(')) {
// If there are no arguments, then we need the template specification
if (function->argumentCount() == 0) {
extraChars += QLatin1Char('<');
@@ -1777,32 +1808,50 @@ void CppCodeCompletion::complete(const TextEditor::CompletionItem &item)
if (completionSettings().m_spaceAfterFunctionName)
extraChars += QLatin1Char(' ');
extraChars += QLatin1Char('(');
+ if (typedChar == QLatin1Char('('))
+ typedChar = QChar();
// If the function doesn't return anything, automatically place the semicolon,
// unless we're doing a scope completion (then it might be function definition).
- bool endWithSemicolon = function->returnType()->isVoidType() && m_completionOperator != T_COLON_COLON;
+ const QChar characterAtCursor = m_editor->characterAt(m_editor->position());
+ bool endWithSemicolon = typedChar == QLatin1Char(';')
+ || (function->returnType()->isVoidType() && m_completionOperator != T_COLON_COLON);
+ const QChar semicolon = typedChar.isNull() ? QLatin1Char(';') : typedChar;
+
+ if (endWithSemicolon && characterAtCursor == semicolon) {
+ endWithSemicolon = false;
+ typedChar = QChar();
+ }
// If the function takes no arguments, automatically place the closing parenthesis
if (item.duplicateCount == 0 && ! function->hasArguments()) {
extraChars += QLatin1Char(')');
- if (endWithSemicolon)
- extraChars += QLatin1Char(';');
+ if (endWithSemicolon) {
+ extraChars += semicolon;
+ typedChar = QChar();
+ }
} else if (autoParenthesesEnabled) {
const QChar lookAhead = m_editor->characterAt(m_editor->position() + 1);
if (MatchingText::shouldInsertMatchingText(lookAhead)) {
extraChars += QLatin1Char(')');
--cursorOffset;
if (endWithSemicolon) {
- extraChars += QLatin1Char(';');
+ extraChars += semicolon;
--cursorOffset;
+ typedChar = QChar();
}
}
+ // TODO: When an opening parenthesis exists, the "semicolon" should really be
+ // inserted after the matching closing parenthesis.
}
}
}
}
if (autoInsertBrackets && item.data.canConvert<CompleteFunctionDeclaration>()) {
+ if (typedChar == QLatin1Char('('))
+ typedChar = QChar();
+
// everything from the closing parenthesis on are extra chars, to
// make sure an auto-inserted ")" gets replaced by ") const" if necessary
int closingParen = toInsert.lastIndexOf(QLatin1Char(')'));
@@ -1811,6 +1860,13 @@ void CppCodeCompletion::complete(const TextEditor::CompletionItem &item)
}
}
+ // Append an unhandled typed character, adjusting cursor offset when it had been adjusted before
+ if (!typedChar.isNull()) {
+ extraChars += typedChar;
+ if (cursorOffset != 0)
+ --cursorOffset;
+ }
+
// Avoid inserting characters that are already there
for (int i = 0; i < extraChars.length(); ++i) {
const QChar a = extraChars.at(i);
@@ -1836,7 +1892,7 @@ bool CppCodeCompletion::partiallyComplete(const QList<TextEditor::CompletionItem
if (m_completionOperator == T_SIGNAL || m_completionOperator == T_SLOT) {
return false;
} else if (completionItems.count() == 1) {
- complete(completionItems.first());
+ complete(completionItems.first(), QChar());
return true;
} else if (m_completionOperator != T_LPAREN) {
return TextEditor::ICompletionCollector::partiallyComplete(completionItems);
diff --git a/src/plugins/cpptools/cppcodecompletion.h b/src/plugins/cpptools/cppcodecompletion.h
index 513b038407..406d4a2f87 100644
--- a/src/plugins/cpptools/cppcodecompletion.h
+++ b/src/plugins/cpptools/cppcodecompletion.h
@@ -78,7 +78,8 @@ public:
int startCompletion(TextEditor::ITextEditable *editor);
void completions(QList<TextEditor::CompletionItem> *completions);
- void complete(const TextEditor::CompletionItem &item);
+ bool typedCharCompletes(const TextEditor::CompletionItem &item, QChar typedChar);
+ void complete(const TextEditor::CompletionItem &item, QChar typedChar);
bool partiallyComplete(const QList<TextEditor::CompletionItem> &completionItems);
void cleanup();
diff --git a/src/plugins/qmljseditor/qmljscodecompletion.cpp b/src/plugins/qmljseditor/qmljscodecompletion.cpp
index 1bd3c77a52..5f28d8acac 100644
--- a/src/plugins/qmljseditor/qmljscodecompletion.cpp
+++ b/src/plugins/qmljseditor/qmljscodecompletion.cpp
@@ -878,8 +878,19 @@ void CodeCompletion::completions(QList<TextEditor::CompletionItem> *completions)
}
}
-void CodeCompletion::complete(const TextEditor::CompletionItem &item)
+bool CodeCompletion::typedCharCompletes(const TextEditor::CompletionItem &item, QChar typedChar)
{
+ if (item.data.canConvert<QString>()) // snippet
+ return false;
+
+ return (item.text.endsWith(QLatin1String(": ")) && typedChar == QLatin1Char(':'))
+ || (item.text.endsWith(QLatin1Char('.')) && typedChar == QLatin1Char('.'));
+}
+
+void CodeCompletion::complete(const TextEditor::CompletionItem &item, QChar typedChar)
+{
+ Q_UNUSED(typedChar) // Currently always included in the completion item when used
+
QString toInsert = item.text;
if (QmlJSTextEditor *edit = qobject_cast<QmlJSTextEditor *>(m_editor->widget())) {
@@ -895,7 +906,7 @@ void CodeCompletion::complete(const TextEditor::CompletionItem &item)
QString replacableChars;
if (toInsert.endsWith(QLatin1String(": ")))
replacableChars = QLatin1String(": ");
- else if (toInsert.endsWith(QLatin1String(".")))
+ else if (toInsert.endsWith(QLatin1Char('.')))
replacableChars = QLatin1String(".");
int replacedLength = 0;
@@ -924,7 +935,7 @@ bool CodeCompletion::partiallyComplete(const QList<TextEditor::CompletionItem> &
const TextEditor::CompletionItem item = completionItems.first();
if (!item.data.canConvert<QString>()) {
- complete(item);
+ complete(item, QChar());
return true;
}
}
diff --git a/src/plugins/qmljseditor/qmljscodecompletion.h b/src/plugins/qmljseditor/qmljscodecompletion.h
index 0cae652ad2..f435badf24 100644
--- a/src/plugins/qmljseditor/qmljscodecompletion.h
+++ b/src/plugins/qmljseditor/qmljscodecompletion.h
@@ -68,7 +68,8 @@ public:
virtual bool triggersCompletion(TextEditor::ITextEditable *editor);
virtual int startCompletion(TextEditor::ITextEditable *editor);
virtual void completions(QList<TextEditor::CompletionItem> *completions);
- virtual void complete(const TextEditor::CompletionItem &item);
+ virtual bool typedCharCompletes(const TextEditor::CompletionItem &item, QChar typedChar);
+ virtual void complete(const TextEditor::CompletionItem &item, QChar typedChar);
virtual bool partiallyComplete(const QList<TextEditor::CompletionItem> &completionItems);
virtual QList<TextEditor::CompletionItem> getCompletions();
diff --git a/src/plugins/texteditor/completionsupport.cpp b/src/plugins/texteditor/completionsupport.cpp
index 3b06580a74..bd6cc6c12e 100644
--- a/src/plugins/texteditor/completionsupport.cpp
+++ b/src/plugins/texteditor/completionsupport.cpp
@@ -67,7 +67,7 @@ CompletionSupport::CompletionSupport()
void CompletionSupport::performCompletion(const CompletionItem &item)
{
- item.collector->complete(item);
+ item.collector->complete(item, m_completionList->typedChar());
m_checkCompletionTrigger = true;
}
diff --git a/src/plugins/texteditor/completionwidget.cpp b/src/plugins/texteditor/completionwidget.cpp
index c8a6eae08a..5b005c17b0 100644
--- a/src/plugins/texteditor/completionwidget.cpp
+++ b/src/plugins/texteditor/completionwidget.cpp
@@ -199,6 +199,11 @@ void CompletionWidget::showCompletions(int startPos)
setFocus();
}
+QChar CompletionWidget::typedChar() const
+{
+ return m_completionListView->m_typedChar;
+}
+
void CompletionWidget::updatePositionAndSize(int startPos)
{
// Determine size by calculating the space of the visible items
@@ -415,6 +420,16 @@ bool CompletionListView::event(QEvent *e)
}
if (forwardKeys && ! m_quickFix) {
+ if (ke->text().length() == 1 && currentIndex().isValid() && qApp->focusWidget() == this) {
+ QChar typedChar = ke->text().at(0);
+ const CompletionItem &item = m_model->itemAt(currentIndex());
+ if (item.collector->typedCharCompletes(item, typedChar)) {
+ m_typedChar = typedChar;
+ m_completionWidget->closeList(currentIndex());
+ return true;
+ }
+ }
+
m_blockFocusOut = true;
QApplication::sendEvent(m_editorWidget, e);
m_blockFocusOut = false;
diff --git a/src/plugins/texteditor/completionwidget.h b/src/plugins/texteditor/completionwidget.h
index ece02904b1..813fd89f30 100644
--- a/src/plugins/texteditor/completionwidget.h
+++ b/src/plugins/texteditor/completionwidget.h
@@ -61,6 +61,8 @@ public:
void setCompletionItems(const QList<TextEditor::CompletionItem> &completionitems);
void showCompletions(int startPos);
+ QChar typedChar() const;
+
signals:
void itemSelected(const TextEditor::CompletionItem &item);
void completionListClosed();
@@ -115,6 +117,7 @@ private:
CompletionSupport *m_support;
QPointer<CompletionInfoFrame> m_infoFrame;
QTimer m_infoTimer;
+ QChar m_typedChar;
};
} // namespace Internal
diff --git a/src/plugins/texteditor/icompletioncollector.h b/src/plugins/texteditor/icompletioncollector.h
index 354e45c75d..dc8549635b 100644
--- a/src/plugins/texteditor/icompletioncollector.h
+++ b/src/plugins/texteditor/icompletioncollector.h
@@ -111,9 +111,19 @@ public:
*/
virtual void completions(QList<CompletionItem> *completions) = 0;
- /* This method should complete the given completion item.
+ /**
+ * This method should return true when the given typed character should cause
+ * the selected completion item to be completed.
*/
- virtual void complete(const CompletionItem &item) = 0;
+ virtual bool typedCharCompletes(const CompletionItem &item, QChar typedChar) = 0;
+
+ /**
+ * This method should complete the given completion item.
+ *
+ * \param typedChar Non-null when completion was triggered by typing a
+ * character. Possible values depend on typedCharCompletes()
+ */
+ virtual void complete(const CompletionItem &item, QChar typedChar) = 0;
/* This method gives the completion collector a chance to partially complete
* based on a set of items. The general use case is to complete the common
@@ -153,6 +163,17 @@ public:
IQuickFixCollector(QObject *parent = 0) : ICompletionCollector(parent) {}
virtual ~IQuickFixCollector() {}
+ virtual bool typedCharCompletes(const CompletionItem &, QChar)
+ { return false; }
+
+ virtual void fix(const TextEditor::CompletionItem &item) = 0;
+
+ virtual void complete(const CompletionItem &item, QChar typedChar)
+ {
+ Q_UNUSED(typedChar)
+ fix(item);
+ }
+
virtual bool triggersCompletion(TextEditor::ITextEditable *)
{ return false; }
diff --git a/src/plugins/texteditor/quickfix.cpp b/src/plugins/texteditor/quickfix.cpp
index 9918ad4f5b..8e5e024750 100644
--- a/src/plugins/texteditor/quickfix.cpp
+++ b/src/plugins/texteditor/quickfix.cpp
@@ -171,7 +171,7 @@ void QuickFixCollector::completions(QList<TextEditor::CompletionItem> *quickFixI
}
}
-void QuickFixCollector::complete(const TextEditor::CompletionItem &item)
+void QuickFixCollector::fix(const TextEditor::CompletionItem &item)
{
const int index = item.data.toInt();
diff --git a/src/plugins/texteditor/quickfix.h b/src/plugins/texteditor/quickfix.h
index fd731c6c5a..2ad179e0ac 100644
--- a/src/plugins/texteditor/quickfix.h
+++ b/src/plugins/texteditor/quickfix.h
@@ -111,7 +111,7 @@ public:
virtual bool triggersCompletion(TextEditor::ITextEditable *editor);
virtual int startCompletion(TextEditor::ITextEditable *editor);
virtual void completions(QList<TextEditor::CompletionItem> *completions);
- virtual void complete(const TextEditor::CompletionItem &item);
+ virtual void fix(const TextEditor::CompletionItem &item);
virtual void cleanup();
virtual TextEditor::QuickFixState *initializeCompletion(TextEditor::ITextEditable *editable) = 0;