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"
|
2021-09-29 19:40:03 +08:00
|
|
|
#include "../mainwindow.h"
|
|
|
|
#include "../editor.h"
|
|
|
|
#include "../editorlist.h"
|
2021-09-30 11:20:43 +08:00
|
|
|
#include "../symbolusagemanager.h"
|
2021-10-10 21:23:25 +08:00
|
|
|
#include "../colorscheme.h"
|
2022-01-27 20:31:44 +08:00
|
|
|
#include "../iconsmanager.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>
|
2022-01-27 20:31:44 +08:00
|
|
|
#include <QPainter>
|
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),
|
2022-11-10 09:05:34 +08:00
|
|
|
#if QT_VERSION >= QT_VERSION_CHECK(5, 15, 0)
|
|
|
|
mMutex()
|
|
|
|
#else
|
2022-01-04 16:50:54 +08:00
|
|
|
mMutex(QMutex::Recursive)
|
2022-11-10 09:05:34 +08:00
|
|
|
#endif
|
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);
|
2022-01-27 20:31:44 +08:00
|
|
|
mDelegate = new CodeCompletionListItemDelegate(mModel,this);
|
2022-10-10 18:05:18 +08:00
|
|
|
QItemSelectionModel *m=mListView->selectionModel();
|
2021-08-25 08:48:33 +08:00
|
|
|
mListView->setModel(mModel);
|
2022-10-10 18:05:18 +08:00
|
|
|
delete m;
|
2022-01-27 20:31:44 +08:00
|
|
|
mListView->setItemDelegate(mDelegate);
|
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;
|
2021-08-27 16:38:55 +08:00
|
|
|
mRecordUsage = false;
|
|
|
|
mSortByScope = true;
|
2021-08-25 00:20:07 +08:00
|
|
|
|
|
|
|
mShowCount = 1000;
|
2021-09-30 20:10:48 +08:00
|
|
|
mShowCodeSnippets = true;
|
2021-08-25 00:20:07 +08:00
|
|
|
|
|
|
|
mIgnoreCase = false;
|
2022-03-01 22:03:54 +08:00
|
|
|
|
|
|
|
mHideSymbolsStartWithTwoUnderline = false;
|
|
|
|
mHideSymbolsStartWithUnderline = 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,
|
2022-01-23 23:27:48 +08:00
|
|
|
int line,
|
2022-11-10 13:35:13 +08:00
|
|
|
CodeCompletionType type,
|
2022-01-23 23:27:48 +08:00
|
|
|
const QSet<QString>& customKeywords)
|
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;
|
2022-11-27 13:32:14 +08:00
|
|
|
switch(type) {
|
|
|
|
case CodeCompletionType::ComplexKeyword:
|
2022-11-10 13:35:13 +08:00
|
|
|
getCompletionListForTypeKeywordComplex(preWord);
|
2022-11-27 13:32:14 +08:00
|
|
|
break;
|
|
|
|
case CodeCompletionType::FunctionWithoutDefinition:
|
2022-11-10 13:35:13 +08:00
|
|
|
mIncludedFiles = mParser->getFileIncludes(filename);
|
|
|
|
getCompletionForFunctionWithoutDefinition(preWord, ownerExpression,memberOperator,memberExpression, filename,line);
|
2022-11-27 13:32:14 +08:00
|
|
|
break;
|
|
|
|
case CodeCompletionType::Namespaces:
|
|
|
|
mIncludedFiles = mParser->getFileIncludes(filename);
|
|
|
|
getCompletionListForNamespaces(preWord,filename,line);
|
|
|
|
break;
|
2023-02-09 21:01:01 +08:00
|
|
|
case CodeCompletionType::KeywordsOnly:
|
|
|
|
mIncludedFiles.clear();
|
|
|
|
getKeywordCompletionFor(customKeywords);
|
|
|
|
break;
|
2022-11-27 13:32:14 +08:00
|
|
|
default:
|
2021-12-03 11:40:05 +08:00
|
|
|
mIncludedFiles = mParser->getFileIncludes(filename);
|
2022-01-23 23:27:48 +08:00
|
|
|
getCompletionFor(ownerExpression,memberOperator,memberExpression, filename,line, customKeywords);
|
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);
|
2021-11-10 21:28:08 +08:00
|
|
|
|
|
|
|
//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-11-10 21:28:08 +08:00
|
|
|
|
2021-08-25 08:48:33 +08:00
|
|
|
mModel->notifyUpdated();
|
|
|
|
setCursor(oldCursor);
|
2021-08-25 00:20:07 +08:00
|
|
|
|
|
|
|
if (!mCompletionStatementList.isEmpty()) {
|
2022-01-27 20:31:44 +08:00
|
|
|
PColorSchemeItem item = mColors->value(StatementKind::skUnknown,PColorSchemeItem());
|
|
|
|
if (item)
|
|
|
|
mDelegate->setNormalColor(item->foreground());
|
|
|
|
else
|
|
|
|
mDelegate->setNormalColor(palette().color(QPalette::Text));
|
2022-01-27 21:27:51 +08:00
|
|
|
item = mColors->value(StatementKind::skKeyword,PColorSchemeItem());
|
2022-01-27 20:31:44 +08:00
|
|
|
if (item)
|
|
|
|
mDelegate->setMatchedColor(item->foreground());
|
|
|
|
else
|
|
|
|
mDelegate->setMatchedColor(palette().color(QPalette::HighlightedText));
|
2021-08-29 10:29:56 +08:00
|
|
|
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();
|
|
|
|
}
|
|
|
|
|
2022-11-28 11:28:02 +08:00
|
|
|
void CodeCompletionPopup::addChildren(const 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);
|
2022-10-28 09:47:34 +08:00
|
|
|
} else if (
|
|
|
|
isIncluded(childStatement->fileName)
|
|
|
|
|| isIncluded(childStatement->definitionFileName)
|
2021-08-24 15:05:10 +08:00
|
|
|
) {
|
|
|
|
//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) {
|
2022-10-28 09:47:34 +08:00
|
|
|
addStatement(childStatement,fileName,line);
|
2021-08-24 15:05:10 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-11-28 11:28:02 +08:00
|
|
|
void CodeCompletionPopup::addFunctionWithoutDefinitionChildren(const PStatement& scopeStatement, const QString &fileName, int line)
|
2022-11-10 13:35:13 +08:00
|
|
|
{
|
|
|
|
if (scopeStatement && !isIncluded(scopeStatement->fileName)
|
|
|
|
&& !isIncluded(scopeStatement->definitionFileName))
|
|
|
|
return;
|
|
|
|
const StatementMap& children = mParser->statementList().childrenStatements(scopeStatement);
|
|
|
|
if (children.isEmpty())
|
|
|
|
return;
|
|
|
|
|
|
|
|
for (const PStatement& childStatement: children) {
|
2022-11-16 10:29:20 +08:00
|
|
|
if (childStatement->inSystemHeader())
|
2022-11-10 13:35:13 +08:00
|
|
|
continue;
|
|
|
|
if (childStatement->fileName.isEmpty()) {
|
|
|
|
// hard defines, do nothing
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
switch(childStatement->kind) {
|
|
|
|
case StatementKind::skConstructor:
|
|
|
|
case StatementKind::skFunction:
|
|
|
|
case StatementKind::skDestructor:
|
2022-11-16 10:29:20 +08:00
|
|
|
if (!childStatement->hasDefinition())
|
2022-11-10 13:35:13 +08:00
|
|
|
addStatement(childStatement,fileName,line);
|
|
|
|
break;
|
|
|
|
case StatementKind::skClass:
|
|
|
|
case StatementKind::skNamespace:
|
|
|
|
if (isIncluded(childStatement->fileName))
|
|
|
|
addStatement(childStatement,fileName,line);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-11-28 11:28:02 +08:00
|
|
|
void CodeCompletionPopup::addStatement(const 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;
|
2022-10-28 09:47:34 +08:00
|
|
|
if (statement->kind == StatementKind::skConstructor
|
|
|
|
|| statement->kind == StatementKind::skDestructor
|
2023-03-10 20:13:52 +08:00
|
|
|
|| statement->kind == StatementKind::skBlock
|
|
|
|
|| statement->properties.testFlag(StatementProperty::spOperatorOverloading))
|
2022-10-28 09:47:34 +08:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
2021-09-27 00:52:25 +08:00
|
|
|
static bool nameComparator(PStatement statement1,PStatement statement2) {
|
2022-01-18 13:08:53 +08:00
|
|
|
return statement1->command < statement2->command;
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool defaultComparator(PStatement statement1,PStatement statement2) {
|
2022-02-11 20:19:48 +08:00
|
|
|
if (statement1->matchPosSpan!=statement2->matchPosSpan)
|
|
|
|
return statement1->matchPosSpan < statement2->matchPosSpan;
|
2022-01-27 18:34:18 +08:00
|
|
|
if (statement1->firstMatchLength != statement2->firstMatchLength)
|
|
|
|
return statement1->firstMatchLength > statement2->firstMatchLength;
|
|
|
|
if (statement1->matchPosTotal != statement2->matchPosTotal)
|
|
|
|
return statement1->matchPosTotal < statement2->matchPosTotal;
|
|
|
|
if (statement1->caseMatched != statement2->caseMatched)
|
|
|
|
return statement1->caseMatched > statement2->caseMatched;
|
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
|
2021-09-27 00:52:25 +08:00
|
|
|
return nameComparator(statement1,statement2);
|
2021-08-24 15:05:10 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
static bool sortByScopeComparator(PStatement statement1,PStatement statement2){
|
2022-02-11 20:19:48 +08:00
|
|
|
if (statement1->matchPosSpan!=statement2->matchPosSpan)
|
|
|
|
return statement1->matchPosSpan < statement2->matchPosSpan;
|
2022-01-27 18:34:18 +08:00
|
|
|
if (statement1->firstMatchLength != statement2->firstMatchLength)
|
|
|
|
return statement1->firstMatchLength > statement2->firstMatchLength;
|
|
|
|
if (statement1->matchPosTotal != statement2->matchPosTotal)
|
|
|
|
return statement1->matchPosTotal < statement2->matchPosTotal;
|
|
|
|
if (statement1->caseMatched != statement2->caseMatched)
|
|
|
|
return statement1->caseMatched > statement2->caseMatched;
|
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;
|
2022-07-22 21:02:07 +08:00
|
|
|
// show non-system defines before keyword
|
2021-08-24 15:05:10 +08:00
|
|
|
} else if (statement1->kind == StatementKind::skKeyword) {
|
2022-07-22 21:02:07 +08:00
|
|
|
if (statement2->kind != StatementKind::skKeyword) {
|
|
|
|
//s1 keyword / s2 system defines, s1 < s2, should return true
|
|
|
|
//s1 keyword / s2 not system defines, s2 < s1, should return false;
|
2022-11-16 10:29:20 +08:00
|
|
|
return statement2->inSystemHeader();
|
2022-07-22 21:02:07 +08:00
|
|
|
} else
|
2021-08-24 15:05:10 +08:00
|
|
|
return statement1->command < statement2->command;
|
|
|
|
} else if (statement2->kind == StatementKind::skKeyword) {
|
2022-07-22 21:02:07 +08:00
|
|
|
//s1 system defines / s2 keyword, s2 < s1, should return false;
|
|
|
|
//s1 not system defines / s2 keyword, s1 < s2, should return true;
|
2022-11-16 10:29:20 +08:00
|
|
|
return (!statement1->inSystemHeader());
|
2022-01-27 18:34:18 +08:00
|
|
|
}
|
|
|
|
// Show stuff from local headers first
|
2022-11-16 10:29:20 +08:00
|
|
|
if (statement1->inSystemHeader() != statement2->inSystemHeader())
|
|
|
|
return !(statement1->inSystemHeader());
|
2021-08-24 15:05:10 +08:00
|
|
|
// Show local statements first
|
2022-11-01 09:02:17 +08:00
|
|
|
if (statement1->scope != StatementScope::Global
|
|
|
|
&& statement2->scope == StatementScope::Global ) {
|
2021-08-24 15:05:10 +08:00
|
|
|
return true;
|
2022-11-01 09:02:17 +08:00
|
|
|
} else if (statement1->scope == StatementScope::Global
|
|
|
|
&& statement2->scope != StatementScope::Global ) {
|
2021-08-24 15:05:10 +08:00
|
|
|
return false;
|
|
|
|
} else
|
2021-09-27 00:52:25 +08:00
|
|
|
return nameComparator(statement1,statement2);
|
2021-08-24 15:05:10 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
static bool sortWithUsageComparator(PStatement statement1,PStatement statement2) {
|
2022-02-11 20:19:48 +08:00
|
|
|
if (statement1->matchPosSpan!=statement2->matchPosSpan)
|
|
|
|
return statement1->matchPosSpan < statement2->matchPosSpan;
|
2022-01-27 18:34:18 +08:00
|
|
|
if (statement1->firstMatchLength != statement2->firstMatchLength)
|
|
|
|
return statement1->firstMatchLength > statement2->firstMatchLength;
|
|
|
|
if (statement1->matchPosTotal != statement2->matchPosTotal)
|
|
|
|
return statement1->matchPosTotal < statement2->matchPosTotal;
|
|
|
|
if (statement1->caseMatched != statement2->caseMatched)
|
|
|
|
return statement1->caseMatched > statement2->caseMatched;
|
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
|
2022-01-27 18:34:18 +08:00
|
|
|
}
|
|
|
|
if (statement1->usageCount != statement2->usageCount)
|
|
|
|
return statement1->usageCount > statement2->usageCount;
|
|
|
|
|
|
|
|
if ((statement1->kind != StatementKind::skKeyword)
|
2021-08-24 15:05:10 +08:00
|
|
|
&& (statement2->kind == StatementKind::skKeyword)) {
|
2021-08-29 10:29:56 +08:00
|
|
|
return true;
|
|
|
|
} else if ((statement1->kind == StatementKind::skKeyword)
|
|
|
|
&& (statement2->kind != StatementKind::skKeyword)) {
|
2021-08-24 15:05:10 +08:00
|
|
|
return false;
|
|
|
|
} else
|
2021-09-27 00:52:25 +08:00
|
|
|
return nameComparator(statement1,statement2);
|
2021-08-24 15:05:10 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
static bool sortByScopeWithUsageComparator(PStatement statement1,PStatement statement2){
|
2022-02-11 20:19:48 +08:00
|
|
|
if (statement1->matchPosSpan!=statement2->matchPosSpan)
|
|
|
|
return statement1->matchPosSpan < statement2->matchPosSpan;
|
2022-01-27 18:34:18 +08:00
|
|
|
if (statement1->firstMatchLength != statement2->firstMatchLength)
|
|
|
|
return statement1->firstMatchLength > statement2->firstMatchLength;
|
|
|
|
if (statement1->matchPosTotal != statement2->matchPosTotal)
|
|
|
|
return statement1->matchPosTotal < statement2->matchPosTotal;
|
|
|
|
if (statement1->caseMatched != statement2->caseMatched)
|
|
|
|
return statement1->caseMatched > statement2->caseMatched;
|
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
|
2022-01-27 18:34:18 +08:00
|
|
|
}
|
|
|
|
if (statement1->usageCount != statement2->usageCount)
|
|
|
|
return statement1->usageCount > statement2->usageCount;
|
|
|
|
|
2022-07-22 21:02:07 +08:00
|
|
|
// show non-system defines before keyword
|
2022-01-27 18:34:18 +08:00
|
|
|
if (statement1->kind == StatementKind::skKeyword) {
|
2022-07-22 21:02:07 +08:00
|
|
|
if (statement2->kind != StatementKind::skKeyword) {
|
|
|
|
//s1 keyword / s2 system defines, s1 < s2, should return true
|
|
|
|
//s1 keyword / s2 not system defines, s2 < s1, should return false;
|
2022-11-16 10:29:20 +08:00
|
|
|
return statement2->inSystemHeader();
|
2022-07-22 21:02:07 +08:00
|
|
|
} else
|
2021-08-24 15:05:10 +08:00
|
|
|
return statement1->command < statement2->command;
|
|
|
|
} else if (statement2->kind == StatementKind::skKeyword) {
|
2022-07-22 21:02:07 +08:00
|
|
|
//s1 system defines / s2 keyword, s2 < s1, should return false;
|
|
|
|
//s1 not system defines / s2 keyword, s1 < s2, should return true;
|
2022-11-16 10:29:20 +08:00
|
|
|
return (!statement1->inSystemHeader());
|
2022-01-27 18:34:18 +08:00
|
|
|
}
|
|
|
|
// Show stuff from local headers first
|
2022-11-16 10:29:20 +08:00
|
|
|
if (statement1->inSystemHeader() != statement2->inSystemHeader())
|
|
|
|
return !(statement1->inSystemHeader());
|
2021-08-24 15:05:10 +08:00
|
|
|
// Show local statements first
|
2022-11-01 09:02:17 +08:00
|
|
|
if (statement1->scope != StatementScope::Global
|
|
|
|
&& statement2->scope == StatementScope::Global ) {
|
2021-08-24 15:05:10 +08:00
|
|
|
return true;
|
2022-11-01 09:02:17 +08:00
|
|
|
} else if (statement1->scope == StatementScope::Global
|
|
|
|
&& statement2->scope != StatementScope::Global ) {
|
2021-08-24 15:05:10 +08:00
|
|
|
return false;
|
|
|
|
} else
|
2021-09-27 00:52:25 +08:00
|
|
|
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();
|
2023-02-09 21:01:01 +08:00
|
|
|
// if (!mParser)
|
|
|
|
// return;
|
|
|
|
// if (!mParser->enabled())
|
|
|
|
// return;
|
2021-08-24 15:05:10 +08:00
|
|
|
//we don't need to freeze here since we use smart pointers
|
|
|
|
// and data have been retrieved from the parser
|
|
|
|
|
2021-08-25 00:20:07 +08:00
|
|
|
mCompletionStatementList.clear();
|
2022-01-27 01:03:01 +08:00
|
|
|
mCompletionStatementList.reserve(mFullCompletionStatementList.size());
|
2022-03-01 22:03:54 +08:00
|
|
|
bool hideSymbolsTwoUnderline = mHideSymbolsStartWithTwoUnderline && !member.startsWith("__") ;
|
|
|
|
bool hideSymbolsUnderline = mHideSymbolsStartWithUnderline && !member.startsWith("_") ;
|
|
|
|
int len = member.length();
|
2022-01-27 01:03:01 +08:00
|
|
|
foreach (const PStatement& statement, mFullCompletionStatementList) {
|
|
|
|
|
|
|
|
int matched = 0;
|
|
|
|
int caseMatched = 0;
|
|
|
|
QString command = statement->command;
|
|
|
|
int pos = 0;
|
|
|
|
int lastPos = -10;
|
|
|
|
int totalPos = 0;
|
|
|
|
statement->matchPositions.clear();
|
2022-03-01 22:03:54 +08:00
|
|
|
if (hideSymbolsTwoUnderline && statement->command.startsWith("__")) {
|
2022-10-28 09:47:34 +08:00
|
|
|
continue;
|
2022-03-01 22:03:54 +08:00
|
|
|
} else if (hideSymbolsUnderline && statement->command.startsWith("_")) {
|
2022-10-28 09:47:34 +08:00
|
|
|
continue;
|
2022-03-01 22:03:54 +08:00
|
|
|
} else {
|
|
|
|
foreach (const QChar& ch, member) {
|
|
|
|
if (mIgnoreCase)
|
|
|
|
pos = command.indexOf(ch,pos,Qt::CaseInsensitive);
|
|
|
|
else
|
|
|
|
pos = command.indexOf(ch,pos,Qt::CaseSensitive);
|
|
|
|
if (pos<0) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (pos == lastPos+1) {
|
|
|
|
statement->matchPositions.last()->end++;
|
|
|
|
} else {
|
|
|
|
PStatementMathPosition matchPosition=std::make_shared<StatementMatchPosition>();
|
|
|
|
matchPosition->start = pos;
|
|
|
|
matchPosition->end = pos+1;
|
|
|
|
statement->matchPositions.append(matchPosition);
|
|
|
|
}
|
|
|
|
if (ch==command[pos])
|
|
|
|
caseMatched++;
|
|
|
|
matched++;
|
|
|
|
totalPos += pos;
|
|
|
|
lastPos = pos;
|
|
|
|
pos+=1;
|
2021-09-27 00:52:25 +08:00
|
|
|
}
|
2021-08-24 15:05:10 +08:00
|
|
|
}
|
2022-01-27 01:03:01 +08:00
|
|
|
|
2022-03-01 22:03:54 +08:00
|
|
|
if (mIgnoreCase && matched== len) {
|
2022-01-27 01:03:01 +08:00
|
|
|
statement->caseMatched = caseMatched;
|
|
|
|
statement->matchPosTotal = totalPos;
|
2022-02-11 20:19:48 +08:00
|
|
|
if (member.length()>0) {
|
2022-01-27 01:03:01 +08:00
|
|
|
statement->firstMatchLength = statement->matchPositions.front()->end - statement->matchPositions.front()->start;
|
2022-02-11 20:19:48 +08:00
|
|
|
statement->matchPosSpan = statement->matchPositions.last()->end - statement->matchPositions.front()->start;
|
|
|
|
} else
|
2022-01-27 01:03:01 +08:00
|
|
|
statement->firstMatchLength = 0;
|
|
|
|
mCompletionStatementList.append(statement);
|
2022-03-01 22:03:54 +08:00
|
|
|
} else if (caseMatched == len) {
|
2022-01-27 01:03:01 +08:00
|
|
|
statement->caseMatched = caseMatched;
|
|
|
|
statement->matchPosTotal = totalPos;
|
2022-02-11 20:19:48 +08:00
|
|
|
if (member.length()>0) {
|
2022-01-27 01:03:01 +08:00
|
|
|
statement->firstMatchLength = statement->matchPositions.front()->end - statement->matchPositions.front()->start;
|
2022-02-11 20:19:48 +08:00
|
|
|
statement->matchPosSpan = statement->matchPositions.last()->end - statement->matchPositions.front()->start;
|
|
|
|
} else
|
2022-01-27 01:03:01 +08:00
|
|
|
statement->firstMatchLength = 0;
|
|
|
|
mCompletionStatementList.append(statement);
|
|
|
|
} else {
|
|
|
|
statement->matchPositions.clear();
|
|
|
|
statement->caseMatched = 0;
|
|
|
|
statement->matchPosTotal = 0;
|
|
|
|
statement->firstMatchLength = 0;
|
2022-02-11 20:19:48 +08:00
|
|
|
statement->matchPosSpan = 0;
|
2022-01-27 01:03:01 +08:00
|
|
|
}
|
|
|
|
}
|
2021-08-24 15:05:10 +08:00
|
|
|
if (mRecordUsage) {
|
|
|
|
int usageCount;
|
2021-08-29 00:48:23 +08:00
|
|
|
foreach (const PStatement& statement,mCompletionStatementList) {
|
2021-09-30 11:20:43 +08:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
// }
|
|
|
|
}
|
|
|
|
|
2023-02-09 21:01:01 +08:00
|
|
|
void CodeCompletionPopup::getKeywordCompletionFor(const QSet<QString> &customKeywords)
|
|
|
|
{
|
|
|
|
//add keywords
|
|
|
|
if (!customKeywords.isEmpty()) {
|
|
|
|
foreach (const QString& keyword,customKeywords) {
|
|
|
|
addKeyword(keyword);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-12-04 10:02:07 +08:00
|
|
|
void CodeCompletionPopup::getCompletionFor(
|
2022-12-11 19:47:43 +08:00
|
|
|
QStringList ownerExpression,
|
2021-12-04 10:02:07 +08:00
|
|
|
const QString& memberOperator,
|
|
|
|
const QStringList& memberExpression,
|
|
|
|
const QString &fileName,
|
2022-01-23 23:27:48 +08:00
|
|
|
int line,
|
|
|
|
const QSet<QString>& customKeywords)
|
2021-08-25 00:20:07 +08:00
|
|
|
{
|
2023-02-09 21:01:01 +08:00
|
|
|
|
|
|
|
if (memberOperator.isEmpty() && ownerExpression.isEmpty() && memberExpression.isEmpty())
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (memberOperator.isEmpty()) {
|
|
|
|
//C++ preprocessor directives
|
|
|
|
if (mMemberPhrase.startsWith('#')) {
|
|
|
|
if (mShowKeywords) {
|
|
|
|
foreach (const QString& keyword, CppDirectives) {
|
|
|
|
addKeyword(keyword);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
//docstring tags (javadoc style)
|
|
|
|
if (mMemberPhrase.startsWith('@')) {
|
|
|
|
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;
|
|
|
|
mFullCompletionStatementList.append(statement);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-01-23 23:27:48 +08:00
|
|
|
if (mShowKeywords) {
|
|
|
|
//add keywords
|
2023-02-09 21:01:01 +08:00
|
|
|
if (!customKeywords.isEmpty()) {
|
2022-01-23 23:27:48 +08:00
|
|
|
foreach (const QString& keyword,customKeywords) {
|
|
|
|
addKeyword(keyword);
|
|
|
|
}
|
2023-02-09 21:01:01 +08:00
|
|
|
}
|
2022-01-23 23:27:48 +08:00
|
|
|
}
|
|
|
|
}
|
2023-02-09 21:01:01 +08:00
|
|
|
|
|
|
|
if (!mParser || !mParser->enabled())
|
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()) {
|
2022-11-10 08:05:04 +08:00
|
|
|
PStatement scopeStatement = mCurrentScope;
|
2021-12-03 20:08:18 +08:00
|
|
|
// 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
|
|
|
|
2022-11-10 08:05:04 +08:00
|
|
|
PStatement scope = mCurrentScope;//the scope the expression in
|
2021-12-03 20:24:49 +08:00
|
|
|
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;
|
|
|
|
}
|
2021-12-03 21:36:12 +08:00
|
|
|
// 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-10-02 17:01:08 +08:00
|
|
|
|
2021-08-25 00:20:07 +08:00
|
|
|
// find the most inner scope statement that has a name (not a block)
|
2022-11-10 08:05:04 +08:00
|
|
|
PStatement scopeTypeStatement = mCurrentScope;
|
2021-08-25 00:20:07 +08:00
|
|
|
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) {
|
2023-03-12 18:24:58 +08:00
|
|
|
if ((childStatement->accessibility==StatementAccessibility::Public)
|
2021-08-25 00:20:07 +08:00
|
|
|
&& !(
|
|
|
|
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 (
|
2022-11-16 10:29:20 +08:00
|
|
|
(childStatement->isStatic())
|
2021-12-08 19:13:47 +08:00
|
|
|
|| (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 (
|
2022-11-16 10:29:20 +08:00
|
|
|
(childStatement->isStatic())
|
2021-12-08 19:13:47 +08:00
|
|
|
|| (childStatement->kind == StatementKind::skTypedef
|
|
|
|
|| childStatement->kind == StatementKind::skClass
|
|
|
|
|| childStatement->kind == StatementKind::skEnum
|
|
|
|
|| childStatement->kind == StatementKind::skEnumClassType
|
|
|
|
|| childStatement->kind == StatementKind::skEnumType
|
|
|
|
)) {
|
2023-03-12 18:24:58 +08:00
|
|
|
if (childStatement->accessibility == StatementAccessibility::Public)
|
2021-12-08 19:13:47 +08:00
|
|
|
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
|
|
|
}
|
|
|
|
|
2022-12-11 19:47:43 +08:00
|
|
|
void CodeCompletionPopup::getCompletionForFunctionWithoutDefinition(const QString& preWord, QStringList ownerExpression, const QString &memberOperator, const QStringList &memberExpression, const QString &fileName, int line)
|
2022-11-10 13:35:13 +08:00
|
|
|
{
|
|
|
|
if(!mParser) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (!mParser->enabled())
|
|
|
|
return;
|
|
|
|
if (memberOperator.isEmpty() && ownerExpression.isEmpty() && memberExpression.isEmpty())
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (!mParser->freeze())
|
|
|
|
return;
|
|
|
|
{
|
|
|
|
auto action = finally([this]{
|
|
|
|
mParser->unFreeze();
|
|
|
|
});
|
|
|
|
|
|
|
|
if (memberOperator.isEmpty()) {
|
|
|
|
getCompletionListForTypeKeywordComplex(preWord);
|
|
|
|
PStatement scopeStatement = mCurrentScope;
|
|
|
|
//add members of current scope that not added before
|
2023-02-05 21:55:23 +08:00
|
|
|
while (scopeStatement && scopeStatement->kind!=StatementKind::skNamespace
|
|
|
|
&& scopeStatement->kind!=StatementKind::skClass) {
|
2022-11-10 13:35:13 +08:00
|
|
|
scopeStatement = scopeStatement->parentScope.lock();
|
|
|
|
}
|
|
|
|
if (scopeStatement) {
|
2023-02-05 21:55:23 +08:00
|
|
|
if (scopeStatement->kind == StatementKind::skNamespace) {
|
|
|
|
//namespace;
|
|
|
|
PStatementList namespaceStatementsList =
|
|
|
|
mParser->findNamespace(scopeStatement->fullName);
|
|
|
|
if (namespaceStatementsList) {
|
|
|
|
foreach (const PStatement& namespaceStatement, *namespaceStatementsList) {
|
|
|
|
addFunctionWithoutDefinitionChildren(namespaceStatement, fileName, line);
|
|
|
|
}
|
2022-11-10 13:35:13 +08:00
|
|
|
}
|
2023-02-05 21:55:23 +08:00
|
|
|
} else {
|
|
|
|
//class
|
|
|
|
addKeyword("operator");
|
|
|
|
addFunctionWithoutDefinitionChildren(scopeStatement, fileName, line);
|
2022-11-10 13:35:13 +08:00
|
|
|
}
|
|
|
|
} else {
|
|
|
|
//global
|
|
|
|
addFunctionWithoutDefinitionChildren(scopeStatement, fileName, line);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if (memberOperator != "::")
|
|
|
|
return;
|
|
|
|
//the identifier to be completed is a member of variable/class
|
2023-02-05 21:55:23 +08:00
|
|
|
|
2022-11-10 13:35:13 +08:00
|
|
|
if (ownerExpression.isEmpty()) {
|
|
|
|
// start with '::', we only find in global
|
|
|
|
// add all global members and not added before
|
|
|
|
addFunctionWithoutDefinitionChildren(nullptr, fileName, line);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (memberExpression.length()==2 && memberExpression.front()!="~")
|
|
|
|
return;
|
|
|
|
if (memberExpression.length()>2)
|
|
|
|
return;
|
|
|
|
|
|
|
|
PStatement scope = mCurrentScope;//the scope the expression in
|
|
|
|
PStatement parentTypeStatement;
|
|
|
|
PEvalStatement ownerStatement = mParser->evalExpression(fileName,
|
|
|
|
ownerExpression,
|
|
|
|
scope);
|
|
|
|
if(!ownerStatement || !ownerStatement->effectiveTypeStatement) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (ownerStatement->kind==EvalStatementKind::Namespace) {
|
|
|
|
//there might be many statements corresponding to one namespace;
|
|
|
|
PStatementList namespaceStatementsList =
|
|
|
|
mParser->findNamespace(ownerStatement->baseType);
|
|
|
|
if (namespaceStatementsList) {
|
|
|
|
foreach (const PStatement& namespaceStatement, *namespaceStatementsList) {
|
|
|
|
addFunctionWithoutDefinitionChildren(namespaceStatement, fileName, line);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return;
|
|
|
|
} else if (ownerStatement->effectiveTypeStatement->kind == StatementKind::skClass) {
|
2023-02-05 21:55:23 +08:00
|
|
|
addKeyword("operator");
|
2022-11-10 13:35:13 +08:00
|
|
|
addFunctionWithoutDefinitionChildren(ownerStatement->effectiveTypeStatement, fileName, line);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void CodeCompletionPopup::getCompletionListForTypeKeywordComplex(const QString &preWord)
|
2021-11-18 12:51:05 +08:00
|
|
|
{
|
|
|
|
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");
|
2022-11-25 10:01:10 +08:00
|
|
|
} else if (preWord == "using") {
|
|
|
|
addKeyword("namespace");
|
2022-11-27 13:32:14 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-12-03 11:02:33 +08:00
|
|
|
void CodeCompletionPopup::getCompletionListForNamespaces(const QString &/*preWord*/,
|
2022-11-27 13:32:14 +08:00
|
|
|
const QString& fileName,
|
|
|
|
int line)
|
|
|
|
{
|
|
|
|
if (!mParser->enabled())
|
|
|
|
return;
|
2022-11-25 10:01:10 +08:00
|
|
|
|
2022-11-27 13:32:14 +08:00
|
|
|
if (!mParser->freeze())
|
|
|
|
return;
|
|
|
|
{
|
|
|
|
auto action = finally([this]{
|
|
|
|
mParser->unFreeze();
|
|
|
|
});
|
|
|
|
QList<QString> namespaceNames = mParser->namespaces();
|
|
|
|
foreach (const QString& name, namespaceNames) {
|
|
|
|
PStatementList namespaces = mParser->findNamespace(name);
|
|
|
|
foreach(const PStatement& statement, *namespaces) {
|
|
|
|
if (isIncluded(statement->fileName)
|
|
|
|
|| isIncluded(statement->definitionFileName)) {
|
|
|
|
addStatement(statement,fileName,line);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
2021-11-18 12:51:05 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
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;
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
2022-03-01 22:03:54 +08:00
|
|
|
void CodeCompletionPopup::setHideSymbolsStartWithTwoUnderline(bool newHideSymbolsStartWithTwoUnderline)
|
|
|
|
{
|
|
|
|
mHideSymbolsStartWithTwoUnderline = newHideSymbolsStartWithTwoUnderline;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool CodeCompletionPopup::hideSymbolsStartWithTwoUnderline() const
|
|
|
|
{
|
|
|
|
return mHideSymbolsStartWithTwoUnderline;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool CodeCompletionPopup::hideSymbolsStartWithUnderline() const
|
|
|
|
{
|
|
|
|
return mHideSymbolsStartWithUnderline;
|
|
|
|
}
|
|
|
|
|
|
|
|
void CodeCompletionPopup::setHideSymbolsStartWithUnderline(bool newHideSymbolsStartWithUnderline)
|
|
|
|
{
|
|
|
|
mHideSymbolsStartWithUnderline = newHideSymbolsStartWithUnderline;
|
|
|
|
}
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2021-10-10 21:23:25 +08:00
|
|
|
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-08-29 10:14:07 +08:00
|
|
|
{
|
2021-12-04 10:02:07 +08:00
|
|
|
return mMemberPhrase;
|
2021-08-29 10:14:07 +08:00
|
|
|
}
|
|
|
|
|
2021-08-29 00:48:23 +08:00
|
|
|
void CodeCompletionPopup::showEvent(QShowEvent *)
|
2021-08-26 17:48:23 +08:00
|
|
|
{
|
|
|
|
mListView->setFocus();
|
|
|
|
}
|
|
|
|
|
2022-11-10 08:05:04 +08:00
|
|
|
const PStatement &CodeCompletionPopup::currentScope() const
|
2021-08-25 23:53:35 +08:00
|
|
|
{
|
2022-11-10 08:05:04 +08:00
|
|
|
return mCurrentScope;
|
2021-08-25 23:53:35 +08:00
|
|
|
}
|
|
|
|
|
2022-11-10 08:05:04 +08:00
|
|
|
void CodeCompletionPopup::setCurrentScope(const PStatement &newCurrentStatement)
|
2021-08-25 23:53:35 +08:00
|
|
|
{
|
2022-11-10 08:05:04 +08:00
|
|
|
mCurrentScope = newCurrentStatement;
|
2021-08-25 23:53:35 +08:00
|
|
|
}
|
|
|
|
|
2021-10-10 21:23:25 +08:00
|
|
|
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::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
|
|
|
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();
|
2022-04-25 10:13:28 +08:00
|
|
|
// foreach (PStatement statement, mFullCompletionStatementList) {
|
|
|
|
// statement->matchPositions.clear();
|
|
|
|
// }
|
2021-08-25 00:20:07 +08:00
|
|
|
mFullCompletionStatementList.clear();
|
|
|
|
mIncludedFiles.clear();
|
|
|
|
mUsings.clear();
|
|
|
|
mAddedStatements.clear();
|
2022-11-10 08:05:04 +08:00
|
|
|
mCurrentScope = nullptr;
|
2021-11-12 02:31:45 +08:00
|
|
|
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 08:52:20 +08:00
|
|
|
{
|
2021-08-27 16:38:55 +08:00
|
|
|
bool result = QWidget::event(event);
|
2021-08-27 08:52:20 +08:00
|
|
|
if (event->type() == QEvent::FontChange) {
|
2022-02-11 20:19:48 +08:00
|
|
|
mListView->setFont(font());
|
|
|
|
mDelegate->setFont(font());
|
2021-08-27 08:52:20 +08:00
|
|
|
}
|
2021-08-27 16:38:55 +08:00
|
|
|
return result;
|
2021-08-27 08:52:20 +08:00
|
|
|
}
|
|
|
|
|
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());
|
2022-01-27 20:31:44 +08:00
|
|
|
return statement->command;
|
2022-01-27 01:03:01 +08:00
|
|
|
}
|
2022-01-27 20:31:44 +08:00
|
|
|
case Qt::DecorationRole:
|
2021-08-28 09:01:40 +08:00
|
|
|
PStatement statement = mStatements->at(index.row());
|
2022-01-27 20:31:44 +08:00
|
|
|
return pIconsManager->getPixmapForStatement(statement);
|
2021-08-25 08:48:33 +08:00
|
|
|
}
|
|
|
|
return QVariant();
|
|
|
|
}
|
|
|
|
|
2022-01-27 20:31:44 +08:00
|
|
|
PStatement CodeCompletionListModel::statement(const QModelIndex &index) const
|
|
|
|
{
|
|
|
|
if (!index.isValid())
|
|
|
|
return PStatement();
|
|
|
|
if (index.row()>=mStatements->count())
|
|
|
|
return PStatement();
|
|
|
|
return mStatements->at(index.row());
|
|
|
|
}
|
|
|
|
|
|
|
|
QPixmap CodeCompletionListModel::statementIcon(const QModelIndex &index) const
|
|
|
|
{
|
|
|
|
if (!index.isValid())
|
|
|
|
return QPixmap();
|
|
|
|
if (index.row()>=mStatements->count())
|
|
|
|
return QPixmap();
|
|
|
|
PStatement statement = mStatements->at(index.row());
|
|
|
|
return pIconsManager->getPixmapForStatement(statement);
|
|
|
|
}
|
|
|
|
|
2021-08-25 08:48:33 +08:00
|
|
|
void CodeCompletionListModel::notifyUpdated()
|
|
|
|
{
|
|
|
|
beginResetModel();
|
|
|
|
endResetModel();
|
|
|
|
}
|
2021-08-28 09:01:40 +08:00
|
|
|
|
2022-01-27 20:31:44 +08:00
|
|
|
void CodeCompletionListItemDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const
|
|
|
|
{
|
|
|
|
PStatement statement;
|
|
|
|
if (mModel && (statement = mModel->statement(index)) ) {
|
|
|
|
painter->save();
|
2022-02-11 20:19:48 +08:00
|
|
|
painter->setFont(font());
|
2022-01-27 21:27:51 +08:00
|
|
|
QColor normalColor = mNormalColor;
|
|
|
|
if (option.state & QStyle::State_Selected) {
|
2022-01-27 20:31:44 +08:00
|
|
|
painter->fillRect(option.rect, option.palette.highlight());
|
2022-01-27 21:27:51 +08:00
|
|
|
normalColor = option.palette.color(QPalette::HighlightedText);
|
|
|
|
}
|
2022-01-27 20:31:44 +08:00
|
|
|
QPixmap icon = mModel->statementIcon(index);
|
|
|
|
int x=option.rect.left();
|
|
|
|
if (!icon.isNull()) {
|
2022-01-27 21:27:51 +08:00
|
|
|
painter->drawPixmap(x+(option.rect.height()-icon.width())/2,option.rect.top()+(option.rect.height()-icon.height())/2,icon);
|
|
|
|
x+=option.rect.height();
|
2022-01-27 20:31:44 +08:00
|
|
|
}
|
|
|
|
QString text = statement->command;
|
|
|
|
int pos=0;
|
|
|
|
int y=option.rect.bottom()-painter->fontMetrics().descent();
|
|
|
|
foreach (const PStatementMathPosition& matchPosition, statement->matchPositions) {
|
|
|
|
if (pos<matchPosition->start) {
|
|
|
|
QString t = text.mid(pos,matchPosition->start-pos);
|
2022-01-27 21:27:51 +08:00
|
|
|
painter->setPen(normalColor);
|
2022-01-27 20:31:44 +08:00
|
|
|
painter->drawText(x,y,t);
|
|
|
|
x+=painter->fontMetrics().horizontalAdvance(t);
|
|
|
|
}
|
|
|
|
QString t = text.mid(matchPosition->start, matchPosition->end-matchPosition->start);
|
|
|
|
painter->setPen(mMatchedColor);
|
|
|
|
painter->drawText(x,y,t);
|
|
|
|
x+=painter->fontMetrics().horizontalAdvance(t);
|
|
|
|
pos=matchPosition->end;
|
|
|
|
}
|
|
|
|
if (pos<text.length()) {
|
|
|
|
QString t = text.mid(pos,text.length()-pos);
|
2022-01-27 21:27:51 +08:00
|
|
|
painter->setPen(normalColor);
|
2022-01-27 20:31:44 +08:00
|
|
|
painter->drawText(x,y,t);
|
|
|
|
x+=painter->fontMetrics().horizontalAdvance(t);
|
|
|
|
}
|
|
|
|
painter->restore();
|
|
|
|
} else {
|
|
|
|
QStyledItemDelegate::paint(painter, option, index);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
CodeCompletionListModel *CodeCompletionListItemDelegate::model() const
|
|
|
|
{
|
|
|
|
return mModel;
|
|
|
|
}
|
|
|
|
|
|
|
|
void CodeCompletionListItemDelegate::setModel(CodeCompletionListModel *newModel)
|
|
|
|
{
|
|
|
|
mModel = newModel;
|
|
|
|
}
|
|
|
|
|
|
|
|
const QColor &CodeCompletionListItemDelegate::normalColor() const
|
|
|
|
{
|
|
|
|
return mNormalColor;
|
|
|
|
}
|
|
|
|
|
|
|
|
void CodeCompletionListItemDelegate::setNormalColor(const QColor &newNormalColor)
|
|
|
|
{
|
|
|
|
mNormalColor = newNormalColor;
|
|
|
|
}
|
|
|
|
|
|
|
|
const QColor &CodeCompletionListItemDelegate::matchedColor() const
|
|
|
|
{
|
|
|
|
return mMatchedColor;
|
|
|
|
}
|
|
|
|
|
|
|
|
void CodeCompletionListItemDelegate::setMatchedColor(const QColor &newMatchedColor)
|
2021-08-28 09:01:40 +08:00
|
|
|
{
|
2022-01-27 20:31:44 +08:00
|
|
|
mMatchedColor = newMatchedColor;
|
2021-08-28 09:01:40 +08:00
|
|
|
}
|
|
|
|
|
2022-02-11 20:19:48 +08:00
|
|
|
const QFont &CodeCompletionListItemDelegate::font() const
|
|
|
|
{
|
|
|
|
return mFont;
|
|
|
|
}
|
|
|
|
|
|
|
|
void CodeCompletionListItemDelegate::setFont(const QFont &newFont)
|
|
|
|
{
|
|
|
|
mFont = newFont;
|
|
|
|
}
|
|
|
|
|
2022-01-27 20:31:44 +08:00
|
|
|
CodeCompletionListItemDelegate::CodeCompletionListItemDelegate(CodeCompletionListModel *model, QWidget *parent) : QStyledItemDelegate(parent),
|
|
|
|
mModel(model)
|
2021-08-28 09:01:40 +08:00
|
|
|
{
|
2022-01-27 20:31:44 +08:00
|
|
|
mNormalColor = qApp->palette().color(QPalette::Text);
|
|
|
|
mMatchedColor = qApp->palette().color(QPalette::BrightText);
|
2021-08-28 09:01:40 +08:00
|
|
|
}
|