diff --git a/NEWS.md b/NEWS.md index af12df1b..7d39c54a 100644 --- a/NEWS.md +++ b/NEWS.md @@ -7,6 +7,7 @@ Red Panda C++ Version 1.0.4 - enhancement: if a project's unit encoding is the same with project's encoding, don't save its encoding - fix: files will be saved to default encoding inspite of its original encoding - fix: parenthesis skip doesn't work when editing non-c/c++ files + - enhancement: prefer local headers over system headers when complete #include header path Red Panda C++ Version 1.0.3 - fix: when oj problem grabbed by competitive companion received, diff --git a/RedPandaIDE/editor.cpp b/RedPandaIDE/editor.cpp index f2a7b3e6..8a0776ce 100644 --- a/RedPandaIDE/editor.cpp +++ b/RedPandaIDE/editor.cpp @@ -3120,7 +3120,7 @@ void Editor::completionInsert(bool appendFunc) void Editor::headerCompletionInsert() { - QString headerName = mHeaderCompletionPopup->selectedFilename(); + QString headerName = mHeaderCompletionPopup->selectedFilename(true); if (headerName.isEmpty()) return; diff --git a/RedPandaIDE/mainwindow.cpp b/RedPandaIDE/mainwindow.cpp index ca258fe4..7b647e40 100644 --- a/RedPandaIDE/mainwindow.cpp +++ b/RedPandaIDE/mainwindow.cpp @@ -570,9 +570,13 @@ void MainWindow::updateEditorColorSchemes() QColor baseColor = palette().color(QPalette::Base); item = pColorManager->getItem(schemeName, SYNS_AttrPreprocessor); if (item) { - mHeaderCompletionPopup->setSuggestionColor(item->foreground()); + mHeaderCompletionPopup->setSuggestionColor(item->foreground(), + item->foreground(), + item->foreground()); } else { - mHeaderCompletionPopup->setSuggestionColor(palette().color(QPalette::Text)); + mHeaderCompletionPopup->setSuggestionColor(palette().color(QPalette::Text), + palette().color(QPalette::Text), + palette().color(QPalette::Text)); } item = pColorManager->getItem(schemeName, COLOR_SCHEME_ERROR); if (item && haveGoodContrast(item->foreground(), baseColor)) { diff --git a/RedPandaIDE/settings.cpp b/RedPandaIDE/settings.cpp index 55216b12..4468ec0f 100644 --- a/RedPandaIDE/settings.cpp +++ b/RedPandaIDE/settings.cpp @@ -2763,7 +2763,7 @@ void Settings::CompilerSets::deleteSet(int index) saveSets(); } -int Settings::CompilerSets::size() const +size_t Settings::CompilerSets::size() const { return mList.size(); } diff --git a/RedPandaIDE/settings.h b/RedPandaIDE/settings.h index 350c2d6f..d8b02412 100644 --- a/RedPandaIDE/settings.h +++ b/RedPandaIDE/settings.h @@ -1334,7 +1334,7 @@ public: void saveDefaultIndex(); void deleteSet(int index); void saveSet(int index); - int size() const; + size_t size() const; int defaultIndex() const; void setDefaultIndex(int value); PCompilerSet defaultSet(); diff --git a/RedPandaIDE/widgets/headercompletionpopup.cpp b/RedPandaIDE/widgets/headercompletionpopup.cpp index 8706ad70..e4ecb6dd 100644 --- a/RedPandaIDE/widgets/headercompletionpopup.cpp +++ b/RedPandaIDE/widgets/headercompletionpopup.cpp @@ -17,9 +17,9 @@ #include "headercompletionpopup.h" #include -#include #include #include +#include HeaderCompletionPopup::HeaderCompletionPopup(QWidget* parent):QWidget(parent) { @@ -86,7 +86,7 @@ bool HeaderCompletionPopup::search(const QString &phrase, bool autoHideOnSingleR if (autoHideOnSingleResult) return true; // if only one suggestion, and is exactly the symbol to search, hide the frame (the search is over) - if (symbol == mCompletionList.front()) + if (symbol == mCompletionList[0]->filename) return true; } } else { @@ -100,43 +100,66 @@ void HeaderCompletionPopup::setKeypressedCallback(const KeyPressedCallback &newK mListView->setKeypressedCallback(newKeypressedCallback); } -void HeaderCompletionPopup::setSuggestionColor(const QColor &color) +void HeaderCompletionPopup::setSuggestionColor(const QColor& localColor, + const QColor& projectColor, + const QColor& systemColor) { - mModel->setColor(color); + mModel->setLocalColor(localColor); + mModel->setProjectColor(projectColor); + mModel->setSystemColor(systemColor); } -QString HeaderCompletionPopup::selectedFilename() +QString HeaderCompletionPopup::selectedFilename(bool updateUsageCount) { if (!isEnabled()) return ""; int index = mListView->currentIndex().row(); + PHeaderCompletionListItem item; if (index>=0 && index0) { - return mCompletionList.front(); + item=mCompletionList.front(); } - return ""; + if (item) { + if (updateUsageCount) { + item->usageCount++; + mHeaderUsageCounts.insert(item->fullpath,item->usageCount); + } + return item->filename; + } + return ""; } +static bool sortByUsage(const PHeaderCompletionListItem& item1,const PHeaderCompletionListItem& item2){ + if (item1->usageCount != item2->usageCount) + return item1->usageCount > item2->usageCount; + + if (item1->itemType != item2->itemType) + return item1->itemTypeitemType; + + return item1->filename < item2->filename; +} + + void HeaderCompletionPopup::filterList(const QString &member) { + Qt::CaseSensitivity caseSensitivity=mIgnoreCase?Qt::CaseInsensitive:Qt::CaseSensitive; mCompletionList.clear(); if (member.isEmpty()) { - foreach (const QString& s,mFullCompletionList) { - mCompletionList.append(s); + foreach (const PHeaderCompletionListItem& item,mFullCompletionList.values()) { + mCompletionList.append(item); } } else { - foreach (const QString& s,mFullCompletionList) { - if (mIgnoreCase && s.startsWith(member, Qt::CaseInsensitive)) { - mCompletionList.append(s); - } else if (s.startsWith(member, Qt::CaseSensitive)){ - mCompletionList.append(s); + foreach (const PHeaderCompletionListItem& item,mFullCompletionList.values()) { + if (item->filename.startsWith(member, caseSensitivity)) { + mCompletionList.append(item); } } } - std::sort(mCompletionList.begin(),mCompletionList.end()); + std::sort(mCompletionList.begin(),mCompletionList.end(), sortByUsage); } + void HeaderCompletionPopup::getCompletionFor(const QString &phrase) { int idx = phrase.lastIndexOf('\\'); @@ -147,33 +170,33 @@ void HeaderCompletionPopup::getCompletionFor(const QString &phrase) if (idx < 0) { // dont have basedir if (mSearchLocal) { QFileInfo fileInfo(mCurrentFile); - addFilesInPath(fileInfo.absolutePath()); + addFilesInPath(fileInfo.absolutePath(), HeaderCompletionListItemType::LocalHeader); }; for (const QString& path: mParser->includePaths()) { - addFilesInPath(path); + addFilesInPath(path, HeaderCompletionListItemType::ProjectHeader); } for (const QString& path: mParser->projectIncludePaths()) { - addFilesInPath(path); + addFilesInPath(path, HeaderCompletionListItemType::SystemHeader); } } else { QString current = phrase.mid(0,idx); if (mSearchLocal) { QFileInfo fileInfo(mCurrentFile); - addFilesInSubDir(fileInfo.absolutePath(),current); + addFilesInSubDir(fileInfo.absolutePath(),current, HeaderCompletionListItemType::LocalHeader); } for (const QString& path: mParser->includePaths()) { - addFilesInSubDir(path,current); + addFilesInSubDir(path,current, HeaderCompletionListItemType::ProjectHeader); } for (const QString& path: mParser->projectIncludePaths()) { - addFilesInSubDir(path,current); + addFilesInSubDir(path,current, HeaderCompletionListItemType::SystemHeader); } } } -void HeaderCompletionPopup::addFilesInPath(const QString &path) +void HeaderCompletionPopup::addFilesInPath(const QString &path, HeaderCompletionListItemType type) { QDir dir(path); if (!dir.exists()) @@ -183,25 +206,30 @@ void HeaderCompletionPopup::addFilesInPath(const QString &path) continue; QString suffix = fileInfo.suffix().toLower(); if (suffix == "h" || suffix == "hpp" || suffix == "") { - addFile(fileInfo.fileName()); + addFile(dir, fileInfo.fileName(), type); } } } -void HeaderCompletionPopup::addFile(const QString &fileName) +void HeaderCompletionPopup::addFile(const QDir& dir, const QString &fileName, HeaderCompletionListItemType type) { if (fileName.isEmpty()) return; if (fileName.startsWith('.')) return; - mFullCompletionList.insert(fileName); + PHeaderCompletionListItem item = std::make_shared(); + item->filename = fileName; + item->itemType = type; + item->fullpath = dir.absoluteFilePath(fileName); + item->usageCount = mHeaderUsageCounts.value(item->fullpath,0); + mFullCompletionList.insert(fileName,item); } -void HeaderCompletionPopup::addFilesInSubDir(const QString &baseDirPath, const QString &subDirName) +void HeaderCompletionPopup::addFilesInSubDir(const QString &baseDirPath, const QString &subDirName, HeaderCompletionListItemType type) { QDir baseDir(baseDirPath); QString subDirPath = baseDir.filePath(subDirName); - addFilesInPath(subDirPath); + addFilesInPath(subDirPath, type); } bool HeaderCompletionPopup::searchLocal() const @@ -259,7 +287,7 @@ bool HeaderCompletionPopup::event(QEvent *event) return result; } -HeaderCompletionListModel::HeaderCompletionListModel(const QStringList *files, QObject *parent): +HeaderCompletionListModel::HeaderCompletionListModel(const QList *files, QObject *parent): QAbstractListModel(parent), mFiles(files) { @@ -280,10 +308,18 @@ QVariant HeaderCompletionListModel::data(const QModelIndex &index, int role) con switch(role) { case Qt::DisplayRole: { - return mFiles->at(index.row()); + return mFiles->at(index.row())->filename; } case Qt::ForegroundRole: - return mColor; + switch(mFiles->at(index.row())->itemType) { + case HeaderCompletionListItemType::LocalHeader: + return mLocalColor; + case HeaderCompletionListItemType::ProjectHeader: + return mProjectColor; + case HeaderCompletionListItemType::SystemHeader: + return mSystemColor; + } + break; } return QVariant(); @@ -295,7 +331,17 @@ void HeaderCompletionListModel::notifyUpdated() endResetModel(); } -void HeaderCompletionListModel::setColor(const QColor &newColor) +void HeaderCompletionListModel::setSystemColor(const QColor &newColor) { - mColor = newColor; + mSystemColor = newColor; +} + +void HeaderCompletionListModel::setProjectColor(const QColor &newColor) +{ + mProjectColor = newColor; +} + +void HeaderCompletionListModel::setLocalColor(const QColor &newColor) +{ + mLocalColor = newColor; } diff --git a/RedPandaIDE/widgets/headercompletionpopup.h b/RedPandaIDE/widgets/headercompletionpopup.h index c0e6756d..1fe2ab89 100644 --- a/RedPandaIDE/widgets/headercompletionpopup.h +++ b/RedPandaIDE/widgets/headercompletionpopup.h @@ -17,22 +17,42 @@ #ifndef HEADERCOMPLETIONPOPUP_H #define HEADERCOMPLETIONPOPUP_H +#include #include #include "codecompletionlistview.h" #include "../parser/cppparser.h" +enum class HeaderCompletionListItemType { + LocalHeader, + ProjectHeader, + SystemHeader +}; + +struct HeaderCompletionListItem { + QString filename; + QString fullpath; + int usageCount; + HeaderCompletionListItemType itemType; +}; + +using PHeaderCompletionListItem=std::shared_ptr; + class HeaderCompletionListModel: public QAbstractListModel { Q_OBJECT public: - explicit HeaderCompletionListModel(const QStringList* files,QObject *parent = nullptr); + explicit HeaderCompletionListModel(const QList* files,QObject *parent = nullptr); int rowCount(const QModelIndex &parent) const override; QVariant data(const QModelIndex &index, int role) const override; void notifyUpdated(); - void setColor(const QColor &newColor); + void setLocalColor(const QColor &newColor); + void setSystemColor(const QColor &newColor); + void setProjectColor(const QColor &newColor); private: - const QStringList* mFiles; - QColor mColor; + const QList* mFiles; + QColor mLocalColor; + QColor mSystemColor; + QColor mProjectColor; }; class HeaderCompletionPopup : public QWidget @@ -44,21 +64,24 @@ public: void prepareSearch(const QString& phrase, const QString& fileName); bool search(const QString& phrase, bool autoHideOnSingleResult); void setKeypressedCallback(const KeyPressedCallback &newKeypressedCallback); - void setSuggestionColor(const QColor& color); - QString selectedFilename(); + void setSuggestionColor(const QColor& localColor, + const QColor& projectColor, + const QColor& systemColor); + QString selectedFilename(bool updateUsageCount); private: void filterList(const QString& member); void getCompletionFor(const QString& phrase); - void addFilesInPath(const QString& path); - void addFile(const QString& fileName); - void addFilesInSubDir(const QString& baseDirPath, const QString& subDirName); + void addFilesInPath(const QString& path, HeaderCompletionListItemType type); + void addFile(const QDir& dir, const QString& fileName, HeaderCompletionListItemType type); + void addFilesInSubDir(const QString& baseDirPath, const QString& subDirName, HeaderCompletionListItemType type); private: CodeCompletionListView* mListView; HeaderCompletionListModel* mModel; - QSet mFullCompletionList; - QStringList mCompletionList; + QHash mFullCompletionList; + QList mCompletionList; + QHash mHeaderUsageCounts; int mShowCount; QSet mAddedFileNames;