diff options
author | Marco Bubke <marco.bubke@theqtcompany.com> | 2016-01-28 16:39:05 +0100 |
---|---|---|
committer | Marco Bubke <marco.bubke@theqtcompany.com> | 2016-02-01 14:38:31 +0000 |
commit | ecca26929214742014674f4982d2120d0e36c2dc (patch) | |
tree | 7260fd62f7df2684293290e531560307eb4b6102 | |
parent | bb3b7307ef0bc1f70b3db823829a0569f49c2cda (diff) | |
download | qt-creator-ecca26929214742014674f4982d2120d0e36c2dc.tar.gz |
Clang: Add ClangPreprocessorAssistProposalItem
Change-Id: Ifb27b9a21b9a2fe9a04496bbb70fa3fa07d1f89c
Reviewed-by: Nikolai Kosjar <nikolai.kosjar@theqtcompany.com>
8 files changed, 286 insertions, 49 deletions
diff --git a/src/plugins/clangcodemodel/clangassistproposalitem.cpp b/src/plugins/clangcodemodel/clangassistproposalitem.cpp index e8a8e97979..57b38c8e9a 100644 --- a/src/plugins/clangcodemodel/clangassistproposalitem.cpp +++ b/src/plugins/clangcodemodel/clangassistproposalitem.cpp @@ -42,21 +42,21 @@ using namespace ClangBackEnd; namespace ClangCodeModel { namespace Internal { -bool ClangAssistProposalItem::prematurelyApplies(const QChar &typedChar) const +bool ClangAssistProposalItem::prematurelyApplies(const QChar &typedCharacter) const { bool applies = false; if (m_completionOperator == T_SIGNAL || m_completionOperator == T_SLOT) - applies = QString::fromLatin1("(,").contains(typedChar); + applies = QString::fromLatin1("(,").contains(typedCharacter); else if (m_completionOperator == T_STRING_LITERAL || m_completionOperator == T_ANGLE_STRING_LITERAL) - applies = (typedChar == QLatin1Char('/')) && text().endsWith(QLatin1Char('/')); + applies = (typedCharacter == QLatin1Char('/')) && text().endsWith(QLatin1Char('/')); else if (codeCompletion().completionKind() == CodeCompletion::ObjCMessageCompletionKind) - applies = QString::fromLatin1(";.,").contains(typedChar); + applies = QString::fromLatin1(";.,").contains(typedCharacter); else - applies = QString::fromLatin1(";.,:(").contains(typedChar); + applies = QString::fromLatin1(";.,:(").contains(typedCharacter); if (applies) - m_typedChar = typedChar; + m_typedCharacter = typedCharacter; return applies; } @@ -87,23 +87,16 @@ void ClangAssistProposalItem::apply(TextEditor::TextEditorWidget *editorWidget, const CodeCompletion ccr = codeCompletion(); QString textToBeInserted = text(); - QString extraChars; + QString extraCharacters; int extraLength = 0; int cursorOffset = 0; bool autoParenthesesEnabled = true; if (m_completionOperator == T_SIGNAL || m_completionOperator == T_SLOT) { - extraChars += QLatin1Char(')'); - if (m_typedChar == QLatin1Char('(')) // Eat the opening parenthesis - m_typedChar = QChar(); - } else if (m_completionOperator == T_STRING_LITERAL || m_completionOperator == T_ANGLE_STRING_LITERAL) { - if (!textToBeInserted.endsWith(QLatin1Char('/'))) { - extraChars += QLatin1Char((m_completionOperator == T_ANGLE_STRING_LITERAL) ? '>' : '"'); - } else { - if (m_typedChar == QLatin1Char('/')) // Eat the slash - m_typedChar = QChar(); - } - } else if (ccr.completionKind() == CodeCompletion::KeywordCompletionKind) { + extraCharacters += QLatin1Char(')'); + if (m_typedCharacter == QLatin1Char('(')) // Eat the opening parenthesis + m_typedCharacter = QChar(); + } else if (ccr.completionKind() == CodeCompletion::KeywordCompletionKind) { CompletionChunksToTextConverter converter; converter.setupForKeywords(); @@ -131,42 +124,42 @@ void ClangAssistProposalItem::apply(TextEditor::TextEditorWidget *editorWidget, // When the user typed the opening parenthesis, he'll likely also type the closing one, // in which case it would be annoying if we put the cursor after the already automatically // inserted closing parenthesis. - const bool skipClosingParenthesis = m_typedChar != QLatin1Char('('); + const bool skipClosingParenthesis = m_typedCharacter != QLatin1Char('('); if (completionSettings.m_spaceAfterFunctionName) - extraChars += QLatin1Char(' '); - extraChars += QLatin1Char('('); - if (m_typedChar == QLatin1Char('(')) - m_typedChar = QChar(); + extraCharacters += QLatin1Char(' '); + extraCharacters += QLatin1Char('('); + if (m_typedCharacter == QLatin1Char('(')) + m_typedCharacter = 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). const QChar characterAtCursor = editorWidget->characterAt(editorWidget->position()); - bool endWithSemicolon = m_typedChar == QLatin1Char(';')/* + bool endWithSemicolon = m_typedCharacter == QLatin1Char(';')/* || (function->returnType()->isVoidType() && m_completionOperator != T_COLON_COLON)*/; //### - const QChar semicolon = m_typedChar.isNull() ? QLatin1Char(';') : m_typedChar; + const QChar semicolon = m_typedCharacter.isNull() ? QLatin1Char(';') : m_typedCharacter; if (endWithSemicolon && characterAtCursor == semicolon) { endWithSemicolon = false; - m_typedChar = QChar(); + m_typedCharacter = QChar(); } // If the function takes no arguments, automatically place the closing parenthesis if (!isOverloaded() && !ccr.hasParameters() && skipClosingParenthesis) { - extraChars += QLatin1Char(')'); + extraCharacters += QLatin1Char(')'); if (endWithSemicolon) { - extraChars += semicolon; - m_typedChar = QChar(); + extraCharacters += semicolon; + m_typedCharacter = QChar(); } } else if (autoParenthesesEnabled) { const QChar lookAhead = editorWidget->characterAt(editorWidget->position() + 1); if (MatchingText::shouldInsertMatchingText(lookAhead)) { - extraChars += QLatin1Char(')'); + extraCharacters += QLatin1Char(')'); --cursorOffset; if (endWithSemicolon) { - extraChars += semicolon; + extraCharacters += semicolon; --cursorOffset; - m_typedChar = QChar(); + m_typedCharacter = QChar(); } } } @@ -187,8 +180,8 @@ void ClangAssistProposalItem::apply(TextEditor::TextEditorWidget *editorWidget, } // Append an unhandled typed character, adjusting cursor offset when it had been adjusted before - if (!m_typedChar.isNull()) { - extraChars += m_typedChar; + if (!m_typedCharacter.isNull()) { + extraCharacters += m_typedCharacter; if (cursorOffset != 0) --cursorOffset; } @@ -205,8 +198,8 @@ void ClangAssistProposalItem::apply(TextEditor::TextEditorWidget *editorWidget, break; } } - for (int i = 0; i < extraChars.length(); ++i) { - const QChar a = extraChars.at(i); + for (int i = 0; i < extraCharacters.length(); ++i) { + const QChar a = extraCharacters.at(i); const QChar b = editorWidget->characterAt(editorWidget->position() + i + existLength); if (a == b) ++extraLength; @@ -214,7 +207,7 @@ void ClangAssistProposalItem::apply(TextEditor::TextEditorWidget *editorWidget, break; } - textToBeInserted += extraChars; + textToBeInserted += extraCharacters; // Insert the remainder of the name const int length = editorWidget->position() - basePosition + existLength + extraLength; diff --git a/src/plugins/clangcodemodel/clangassistproposalitem.h b/src/plugins/clangcodemodel/clangassistproposalitem.h index 68d74ea6c2..776d7e196a 100644 --- a/src/plugins/clangcodemodel/clangassistproposalitem.h +++ b/src/plugins/clangcodemodel/clangassistproposalitem.h @@ -39,9 +39,7 @@ class ClangAssistProposalItem final : public TextEditor::AssistProposalItemInter { friend bool operator<(const ClangAssistProposalItem &first, const ClangAssistProposalItem &second); public: - ClangAssistProposalItem() {} - - bool prematurelyApplies(const QChar &c) const final; + bool prematurelyApplies(const QChar &typedCharacter) const final; bool implicitlyApplies() const final; void apply(TextEditor::TextEditorWidget *editorWidget, int basePosition) const final; @@ -66,7 +64,7 @@ private: QList<ClangBackEnd::CodeCompletion> m_overloads; QString m_text; unsigned m_completionOperator; - mutable QChar m_typedChar; + mutable QChar m_typedCharacter; }; } // namespace Internal diff --git a/src/plugins/clangcodemodel/clangcodemodel.pro b/src/plugins/clangcodemodel/clangcodemodel.pro index cf2b1ce027..e3a3294c8a 100644 --- a/src/plugins/clangcodemodel/clangcodemodel.pro +++ b/src/plugins/clangcodemodel/clangcodemodel.pro @@ -27,6 +27,7 @@ SOURCES += \ clangfunctionhintmodel.cpp \ clanghighlightingmarksreporter.cpp \ clangmodelmanagersupport.cpp \ + clangpreprocessorassistproposalitem.cpp \ clangtextmark.cpp \ clangutils.cpp @@ -53,6 +54,7 @@ HEADERS += \ clangfunctionhintmodel.h \ clanghighlightingmarksreporter.h \ clangmodelmanagersupport.h \ + clangpreprocessorassistproposalitem.h \ clangtextmark.h \ clangutils.h diff --git a/src/plugins/clangcodemodel/clangcodemodel.qbs b/src/plugins/clangcodemodel/clangcodemodel.qbs index 5be9afc9a0..8d72501868 100644 --- a/src/plugins/clangcodemodel/clangcodemodel.qbs +++ b/src/plugins/clangcodemodel/clangcodemodel.qbs @@ -79,6 +79,8 @@ QtcPlugin { "clanghighlightingmarksreporter.h", "clangmodelmanagersupport.cpp", "clangmodelmanagersupport.h", + "clangpreprocessorassistproposalitem.cpp", + "clangpreprocessorassistproposalitem.h", "clangtextmark.cpp", "clangtextmark.h", "clangutils.cpp", diff --git a/src/plugins/clangcodemodel/clangcompletionassistprocessor.cpp b/src/plugins/clangcodemodel/clangcompletionassistprocessor.cpp index fc4cd98619..5f3f6f6c49 100644 --- a/src/plugins/clangcodemodel/clangcompletionassistprocessor.cpp +++ b/src/plugins/clangcodemodel/clangcompletionassistprocessor.cpp @@ -33,6 +33,7 @@ #include "clangeditordocumentprocessor.h" #include "clangfunctionhintmodel.h" #include "clangcompletionchunkstotextconverter.h" +#include "clangpreprocessorassistproposalitem.h" #include <cpptools/cppdoxygen.h> #include <cpptools/cppmodelmanager.h> @@ -533,11 +534,11 @@ void ClangCompletionAssistProcessor::completeIncludePath(const QString &realPath if (fileInfo.isDir()) text += QLatin1Char('/'); - auto *item = new ClangAssistProposalItem; // TODO: Add IncludeAssistProposalItem + auto *item = new ClangPreprocessorAssistProposalItem; item->setText(text); - //item->setDetail(hint); - //item->setIcon(m_icons.keywordIcon()); - item->keepCompletionOperator(m_completionOperator); + item->setDetail(hint); + item->setIcon(m_icons.keywordIcon()); + item->setCompletionOperator(m_completionOperator); m_completions.append(item); } } @@ -567,11 +568,11 @@ void ClangCompletionAssistProcessor::addCompletionItem(const QString &text, const QIcon &icon, int order) { - ClangAssistProposalItem *item = new ClangAssistProposalItem; + auto *item = new ClangPreprocessorAssistProposalItem; item->setText(text); - //item->setIcon(icon); TODO: Add item for macros and includes + item->setIcon(icon); item->setOrder(order); - item->keepCompletionOperator(m_completionOperator); + item->setCompletionOperator(m_completionOperator); m_completions.append(item); } diff --git a/src/plugins/clangcodemodel/clangpreprocessorassistproposalitem.cpp b/src/plugins/clangcodemodel/clangpreprocessorassistproposalitem.cpp new file mode 100644 index 0000000000..23fcd4473b --- /dev/null +++ b/src/plugins/clangcodemodel/clangpreprocessorassistproposalitem.cpp @@ -0,0 +1,169 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +****************************************************************************/ + +#include "clangpreprocessorassistproposalitem.h" + +#include <texteditor/texteditor.h> + +#include <cplusplus/Token.h> + +namespace ClangCodeModel { + +bool ClangPreprocessorAssistProposalItem::prematurelyApplies(const QChar &typedCharacter) const +{ + bool applies = false; + + if (isInclude()) + applies = typedCharacter == QLatin1Char('/') && text().endsWith(QLatin1Char('/')); + + if (applies) + m_typedCharacter = typedCharacter; + + return applies; +} + +bool ClangPreprocessorAssistProposalItem::implicitlyApplies() const +{ + return false; +} + +void ClangPreprocessorAssistProposalItem::apply(TextEditor::TextEditorWidget *editorWidget, + int basePosition) const +{ + // TODO move in an extra class under tests + + QString textToBeInserted = text(); + + QString extraCharacters; + int extraLength = 0; + int cursorOffset = 0; + + if (isInclude()) { + if (!textToBeInserted.endsWith(QLatin1Char('/'))) { + extraCharacters += QLatin1Char((m_completionOperator == CPlusPlus::T_ANGLE_STRING_LITERAL) ? '>' : '"'); + } else { + if (m_typedCharacter == QLatin1Char('/')) // Eat the slash + m_typedCharacter = QChar(); + } + } + + if (!m_typedCharacter.isNull()) { + extraCharacters += m_typedCharacter; + if (cursorOffset != 0) + --cursorOffset; + } + + // Avoid inserting characters that are already there + const int endsPosition = editorWidget->position(TextEditor::EndOfLinePosition); + const QString existingText = editorWidget->textAt(editorWidget->position(), endsPosition - editorWidget->position()); + int existLength = 0; + if (!existingText.isEmpty()) { + // Calculate the exist length in front of the extra chars + existLength = textToBeInserted.length() - (editorWidget->position() - basePosition); + while (!existingText.startsWith(textToBeInserted.right(existLength))) { + if (--existLength == 0) + break; + } + } + for (int i = 0; i < extraCharacters.length(); ++i) { + const QChar a = extraCharacters.at(i); + const QChar b = editorWidget->characterAt(editorWidget->position() + i + existLength); + if (a == b) + ++extraLength; + else + break; + } + + textToBeInserted += extraCharacters; + + // Insert the remainder of the name + const int length = editorWidget->position() - basePosition + existLength + extraLength; + const auto textToBeReplaced = editorWidget->textAt(basePosition, length); + + if (textToBeReplaced != textToBeInserted) { + editorWidget->setCursorPosition(basePosition); + editorWidget->replace(length, textToBeInserted); + if (cursorOffset) + editorWidget->setCursorPosition(editorWidget->position() + cursorOffset); + } +} + +void ClangPreprocessorAssistProposalItem::setText(const QString &text) +{ + m_text = text; +} + +QString ClangPreprocessorAssistProposalItem::text() const +{ + return m_text; +} + +void ClangPreprocessorAssistProposalItem::setIcon(const QIcon &icon) +{ + m_icon = icon; +} + +QIcon ClangPreprocessorAssistProposalItem::icon() const +{ + return m_icon; +} + +void ClangPreprocessorAssistProposalItem::setDetail(const QString &detail) +{ + m_detail = detail; +} + +QString ClangPreprocessorAssistProposalItem::detail() const +{ + return QString(); +} + +bool ClangPreprocessorAssistProposalItem::isSnippet() const +{ + return false; +} + +bool ClangPreprocessorAssistProposalItem::isValid() const +{ + return true; +} + +quint64 ClangPreprocessorAssistProposalItem::hash() const +{ + return 0; +} + +void ClangPreprocessorAssistProposalItem::setCompletionOperator(uint completionOperator) +{ + m_completionOperator = completionOperator; +} + +bool ClangPreprocessorAssistProposalItem::isInclude() const +{ + return m_completionOperator == CPlusPlus::T_STRING_LITERAL + || m_completionOperator == CPlusPlus::T_ANGLE_STRING_LITERAL; +} + +} // namespace ClangCodeModel diff --git a/src/plugins/clangcodemodel/clangpreprocessorassistproposalitem.h b/src/plugins/clangcodemodel/clangpreprocessorassistproposalitem.h new file mode 100644 index 0000000000..7b63d432bd --- /dev/null +++ b/src/plugins/clangcodemodel/clangpreprocessorassistproposalitem.h @@ -0,0 +1,72 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +****************************************************************************/ + +#ifndef CLANGCODEMODEL_PREPROCESSORASSISTPROPOSALITEM_H +#define CLANGCODEMODEL_PREPROCESSORASSISTPROPOSALITEM_H + +#include <texteditor/codeassist/assistproposaliteminterface.h> + +#include <QIcon> +#include <QString> + +namespace ClangCodeModel { + +class ClangPreprocessorAssistProposalItem final : public TextEditor::AssistProposalItemInterface +{ +public: + bool prematurelyApplies(const QChar &typedChar) const final; + virtual bool implicitlyApplies() const final; + void apply(TextEditor::TextEditorWidget *editorWidget, int basePosition) const final; + + void setText(const QString &text); + QString text() const final; + + void setIcon(const QIcon &icon); + QIcon icon() const final; + + void setDetail(const QString &detail); + QString detail() const final; + + bool isSnippet() const final; + bool isValid() const final; + + quint64 hash() const final; + + void setCompletionOperator(uint completionOperator); + +private: + bool isInclude() const; + +private: + QString m_text; + QString m_detail; + QIcon m_icon; + uint m_completionOperator; + mutable QChar m_typedCharacter; +}; + +} // namespace ClangCodeModel + +#endif // CLANGCODEMODEL_PREPROCESSORASSISTPROPOSALITEM_H diff --git a/src/plugins/texteditor/codeassist/assistproposaliteminterface.h b/src/plugins/texteditor/codeassist/assistproposaliteminterface.h index 797bf78c7c..38fc4a2c73 100644 --- a/src/plugins/texteditor/codeassist/assistproposaliteminterface.h +++ b/src/plugins/texteditor/codeassist/assistproposaliteminterface.h @@ -48,7 +48,7 @@ public: virtual QString text() const = 0; virtual bool implicitlyApplies() const = 0; - virtual bool prematurelyApplies(const QChar &character) const = 0; + virtual bool prematurelyApplies(const QChar &typedCharacter) const = 0; virtual void apply(TextEditorWidget *editorWidget, int basePosition) const = 0; virtual QIcon icon() const = 0; virtual QString detail() const = 0; |