From 620bdc8266f27feb2ebf5ee4bc61a8746b10f966 Mon Sep 17 00:00:00 2001 From: Roy Qu Date: Thu, 27 Jan 2022 18:34:18 +0800 Subject: [PATCH] - fix: code folding calcuation not correct when some codes are folded and editing after them --- NEWS.md | 3 + RedPandaIDE/RedPandaIDE.pro | 3 + RedPandaIDE/mainwindow.cpp | 59 ++++++- RedPandaIDE/mainwindow.h | 2 + RedPandaIDE/mainwindow.ui | 10 +- RedPandaIDE/parser/cppparser.cpp | 1 - RedPandaIDE/parser/parserutils.h | 1 - RedPandaIDE/project.cpp | 20 +-- RedPandaIDE/project.h | 4 +- RedPandaIDE/qsynedit/SynEdit.cpp | 10 +- RedPandaIDE/widgets/codecompletionpopup.cpp | 162 ++++++-------------- 11 files changed, 136 insertions(+), 139 deletions(-) diff --git a/NEWS.md b/NEWS.md index 4a58aba8..6849e2ec 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,6 +1,9 @@ Red Panda C++ Version 0.14.0 - enhancement: custom icon set ( in the configuration folder) - enhancement: show custom icon set folder in options -> enviroment -> folders + - enhancement: add class ( to project) wizard + - enhancement: greatly speed up code completion + - fix: code folding calcuation not correct when some codes are folded and editing after them Red Panda C++ Version 0.13.4 - fix: when copy comments, don't auto indent diff --git a/RedPandaIDE/RedPandaIDE.pro b/RedPandaIDE/RedPandaIDE.pro index 1f71ac35..8bf3d6e7 100644 --- a/RedPandaIDE/RedPandaIDE.pro +++ b/RedPandaIDE/RedPandaIDE.pro @@ -144,6 +144,7 @@ SOURCES += \ widgets/labelwithmenu.cpp \ widgets/lightfusionstyle.cpp \ widgets/macroinfomodel.cpp \ + widgets/newclassdialog.cpp \ widgets/newprojectdialog.cpp \ widgets/ojproblempropertywidget.cpp \ widgets/ojproblemsetmodel.cpp \ @@ -268,6 +269,7 @@ HEADERS += \ widgets/labelwithmenu.h \ widgets/lightfusionstyle.h \ widgets/macroinfomodel.h \ + widgets/newclassdialog.h \ widgets/newprojectdialog.h \ widgets/ojproblempropertywidget.h \ widgets/ojproblemsetmodel.h \ @@ -316,6 +318,7 @@ FORMS += \ settingsdialog/settingsdialog.ui \ widgets/custommakefileinfodialog.ui \ widgets/filepropertiesdialog.ui \ + widgets/newclassdialog.ui \ widgets/newprojectdialog.ui \ widgets/ojproblempropertywidget.ui \ widgets/searchdialog.ui \ diff --git a/RedPandaIDE/mainwindow.cpp b/RedPandaIDE/mainwindow.cpp index 3afcc388..829e7f91 100644 --- a/RedPandaIDE/mainwindow.cpp +++ b/RedPandaIDE/mainwindow.cpp @@ -37,6 +37,7 @@ #include "problems/problemcasevalidator.h" #include "widgets/ojproblempropertywidget.h" #include "iconsmanager.h" +#include "widgets/newclassdialog.h" #include #include @@ -284,6 +285,7 @@ MainWindow::MainWindow(QWidget *parent) } //class browser + ui->classBrowser->setUniformRowHeights(true); ui->classBrowser->setModel(&mClassBrowserModel); connect(&mFileSystemWatcher,&QFileSystemWatcher::fileChanged, @@ -469,6 +471,7 @@ void MainWindow::updateProjectActions() ui->actionMakeClean->setEnabled(hasProject); ui->actionProject_options->setEnabled(hasProject); ui->actionClose_Project->setEnabled(hasProject); + ui->actionAdd_Class->setEnabled(hasProject); ui->actionProject_Open_Folder_In_Explorer->setEnabled(hasProject); ui->actionProject_Open_In_Terminal->setEnabled(hasProject); updateCompileActions(); @@ -2454,7 +2457,7 @@ void MainWindow::buildContextMenus() FolderNode * node = static_cast(current.internalPointer()); PFolderNode folderNode = mProject->pointerToNode(node); if (!folderNode) - folderNode = mProject->node(); + folderNode = mProject->rootNode(); if (folderNode->unitIndex>=0) return; QString s=tr("New folder"); @@ -6146,3 +6149,57 @@ void MainWindow::on_actionDelete_to_Word_End_triggered() } } + +void MainWindow::on_actionAdd_Class_triggered() +{ + if (!mProject) + return; + NewClassDialog dialog; + dialog.setPath(mProject->folder()); + if (dialog.exec()==QDialog::Accepted) { + qDebug()<<"Let's create class"; + QDir dir(dialog.path()); + if (dialog.className().isEmpty() + || dialog.sourceName().isEmpty() + || dialog.headerName().isEmpty() + || !dir.exists()) + return; + QString header_macro = dialog.className().toUpper()+"_H"; + QStringList header; + QString indents; + if (pSettings->editor().tabToSpaces()) { + indents = QString(pSettings->editor().tabWidth(),' '); + } else { + indents = "\t"; + } + header.append(QString("#ifndef %1").arg(header_macro)); + header.append(QString("#define %1").arg(header_macro)); + header.append(""); + header.append(QString("class %1 {").arg(dialog.className())); + header.append("public:"); + header.append(""); + header.append("private:"); + header.append(""); + header.append("};"); + header.append(""); + header.append("#endif"); + QString headerFilename = includeTrailingPathDelimiter(dialog.path())+dialog.headerName(); + stringsToFile(header, headerFilename); + QStringList source; + source.append(QString("#include \"%1\";").arg(dialog.headerName())); + source.append(""); + source.append(""); + QString sourceFilename = includeTrailingPathDelimiter(dialog.path())+dialog.sourceName(); + stringsToFile(source, sourceFilename); + + mProject->addUnit(headerFilename,mProject->rootNode(),false); + mProject->cppParser()->addFileToScan(headerFilename); + mProject->addUnit(sourceFilename,mProject->rootNode(),false); + mProject->cppParser()->addFileToScan(sourceFilename); + mProject->rebuildNodes(); + mProject->saveUnits(); + parseFileList(mProject->cppParser()); + updateProjectView(); + } +} + diff --git a/RedPandaIDE/mainwindow.h b/RedPandaIDE/mainwindow.h index 9f397e49..e07b615b 100644 --- a/RedPandaIDE/mainwindow.h +++ b/RedPandaIDE/mainwindow.h @@ -560,6 +560,8 @@ private slots: void on_actionDelete_to_Word_End_triggered(); + void on_actionAdd_Class_triggered(); + private: Ui::MainWindow *ui; EditorList *mEditorList; diff --git a/RedPandaIDE/mainwindow.ui b/RedPandaIDE/mainwindow.ui index 0e41e1ff..1ef9b664 100644 --- a/RedPandaIDE/mainwindow.ui +++ b/RedPandaIDE/mainwindow.ui @@ -85,7 +85,7 @@ QTabWidget::West - 1 + 2 true @@ -506,7 +506,7 @@ QTabWidget::South - 2 + 5 @@ -1493,6 +1493,7 @@ + @@ -2696,6 +2697,11 @@ Ctrl+Shift+E + + + Add Class... + + diff --git a/RedPandaIDE/parser/cppparser.cpp b/RedPandaIDE/parser/cppparser.cpp index 37e09833..379ed3d9 100644 --- a/RedPandaIDE/parser/cppparser.cpp +++ b/RedPandaIDE/parser/cppparser.cpp @@ -1192,7 +1192,6 @@ PStatement CppParser::addStatement(const PStatement& parent, else result->fullName = getFullStatementName(newCommand, parent); result->usageCount = -1; - result->freqTop = 0; mStatementList.add(result); if (result->kind == StatementKind::skNamespace) { PStatementList namespaceList = mNamespaces.value(result->fullName,PStatementList()); diff --git a/RedPandaIDE/parser/parserutils.h b/RedPandaIDE/parser/parserutils.h index 2ffddd31..6fde028e 100644 --- a/RedPandaIDE/parser/parserutils.h +++ b/RedPandaIDE/parser/parserutils.h @@ -168,7 +168,6 @@ struct Statement { QString noNameArgs;// Args without name // fields for code completion int usageCount; //Usage Count - int freqTop; // Usage Count Rank int matchPosTotal; // total of matched positions int firstMatchLength; // length of first match; int caseMatched; // if match with case diff --git a/RedPandaIDE/project.cpp b/RedPandaIDE/project.cpp index bb402939..214e72de 100644 --- a/RedPandaIDE/project.cpp +++ b/RedPandaIDE/project.cpp @@ -880,6 +880,11 @@ PProjectUnit Project::addUnit(const QString &inFileName, PFolderNode parentNode, return newUnit; } +QString Project::folder() +{ + return extractFileDir(filename()); +} + void Project::buildPrivateResource(bool forceSave) { int comp = 0; @@ -1601,16 +1606,11 @@ ProjectModel *Project::model() return &mModel; } -const PFolderNode &Project::node() const +const PFolderNode &Project::rootNode() const { return mNode; } -void Project::setNode(const PFolderNode &newNode) -{ - mNode = newNode; -} - const QString &Project::name() const { return mName; @@ -1851,7 +1851,7 @@ Project *ProjectModel::project() const QModelIndex ProjectModel::index(int row, int column, const QModelIndex &parent) const { if (!parent.isValid()) { - return createIndex(row,column,mProject->node().get()); + return createIndex(row,column,mProject->rootNode().get()); } FolderNode* parentNode = static_cast(parent.internalPointer()); if (!parentNode) { @@ -1880,7 +1880,7 @@ int ProjectModel::rowCount(const QModelIndex &parent) const if (p) { return p->children.count(); } else { - return mProject->node()->children.count(); + return mProject->rootNode()->children.count(); } } @@ -1919,7 +1919,7 @@ Qt::ItemFlags ProjectModel::flags(const QModelIndex &index) const FolderNode* p = static_cast(index.internalPointer()); if (!p) return Qt::NoItemFlags; - if (p==mProject->node().get()) + if (p==mProject->rootNode().get()) return Qt::ItemIsEnabled | Qt::ItemIsDropEnabled | Qt::ItemIsEditable; Qt::ItemFlags flags = Qt::ItemIsEnabled | Qt::ItemIsEditable | Qt::ItemIsSelectable | Qt::ItemIsDragEnabled; if (p->unitIndex<0) { @@ -1938,7 +1938,7 @@ bool ProjectModel::setData(const QModelIndex &index, const QVariant &value, int if (!node) return false; if (role == Qt::EditRole) { - if (node == mProject->node()) { + if (node == mProject->rootNode()) { QString newName = value.toString().trimmed(); if (newName.isEmpty()) return false; diff --git a/RedPandaIDE/project.h b/RedPandaIDE/project.h index c1536f89..7353aad9 100644 --- a/RedPandaIDE/project.h +++ b/RedPandaIDE/project.h @@ -152,6 +152,7 @@ public: PProjectUnit addUnit(const QString& inFileName, PFolderNode parentNode, bool rebuild); + QString folder(); void buildPrivateResource(bool forceSave=false); void checkProjectFileForUpdate(SimpleIni& ini); void closeUnit(int index); @@ -205,8 +206,7 @@ public: const QString &name() const; void setName(const QString &newName); - const PFolderNode &node() const; - void setNode(const PFolderNode &newNode); + const PFolderNode &rootNode() const; ProjectOptions &options(); diff --git a/RedPandaIDE/qsynedit/SynEdit.cpp b/RedPandaIDE/qsynedit/SynEdit.cpp index 06065d98..60e2c1a1 100644 --- a/RedPandaIDE/qsynedit/SynEdit.cpp +++ b/RedPandaIDE/qsynedit/SynEdit.cpp @@ -3358,15 +3358,17 @@ void SynEdit::rescanForFoldRanges() // Combine new with old folds, preserve parent order for (int i = 0; i< TemporaryAllFoldRanges->count();i++) { - for (int j = 0; j< mAllFoldRanges.count() - 1;j++) { + int j=0; + while (j < mAllFoldRanges.count()) { if (TemporaryAllFoldRanges->range(i)->fromLine < mAllFoldRanges[j]->fromLine) { mAllFoldRanges.insert(j, TemporaryAllFoldRanges->range(i)); break; } - // If we can't prepend #i anywhere, just dump it at the end - if (j == mAllFoldRanges.count() - 1) - mAllFoldRanges.add(TemporaryAllFoldRanges->range(i)); + j++; } + // If we can't prepend #i anywhere, just dump it at the end + if (j >= mAllFoldRanges.count()) + mAllFoldRanges.add(TemporaryAllFoldRanges->range(i)); } } else { diff --git a/RedPandaIDE/widgets/codecompletionpopup.cpp b/RedPandaIDE/widgets/codecompletionpopup.cpp index a427ef1a..471a81e2 100644 --- a/RedPandaIDE/widgets/codecompletionpopup.cpp +++ b/RedPandaIDE/widgets/codecompletionpopup.cpp @@ -216,21 +216,12 @@ static bool nameComparator(PStatement statement1,PStatement statement2) { } static bool defaultComparator(PStatement statement1,PStatement statement2) { - if (statement1->firstMatchLength > statement2->firstMatchLength) { - return true; - } else if (statement1->firstMatchLength < statement2->firstMatchLength) { - return false; - } - if (statement1->matchPosTotal < statement2->matchPosTotal) { - return true; - } else if (statement1->matchPosTotal > statement2->matchPosTotal) { - return false; - } - if (statement1->caseMatched > statement2->caseMatched) { - return true; - } else if (statement1->caseMatched < statement2->caseMatched) { - return false; - } + 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; // Show user template first if (statement1->kind == StatementKind::skUserCodeSnippet) { if (statement2->kind != StatementKind::skUserCodeSnippet) @@ -251,21 +242,12 @@ static bool defaultComparator(PStatement statement1,PStatement statement2) { } static bool sortByScopeComparator(PStatement statement1,PStatement statement2){ - if (statement1->firstMatchLength > statement2->firstMatchLength) { - return true; - } else if (statement1->firstMatchLength < statement2->firstMatchLength) { - return false; - } - if (statement1->matchPosTotal < statement2->matchPosTotal) { - return true; - } else if (statement1->matchPosTotal > statement2->matchPosTotal) { - return false; - } - if (statement1->caseMatched > statement2->caseMatched) { - return true; - } else if (statement1->caseMatched < statement2->caseMatched) { - return false; - } + 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; // Show user template first if (statement1->kind == StatementKind::skUserCodeSnippet) { if (statement2->kind != StatementKind::skUserCodeSnippet) @@ -282,13 +264,12 @@ static bool sortByScopeComparator(PStatement statement1,PStatement statement2){ return statement1->command < statement2->command; } else if (statement2->kind == StatementKind::skKeyword) { return false; - // Show stuff from local headers first - } else if (!(statement1->inSystemHeader) && statement2->inSystemHeader) { - return true; - } else if (statement1->inSystemHeader && !(statement2->inSystemHeader)) { - return false; + } + // Show stuff from local headers first + if (statement1->inSystemHeader != statement2->inSystemHeader) + return !(statement1->inSystemHeader); // Show local statements first - } else if (statement1->scope != StatementScope::ssGlobal + if (statement1->scope != StatementScope::ssGlobal && statement2->scope == StatementScope::ssGlobal ) { return true; } else if (statement1->scope == StatementScope::ssGlobal @@ -299,21 +280,12 @@ static bool sortByScopeComparator(PStatement statement1,PStatement statement2){ } static bool sortWithUsageComparator(PStatement statement1,PStatement statement2) { - if (statement1->firstMatchLength > statement2->firstMatchLength) { - return true; - } else if (statement1->firstMatchLength < statement2->firstMatchLength) { - return false; - } - if (statement1->matchPosTotal < statement2->matchPosTotal) { - return true; - } else if (statement1->matchPosTotal > statement2->matchPosTotal) { - return false; - } - if (statement1->caseMatched > statement2->caseMatched) { - return true; - } else if (statement1->caseMatched < statement2->caseMatched) { - return false; - } + 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; // Show user template first if (statement1->kind == StatementKind::skUserCodeSnippet) { if (statement2->kind != StatementKind::skUserCodeSnippet) @@ -323,12 +295,11 @@ static bool sortWithUsageComparator(PStatement statement1,PStatement statement2) } else if (statement2->kind == StatementKind::skUserCodeSnippet) { 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 (statement1->usageCount != statement2->usageCount) + return statement1->usageCount > statement2->usageCount; + + if ((statement1->kind != StatementKind::skKeyword) && (statement2->kind == StatementKind::skKeyword)) { return true; } else if ((statement1->kind == StatementKind::skKeyword) @@ -339,21 +310,12 @@ static bool sortWithUsageComparator(PStatement statement1,PStatement statement2) } static bool sortByScopeWithUsageComparator(PStatement statement1,PStatement statement2){ - if (statement1->firstMatchLength > statement2->firstMatchLength) { - return true; - } else if (statement1->firstMatchLength < statement2->firstMatchLength) { - return false; - } - if (statement1->matchPosTotal < statement2->matchPosTotal) { - return true; - } else if (statement1->matchPosTotal > statement2->matchPosTotal) { - return false; - } - if (statement1->caseMatched > statement2->caseMatched) { - return true; - } else if (statement1->caseMatched < statement2->caseMatched) { - return false; - } + 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; // Show user template first if (statement1->kind == StatementKind::skUserCodeSnippet) { if (statement2->kind != StatementKind::skUserCodeSnippet) @@ -363,25 +325,23 @@ static bool sortByScopeWithUsageComparator(PStatement statement1,PStatement stat } else if (statement2->kind == StatementKind::skUserCodeSnippet) { 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 (statement1->usageCount != statement2->usageCount) + return statement1->usageCount > statement2->usageCount; + + 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 - } else if (!(statement1->inSystemHeader) && statement2->inSystemHeader) { - return true; - } else if (statement1->inSystemHeader && !(statement2->inSystemHeader)) { - return false; + } + // Show stuff from local headers first + if (statement1->inSystemHeader != statement2->inSystemHeader) + return !(statement1->inSystemHeader); // Show local statements first - } else if (statement1->scope != StatementScope::ssGlobal + if (statement1->scope != StatementScope::ssGlobal && statement2->scope == StatementScope::ssGlobal ) { return true; } else if (statement1->scope == StatementScope::ssGlobal @@ -414,9 +374,6 @@ void CodeCompletionPopup::filterList(const QString &member) mCompletionStatementList.clear(); mCompletionStatementList.reserve(mFullCompletionStatementList.size()); foreach (const PStatement& statement, mFullCompletionStatementList) { - Qt::CaseSensitivity cs = (mIgnoreCase? - Qt::CaseInsensitive: - Qt::CaseSensitive); int matched = 0; int caseMatched = 0; @@ -473,9 +430,6 @@ void CodeCompletionPopup::filterList(const QString &member) } } if (mRecordUsage) { - int topCount = 0; - int secondCount = 0; - int thirdCount = 0; int usageCount; foreach (const PStatement& statement,mCompletionStatementList) { if (statement->usageCount == -1) { @@ -486,32 +440,6 @@ void CodeCompletionPopup::filterList(const QString &member) usageCount = 0; } 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; - } - } - foreach (const PStatement& statement, mCompletionStatementList) { - 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) { @@ -606,7 +534,6 @@ void CodeCompletionPopup::getCompletionFor( statement->kind = StatementKind::skUserCodeSnippet; statement->fullName = codeIn->prefix; statement->usageCount = 0; - statement->freqTop = 0; mFullCompletionStatementList.append(statement); } } @@ -852,7 +779,6 @@ void CodeCompletionPopup::addKeyword(const QString &keyword) statement->kind = StatementKind::skKeyword; statement->fullName = keyword; statement->usageCount = 0; - statement->freqTop = 0; mFullCompletionStatementList.append(statement); }