RedPanda-CPP/RedPandaIDE/widgets/codecompletionpopup.cpp

966 lines
34 KiB
C++
Raw Normal View History

2021-12-26 23:18:28 +08:00
/*
* Copyright (C) 2020-2022 Roy Qu (royqh1979@gmail.com)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
2021-08-29 00:48:23 +08:00
#include "codecompletionpopup.h"
2021-08-24 15:05:10 +08:00
#include "../utils.h"
#include "../mainwindow.h"
#include "../editor.h"
#include "../editorlist.h"
#include "../symbolusagemanager.h"
#include "../colorscheme.h"
2021-08-23 21:50:53 +08:00
2021-08-24 09:59:44 +08:00
#include <QKeyEvent>
2021-08-24 15:05:10 +08:00
#include <QVBoxLayout>
2021-08-27 16:38:55 +08:00
#include <QDebug>
2021-08-28 09:01:40 +08:00
#include <QApplication>
2021-08-24 09:59:44 +08:00
2021-08-29 00:48:23 +08:00
CodeCompletionPopup::CodeCompletionPopup(QWidget *parent) :
2022-01-04 16:50:54 +08:00
QWidget(parent),
mMutex(QMutex::Recursive)
2021-08-23 21:50:53 +08:00
{
2021-08-24 09:59:44 +08:00
setWindowFlags(Qt::Popup);
mListView = new CodeCompletionListView(this);
2021-08-25 08:48:33 +08:00
mModel=new CodeCompletionListModel(&mCompletionStatementList);
2021-08-28 09:01:40 +08:00
mModel->setColorCallback([this](PStatement statement)->QColor{
StatementKind kind;
if (mParser) {
kind = mParser->getKindOfStatement(statement);
} else {
kind = statement->kind;
}
PColorSchemeItem item = mColors->value(kind,PColorSchemeItem());
if (item) {
return item->foreground();
}
return palette().color(QPalette::Text);
2021-08-28 09:01:40 +08:00
});
2021-08-25 08:48:33 +08:00
mListView->setModel(mModel);
2021-08-24 09:59:44 +08:00
setLayout(new QVBoxLayout());
layout()->addWidget(mListView);
layout()->setMargin(0);
2021-08-25 00:20:07 +08:00
mShowKeywords=true;
mUseCppKeyword=true;
2021-08-27 16:38:55 +08:00
mRecordUsage = false;
mSortByScope = true;
2021-08-25 00:20:07 +08:00
mOnlyGlobals = false;
mShowCount = 1000;
2021-09-30 20:10:48 +08:00
mShowCodeSnippets = true;
2021-08-25 00:20:07 +08:00
mIgnoreCase = false;
2021-08-23 21:50:53 +08:00
}
2021-08-29 00:48:23 +08:00
CodeCompletionPopup::~CodeCompletionPopup()
2021-08-23 21:50:53 +08:00
{
2021-08-25 08:48:33 +08:00
delete mListView;
delete mModel;
2021-08-24 09:59:44 +08:00
}
2021-08-29 00:48:23 +08:00
void CodeCompletionPopup::setKeypressedCallback(const KeyPressedCallback &newKeypressedCallback)
2021-08-24 09:59:44 +08:00
{
mListView->setKeypressedCallback(newKeypressedCallback);
}
2021-12-04 10:02:07 +08:00
void CodeCompletionPopup::prepareSearch(
const QString &preWord,
const QStringList &ownerExpression,
const QString& memberOperator,
const QStringList& memberExpression,
const QString &filename,
int line)
2021-12-03 11:40:05 +08:00
{
QMutexLocker locker(&mMutex);
if (!isEnabled())
return;
//Screen.Cursor := crHourglass;
QCursor oldCursor = cursor();
setCursor(Qt::CursorShape::WaitCursor);
2021-12-04 10:02:07 +08:00
mMemberPhrase = memberExpression.join("");
mMemberOperator = memberOperator;
2021-12-03 11:40:05 +08:00
if (preWord.isEmpty()) {
mIncludedFiles = mParser->getFileIncludes(filename);
2021-12-04 10:02:07 +08:00
getCompletionFor(ownerExpression,memberOperator,memberExpression, filename,line);
2021-12-03 11:40:05 +08:00
} else {
2021-12-04 14:53:21 +08:00
getCompletionListForPreWord(preWord);
2021-12-03 11:40:05 +08:00
}
setCursor(oldCursor);
}
2021-12-04 14:53:21 +08:00
bool CodeCompletionPopup::search(const QString &memberPhrase, bool autoHideOnSingleResult)
2021-08-25 00:20:07 +08:00
{
QMutexLocker locker(&mMutex);
2021-12-04 14:53:21 +08:00
mMemberPhrase = memberPhrase;
2021-08-25 00:20:07 +08:00
2021-08-25 08:48:33 +08:00
if (!isEnabled()) {
2021-08-25 00:20:07 +08:00
hide();
return false;
}
QCursor oldCursor = cursor();
setCursor(Qt::CursorShape::WaitCursor);
// filter fFullCompletionStatementList to fCompletionStatementList
2021-12-04 14:53:21 +08:00
filterList(memberPhrase);
//if can't find a destructor, maybe '~' is only an operator
2021-12-04 10:02:07 +08:00
// if (mCompletionStatementList.isEmpty() && phrase.startsWith('~')) {
// symbol = phrase.mid(1);
// filterList(symbol);
// }
2021-08-25 08:48:33 +08:00
mModel->notifyUpdated();
setCursor(oldCursor);
2021-08-25 00:20:07 +08:00
if (!mCompletionStatementList.isEmpty()) {
mListView->setCurrentIndex(mModel->index(0,0));
2021-08-25 00:20:07 +08:00
// if only one suggestion, and is exactly the symbol to search, hide the frame (the search is over)
// if only one suggestion and auto hide , don't show the frame
if(mCompletionStatementList.count() == 1)
if (autoHideOnSingleResult
2021-12-04 14:53:21 +08:00
|| (memberPhrase == mCompletionStatementList.front()->command)) {
2021-08-25 00:20:07 +08:00
return true;
}
} else {
hide();
}
2021-08-25 08:48:33 +08:00
return false;
2021-08-25 00:20:07 +08:00
}
2021-08-29 00:48:23 +08:00
PStatement CodeCompletionPopup::selectedStatement()
2021-08-26 17:48:23 +08:00
{
if (isEnabled()) {
int index = mListView->currentIndex().row();
if (mListView->currentIndex().isValid()
&& (index<mCompletionStatementList.count()) ) {
return mCompletionStatementList[index];
} else {
if (!mCompletionStatementList.isEmpty())
return mCompletionStatementList.front();
else
return PStatement();
}
} else
return PStatement();
}
2021-08-29 00:48:23 +08:00
void CodeCompletionPopup::addChildren(PStatement scopeStatement, const QString &fileName, int line)
2021-08-24 15:05:10 +08:00
{
if (scopeStatement && !isIncluded(scopeStatement->fileName)
&& !isIncluded(scopeStatement->definitionFileName))
return;
const StatementMap& children = mParser->statementList().childrenStatements(scopeStatement);
if (children.isEmpty())
return;
if (!scopeStatement) { //Global scope
2021-08-29 00:48:23 +08:00
for (const PStatement& childStatement: children) {
2021-08-24 15:05:10 +08:00
if (childStatement->fileName.isEmpty()) {
// hard defines
addStatement(childStatement,fileName,-1);
} else if (!( childStatement->kind == StatementKind::skConstructor
|| childStatement->kind == StatementKind::skDestructor
|| childStatement->kind == StatementKind::skBlock)
&& (!mAddedStatements.contains(childStatement->command))
&& (
isIncluded(childStatement->fileName)
|| isIncluded(childStatement->definitionFileName)
)
) {
//we must check if the statement is included by the file
addStatement(childStatement,fileName,line);
}
}
} else {
2021-08-29 00:48:23 +08:00
for (const PStatement& childStatement: children) {
2021-08-24 15:05:10 +08:00
if (!( childStatement->kind == StatementKind::skConstructor
|| childStatement->kind == StatementKind::skDestructor
|| childStatement->kind == StatementKind::skBlock)
&& (!mAddedStatements.contains(childStatement->command)))
addStatement(childStatement,fileName,line);
}
}
}
2021-08-29 00:48:23 +08:00
void CodeCompletionPopup::addStatement(PStatement statement, const QString &fileName, int line)
2021-08-24 15:05:10 +08:00
{
2021-08-25 00:20:07 +08:00
if (mAddedStatements.contains(statement->command))
return;
2021-08-24 15:05:10 +08:00
if ((line!=-1)
&& (line < statement->line)
&& (fileName == statement->fileName))
return;
mAddedStatements.insert(statement->command);
mFullCompletionStatementList.append(statement);
}
static bool nameComparator(PStatement statement1,PStatement statement2) {
return statement1->command < statement2->command;
}
static bool defaultComparator(PStatement statement1,PStatement statement2) {
if (statement1->caseMatch && !statement2->caseMatch) {
return true;
} else if (!statement1->caseMatch && statement2->caseMatch) {
return false;
}
2021-08-24 15:05:10 +08:00
// Show user template first
2021-09-30 21:25:48 +08:00
if (statement1->kind == StatementKind::skUserCodeSnippet) {
if (statement2->kind != StatementKind::skUserCodeSnippet)
2021-08-24 15:05:10 +08:00
return true;
else
return statement1->command < statement2->command;
2021-09-30 21:25:48 +08:00
} else if (statement2->kind == StatementKind::skUserCodeSnippet) {
2021-08-24 15:05:10 +08:00
return false;
// show keywords first
} else if ((statement1->kind == StatementKind::skKeyword)
&& (statement2->kind != StatementKind::skKeyword)) {
return true;
} else if ((statement1->kind != StatementKind::skKeyword)
&& (statement2->kind == StatementKind::skKeyword)) {
return false;
} else
return nameComparator(statement1,statement2);
2021-08-24 15:05:10 +08:00
}
static bool sortByScopeComparator(PStatement statement1,PStatement statement2){
if (statement1->caseMatch && !statement2->caseMatch) {
return true;
} else if (!statement1->caseMatch && statement2->caseMatch) {
return false;
}
2021-08-24 15:05:10 +08:00
// Show user template first
2021-09-30 21:25:48 +08:00
if (statement1->kind == StatementKind::skUserCodeSnippet) {
if (statement2->kind != StatementKind::skUserCodeSnippet)
2021-08-24 15:05:10 +08:00
return true;
else
return statement1->command < statement2->command;
2021-09-30 21:25:48 +08:00
} else if (statement2->kind == StatementKind::skUserCodeSnippet) {
2021-08-24 15:05:10 +08:00
return false;
// show keywords first
} else if (statement1->kind == StatementKind::skKeyword) {
if (statement2->kind != StatementKind::skKeyword)
return true;
else
return statement1->command < statement2->command;
} else if (statement2->kind == StatementKind::skKeyword) {
return false;
// Show stuff from local headers first
2021-08-28 09:01:40 +08:00
} else if (!(statement1->inSystemHeader) && statement2->inSystemHeader) {
return true;
} else if (statement1->inSystemHeader && !(statement2->inSystemHeader)) {
2021-08-24 15:05:10 +08:00
return false;
// Show local statements first
} else if (statement1->scope != StatementScope::ssGlobal
2021-08-27 16:38:55 +08:00
&& statement2->scope == StatementScope::ssGlobal ) {
2021-08-24 15:05:10 +08:00
return true;
} else if (statement1->scope == StatementScope::ssGlobal
2021-08-27 16:38:55 +08:00
&& statement2->scope != StatementScope::ssGlobal ) {
2021-08-24 15:05:10 +08:00
return false;
} else
return nameComparator(statement1,statement2);
2021-08-24 15:05:10 +08:00
}
static bool sortWithUsageComparator(PStatement statement1,PStatement statement2) {
if (statement1->caseMatch && !statement2->caseMatch) {
return true;
} else if (!statement1->caseMatch && statement2->caseMatch) {
return false;
}
2021-08-24 15:05:10 +08:00
// Show user template first
2021-09-30 21:25:48 +08:00
if (statement1->kind == StatementKind::skUserCodeSnippet) {
if (statement2->kind != StatementKind::skUserCodeSnippet)
2021-08-24 15:05:10 +08:00
return true;
else
return statement1->command < statement2->command;
2021-09-30 21:25:48 +08:00
} else if (statement2->kind == StatementKind::skUserCodeSnippet) {
2021-08-24 15:05:10 +08:00
return false;
//show most freq first
} else if (statement1->freqTop > statement2->freqTop) {
return true;
} else if (statement1->freqTop < statement2->freqTop) {
return false;
// show keywords first
} else if ((statement1->kind != StatementKind::skKeyword)
&& (statement2->kind == StatementKind::skKeyword)) {
return true;
} else if ((statement1->kind == StatementKind::skKeyword)
&& (statement2->kind != StatementKind::skKeyword)) {
2021-08-24 15:05:10 +08:00
return false;
} else
return nameComparator(statement1,statement2);
2021-08-24 15:05:10 +08:00
}
static bool sortByScopeWithUsageComparator(PStatement statement1,PStatement statement2){
if (statement1->caseMatch && !statement2->caseMatch) {
return true;
} else if (!statement1->caseMatch && statement2->caseMatch) {
return false;
}
2021-08-24 15:05:10 +08:00
// Show user template first
2021-09-30 21:25:48 +08:00
if (statement1->kind == StatementKind::skUserCodeSnippet) {
if (statement2->kind != StatementKind::skUserCodeSnippet)
2021-08-24 15:05:10 +08:00
return true;
else
return statement1->command < statement2->command;
2021-09-30 21:25:48 +08:00
} else if (statement2->kind == StatementKind::skUserCodeSnippet) {
2021-08-24 15:05:10 +08:00
return false;
//show most freq first
} else if (statement1->freqTop > statement2->freqTop) {
return true;
} else if (statement1->freqTop < statement2->freqTop) {
return false;
// show keywords first
} else if (statement1->kind == StatementKind::skKeyword) {
if (statement2->kind != StatementKind::skKeyword)
return true;
else
return statement1->command < statement2->command;
} else if (statement2->kind == StatementKind::skKeyword) {
return false;
// Show stuff from local headers first
2021-08-28 09:01:40 +08:00
} else if (!(statement1->inSystemHeader) && statement2->inSystemHeader) {
return true;
} else if (statement1->inSystemHeader && !(statement2->inSystemHeader)) {
2021-08-24 15:05:10 +08:00
return false;
// Show local statements first
} else if (statement1->scope != StatementScope::ssGlobal
2021-08-27 16:38:55 +08:00
&& statement2->scope == StatementScope::ssGlobal ) {
2021-08-24 15:05:10 +08:00
return true;
} else if (statement1->scope == StatementScope::ssGlobal
2021-08-27 16:38:55 +08:00
&& statement2->scope != StatementScope::ssGlobal ) {
2021-08-24 15:05:10 +08:00
return false;
} else
return nameComparator(statement1,statement2);
2021-08-24 15:05:10 +08:00
}
2021-08-29 00:48:23 +08:00
void CodeCompletionPopup::filterList(const QString &member)
2021-08-24 15:05:10 +08:00
{
QMutexLocker locker(&mMutex);
mCompletionStatementList.clear();
if (!mParser)
return;
if (!mParser->enabled())
return;
//we don't need to freeze here since we use smart pointers
// and data have been retrieved from the parser
// if (!mParser->freeze())
// return;
// {
// auto action = finally([this]{
// mParser->unFreeze();
// });
// if (mParserSerialId!=mParser->serialId()) {
// return;
// }
2021-08-25 00:20:07 +08:00
mCompletionStatementList.clear();
2021-08-24 15:05:10 +08:00
if (!member.isEmpty()) { // filter
2021-08-25 00:20:07 +08:00
mCompletionStatementList.reserve(mFullCompletionStatementList.size());
2021-08-29 00:48:23 +08:00
foreach (const PStatement& statement, mFullCompletionStatementList) {
2021-08-24 15:05:10 +08:00
Qt::CaseSensitivity cs = (mIgnoreCase?
Qt::CaseInsensitive:
Qt::CaseSensitive);
if (statement->command.startsWith(member, cs)) {
if (mIgnoreCase) {
statement->caseMatch =
statement->command.startsWith(
member,Qt::CaseSensitive);
} else {
statement->caseMatch = true;
}
2021-08-25 00:20:07 +08:00
mCompletionStatementList.append(statement);
}
2021-08-24 15:05:10 +08:00
}
} else
2021-08-25 00:20:07 +08:00
mCompletionStatementList.append(mFullCompletionStatementList);
2021-08-24 15:05:10 +08:00
if (mRecordUsage) {
int topCount = 0;
int secondCount = 0;
int thirdCount = 0;
int usageCount;
2021-08-29 00:48:23 +08:00
foreach (const PStatement& statement,mCompletionStatementList) {
if (statement->usageCount == -1) {
PSymbolUsage usage = pMainWindow->symbolUsageManager()->findUsage(statement->fullName);
if (usage) {
usageCount = usage->count;
} else {
usageCount = 0;
}
2021-08-24 15:05:10 +08:00
statement->usageCount = usageCount;
} else
usageCount = statement->usageCount;
if (usageCount>topCount) {
thirdCount = secondCount;
secondCount = topCount;
topCount = usageCount;
} else if (usageCount == topCount) {
continue;
} else if (usageCount > secondCount) {
thirdCount = secondCount;
secondCount = usageCount;
} else if (usageCount == secondCount) {
continue;
} else if (usageCount>thirdCount) {
thirdCount = usageCount;
}
}
2021-08-29 00:48:23 +08:00
foreach (const PStatement& statement, mCompletionStatementList) {
2021-08-24 15:05:10 +08:00
if (statement->usageCount == 0) {
statement->freqTop = 0;
} else if (statement->usageCount == topCount) {
statement->freqTop = 30;
} else if (statement->usageCount == secondCount) {
statement->freqTop = 20;
} else if (statement->usageCount == thirdCount) {
statement->freqTop = 10;
}
}
if (mSortByScope) {
2021-08-25 00:20:07 +08:00
std::sort(mCompletionStatementList.begin(),
mCompletionStatementList.end(),
sortByScopeWithUsageComparator);
2021-08-24 15:05:10 +08:00
} else {
2021-08-25 00:20:07 +08:00
std::sort(mCompletionStatementList.begin(),
mCompletionStatementList.end(),
sortWithUsageComparator);
2021-08-24 15:05:10 +08:00
}
} else if (mSortByScope) {
2021-08-25 00:20:07 +08:00
std::sort(mCompletionStatementList.begin(),
mCompletionStatementList.end(),
sortByScopeComparator);
2021-08-24 15:05:10 +08:00
} else {
2021-08-25 00:20:07 +08:00
std::sort(mCompletionStatementList.begin(),
mCompletionStatementList.end(),
defaultComparator);
}
// }
}
2021-12-04 10:02:07 +08:00
void CodeCompletionPopup::getCompletionFor(
const QStringList &ownerExpression,
const QString& memberOperator,
const QStringList& memberExpression,
const QString &fileName,
int line)
2021-08-25 00:20:07 +08:00
{
if(!mParser)
return;
if (!mParser->enabled())
return;
2021-12-04 10:02:07 +08:00
if (memberOperator.isEmpty() && ownerExpression.isEmpty() && memberExpression.isEmpty())
2021-12-03 20:08:18 +08:00
return;
if (!mParser->freeze())
return;
{
auto action = finally([this]{
mParser->unFreeze();
});
2021-12-04 10:02:07 +08:00
if (memberOperator.isEmpty()) {
2021-12-03 20:08:18 +08:00
//C++ preprocessor directives
2021-12-04 10:02:07 +08:00
if (mMemberPhrase.startsWith('#')) {
2021-12-03 20:08:18 +08:00
if (mShowKeywords) {
foreach (const QString& keyword, CppDirectives) {
addKeyword(keyword);
}
}
return;
}
//docstring tags (javadoc style)
2021-12-04 10:02:07 +08:00
if (mMemberPhrase.startsWith('@')) {
2021-12-03 20:08:18 +08:00
if (mShowKeywords) {
foreach (const QString& keyword,JavadocTags) {
addKeyword(keyword);
}
}
return;
}
//the identifier to be completed is not a member of variable/class
if (mShowCodeSnippets) {
//add custom code templates
foreach (const PCodeSnippet& codeIn,mCodeSnippets) {
if (!codeIn->code.isEmpty()) {
PStatement statement = std::make_shared<Statement>();
statement->command = codeIn->prefix;
statement->value = codeIn->code;
statement->kind = StatementKind::skUserCodeSnippet;
statement->fullName = codeIn->prefix;
statement->usageCount = 0;
statement->freqTop = 0;
mFullCompletionStatementList.append(statement);
}
}
}
if (mShowKeywords) {
//add keywords
if (mUseCppKeyword) {
foreach (const QString& keyword,CppKeywords.keys()) {
addKeyword(keyword);
}
} else {
foreach (const QString& keyword,CKeywords) {
addKeyword(keyword);
}
}
}
PStatement scopeStatement = mCurrentStatement;
// repeat until reach global
while (scopeStatement) {
//add members of current scope that not added before
if (scopeStatement->kind == StatementKind::skClass) {
addChildren(scopeStatement, fileName, -1);
} else {
addChildren(scopeStatement, fileName, line);
}
// add members of all usings (in current scope ) and not added before
2021-08-29 00:48:23 +08:00
foreach (const QString& namespaceName,scopeStatement->usingList) {
2021-08-25 00:20:07 +08:00
PStatementList namespaceStatementsList =
mParser->findNamespace(namespaceName);
if (!namespaceStatementsList)
continue;
2021-08-29 00:48:23 +08:00
foreach (const PStatement& namespaceStatement,*namespaceStatementsList) {
2021-08-25 00:20:07 +08:00
addChildren(namespaceStatement, fileName, line);
}
}
scopeStatement=scopeStatement->parentScope.lock();
}
// add all global members and not added before
addChildren(nullptr, fileName, line);
// add members of all fusings
mUsings = mParser->getFileUsings(fileName);
2021-08-29 00:48:23 +08:00
foreach (const QString& namespaceName, mUsings) {
2021-08-25 00:20:07 +08:00
PStatementList namespaceStatementsList =
mParser->findNamespace(namespaceName);
if (!namespaceStatementsList)
continue;
2021-08-29 00:48:23 +08:00
foreach (const PStatement& namespaceStatement, *namespaceStatementsList) {
2021-08-25 00:20:07 +08:00
addChildren(namespaceStatement, fileName, line);
}
}
2021-12-03 20:24:49 +08:00
} else {
//the identifier to be completed is a member of variable/class
2021-12-04 10:02:07 +08:00
if (memberOperator == "::" && ownerExpression.isEmpty()) {
2021-12-03 20:24:49 +08:00
// start with '::', we only find in global
// add all global members and not added before
addChildren(nullptr, fileName, line);
return;
}
if (memberExpression.length()==2 && memberExpression.front()!="~")
return;
if (memberExpression.length()>2)
return;
2021-12-08 19:13:47 +08:00
2021-12-03 20:24:49 +08:00
PStatement scope = mCurrentStatement;//the scope the expression in
PStatement parentTypeStatement;
2021-12-08 19:13:47 +08:00
// QString scopeName = ownerExpression.join("");
// PStatement ownerStatement = mParser->findStatementOf(
// fileName,
// scopeName,
// mCurrentStatement,
// parentTypeStatement);
PEvalStatement ownerStatement = mParser->evalExpression(fileName,
ownerExpression,
scope);
2021-12-04 14:53:21 +08:00
// qDebug()<<scopeName;
// qDebug()<<memberOperator;
// qDebug()<<memberExpression;
2021-12-08 19:13:47 +08:00
if(!ownerStatement || !ownerStatement->effectiveTypeStatement) {
2021-12-08 21:44:40 +08:00
// qDebug()<<"statement not found!";
2021-12-03 20:24:49 +08:00
return;
}
// qDebug()<<"found: "<<ownerStatement->fullName;
2021-12-03 20:24:49 +08:00
if (memberOperator == "::") {
2021-12-08 19:13:47 +08:00
if (ownerStatement->kind==EvalStatementKind::Namespace) {
2021-12-03 20:24:49 +08:00
//there might be many statements corresponding to one namespace;
2021-08-25 00:20:07 +08:00
PStatementList namespaceStatementsList =
2021-12-08 19:13:47 +08:00
mParser->findNamespace(ownerStatement->baseType);
2021-08-25 00:20:07 +08:00
if (namespaceStatementsList) {
2021-08-29 00:48:23 +08:00
foreach (const PStatement& namespaceStatement, *namespaceStatementsList) {
2021-08-25 00:20:07 +08:00
addChildren(namespaceStatement, fileName, line);
}
}
2021-12-03 20:24:49 +08:00
return;
2021-08-25 00:20:07 +08:00
}
}
2021-08-25 00:20:07 +08:00
// find the most inner scope statement that has a name (not a block)
PStatement scopeTypeStatement = mCurrentStatement;
while (scopeTypeStatement && !isScopeTypeKind(scopeTypeStatement->kind)) {
scopeTypeStatement = scopeTypeStatement->parentScope.lock();
}
if (
2021-12-03 20:24:49 +08:00
(memberOperator != "::")
2021-08-25 00:20:07 +08:00
&& (
2021-12-08 19:13:47 +08:00
ownerStatement->kind == EvalStatementKind::Variable)
2021-08-25 00:20:07 +08:00
) {
// Get type statement of current (scope) statement
2021-12-08 19:13:47 +08:00
PStatement classTypeStatement = ownerStatement->effectiveTypeStatement;
2021-08-25 00:20:07 +08:00
if (!classTypeStatement)
return;
//is a smart pointer
if (STLPointers.contains(classTypeStatement->fullName)
2021-12-03 20:24:49 +08:00
&& (memberOperator == "->"
2021-12-08 21:44:40 +08:00
|| memberOperator == "->*")
&& ownerStatement->baseStatement) {
2021-08-25 00:20:07 +08:00
QString typeName= mParser->findFirstTemplateParamOf(
fileName,
2021-12-08 21:44:40 +08:00
ownerStatement->baseStatement->type,
2021-12-08 19:13:47 +08:00
scope);
2021-08-25 00:20:07 +08:00
classTypeStatement = mParser->findTypeDefinitionOf(
fileName,
typeName,
2021-12-08 19:13:47 +08:00
scope);
2021-08-25 00:20:07 +08:00
if (!classTypeStatement)
return;
}
if (!isIncluded(classTypeStatement->fileName) &&
!isIncluded(classTypeStatement->definitionFileName))
return;
2021-12-08 19:13:47 +08:00
if ((classTypeStatement == scopeTypeStatement) || (ownerStatement->effectiveTypeStatement->command == "this")) {
2021-08-25 00:20:07 +08:00
//we can use all members
addChildren(classTypeStatement,fileName,-1);
} else { // we can only use public members
const StatementMap& children = mParser->statementList().childrenStatements(classTypeStatement);
if (children.isEmpty())
return;
2021-08-29 00:48:23 +08:00
foreach (const PStatement& childStatement, children) {
2021-08-25 00:20:07 +08:00
if ((childStatement->classScope==StatementClassScope::scsPublic)
&& !(
childStatement->kind == StatementKind::skConstructor
|| childStatement->kind == StatementKind::skDestructor)
&& !mAddedStatements.contains(childStatement->command)) {
addStatement(childStatement,fileName,-1);
}
}
}
//todo friend
2021-12-03 20:24:49 +08:00
} else if ((memberOperator == "::")
2021-12-08 19:13:47 +08:00
&& (ownerStatement->kind == EvalStatementKind::Type)) {
2021-08-25 00:20:07 +08:00
//we can add all child enum definess
2021-12-08 19:13:47 +08:00
PStatement classTypeStatement = ownerStatement->effectiveTypeStatement;
if (!classTypeStatement)
2021-08-25 00:20:07 +08:00
return;
if (!isIncluded(classTypeStatement->fileName) &&
!isIncluded(classTypeStatement->definitionFileName))
return;
2021-12-08 19:13:47 +08:00
if (classTypeStatement->kind == StatementKind::skEnumType
|| classTypeStatement->kind == StatementKind::skEnumClassType) {
2021-08-25 00:20:07 +08:00
const StatementMap& children =
mParser->statementList().childrenStatements(classTypeStatement);
2021-12-08 19:13:47 +08:00
foreach (const PStatement& child,children) {
addStatement(child,fileName,line);
2021-08-25 00:20:07 +08:00
}
} else {
2021-12-08 19:13:47 +08:00
//class
if (classTypeStatement == scopeTypeStatement) {
//we can use all static members
const StatementMap& children =
mParser->statementList().childrenStatements(classTypeStatement);
foreach (const PStatement& childStatement, children) {
if (
(childStatement->isStatic)
|| (childStatement->kind == StatementKind::skTypedef
|| childStatement->kind == StatementKind::skClass
|| childStatement->kind == StatementKind::skEnum
|| childStatement->kind == StatementKind::skEnumClassType
|| childStatement->kind == StatementKind::skEnumType
)) {
2021-08-25 00:20:07 +08:00
addStatement(childStatement,fileName,-1);
2021-12-08 19:13:47 +08:00
}
}
} else {
// we can only use public static members
const StatementMap& children =
mParser->statementList().childrenStatements(classTypeStatement);
foreach (const PStatement& childStatement,children) {
if (
(childStatement->isStatic)
|| (childStatement->kind == StatementKind::skTypedef
|| childStatement->kind == StatementKind::skClass
|| childStatement->kind == StatementKind::skEnum
|| childStatement->kind == StatementKind::skEnumClassType
|| childStatement->kind == StatementKind::skEnumType
)) {
if (childStatement->classScope == StatementClassScope::scsPublic)
addStatement(childStatement,fileName,-1);
}
2021-08-25 00:20:07 +08:00
}
}
}
}
}
2021-08-24 15:05:10 +08:00
}
2021-08-25 00:20:07 +08:00
}
2021-12-04 14:53:21 +08:00
void CodeCompletionPopup::getCompletionListForPreWord(const QString &preWord)
{
mFullCompletionStatementList.clear();
if (preWord == "long") {
addKeyword("long");
addKeyword("double");
addKeyword("int");
} else if (preWord == "short") {
addKeyword("int");
} else if (preWord == "signed") {
addKeyword("long");
addKeyword("short");
addKeyword("int");
addKeyword("char");
} else if (preWord == "unsigned") {
addKeyword("long");
addKeyword("short");
addKeyword("int");
addKeyword("char");
}
}
void CodeCompletionPopup::addKeyword(const QString &keyword)
{
PStatement statement = std::make_shared<Statement>();
statement->command = keyword;
statement->kind = StatementKind::skKeyword;
statement->fullName = keyword;
statement->usageCount = 0;
statement->freqTop = 0;
mFullCompletionStatementList.append(statement);
}
2021-08-29 00:48:23 +08:00
bool CodeCompletionPopup::isIncluded(const QString &fileName)
2021-08-25 00:20:07 +08:00
{
return mIncludedFiles.contains(fileName);
}
2021-12-04 10:02:07 +08:00
const QString &CodeCompletionPopup::memberOperator() const
{
return mMemberOperator;
}
2021-09-30 20:10:48 +08:00
const QList<PCodeSnippet> &CodeCompletionPopup::codeSnippets() const
{
return mCodeSnippets;
}
void CodeCompletionPopup::setCodeSnippets(const QList<PCodeSnippet> &newCodeSnippets)
{
mCodeSnippets = newCodeSnippets;
}
void CodeCompletionPopup::setColors(const std::shared_ptr<QHash<StatementKind, std::shared_ptr<ColorSchemeItem> > > &newColors)
2021-09-25 23:12:36 +08:00
{
mColors = newColors;
}
2021-12-04 10:02:07 +08:00
const QString &CodeCompletionPopup::memberPhrase() const
{
2021-12-04 10:02:07 +08:00
return mMemberPhrase;
}
2021-08-29 00:48:23 +08:00
void CodeCompletionPopup::showEvent(QShowEvent *)
2021-08-26 17:48:23 +08:00
{
mListView->setFocus();
}
2021-08-29 00:48:23 +08:00
const PStatement &CodeCompletionPopup::currentStatement() const
2021-08-25 23:53:35 +08:00
{
return mCurrentStatement;
}
2021-08-29 00:48:23 +08:00
void CodeCompletionPopup::setCurrentStatement(const PStatement &newCurrentStatement)
2021-08-25 23:53:35 +08:00
{
mCurrentStatement = newCurrentStatement;
}
const std::shared_ptr<QHash<StatementKind, std::shared_ptr<ColorSchemeItem> > >& CodeCompletionPopup::colors() const
2021-08-28 09:01:40 +08:00
{
return mColors;
}
2021-08-29 00:48:23 +08:00
bool CodeCompletionPopup::useCppKeyword() const
2021-08-25 23:53:35 +08:00
{
return mUseCppKeyword;
}
2021-08-29 00:48:23 +08:00
void CodeCompletionPopup::setUseCppKeyword(bool newUseCppKeyword)
2021-08-25 23:53:35 +08:00
{
mUseCppKeyword = newUseCppKeyword;
}
2021-08-29 00:48:23 +08:00
bool CodeCompletionPopup::sortByScope() const
2021-08-25 23:53:35 +08:00
{
return mSortByScope;
}
2021-08-29 00:48:23 +08:00
void CodeCompletionPopup::setSortByScope(bool newSortByScope)
2021-08-25 23:53:35 +08:00
{
mSortByScope = newSortByScope;
}
2021-08-29 00:48:23 +08:00
bool CodeCompletionPopup::ignoreCase() const
2021-08-25 23:53:35 +08:00
{
return mIgnoreCase;
}
2021-08-29 00:48:23 +08:00
void CodeCompletionPopup::setIgnoreCase(bool newIgnoreCase)
2021-08-25 23:53:35 +08:00
{
mIgnoreCase = newIgnoreCase;
}
2021-09-30 21:25:48 +08:00
bool CodeCompletionPopup::showCodeSnippets() const
2021-08-25 23:53:35 +08:00
{
2021-09-30 20:10:48 +08:00
return mShowCodeSnippets;
2021-08-25 23:53:35 +08:00
}
2021-09-30 21:25:48 +08:00
void CodeCompletionPopup::setShowCodeSnippets(bool newShowCodeIns)
2021-08-25 23:53:35 +08:00
{
2021-09-30 20:10:48 +08:00
mShowCodeSnippets = newShowCodeIns;
2021-08-25 23:53:35 +08:00
}
2021-08-29 00:48:23 +08:00
bool CodeCompletionPopup::showKeywords() const
2021-08-25 23:53:35 +08:00
{
return mShowKeywords;
}
2021-08-29 00:48:23 +08:00
void CodeCompletionPopup::setShowKeywords(bool newShowKeywords)
2021-08-25 23:53:35 +08:00
{
mShowKeywords = newShowKeywords;
}
2021-08-29 00:48:23 +08:00
bool CodeCompletionPopup::recordUsage() const
2021-08-25 23:53:35 +08:00
{
return mRecordUsage;
}
2021-08-29 00:48:23 +08:00
void CodeCompletionPopup::setRecordUsage(bool newRecordUsage)
2021-08-25 23:53:35 +08:00
{
mRecordUsage = newRecordUsage;
}
2021-08-29 00:48:23 +08:00
bool CodeCompletionPopup::onlyGlobals() const
2021-08-25 23:53:35 +08:00
{
return mOnlyGlobals;
}
2021-08-29 00:48:23 +08:00
void CodeCompletionPopup::setOnlyGlobals(bool newOnlyGlobals)
2021-08-25 23:53:35 +08:00
{
mOnlyGlobals = newOnlyGlobals;
}
2021-08-29 00:48:23 +08:00
int CodeCompletionPopup::showCount() const
2021-08-25 23:53:35 +08:00
{
return mShowCount;
}
2021-08-29 00:48:23 +08:00
void CodeCompletionPopup::setShowCount(int newShowCount)
2021-08-25 23:53:35 +08:00
{
mShowCount = newShowCount;
}
2021-08-29 00:48:23 +08:00
const PCppParser &CodeCompletionPopup::parser() const
2021-08-25 23:53:35 +08:00
{
return mParser;
}
2021-08-29 00:48:23 +08:00
void CodeCompletionPopup::setParser(const PCppParser &newParser)
2021-08-25 23:53:35 +08:00
{
mParser = newParser;
}
2021-08-29 00:48:23 +08:00
void CodeCompletionPopup::hideEvent(QHideEvent *event)
2021-08-25 00:20:07 +08:00
{
QMutexLocker locker(&mMutex);
2021-08-25 08:48:33 +08:00
mListView->setKeypressedCallback(nullptr);
2021-08-25 00:20:07 +08:00
mCompletionStatementList.clear();
mFullCompletionStatementList.clear();
mIncludedFiles.clear();
mUsings.clear();
mAddedStatements.clear();
mParser = nullptr;
2021-08-25 00:20:07 +08:00
QWidget::hideEvent(event);
2021-08-24 15:05:10 +08:00
}
2021-08-29 00:48:23 +08:00
bool CodeCompletionPopup::event(QEvent *event)
{
2021-08-27 16:38:55 +08:00
bool result = QWidget::event(event);
if (event->type() == QEvent::FontChange) {
2021-08-27 16:38:55 +08:00
mListView->setFont(font());
}
2021-08-27 16:38:55 +08:00
return result;
}
2021-08-29 00:48:23 +08:00
CodeCompletionListModel::CodeCompletionListModel(const StatementList *statements, QObject *parent):
2021-08-25 08:48:33 +08:00
QAbstractListModel(parent),
mStatements(statements)
{
}
2021-08-25 23:53:35 +08:00
int CodeCompletionListModel::rowCount(const QModelIndex &) const
2021-08-25 08:48:33 +08:00
{
return mStatements->count();
}
QVariant CodeCompletionListModel::data(const QModelIndex &index, int role) const
{
if (!index.isValid())
return QVariant();
2021-08-26 17:48:23 +08:00
if (index.row()>=mStatements->count())
return QVariant();
2021-08-28 09:01:40 +08:00
switch(role) {
case Qt::DisplayRole: {
2021-08-25 08:48:33 +08:00
PStatement statement = mStatements->at(index.row());
return statement->command;
2021-08-28 09:01:40 +08:00
}
case Qt::ForegroundRole: {
PStatement statement = mStatements->at(index.row());
if (mColorCallback)
return mColorCallback(statement);
return qApp->palette().color(QPalette::Text);
2021-08-28 09:01:40 +08:00
}
2021-08-25 08:48:33 +08:00
}
return QVariant();
}
void CodeCompletionListModel::notifyUpdated()
{
beginResetModel();
endResetModel();
}
2021-08-28 09:01:40 +08:00
const ColorCallback &CodeCompletionListModel::colorCallback() const
{
return mColorCallback;
}
void CodeCompletionListModel::setColorCallback(const ColorCallback &newColorCallback)
{
mColorCallback = newColorCallback;
}