Commit ecca2692 authored by Marco Bubke's avatar Marco Bubke
Browse files

Clang: Add ClangPreprocessorAssistProposalItem



Change-Id: Ifb27b9a21b9a2fe9a04496bbb70fa3fa07d1f89c
Reviewed-by: default avatarNikolai Kosjar <nikolai.kosjar@theqtcompany.com>
parent bb3b7307
......@@ -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;
......
......@@ -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
......
......@@ -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
......
......@@ -79,6 +79,8 @@ QtcPlugin {
"clanghighlightingmarksreporter.h",
"clangmodelmanagersupport.cpp",
"clangmodelmanagersupport.h",
"clangpreprocessorassistproposalitem.cpp",
"clangpreprocessorassistproposalitem.h",
"clangtextmark.cpp",
"clangtextmark.h",
"clangutils.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);
}
......
/****************************************************************************
**
** 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
/****************************************************************************
**
** 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
......@@ -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;
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment