From b571e5f5352d4bac8a993417ad2445520ac5b9be Mon Sep 17 00:00:00 2001 From: Roy Qu Date: Mon, 3 Jul 2023 09:36:27 +0800 Subject: [PATCH] - enhancement: Show code completion suggestion after "typedef" and "const". --- NEWS.md | 1 + RedPandaIDE/editor.cpp | 7 +++- RedPandaIDE/parser/cppparser.cpp | 39 +++++++++++++++++++ RedPandaIDE/parser/cppparser.h | 4 ++ RedPandaIDE/widgets/codecompletionpopup.cpp | 43 +++++++++++++++++++-- RedPandaIDE/widgets/codecompletionpopup.h | 6 ++- 6 files changed, 95 insertions(+), 5 deletions(-) diff --git a/NEWS.md b/NEWS.md index d36743c7..611caf96 100644 --- a/NEWS.md +++ b/NEWS.md @@ -24,6 +24,7 @@ Red Panda C++ Version 2.23 - improvement: Correctly eppands macros when real param string contains '(' or ')'. - enhancement: add "OI Wiki" and "turtle graphics tutorial" in help menu for zh_CN locale. - fix: Replace panel should be hidden after finding occurrencies. + - enhancement: Show code completion suggestion after "typedef" and "const". Red Panda C++ Version 2.22 diff --git a/RedPandaIDE/editor.cpp b/RedPandaIDE/editor.cpp index d0a284d2..6fc46845 100644 --- a/RedPandaIDE/editor.cpp +++ b/RedPandaIDE/editor.cpp @@ -857,7 +857,12 @@ void Editor::keyPressEvent(QKeyEvent *event) } else { QString lastWord = getPreviousWordAtPositionForSuggestion(caretXY()); if (mParser && !lastWord.isEmpty()) { - if (lastWord == "using") { + if (lastWord == "typedef" || lastWord == "const") { + processCommand(QSynedit::EditCommand::Char,ch,nullptr); + showCompletion(lastWord,false, CodeCompletionType::Types); + handled=true; + return; + } else if (lastWord == "using") { processCommand(QSynedit::EditCommand::Char,ch,nullptr); showCompletion(lastWord,false, CodeCompletionType::ComplexKeyword); handled=true; diff --git a/RedPandaIDE/parser/cppparser.cpp b/RedPandaIDE/parser/cppparser.cpp index 03f35dc1..e49dd57a 100644 --- a/RedPandaIDE/parser/cppparser.cpp +++ b/RedPandaIDE/parser/cppparser.cpp @@ -589,6 +589,15 @@ PStatement CppParser::findAliasedStatement(const PStatement &statement) return PStatement(); return doFindAliasedStatement(statement); } + +QList CppParser::listTypeStatements(const QString &fileName, int line) +{ + QMutexLocker locker(&mMutex); + if (mParsing) + return QList(); + return doListTypeStatements(fileName,line); +} + PStatement CppParser::doFindAliasedStatement(const PStatement &statement) const { if (!statement) @@ -612,6 +621,36 @@ PStatement CppParser::doFindAliasedStatement(const PStatement &statement) const return PStatement(); } +QList CppParser::doListTypeStatements(const QString &fileName, int line) const +{ + QList result; + QSet usedNamespaces; + PStatement scopeStatement = doFindScopeStatement(fileName,line); + while (true) { + const StatementMap& statementMap = mStatementList.childrenStatements(scopeStatement); + foreach (const PStatement statement, statementMap.values()) { + if (isTypeStatement(statement->kind)) + result.append(statement); + } + if (!scopeStatement) + break; + usedNamespaces = usedNamespaces.unite(scopeStatement->usingList); + scopeStatement=scopeStatement->parentScope.lock(); + } + usedNamespaces = usedNamespaces.unite(internalGetFileUsings(fileName)); + foreach(const QString& ns, usedNamespaces) { + PStatementList namespaceStatementsList=doFindNamespace(ns); + foreach (const PStatement& namespaceStatement,*namespaceStatementsList) { + const StatementMap& statementMap = mStatementList.childrenStatements(namespaceStatement); + foreach (const PStatement statement, statementMap.values()) { + if (isTypeStatement(statement->kind)) + result.append(statement); + } + } + } + return result; +} + PStatement CppParser::findStatementStartingFrom(const QString &fileName, const QString &phrase, const PStatement& startScope) const { PStatement scopeStatement = startScope; diff --git a/RedPandaIDE/parser/cppparser.h b/RedPandaIDE/parser/cppparser.h index 24c16b8b..8529c0bd 100644 --- a/RedPandaIDE/parser/cppparser.h +++ b/RedPandaIDE/parser/cppparser.h @@ -77,6 +77,8 @@ public: int line); PStatement findAliasedStatement(const PStatement& statement); + QList listTypeStatements(const QString& fileName,int line); + /** * @brief evaluate the expression * @param fileName @@ -251,6 +253,8 @@ private: int line) const; PStatement doFindAliasedStatement(const PStatement& statement) const; + QList doListTypeStatements(const QString& fileName,int line) const; + PStatement doFindTypeDefinitionOf(const QString& fileName, const QString& aType, const PStatement& currentClass) const; diff --git a/RedPandaIDE/widgets/codecompletionpopup.cpp b/RedPandaIDE/widgets/codecompletionpopup.cpp index 84cbb694..8f7ece8c 100644 --- a/RedPandaIDE/widgets/codecompletionpopup.cpp +++ b/RedPandaIDE/widgets/codecompletionpopup.cpp @@ -94,7 +94,11 @@ void CodeCompletionPopup::prepareSearch( mMemberOperator = memberOperator; switch(type) { case CodeCompletionType::ComplexKeyword: - getCompletionListForTypeKeywordComplex(preWord); + getCompletionListForComplexKeyword(preWord); + break; + case CodeCompletionType::Types: + mIncludedFiles = mParser->getFileIncludes(filename); + getCompletionListForTypes(preWord,filename,line); break; case CodeCompletionType::FunctionWithoutDefinition: mIncludedFiles = mParser->getFileIncludes(filename); @@ -892,7 +896,7 @@ void CodeCompletionPopup::getCompletionForFunctionWithoutDefinition(const QStrin }); if (memberOperator.isEmpty()) { - getCompletionListForTypeKeywordComplex(preWord); + getCompletionListForComplexKeyword(preWord); PStatement scopeStatement = mCurrentScope; //add members of current scope that not added before while (scopeStatement && scopeStatement->kind!=StatementKind::skNamespace @@ -960,7 +964,7 @@ void CodeCompletionPopup::getCompletionForFunctionWithoutDefinition(const QStrin } } -void CodeCompletionPopup::getCompletionListForTypeKeywordComplex(const QString &preWord) +void CodeCompletionPopup::getCompletionListForComplexKeyword(const QString &preWord) { mFullCompletionStatementList.clear(); if (preWord == "long") { @@ -1012,6 +1016,39 @@ void CodeCompletionPopup::getCompletionListForNamespaces(const QString &/*preWor } } +void CodeCompletionPopup::getCompletionListForTypes(const QString &preWord, const QString &fileName, int line) +{ + if (preWord=="typedef") { + addKeyword("const"); + addKeyword("struct"); + addKeyword("class"); + } + + if (mShowKeywords) { + //add keywords + foreach (const QString& keyword,CppTypeKeywords) { + addKeyword(keyword); + } + } + if (!mParser->enabled()) + return; + + if (!mParser->freeze()) + return; + { + auto action = finally([this]{ + mParser->unFreeze(); + }); + QList statements = mParser->listTypeStatements(fileName,line); + foreach(const PStatement& statement, statements) { + if (isIncluded(statement->fileName) + || isIncluded(statement->definitionFileName)) { + addStatement(statement,fileName,line); + } + } + } +} + void CodeCompletionPopup::addKeyword(const QString &keyword) { PStatement statement = std::make_shared(); diff --git a/RedPandaIDE/widgets/codecompletionpopup.h b/RedPandaIDE/widgets/codecompletionpopup.h index 54fc3430..303f1ddf 100644 --- a/RedPandaIDE/widgets/codecompletionpopup.h +++ b/RedPandaIDE/widgets/codecompletionpopup.h @@ -42,6 +42,7 @@ enum class CodeCompletionType { ComplexKeyword, FunctionWithoutDefinition, Namespaces, + Types, KeywordsOnly }; @@ -151,10 +152,13 @@ private: const QString& fileName, int line); - void getCompletionListForTypeKeywordComplex(const QString& preWord); + void getCompletionListForComplexKeyword(const QString& preWord); void getCompletionListForNamespaces(const QString &preWord, const QString& fileName, int line); + void getCompletionListForTypes(const QString &preWord, + const QString& fileName, + int line); void addKeyword(const QString& keyword); bool isIncluded(const QString& fileName); private: