diff --git a/RedPandaIDE/editor.cpp b/RedPandaIDE/editor.cpp index f4c557f2..a8f83fc2 100644 --- a/RedPandaIDE/editor.cpp +++ b/RedPandaIDE/editor.cpp @@ -528,6 +528,47 @@ bool Editor::onGetSpecialLineColors(int Line, QColor &foreground, QColor &backgr return false; } +void Editor::onPreparePaintHighlightToken(int row, int column, const QString &token, PSynHighlighterAttribute attr, SynFontStyles &style, QColor &foreground, QColor &background) +{ + if (token.isEmpty()) + return; + //selection + if (selAvail() && highlighter()) { + if (( + (attr->name() == SYNS_AttrIdentifier) + || (attr->name() == SYNS_AttrReservedWord) + || (attr->name() == SYNS_AttrPreprocessor) + ) + && (token == selText())) { + foreground = selectedForeground(); + background = selectedBackground(); + return; + } + } + + + if (mParser && mCompletionPopup && (attr->name() == SYNS_AttrIdentifier)) { + BufferCoord p=displayToBufferPos(DisplayCoord{column+1,row}); + BufferCoord pBeginPos,pEndPos; + QString s= getWordAtPosition(p, pBeginPos,pEndPos, WordPurpose::wpInformation); + PStatement statement = mParser->findStatementOf(mFilename, + s , p.Line); + StatementKind kind = mParser->getKindOfStatement(statement); + if (kind == StatementKind::skUnknown) { + if ((pEndPos.Line>=1) + && (pEndPos.Char < lines()->getString(pEndPos.Line-1).length()) + && (lines()->getString(pEndPos.Line-1)[pEndPos.Char] == '(')) { + kind = StatementKind::skFunction; + } else { + kind = StatementKind::skVariable; + } + } + foreground = mCompletionPopup->colors().value(kind, + highlighter()->identifierAttribute()->foreground()); + return; + } +} + void Editor::copyToClipboard() { if (pSettings->editor().copySizeLimit()) { @@ -1452,8 +1493,8 @@ void Editor::completionInsert(bool appendFunc) QString funcAddOn = ""; // delete the part of the word that's already been typed ... - BufferCoord p = wordEnd(); - setBlockBegin(wordStart()); + BufferCoord p = WordEnd(); + setBlockBegin(WordStart()); setBlockEnd(p); // if we are inserting a function, @@ -1970,6 +2011,11 @@ void Editor::applyColorScheme(const QString& schemeName) if (item) { this->mSyntaxWarningColor = item->foreground(); } + item = pColorManager->getItem(schemeName,COLOR_SCHEME_SELECTION); + if (item) { + setSelectedForeground(item->foreground()); + setSelectedBackground(item->background()); + } item = pColorManager->getItem(schemeName,COLOR_SCHEME_ACTIVE_BREAKPOINT); if (item) { this->mActiveBreakpointForegroundColor = item->foreground(); @@ -1980,6 +2026,58 @@ void Editor::applyColorScheme(const QString& schemeName) this->mBreakpointForegroundColor = item->foreground(); this->mBreakpointBackgroundColor = item->background(); } + //color for code completion popup + if (mCompletionPopup) { + item = pColorManager->getItem(schemeName, SYNS_AttrFunction); + if (item) { + mCompletionPopup->colors().insert(StatementKind::skFunction,item->foreground()); + mCompletionPopup->colors().insert(StatementKind::skConstructor,item->foreground()); + mCompletionPopup->colors().insert(StatementKind::skDestructor,item->foreground()); + } + item = pColorManager->getItem(schemeName, SYNS_AttrClass); + if (item) { + mCompletionPopup->colors().insert(StatementKind::skClass,item->foreground()); + mCompletionPopup->colors().insert(StatementKind::skTypedef,item->foreground()); + mCompletionPopup->colors().insert(StatementKind::skAlias,item->foreground()); + } + item = pColorManager->getItem(schemeName, SYNS_AttrIdentifier); + if (item) { + mCompletionPopup->colors().insert(StatementKind::skEnumType,item->foreground()); + mCompletionPopup->colors().insert(StatementKind::skEnumClassType,item->foreground()); + } + item = pColorManager->getItem(schemeName, SYNS_AttrVariable); + if (item) { + mCompletionPopup->colors().insert(StatementKind::skVariable,item->foreground()); + } + item = pColorManager->getItem(schemeName, SYNS_AttrLocalVariable); + if (item) { + mCompletionPopup->colors().insert(StatementKind::skLocalVariable,item->foreground()); + mCompletionPopup->colors().insert(StatementKind::skParameter,item->foreground()); + } + item = pColorManager->getItem(schemeName, SYNS_AttrGlobalVariable); + if (item) { + mCompletionPopup->colors().insert(StatementKind::skGlobalVariable,item->foreground()); + } + item = pColorManager->getItem(schemeName, SYNS_AttrGlobalVariable); + if (item) { + mCompletionPopup->colors().insert(StatementKind::skGlobalVariable,item->foreground()); + } + item = pColorManager->getItem(schemeName, SYNS_AttrPreprocessor); + if (item) { + mCompletionPopup->colors().insert(StatementKind::skPreprocessor,item->foreground()); + mCompletionPopup->colors().insert(StatementKind::skEnum,item->foreground()); + } + item = pColorManager->getItem(schemeName, SYNS_AttrReservedWord); + if (item) { + mCompletionPopup->colors().insert(StatementKind::skKeyword,item->foreground()); + mCompletionPopup->colors().insert(StatementKind::skUserCodeIn,item->foreground()); + } + item = pColorManager->getItem(schemeName, SYNS_AttrString); + if (item) { + mCompletionPopup->colors().insert(StatementKind::skNamespace,item->foreground()); + mCompletionPopup->colors().insert(StatementKind::skNamespaceAlias,item->foreground()); + } + } this->invalidate(); } diff --git a/RedPandaIDE/editor.h b/RedPandaIDE/editor.h index 1d5b79a0..e41e886c 100644 --- a/RedPandaIDE/editor.h +++ b/RedPandaIDE/editor.h @@ -211,6 +211,10 @@ protected: // SynEdit interface protected: bool onGetSpecialLineColors(int Line, QColor &foreground, QColor &backgroundColor) override; + + // SynEdit interface +protected: + void onPreparePaintHighlightToken(int row, int column, const QString &token, PSynHighlighterAttribute attr, SynFontStyles &style, QColor &foreground, QColor &background) override; }; #endif // EDITOR_H diff --git a/RedPandaIDE/parser/cppparser.cpp b/RedPandaIDE/parser/cppparser.cpp index 65335da8..7ae52513 100644 --- a/RedPandaIDE/parser/cppparser.cpp +++ b/RedPandaIDE/parser/cppparser.cpp @@ -799,6 +799,7 @@ void CppParser::reset() mPreprocessor.includesList().clear(); mNamespaces.clear(); + mInlineNamespaces.clear(); mPreprocessor.projectIncludePaths().clear(); mPreprocessor.includePaths().clear(); @@ -2041,8 +2042,15 @@ void CppParser::handleNamespace() //wrong namespace define, stop handling return; QString command = mTokenizer[mIndex]->text; - if (command.startsWith("__")) // hack for inline namespaces - isInline = true; + + QString fullName = getFullStatementName(command,getCurrentScope()); + if (isInline) { + mInlineNamespaces.insert(fullName); + } else if (mInlineNamespaces.contains(fullName)) { + isInline = true; + } +// if (command.startsWith("__")) // hack for inline namespaces +// isInline = true; mIndex++; if (mIndex>=mTokenizer.tokenCount()) return; @@ -2954,15 +2962,15 @@ void CppParser::internalParse(const QString &fileName) if (!handleStatement()) break; } -//#ifdef QT_DEBUG - StringsToFile(mPreprocessor.result(),"f:\\preprocess.txt"); - mPreprocessor.dumpDefinesTo("f:\\defines.txt"); - mPreprocessor.dumpIncludesListTo("f:\\includes.txt"); - mStatementList.dump("f:\\stats.txt"); - mTokenizer.dumpTokens("f:\\tokens.txt"); -//#endif #ifdef QT_DEBUG - mStatementList.dumpAll("f:\\all-stats.txt"); +// StringsToFile(mPreprocessor.result(),"f:\\preprocess.txt"); +// mPreprocessor.dumpDefinesTo("f:\\defines.txt"); +// mPreprocessor.dumpIncludesListTo("f:\\includes.txt"); +// mStatementList.dump("f:\\stats.txt"); +// mTokenizer.dumpTokens("f:\\tokens.txt"); +#endif +#ifdef QT_DEBUG +// mStatementList.dumpAll("f:\\all-stats.txt"); #endif } } diff --git a/RedPandaIDE/parser/cppparser.h b/RedPandaIDE/parser/cppparser.h index dbd672ef..9a79a4ac 100644 --- a/RedPandaIDE/parser/cppparser.h +++ b/RedPandaIDE/parser/cppparser.h @@ -352,6 +352,7 @@ private: int mLockCount; // lock(don't reparse) when we need to find statements in a batch bool mParsing; QHash mNamespaces; //TStringList> namespace and the statements in its scope + QSet mInlineNamespaces; //fRemovedStatements: THashedStringList; //THashedStringList QRecursiveMutex mMutex; diff --git a/RedPandaIDE/parser/parserutils.h b/RedPandaIDE/parser/parserutils.h index 5cfc819e..6c349d2f 100644 --- a/RedPandaIDE/parser/parserutils.h +++ b/RedPandaIDE/parser/parserutils.h @@ -42,7 +42,7 @@ enum class SkipType { skNone // It's a keyword but don't process here }; -enum class StatementKind { +enum StatementKind { skUnknown, skPreprocessor, skEnumType, diff --git a/RedPandaIDE/qsynedit/SynEdit.cpp b/RedPandaIDE/qsynedit/SynEdit.cpp index 5fb67a75..a65ec4f0 100644 --- a/RedPandaIDE/qsynedit/SynEdit.cpp +++ b/RedPandaIDE/qsynedit/SynEdit.cpp @@ -1179,8 +1179,8 @@ BufferCoord SynEdit::WordStartEx(const BufferCoord &XY) // valid line? if ((CY >= 1) && (CY <= mLines->count())) { QString Line = mLines->getString(CY - 1); - CX = std::min(CX, Line.length()); - if (CX > 1) { + CX = std::min(CX, Line.length()+1); + if (CX-1 >= 0) { if (!(Line[CX - 1].isSpace())) CX = StrRScanForNonWordChar(Line, CX - 1) + 1; else @@ -3209,6 +3209,26 @@ void SynEdit::doScrolled(int) invalidate(); } +const QColor &SynEdit::selectedBackground() const +{ + return mSelectedBackground; +} + +void SynEdit::setSelectedBackground(const QColor &newSelectedBackground) +{ + mSelectedBackground = newSelectedBackground; +} + +const QColor &SynEdit::selectedForeground() const +{ + return mSelectedForeground; +} + +void SynEdit::setSelectedForeground(const QColor &newSelectedForeground) +{ + mSelectedForeground = newSelectedForeground; +} + int SynEdit::textHeight() const { return mTextHeight; @@ -4654,6 +4674,11 @@ void SynEdit::onPaint(QPainter &) } +void SynEdit::onPreparePaintHighlightToken(int row, int column, const QString &token, PSynHighlighterAttribute attr, SynFontStyles &style, QColor &foreground, QColor &background) +{ + +} + void SynEdit::onProcessCommand(SynEditorCommand , QChar , void *) { @@ -5668,56 +5693,6 @@ void SynEdit::setSelLength(int Value) } } -BufferCoord SynEdit::wordStart() -{ - return wordStart(caretXY()); -} - -BufferCoord SynEdit::wordStart(const BufferCoord &value) -{ - int cx = value.Char-1; - int cy = value.Line; - // valid line? - if ((cy <1) || (cy > lines()->count())) - return value; - QString line = lines()->getString(cy - 1); - if (cx>=line.length()) { - cx=line.length()-1; - } - - while (cx>=0 && cx lines()->count())) - return value; - QString line = lines()->getString(cy - 1); - - while (cx>=0 && cx; using SynProcessCommandProc = std::function; using SynMouseCursorProc = std::function; using SynPaintProc = std::function; -using SynPreparePaintHighlightTokenProc = std::function; +//using SynPreparePaintHighlightTokenProc = std::function; using SynSearchMathedProc = std::function; @@ -217,11 +217,6 @@ public: void setSelText(const QString& Value); void setSelLength(int Value); - BufferCoord wordStart(); - BufferCoord wordStart(const BufferCoord& value); - BufferCoord wordEnd(); - BufferCoord wordEnd(const BufferCoord& value); - int searchReplace(const QString& sSearch, const QString& sReplace, SynSearchOptions options, PSynSearchBase searchEngine, SynSearchMathedProc matchedCallback = nullptr); @@ -335,6 +330,12 @@ public: int textHeight() const; + const QColor &selectedForeground() const; + void setSelectedForeground(const QColor &newSelectedForeground); + + const QColor &selectedBackground() const; + void setSelectedBackground(const QColor &newSelectedBackground); + signals: void Changed(); @@ -370,6 +371,9 @@ protected: virtual void onGutterGetText(int aLine, QString& aText); virtual void onGutterPaint(QPainter& painter, int aLine, int X, int Y); virtual void onPaint(QPainter& painter); + virtual void onPreparePaintHighlightToken(int row, + int column, const QString& token, PSynHighlighterAttribute attr, + SynFontStyles& style, QColor& foreground, QColor& background); virtual void onProcessCommand(SynEditorCommand Command, QChar AChar, void * pData); virtual void onCommandProcessed(SynEditorCommand Command, QChar AChar, void * pData); virtual void ExecuteCommand(SynEditorCommand Command, QChar AChar, void * pData); @@ -605,7 +609,7 @@ private: SynProcessCommandProc mOnCommandProcessed; SynMouseCursorProc mOnMouseCursor; SynPaintProc mOnPaint; - SynPreparePaintHighlightTokenProc mOnPaintHighlightToken; +// SynPreparePaintHighlightTokenProc mOnPaintHighlightToken; SynPlaceMarkProc mOnPlaceMark; SynProcessCommandProc mOnProcessingCommand; SynProcessCommandProc mOnProcessingUserCommand; diff --git a/RedPandaIDE/qsynedit/TextPainter.cpp b/RedPandaIDE/qsynedit/TextPainter.cpp index 5cca71df..8373bc78 100644 --- a/RedPandaIDE/qsynedit/TextPainter.cpp +++ b/RedPandaIDE/qsynedit/TextPainter.cpp @@ -582,8 +582,7 @@ void SynEditTextPainter::AddHighlightToken(const QString &Token, int ColumnsBefo } //todo : change char(getTokenPos) to column? - if (edit->mOnPaintHighlightToken) - edit->mOnPaintHighlightToken(cLine,edit->mHighlighter->getTokenPos(), + edit->onPreparePaintHighlightToken(cLine,edit->mHighlighter->getTokenPos(), Token,p_Attri,Style,Foreground,Background); // Do we have to paint the old chars first, or can we just append? diff --git a/RedPandaIDE/widgets/codecompletionview.cpp b/RedPandaIDE/widgets/codecompletionview.cpp index efcc8fcb..7948b768 100644 --- a/RedPandaIDE/widgets/codecompletionview.cpp +++ b/RedPandaIDE/widgets/codecompletionview.cpp @@ -4,6 +4,7 @@ #include #include #include +#include CodeCompletionView::CodeCompletionView(QWidget *parent) : QWidget(parent) @@ -11,6 +12,15 @@ CodeCompletionView::CodeCompletionView(QWidget *parent) : setWindowFlags(Qt::Popup); mListView = new CodeCompletionListView(this); mModel=new CodeCompletionListModel(&mCompletionStatementList); + mModel->setColorCallback([this](PStatement statement)->QColor{ + StatementKind kind; + if (mParser) { + kind = mParser->getKindOfStatement(statement); + } else { + kind = statement->kind; + } + return mColors.value(kind,palette().color(QPalette::Text)); + }); mListView->setModel(mModel); setLayout(new QVBoxLayout()); layout()->addWidget(mListView); @@ -213,9 +223,9 @@ static bool sortByScopeComparator(PStatement statement1,PStatement statement2){ } else if (statement2->kind == StatementKind::skKeyword) { return false; // Show stuff from local headers first - } else if (statement1->inSystemHeader && (!statement2->inSystemHeader)) { + } else if (statement1->inSystemHeader && !(statement2->inSystemHeader)) { return true; - } else if ((!statement1->inSystemHeader) && statement2->inSystemHeader) { + } else if (!(statement1->inSystemHeader) && statement2->inSystemHeader) { return false; // Show local statements first } else if (statement1->scope != StatementScope::ssGlobal @@ -277,9 +287,9 @@ static bool sortByScopeWithUsageComparator(PStatement statement1,PStatement stat } else if (statement2->kind == StatementKind::skKeyword) { return false; // Show stuff from local headers first - } else if (statement1->inSystemHeader && ! statement2->inSystemHeader) { + } else if (statement1->inSystemHeader && ! (statement2->inSystemHeader)) { return true; - } else if (!statement1->inSystemHeader && statement2->inSystemHeader) { + } else if (!(statement1->inSystemHeader) && statement2->inSystemHeader) { return false; // Show local statements first } else if (statement1->scope != StatementScope::ssGlobal @@ -713,6 +723,11 @@ void CodeCompletionView::setCurrentStatement(const PStatement &newCurrentStateme mCurrentStatement = newCurrentStatement; } +QHash &CodeCompletionView::colors() +{ + return mColors; +} + bool CodeCompletionView::useCppKeyword() const { return mUseCppKeyword; @@ -870,9 +885,18 @@ QVariant CodeCompletionListModel::data(const QModelIndex &index, int role) const if (index.row()>=mStatements->count()) return QVariant(); - if (role == Qt::DisplayRole) { + switch(role) { + case Qt::DisplayRole: { PStatement statement = mStatements->at(index.row()); return statement->command; + } + case Qt::ForegroundRole: { + PStatement statement = mStatements->at(index.row()); + if (mColorCallback) + return mColorCallback(statement); + QApplication *app = dynamic_cast(QApplication::instance()); + return app->palette().color(QPalette::Text); + } } return QVariant(); } @@ -882,3 +906,13 @@ void CodeCompletionListModel::notifyUpdated() beginResetModel(); endResetModel(); } + +const ColorCallback &CodeCompletionListModel::colorCallback() const +{ + return mColorCallback; +} + +void CodeCompletionListModel::setColorCallback(const ColorCallback &newColorCallback) +{ + mColorCallback = newColorCallback; +} diff --git a/RedPandaIDE/widgets/codecompletionview.h b/RedPandaIDE/widgets/codecompletionview.h index 8873433d..c1aee6cb 100644 --- a/RedPandaIDE/widgets/codecompletionview.h +++ b/RedPandaIDE/widgets/codecompletionview.h @@ -22,6 +22,8 @@ private: KeyPressedCallback mKeypressedCallback; }; +using ColorCallback = std::function; + class CodeCompletionListModel : public QAbstractListModel { Q_OBJECT public: @@ -29,9 +31,12 @@ public: int rowCount(const QModelIndex &parent) const override; QVariant data(const QModelIndex &index, int role) const override; void notifyUpdated(); + const ColorCallback &colorCallback() const; + void setColorCallback(const ColorCallback &newColorCallback); + private: const StatementList* mStatements; - + ColorCallback mColorCallback; }; class CodeCompletionView : public QWidget @@ -77,6 +82,7 @@ public: const PStatement ¤tStatement() const; void setCurrentStatement(const PStatement &newCurrentStatement); + QHash& colors(); private: void addChildren(PStatement scopeStatement, const QString& fileName, @@ -98,6 +104,7 @@ private: QString mPhrase; QHash mSymbolUsage; QRecursiveMutex mMutex; + QHash mColors; PCppParser mParser; PStatement mCurrentStatement;