summaryrefslogtreecommitdiff
path: root/src/plugins/cpptools/cppcodecompletion.cpp
diff options
context:
space:
mode:
authorThorbjørn Lindeijer <thorbjorn.lindeijer@nokia.com>2009-07-23 16:46:30 +0200
committerThorbjørn Lindeijer <thorbjorn.lindeijer@nokia.com>2009-07-23 16:49:36 +0200
commit47a2097341928206d002dd861da97080af24dcc8 (patch)
tree14d27ce96f7fbbb9c38fe07664717657dd2e6dc6 /src/plugins/cpptools/cppcodecompletion.cpp
parent1ccf39f8cea5585b99f0cd2e9f71441cadbece8c (diff)
downloadqt-creator-47a2097341928206d002dd861da97080af24dcc8.tar.gz
Implemented include completion
Done-with: danimo
Diffstat (limited to 'src/plugins/cpptools/cppcodecompletion.cpp')
-rw-r--r--src/plugins/cpptools/cppcodecompletion.cpp164
1 files changed, 151 insertions, 13 deletions
diff --git a/src/plugins/cpptools/cppcodecompletion.cpp b/src/plugins/cpptools/cppcodecompletion.cpp
index a98e7d1c19..174234f076 100644
--- a/src/plugins/cpptools/cppcodecompletion.cpp
+++ b/src/plugins/cpptools/cppcodecompletion.cpp
@@ -52,10 +52,12 @@
#include <coreplugin/icore.h>
#include <coreplugin/editormanager/editormanager.h>
+#include <coreplugin/mimedatabase.h>
#include <texteditor/itexteditor.h>
#include <texteditor/itexteditable.h>
-#include <utils/qtcassert.h>
#include <texteditor/basetexteditor.h>
+#include <projectexplorer/projectexplorer.h>
+#include <utils/qtcassert.h>
#include <QtCore/QDebug>
#include <QtCore/QMap>
@@ -585,6 +587,15 @@ static int startOfOperator(TextEditor::ITextEditable *editor,
} else if ((ch2.isNull() || ch2.isSpace()) && (ch == QLatin1Char('@') || ch == QLatin1Char('\\'))) {
k = T_DOXY_COMMENT;
--start;
+ } else if (ch == QLatin1Char('<')) {
+ k = T_ANGLE_STRING_LITERAL;
+ --start;
+ } else if (ch == QLatin1Char('"')) {
+ k = T_STRING_LITERAL;
+ --start;
+ } else if (ch == QLatin1Char('/')) {
+ k = T_SLASH;
+ --start;
}
if (start == pos)
@@ -594,6 +605,17 @@ static int startOfOperator(TextEditor::ITextEditable *editor,
QTextCursor tc(edit->textCursor());
tc.setPosition(pos);
+ // Include completion: make sure the quote character is the first one on the line
+ if (k == T_STRING_LITERAL) {
+ QTextCursor s = tc;
+ s.movePosition(QTextCursor::StartOfLine, QTextCursor::KeepAnchor);
+ QString sel = s.selectedText();
+ if (sel.indexOf(QLatin1Char('"')) < sel.length() - 1) {
+ k = T_EOF_SYMBOL;
+ start = pos;
+ }
+ }
+
static CPlusPlus::TokenUnderCursor tokenUnderCursor;
const SimpleToken tk = tokenUnderCursor(tc);
@@ -601,7 +623,16 @@ static int startOfOperator(TextEditor::ITextEditable *editor,
k = T_EOF_SYMBOL;
start = pos;
}
- else if (tk.is(T_COMMENT) || tk.isLiteral()) {
+ // Don't complete in comments or strings, but still check for include completion
+ else if (tk.is(T_COMMENT) || (tk.isLiteral() &&
+ (k != T_STRING_LITERAL
+ && k != T_ANGLE_STRING_LITERAL
+ && k != T_SLASH))) {
+ k = T_EOF_SYMBOL;
+ start = pos;
+ }
+ // Include completion: can be triggered by slash, but only in a string
+ else if (k == T_SLASH && (tk.isNot(T_STRING_LITERAL) && tk.isNot(T_ANGLE_STRING_LITERAL))) {
k = T_EOF_SYMBOL;
start = pos;
}
@@ -627,6 +658,32 @@ static int startOfOperator(TextEditor::ITextEditable *editor,
}
}
+ // Check for include preprocessor directive
+ if (k == T_STRING_LITERAL || k == T_ANGLE_STRING_LITERAL || k == T_SLASH) {
+ const QList<SimpleToken> &tokens = tokenUnderCursor.tokens();
+ int i = 0;
+ bool include = false;
+ for (; i < tokens.size(); ++i) {
+ const SimpleToken &token = tokens.at(i);
+ if (token.position() == tk.position()) {
+ if (i == 0) // no token on the left, but might be on a previous line
+ break;
+ const SimpleToken &previousToken = tokens.at(i - 1);
+ if (previousToken.is(T_IDENTIFIER)) {
+ if (previousToken.text() == QLatin1String("include")) {
+ include = true;
+ break;
+ }
+ }
+ }
+ }
+
+ if (!include) {
+ k = T_EOF_SYMBOL;
+ start = pos;
+ }
+ }
+
if (kind)
*kind = k;
@@ -685,6 +742,18 @@ int CppCodeCompletion::startCompletion(TextEditor::ITextEditable *editor)
return m_startPosition;
}
+ // Include completion
+ if (m_completionOperator == T_STRING_LITERAL
+ || m_completionOperator == T_ANGLE_STRING_LITERAL
+ || m_completionOperator == T_SLASH) {
+
+ QTextCursor c = edit->textCursor();
+ c.setPosition(endOfExpression);
+ if (completeInclude(c))
+ m_startPosition = startOfName;
+ return m_startPosition;
+ }
+
ExpressionUnderCursor expressionUnderCursor;
QTextCursor tc(edit->document());
@@ -1121,6 +1190,72 @@ void CppCodeCompletion::addCompletionItem(Symbol *symbol)
m_completions.append(item);
}
+bool CppCodeCompletion::completeInclude(const QTextCursor &cursor)
+{
+ QString directoryPrefix;
+ if (m_completionOperator == T_SLASH) {
+ QTextCursor c = cursor;
+ c.movePosition(QTextCursor::StartOfLine, QTextCursor::KeepAnchor);
+ QString sel = c.selectedText();
+ int startCharPos = sel.indexOf(QLatin1Char('"'));
+ if (startCharPos == -1) {
+ startCharPos = sel.indexOf(QLatin1Char('<'));
+ m_completionOperator = T_ANGLE_STRING_LITERAL;
+ } else {
+ m_completionOperator = T_STRING_LITERAL;
+ }
+ if (startCharPos != -1)
+ directoryPrefix = sel.mid(startCharPos + 1, sel.length() - 1);
+ }
+
+ // Make completion for all relevant includes
+ if (ProjectExplorer::Project *project = ProjectExplorer::ProjectExplorerPlugin::instance()->currentProject()) {
+ QStringList items;
+ QStringList includePaths = m_manager->projectInfo(project).includePaths;
+ const QString currentFilePath = QFileInfo(m_editor->file()->fileName()).path();
+ if (!includePaths.contains(currentFilePath))
+ includePaths.append(currentFilePath);
+
+ const Core::MimeDatabase *mimeDatabase = Core::ICore::instance()->mimeDatabase();
+ const Core::MimeType mimeType = mimeDatabase->findByType(QLatin1String("text/x-c++hdr"));
+ const QStringList suffixes = mimeType.suffixes();
+
+ foreach (const QString &includePath, includePaths) {
+ QString realPath = includePath;
+ if (!directoryPrefix.isEmpty()) {
+ realPath += QLatin1Char('/');
+ realPath += directoryPrefix;
+ }
+ // TODO: This should be cached
+ QDirIterator i(realPath, QDir::Files | QDir::Dirs | QDir::NoDotAndDotDot);
+ while (i.hasNext()) {
+ const QString fileName = i.next();
+ const QFileInfo fileInfo = i.fileInfo();
+ const QString suffix = fileInfo.suffix();
+ if (suffix.isEmpty() || suffixes.contains(suffix)) {
+ QString text = fileName.mid(realPath.length() + 1);
+ if (fileInfo.isDir())
+ text += QLatin1Char('/');
+ items.append(text);
+ }
+ }
+ }
+
+ if (!items.isEmpty()) {
+ foreach (const QString &itemText, items) {
+ TextEditor::CompletionItem item(this);
+ item.m_text += itemText;
+ // TODO: Icon for include files
+ item.m_icon = m_icons.keywordIcon();
+ m_completions.append(item);
+ }
+ return true;
+ }
+ }
+
+ return false;
+}
+
void CppCodeCompletion::completeNamespace(const QList<Symbol *> &candidates,
const LookupContext &context)
{
@@ -1324,16 +1459,18 @@ void CppCodeCompletion::complete(const TextEditor::CompletionItem &item)
if (item.m_data.isValid())
symbol = item.m_data.value<Symbol *>();
+ QString toInsert;
+ int extraLength = 0;
+
if (m_completionOperator == T_SIGNAL || m_completionOperator == T_SLOT) {
- QString toInsert = item.m_text;
+ toInsert = item.m_text;
toInsert += QLatin1Char(')');
- // Insert the remainder of the name
- int length = m_editor->position() - m_startPosition;
- m_editor->setCurPos(m_startPosition);
- m_editor->replace(length, toInsert);
+ } else if (m_completionOperator == T_STRING_LITERAL || m_completionOperator == T_ANGLE_STRING_LITERAL) {
+ toInsert = item.m_text;
+ if (!toInsert.endsWith(QLatin1Char('/')))
+ toInsert += QLatin1Char((m_completionOperator == T_ANGLE_STRING_LITERAL) ? '>' : '"');
} else {
- QString toInsert = item.m_text;
- int extraLength = 0;
+ toInsert = item.m_text;
//qDebug() << "current symbol:" << overview.prettyName(symbol->name())
//<< overview.prettyType(symbol->type());
@@ -1381,11 +1518,12 @@ void CppCodeCompletion::complete(const TextEditor::CompletionItem &item)
toInsert += extraChars;
}
- // Insert the remainder of the name
- int length = m_editor->position() - m_startPosition + extraLength;
- m_editor->setCurPos(m_startPosition);
- m_editor->replace(length, toInsert);
}
+
+ // Insert the remainder of the name
+ int length = m_editor->position() - m_startPosition + extraLength;
+ m_editor->setCurPos(m_startPosition);
+ m_editor->replace(length, toInsert);
}
bool CppCodeCompletion::partiallyComplete(const QList<TextEditor::CompletionItem> &completionItems)