From b518304f56863135e65db4ba3f4de30c5a7f0697 Mon Sep 17 00:00:00 2001 From: royqh1979 Date: Thu, 30 Sep 2021 11:20:43 +0800 Subject: [PATCH] - implement: symbol usage count work save: code snippets --- NEWS.md | 3 +- RedPandaIDE/RedPandaIDE.pro | 4 + RedPandaIDE/codesnippetsmanager.cpp | 109 ++++++++++++++++++ RedPandaIDE/codesnippetsmanager.h | 32 +++++ RedPandaIDE/editor.cpp | 18 ++- RedPandaIDE/mainwindow.cpp | 8 +- RedPandaIDE/mainwindow.h | 4 + RedPandaIDE/parser/cppparser.cpp | 2 +- RedPandaIDE/parser/parserutils.h | 4 +- .../settingsdialog/editorautosavewidget.cpp | 1 + .../editorcodecompletionwidget.cpp | 8 ++ .../editorcodecompletionwidget.h | 2 + RedPandaIDE/symbolusagemanager.cpp | 102 ++++++++++++++++ RedPandaIDE/symbolusagemanager.h | 32 +++++ RedPandaIDE/systemconsts.h | 3 +- RedPandaIDE/widgets/codecompletionpopup.cpp | 12 +- RedPandaIDE/widgets/codecompletionpopup.h | 1 - 17 files changed, 323 insertions(+), 22 deletions(-) create mode 100644 RedPandaIDE/codesnippetsmanager.cpp create mode 100644 RedPandaIDE/codesnippetsmanager.h create mode 100644 RedPandaIDE/symbolusagemanager.cpp create mode 100644 RedPandaIDE/symbolusagemanager.h diff --git a/NEWS.md b/NEWS.md index 78b5bc9b..0e8d583f 100644 --- a/NEWS.md +++ b/NEWS.md @@ -13,8 +13,9 @@ Version 0.2.2 - fix: can't coorectly show code completion for array elements - enhancement: show caret when show code/header completions - fix: correctly display pointer info in watch console - - enhancement: search in project + - implement: search in project - enhancement: view memory when debugging + - implement: symbol usage count Version 0.2.1 - fix: crash when load last opens diff --git a/RedPandaIDE/RedPandaIDE.pro b/RedPandaIDE/RedPandaIDE.pro index 2c858dd2..e9e97ff5 100644 --- a/RedPandaIDE/RedPandaIDE.pro +++ b/RedPandaIDE/RedPandaIDE.pro @@ -18,6 +18,7 @@ SOURCES += \ autolinkmanager.cpp \ caretlist.cpp \ codeformatter.cpp \ + codesnippetsmanager.cpp \ codetemplate.cpp \ colorscheme.cpp \ compiler/projectcompiler.cpp \ @@ -57,6 +58,7 @@ SOURCES += \ settingsdialog/projectoutputwidget.cpp \ settingsdialog/projectprecompilewidget.cpp \ settingsdialog/projectversioninfowidget.cpp \ + symbolusagemanager.cpp \ widgets/classbrowser.cpp \ widgets/codecompletionlistview.cpp \ widgets/codecompletionpopup.cpp \ @@ -117,6 +119,7 @@ HEADERS += \ autolinkmanager.h \ caretlist.h \ codeformatter.h \ + codesnippetsmanager.h \ codetemplate.h \ colorscheme.h \ compiler/compiler.h \ @@ -155,6 +158,7 @@ HEADERS += \ settingsdialog/projectoutputwidget.h \ settingsdialog/projectprecompilewidget.h \ settingsdialog/projectversioninfowidget.h \ + symbolusagemanager.h \ widgets/classbrowser.h \ widgets/codecompletionlistview.h \ widgets/codecompletionpopup.h \ diff --git a/RedPandaIDE/codesnippetsmanager.cpp b/RedPandaIDE/codesnippetsmanager.cpp new file mode 100644 index 00000000..cad13ba0 --- /dev/null +++ b/RedPandaIDE/codesnippetsmanager.cpp @@ -0,0 +1,109 @@ +#include "codesnippetsmanager.h" +#include "settings.h" +#include "systemconsts.h" +#include + +#include +#include +#include +#include + +CodeSnippetsManager::CodeSnippetsManager(QObject *parent) : QObject(parent) +{ + +} + +void CodeSnippetsManager::load() +{ + //if config file not exists, copy it from data + //read config file +} + +void CodeSnippetsManager::save() +{ + QString filename = pSettings->dirs().config() + DEV_CODESNIPPET_FILE; + QFile file(filename); + if (!file.open(QFile::WriteOnly | QFile::Truncate)) { + QMessageBox::critical(nullptr, + tr("Save code snippets failed"), + tr("Can't open code snippet file '%1' for write.") + .arg(filename)); + } + QJsonArray array; + foreach (const PCodeSnippet& snippet,mSnippets) { + QJsonObject object; + object["caption"]=snippet->caption; + object["prefix"]=snippet->prefix; + object["code"]=snippet->code; + object["description"]=snippet->desc; + object["section"]=snippet->section; + array.append(object); + } + QJsonDocument doc; + doc.setArray(array); + if (file.write(doc.toJson())<0) { + QMessageBox::critical(nullptr, + tr("Save code snippets failed"), + tr("Write to code snippet file '%1' failed.") + .arg(filename)); + } +} + +void CodeSnippetsManager::addSnippet(const QString &caption, const QString &prefix, const QString &code, const QString &description, int menuSection) +{ + PCodeSnippet snippet = std::make_shared(); + snippet->caption = caption; + snippet->prefix = prefix; + snippet->code = code; + snippet->desc = description; + snippet->section = menuSection; + mSnippets.append(snippet); +} + +void CodeSnippetsManager::remove(int index) +{ + Q_ASSERT(index>=0 && index &CodeSnippetsManager::snippets() const +{ + return mSnippets; +} + +int CodeSnippetsModel::rowCount(const QModelIndex &parent) const +{ + return mSnippets.count(); +} + +int CodeSnippetsModel::columnCount(const QModelIndex &parent) const +{ + return 4; +} + +bool CodeSnippetsModel::setData(const QModelIndex &index, const QVariant &value, int role) +{ + +} + +QVariant CodeSnippetsModel::headerData(int section, Qt::Orientation orientation, int role) const +{ + if (orientation == Qt::Horizontal && role == Qt::DisplayRole) { + switch(section) { + case 0: + return tr("Caption"); + case 1: + return tr("Completion Prefix"); + case 2: + return tr("Description"); + case 3: + return tr("Menu Section"); + } + } + return QVariant(); +} diff --git a/RedPandaIDE/codesnippetsmanager.h b/RedPandaIDE/codesnippetsmanager.h new file mode 100644 index 00000000..11420242 --- /dev/null +++ b/RedPandaIDE/codesnippetsmanager.h @@ -0,0 +1,32 @@ +#ifndef CODESNIPPETSMANAGER_H +#define CODESNIPPETSMANAGER_H + +#include +#include "parser/parserutils.h" + +class CodeSnippetsManager : public QObject +{ + Q_OBJECT +public: + explicit CodeSnippetsManager(QObject *parent = nullptr); + + void load(); + void save(); + void addSnippet( + const QString& caption, + const QString& prefix, + const QString& code, + const QString& description, + int menuSection); + void remove(int index); + void clear(); + const QList &snippets() const; + +signals: +private: + QList mSnippets; + +private: +}; + +#endif // CODESNIPPETSMANAGER_H diff --git a/RedPandaIDE/editor.cpp b/RedPandaIDE/editor.cpp index 235e587b..5129d057 100644 --- a/RedPandaIDE/editor.cpp +++ b/RedPandaIDE/editor.cpp @@ -1900,17 +1900,13 @@ void Editor::completionInsert(bool appendFunc) PStatement statement = mCompletionPopup->selectedStatement(); if (!statement) return; -// if devCodeCompletion.RecordUsage and (Statement^._Kind <> skUserCodeIn) then begin -// idx:=Utils.FastIndexOf(dmMain.SymbolUsage,Statement^._FullName); -// if idx = -1 then begin -// usageCount:=1; -// dmMain.SymbolUsage.AddObject(Statement^._FullName, pointer(1)) -// end else begin -// usageCount := 1 + integer(dmMain.SymbolUsage.Objects[idx]); -// dmMain.SymbolUsage.Objects[idx] := pointer( usageCount ); -// end; -// Statement^._UsageCount := usageCount; -// end; + + if (pSettings->codeCompletion().recordUsage() + && statement->kind != StatementKind::skUserCodeIn) { + statement->usageCount+=1; + pMainWindow->symbolUsageManager()->updateUsage(statement->fullName, + statement->usageCount); + } QString funcAddOn = ""; diff --git a/RedPandaIDE/mainwindow.cpp b/RedPandaIDE/mainwindow.cpp index f65b8553..fd024424 100644 --- a/RedPandaIDE/mainwindow.cpp +++ b/RedPandaIDE/mainwindow.cpp @@ -123,6 +123,8 @@ MainWindow::MainWindow(QWidget *parent) connect(ui->cbMemoryAddress->lineEdit(), &QLineEdit::returnPressed, this, &MainWindow::onDebugMemoryAddressInput); + mSymbolUsageManager = std::make_shared(); + mSymbolUsageManager->load(); mSearchResultTreeModel = std::make_shared(&mSearchResultModel); mSearchResultListModel = std::make_shared(&mSearchResultModel); mSearchViewDelegate = std::make_shared(mSearchResultTreeModel); @@ -2391,7 +2393,7 @@ void MainWindow::closeEvent(QCloseEvent *event) { mCompilerManager->stopCompile(); mCompilerManager->stopRun(); - + mSymbolUsageManager->save(); event->accept(); return; } @@ -3746,3 +3748,7 @@ void MainWindow::on_classBrowser_doubleClicked(const QModelIndex &index) } } +PSymbolUsageManager &MainWindow::symbolUsageManager() +{ + return mSymbolUsageManager; +} diff --git a/RedPandaIDE/mainwindow.h b/RedPandaIDE/mainwindow.h index ac3206f7..032bb517 100644 --- a/RedPandaIDE/mainwindow.h +++ b/RedPandaIDE/mainwindow.h @@ -11,6 +11,7 @@ #include "widgets/headercompletionpopup.h" #include "widgets/functiontooltipwidget.h" #include "caretlist.h" +#include "symbolusagemanager.h" QT_BEGIN_NAMESPACE namespace Ui { class MainWindow; } @@ -113,6 +114,8 @@ public: const std::shared_ptr > &statementColors() const; + PSymbolUsageManager &symbolUsageManager(); + public slots: void onCompileLog(const QString& msg); void onCompileIssue(PCompileIssue issue); @@ -379,6 +382,7 @@ private: PSearchResultTreeViewDelegate mSearchViewDelegate; ClassBrowserModel mClassBrowserModel; std::shared_ptr> mStatementColors; + PSymbolUsageManager mSymbolUsageManager; bool mCheckSyntaxInBack; bool mOpenClosingBottomPanel; diff --git a/RedPandaIDE/parser/cppparser.cpp b/RedPandaIDE/parser/cppparser.cpp index 3e34afa5..872add99 100644 --- a/RedPandaIDE/parser/cppparser.cpp +++ b/RedPandaIDE/parser/cppparser.cpp @@ -1077,7 +1077,7 @@ PStatement CppParser::addStatement(const PStatement& parent, result->fullName = newCommand; else result->fullName = getFullStatementName(newCommand, parent); - result->usageCount = 0; + result->usageCount = -1; result->freqTop = 0; mStatementList.add(result); if (result->kind == StatementKind::skNamespace) { diff --git a/RedPandaIDE/parser/parserutils.h b/RedPandaIDE/parser/parserutils.h index c4c63a3b..f010740f 100644 --- a/RedPandaIDE/parser/parserutils.h +++ b/RedPandaIDE/parser/parserutils.h @@ -5,7 +5,7 @@ #include #include -struct CodeIns { +struct CodeSnippet { QString caption; //Name QString prefix; //Prefix used in code suggestion QString code; //Code body @@ -13,7 +13,7 @@ struct CodeIns { int section; //Section in the menu }; -using PCodeIns = std::shared_ptr; +using PCodeIns = std::shared_ptr; // preprocess/ macro define struct Define { diff --git a/RedPandaIDE/settingsdialog/editorautosavewidget.cpp b/RedPandaIDE/settingsdialog/editorautosavewidget.cpp index 1a9fad19..85668668 100644 --- a/RedPandaIDE/settingsdialog/editorautosavewidget.cpp +++ b/RedPandaIDE/settingsdialog/editorautosavewidget.cpp @@ -42,6 +42,7 @@ void EditorAutoSaveWidget::doLoad() break; case astAllOpennedFiles: ui->rbAllOpennedFiles->setChecked(true); + break; default: ui->rbProjectFiles->setChecked(true); } diff --git a/RedPandaIDE/settingsdialog/editorcodecompletionwidget.cpp b/RedPandaIDE/settingsdialog/editorcodecompletionwidget.cpp index fb141e97..07eac772 100644 --- a/RedPandaIDE/settingsdialog/editorcodecompletionwidget.cpp +++ b/RedPandaIDE/settingsdialog/editorcodecompletionwidget.cpp @@ -1,6 +1,8 @@ #include "editorcodecompletionwidget.h" #include "ui_editorcodecompletionwidget.h" #include "../settings.h" +#include "../mainwindow.h" +#include "../symbolusagemanager.h" EditorCodeCompletionWidget::EditorCodeCompletionWidget(const QString& name, const QString& group, QWidget *parent) : @@ -56,3 +58,9 @@ void EditorCodeCompletionWidget::doSave() pSettings->codeCompletion().save(); } + +void EditorCodeCompletionWidget::on_btnClearUsageData_clicked() +{ + pMainWindow->symbolUsageManager()->reset(); +} + diff --git a/RedPandaIDE/settingsdialog/editorcodecompletionwidget.h b/RedPandaIDE/settingsdialog/editorcodecompletionwidget.h index 210011df..336c01dc 100644 --- a/RedPandaIDE/settingsdialog/editorcodecompletionwidget.h +++ b/RedPandaIDE/settingsdialog/editorcodecompletionwidget.h @@ -23,6 +23,8 @@ private: protected: void doLoad() override; void doSave() override; +private slots: + void on_btnClearUsageData_clicked(); }; #endif // EDITORCODECOMPLETIONWIDGET_H diff --git a/RedPandaIDE/symbolusagemanager.cpp b/RedPandaIDE/symbolusagemanager.cpp new file mode 100644 index 00000000..e802d971 --- /dev/null +++ b/RedPandaIDE/symbolusagemanager.cpp @@ -0,0 +1,102 @@ +#include "symbolusagemanager.h" +#include "settings.h" +#include "systemconsts.h" + +#include +#include +#include +#include +#include + +SymbolUsageManager::SymbolUsageManager(QObject *parent) : QObject(parent) +{ + +} + +void SymbolUsageManager::load() +{ + QString filename = includeTrailingPathDelimiter(pSettings->dirs().config()) + + DEV_SYMBOLUSAGE_FILE; + if (!fileExists(filename)) + return; + QFile file(filename); + if (!file.open(QFile::ReadOnly)) { + QMessageBox::critical(nullptr, + tr("Load symbol usage info failed"), + tr("Can't open symbol usage file '%1' for read.") + .arg(filename)); + } + QByteArray contents = file.readAll(); + QJsonParseError error; + QJsonDocument doc = QJsonDocument::fromJson(contents,&error); + if (error.error != QJsonParseError::NoError) { + QMessageBox::critical(nullptr, + tr("Load symbol usage info failed"), + tr("Can't parse symbol usage file '%1'.") + .arg(filename)); + } + + mUsages.clear(); + QJsonArray array = doc.array(); + foreach (const QJsonValue& val, array) { + QJsonObject obj = val.toObject(); + QString fullname = obj["symbol"].toString(); + int count = obj["count"].toInt(); + PSymbolUsage usage = std::make_shared(); + usage->fullName = fullname; + usage->count = count; + mUsages.insert(fullname,usage); + } +} + +void SymbolUsageManager::save() +{ + QString filename = includeTrailingPathDelimiter(pSettings->dirs().config()) + + DEV_SYMBOLUSAGE_FILE; + QFile file(filename); + if (!file.open(QFile::WriteOnly | QFile::Truncate)) { + QMessageBox::critical(nullptr, + tr("Save symbol usage info failed"), + tr("Can't open symbol usage file '%1' for write.") + .arg(filename)); + } + QJsonArray array; + foreach (const PSymbolUsage& usage,mUsages) { + QJsonObject object; + object["symbol"]=usage->fullName; + object["count"]=usage->count; + array.append(object); + } + QJsonDocument doc; + doc.setArray(array); + if (file.write(doc.toJson())<0) { + QMessageBox::critical(nullptr, + tr("Save symbol usage info failed"), + tr("Write to symbol usage file '%1' failed.") + .arg(filename)); + } +} + +void SymbolUsageManager::reset() +{ + mUsages.clear(); + save(); +} + +PSymbolUsage SymbolUsageManager::findUsage(const QString &fullName) const +{ + return mUsages.value(fullName,PSymbolUsage()); +} + +void SymbolUsageManager::updateUsage(const QString &symbol, int count) +{ + PSymbolUsage usage = mUsages.value(symbol,PSymbolUsage()); + if (usage) { + usage->count = count; + } else { + usage = std::make_shared(); + usage->fullName = symbol; + usage->count = count; + mUsages.insert(symbol,usage); + } +} diff --git a/RedPandaIDE/symbolusagemanager.h b/RedPandaIDE/symbolusagemanager.h new file mode 100644 index 00000000..b788d733 --- /dev/null +++ b/RedPandaIDE/symbolusagemanager.h @@ -0,0 +1,32 @@ +#ifndef SYMBOLUSAGEMANAGER_H +#define SYMBOLUSAGEMANAGER_H + +#include +#include +#include +#include + +struct SymbolUsage { + QString fullName; + int count; +}; +using PSymbolUsage = std::shared_ptr; + +class SymbolUsageManager : public QObject +{ + Q_OBJECT +public: + explicit SymbolUsageManager(QObject *parent = nullptr); + void load(); + void save(); + void reset(); + PSymbolUsage findUsage(const QString& fullName) const; + void updateUsage(const QString& symbol, int count); +signals: +private: + QHash mUsages; +}; + +using PSymbolUsageManager = std::shared_ptr; + +#endif // SYMBOLUSAGEMANAGER_H diff --git a/RedPandaIDE/systemconsts.h b/RedPandaIDE/systemconsts.h index 81cd2f83..b1709be6 100644 --- a/RedPandaIDE/systemconsts.h +++ b/RedPandaIDE/systemconsts.h @@ -32,7 +32,8 @@ #define TEMPLATE_EXT "template" #define DEV_INTERNAL_OPEN "$__DEV_INTERNAL_OPEN" #define DEV_LASTOPENS_FILE "lastopens.ini" - +#define DEV_SYMBOLUSAGE_FILE "symbolusage.json" +#define DEV_CODESNIPPET_FILE "codesnippets.json" #ifdef Q_OS_WIN # define PATH_SENSITIVITY Qt::CaseInsensitive # define PATH_SEPARATOR ";" diff --git a/RedPandaIDE/widgets/codecompletionpopup.cpp b/RedPandaIDE/widgets/codecompletionpopup.cpp index 7c750695..a9f690ad 100644 --- a/RedPandaIDE/widgets/codecompletionpopup.cpp +++ b/RedPandaIDE/widgets/codecompletionpopup.cpp @@ -3,6 +3,7 @@ #include "../mainwindow.h" #include "../editor.h" #include "../editorlist.h" +#include "../symbolusagemanager.h" #include #include @@ -360,10 +361,13 @@ void CodeCompletionPopup::filterList(const QString &member) int thirdCount = 0; int usageCount; foreach (const PStatement& statement,mCompletionStatementList) { - if (statement->usageCount == 0) { - usageCount = mSymbolUsage.value(statement->fullName,0); - if (usageCount == 0) - continue; + if (statement->usageCount == -1) { + PSymbolUsage usage = pMainWindow->symbolUsageManager()->findUsage(statement->fullName); + if (usage) { + usageCount = usage->count; + } else { + usageCount = 0; + } statement->usageCount = usageCount; } else usageCount = statement->usageCount; diff --git a/RedPandaIDE/widgets/codecompletionpopup.h b/RedPandaIDE/widgets/codecompletionpopup.h index ee6dd64c..aba5d2e0 100644 --- a/RedPandaIDE/widgets/codecompletionpopup.h +++ b/RedPandaIDE/widgets/codecompletionpopup.h @@ -85,7 +85,6 @@ private: QSet mUsings; QSet mAddedStatements; QString mPhrase; - QHash mSymbolUsage; QRecursiveMutex mMutex; std::shared_ptr> mColors;