diff --git a/interfaces/icompletionsettings.h b/interfaces/icompletionsettings.h index c41ee20f4c..4b95c5184c 100644 --- a/interfaces/icompletionsettings.h +++ b/interfaces/icompletionsettings.h @@ -1,64 +1,65 @@ /*************************************************************************** * Copyright 2008 David Nolden * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU Library General Public License as * * published by the Free Software Foundation; either version 2 of the * * License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU Library General Public * * License along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * ***************************************************************************/ #ifndef KDEVPLATFORM_ICOMPLETIONSETTINGS_H #define KDEVPLATFORM_ICOMPLETIONSETTINGS_H #include #include "interfacesexport.h" namespace KDevelop { class KDEVPLATFORMINTERFACES_EXPORT ICompletionSettings : public QObject { Q_OBJECT public: virtual ~ICompletionSettings(); enum CompletionLevel { Minimal, MinimalWhenAutomatic, AlwaysFull, LAST_LEVEL }; Q_SCRIPTABLE virtual int minFilesForSimplifiedParsing() const = 0; Q_SCRIPTABLE virtual CompletionLevel completionLevel() const = 0; Q_SCRIPTABLE virtual bool automaticCompletionEnabled() const = 0; Q_SCRIPTABLE virtual int localColorizationLevel() const = 0; Q_SCRIPTABLE virtual int globalColorizationLevel() const = 0; Q_SCRIPTABLE virtual bool highlightSemanticProblems() const = 0; Q_SCRIPTABLE virtual bool highlightProblematicLines() const = 0; + Q_SCRIPTABLE virtual bool boldDeclarations() const = 0; Q_SCRIPTABLE virtual bool showMultiLineSelectionInformation() const = 0; Q_SCRIPTABLE virtual QStringList todoMarkerWords() const = 0; Q_SIGNALS: void settingsChanged(ICompletionSettings*); }; } #endif diff --git a/language/highlighting/codehighlighting.cpp b/language/highlighting/codehighlighting.cpp index 918038bb9c..5e62704913 100644 --- a/language/highlighting/codehighlighting.cpp +++ b/language/highlighting/codehighlighting.cpp @@ -1,604 +1,606 @@ /* * This file is part of KDevelop * * Copyright 2007-2010 David Nolden * Copyright 2006 Hamish Rodda * Copyright 2009 Milian Wolff * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Library General Public License as * published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public * License along with this program; if not, write to the * Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "codehighlighting.h" #include #include "../../interfaces/icore.h" #include "../../interfaces/ilanguagecontroller.h" #include "../../interfaces/icompletionsettings.h" #include "../../util/foregroundlock.h" #include "util/debug.h" #include "../duchain/declaration.h" #include "../duchain/types/functiontype.h" #include "../duchain/types/enumeratortype.h" #include "../duchain/types/typealiastype.h" #include "../duchain/types/enumerationtype.h" #include "../duchain/types/structuretype.h" #include "../duchain/functiondefinition.h" #include "../duchain/use.h" #include "colorcache.h" #include "configurablecolors.h" #include #include #include #include using namespace KTextEditor; static const float highlightingZDepth = -500; #define ifDebug(x) namespace KDevelop { ///@todo Don't highlighting everything, only what is visible on-demand CodeHighlighting::CodeHighlighting( QObject * parent ) : QObject(parent), m_localColorization(true), m_globalColorization(true), m_dataMutex(QMutex::Recursive) { qRegisterMetaType("KDevelop::IndexedString"); adaptToColorChanges(); connect(ColorCache::self(), &ColorCache::colorsGotChanged, this, &CodeHighlighting::adaptToColorChanges); } CodeHighlighting::~CodeHighlighting( ) { qDeleteAll(m_highlights.values()); } void CodeHighlighting::adaptToColorChanges() { QMutexLocker lock(&m_dataMutex); // disable local highlighting if the ratio is set to 0 m_localColorization = ICore::self()->languageController()->completionSettings()->localColorizationLevel() > 0; // disable global highlighting if the ratio is set to 0 m_globalColorization = ICore::self()->languageController()->completionSettings()->globalColorizationLevel() > 0; m_declarationAttributes.clear(); m_definitionAttributes.clear(); m_depthAttributes.clear(); m_referenceAttributes.clear(); } KTextEditor::Attribute::Ptr CodeHighlighting::attributeForType( Types type, Contexts context, const QColor &color ) const { QMutexLocker lock(&m_dataMutex); KTextEditor::Attribute::Ptr a; switch (context) { case DefinitionContext: a = m_definitionAttributes[type]; break; case DeclarationContext: a = m_declarationAttributes[type]; break; case ReferenceContext: a = m_referenceAttributes[type]; break; } if ( !a || color.isValid() ) { a = KTextEditor::Attribute::Ptr(new KTextEditor::Attribute(*ColorCache::self()->defaultColors()->getAttribute(type))); if ( context == DefinitionContext || context == DeclarationContext ) { - a->setFontBold(); + if (ICore::self()->languageController()->completionSettings()->boldDeclarations()) { + a->setFontBold(); + } } if( color.isValid() ) { a->setForeground(color); // a->setBackground(QColor(mix(0xffffff-color, backgroundColor(), 255-backgroundTinting))); } else { switch (context) { case DefinitionContext: m_definitionAttributes.insert(type, a); break; case DeclarationContext: m_declarationAttributes.insert(type, a); break; case ReferenceContext: m_referenceAttributes.insert(type, a); break; } } } return a; } ColorMap emptyColorMap() { ColorMap ret(ColorCache::self()->validColorCount()+1, 0); return ret; } CodeHighlightingInstance* CodeHighlighting::createInstance() const { return new CodeHighlightingInstance(this); } bool CodeHighlighting::hasHighlighting(IndexedString url) const { DocumentChangeTracker* tracker = ICore::self()->languageController()->backgroundParser()->trackerForUrl(url); if(tracker) { QMutexLocker lock(&m_dataMutex); return m_highlights.contains(tracker) && !m_highlights[tracker]->m_highlightedRanges.isEmpty(); } return false; } void CodeHighlighting::highlightDUChain(ReferencedTopDUContext context) { ENSURE_CHAIN_NOT_LOCKED IndexedString url; { DUChainReadLocker lock; if (!context) return; url = context->url(); } // This prevents the background-parser from updating the top-context while we're working with it UrlParseLock urlLock(context->url()); DUChainReadLocker lock; qint64 revision = context->parsingEnvironmentFile()->modificationRevision().revision; qCDebug(LANGUAGE) << "highlighting du chain" << url.toUrl(); if ( !m_localColorization && !m_globalColorization ) { qCDebug(LANGUAGE) << "highlighting disabled"; QMetaObject::invokeMethod(this, "clearHighlightingForDocument", Qt::QueuedConnection, Q_ARG(KDevelop::IndexedString, url)); return; } CodeHighlightingInstance* instance = createInstance(); lock.unlock(); instance->highlightDUChain(context.data()); DocumentHighlighting* highlighting = new DocumentHighlighting; highlighting->m_document = url; highlighting->m_waitingRevision = revision; highlighting->m_waiting = instance->m_highlight; std::sort(highlighting->m_waiting.begin(), highlighting->m_waiting.end()); QMetaObject::invokeMethod(this, "applyHighlighting", Qt::QueuedConnection, Q_ARG(void*, highlighting)); delete instance; } void CodeHighlightingInstance::highlightDUChain(TopDUContext* context) { m_contextClasses.clear(); m_useClassCache = true; //Highlight highlightDUChain(context, QHash(), emptyColorMap()); m_functionColorsForDeclarations.clear(); m_functionDeclarationsForColors.clear(); m_useClassCache = false; m_contextClasses.clear(); } void CodeHighlightingInstance::highlightDUChain(DUContext* context, QHash colorsForDeclarations, ColorMap declarationsForColors) { DUChainReadLocker lock; TopDUContext* top = context->topContext(); //Merge the colors from the function arguments foreach( const DUContext::Import &imported, context->importedParentContexts() ) { if(!imported.context(top) || (imported.context(top)->type() != DUContext::Other && imported.context(top)->type() != DUContext::Function)) continue; //For now it's enough simply copying them, because we only pass on colors within function bodies. if (m_functionColorsForDeclarations.contains(imported.context(top))) colorsForDeclarations = m_functionColorsForDeclarations[imported.context(top)]; if (m_functionDeclarationsForColors.contains(imported.context(top))) declarationsForColors = m_functionDeclarationsForColors[imported.context(top)]; } QList takeFreeColors; foreach (Declaration* dec, context->localDeclarations()) { if (!useRainbowColor(dec)) { highlightDeclaration(dec, QColor(QColor::Invalid)); continue; } //Initially pick a color using the hash, so the chances are good that the same identifier gets the same color always. uint colorNum = dec->identifier().hash() % ColorCache::self()->validColorCount(); if( declarationsForColors[colorNum] ) { takeFreeColors << dec; //Use one of the colors that stays free continue; } colorsForDeclarations[dec] = colorNum; declarationsForColors[colorNum] = dec; highlightDeclaration(dec, ColorCache::self()->generatedColor(colorNum)); } foreach( Declaration* dec, takeFreeColors ) { uint colorNum = dec->identifier().hash() % ColorCache::self()->validColorCount(); uint oldColorNum = colorNum; while( declarationsForColors[colorNum] ) { colorNum = (colorNum+1) % ColorCache::self()->validColorCount(); if( colorNum == oldColorNum ) { colorNum = ColorCache::self()->validColorCount(); break; } } if(colorNum != ColorCache::self()->validColorCount()) { //If no color could be found, use default color,, not black colorsForDeclarations[dec] = colorNum; declarationsForColors[colorNum] = dec; highlightDeclaration(dec, ColorCache::self()->generatedColor(colorNum)); }else{ highlightDeclaration(dec, QColor(QColor::Invalid)); } } for(int a = 0; a < context->usesCount(); ++a) { Declaration* decl = context->topContext()->usedDeclarationForIndex(context->uses()[a].m_declarationIndex); QColor color(QColor::Invalid); if( colorsForDeclarations.contains(decl) ) color = ColorCache::self()->generatedColor(colorsForDeclarations[decl]); highlightUse(context, a, color); } if(context->type() == DUContext::Other || context->type() == DUContext::Function) { m_functionColorsForDeclarations[IndexedDUContext(context)] = colorsForDeclarations; m_functionDeclarationsForColors[IndexedDUContext(context)] = declarationsForColors; } QVector< DUContext* > children = context->childContexts(); lock.unlock(); // Periodically release the lock, so that the UI won't be blocked too much foreach (DUContext* child, children) highlightDUChain(child, colorsForDeclarations, declarationsForColors ); } KTextEditor::Attribute::Ptr CodeHighlighting::attributeForDepth(int depth) const { while (depth >= m_depthAttributes.count()) { KTextEditor::Attribute::Ptr a(new KTextEditor::Attribute()); a->setBackground(QColor(Qt::white).dark(100 + (m_depthAttributes.count() * 25))); a->setBackgroundFillWhitespace(true); if (depth % 2) a->setOutline(Qt::red); m_depthAttributes.append(a); } return m_depthAttributes[depth]; } KDevelop::Declaration* CodeHighlightingInstance::localClassFromCodeContext(KDevelop::DUContext* context) const { if(!context) return 0; if(m_contextClasses.contains(context)) return m_contextClasses[context]; DUContext* startContext = context; while( context->parentContext() && context->type() == DUContext::Other && context->parentContext()->type() == DUContext::Other ) { //Move context to the top context of type "Other". This is needed because every compound-statement creates a new sub-context. context = context->parentContext(); } ///Step 1: Find the function-declaration for the function we are in Declaration* functionDeclaration = 0; if( FunctionDefinition* def = dynamic_cast(context->owner()) ) { if(m_contextClasses.contains(context)) return m_contextClasses[context]; functionDeclaration = def->declaration(startContext->topContext()); } if( !functionDeclaration && context->owner() ) functionDeclaration = context->owner(); if(!functionDeclaration) { if(m_useClassCache) m_contextClasses[context] = 0; return 0; } Declaration* decl = functionDeclaration->context()->owner(); if(m_useClassCache) m_contextClasses[context] = decl; return decl; } CodeHighlightingInstance::Types CodeHighlightingInstance::typeForDeclaration(Declaration * dec, DUContext* context) const { /** * We highlight in 3 steps by priority: * 1. Is the item in the local class or an inherited class? If yes, highlight. * 2. What kind of item is it? If it's a type/function/enumerator, highlight by type. * 3. Else, highlight by scope. * * */ // if(ClassMemberDeclaration* classMember = dynamic_cast(dec)) // if(!Cpp::isAccessible(context, classMember)) // return ErrorVariableType; if(!dec) return ErrorVariableType; Types type = LocalVariableType; if(dec->kind() == Declaration::Namespace) return NamespaceType; if (context && dec->context() && dec->context()->type() == DUContext::Class) { //It is a use. //Determine the class we're in Declaration* klass = localClassFromCodeContext(context); if(klass) { if (klass->internalContext() == dec->context()) type = LocalClassMemberType; //Using Member of the local class else if (dec->context()->type() == DUContext::Class && klass->internalContext() && klass->internalContext()->imports(dec->context())) type = InheritedClassMemberType; //Using Member of an inherited class } } if (type == LocalVariableType) { if (dec->kind() == Declaration::Type || dec->type() || dec->type()) { if (dec->isForwardDeclaration()) type = ForwardDeclarationType; else if (dec->type()) type = FunctionType; else if(dec->type()) type = ClassType; else if(dec->type()) type = TypeAliasType; else if(dec->type()) type = EnumType; else if(dec->type()) type = EnumeratorType; } } if (type == LocalVariableType) { switch (dec->context()->type()) { case DUContext::Namespace: type = NamespaceVariableType; break; case DUContext::Class: type = MemberVariableType; break; case DUContext::Function: type = FunctionVariableType; break; default: break; } } return type; } bool CodeHighlightingInstance::useRainbowColor(Declaration* dec) const { return dec->context()->type() == DUContext::Function || (dec->context()->type() == DUContext::Other && dec->context()->owner()); } void CodeHighlightingInstance::highlightDeclaration(Declaration * declaration, const QColor &color) { HighlightedRange h; h.range = declaration->range(); h.attribute = m_highlighting->attributeForType(typeForDeclaration(declaration, 0), DeclarationContext, color); m_highlight.push_back(h); } void CodeHighlightingInstance::highlightUse(DUContext* context, int index, const QColor &color) { Types type = ErrorVariableType; Declaration* decl = context->topContext()->usedDeclarationForIndex(context->uses()[index].m_declarationIndex); type = typeForDeclaration(decl, context); if(type != ErrorVariableType || ICore::self()->languageController()->completionSettings()->highlightSemanticProblems()) { HighlightedRange h; h.range = context->uses()[index].m_range; h.attribute = m_highlighting->attributeForType(type, ReferenceContext, color); m_highlight.push_back(h); } } void CodeHighlightingInstance::highlightUses(DUContext* context) { for(int a = 0; a < context->usesCount(); ++a) highlightUse(context, a, QColor(QColor::Invalid)); } void CodeHighlighting::clearHighlightingForDocument(IndexedString document) { VERIFY_FOREGROUND_LOCKED QMutexLocker lock(&m_dataMutex); DocumentChangeTracker* tracker = ICore::self()->languageController()->backgroundParser()->trackerForUrl(document); if(m_highlights.contains(tracker)) { disconnect(tracker, &DocumentChangeTracker::destroyed, this, &CodeHighlighting::trackerDestroyed); qDeleteAll(m_highlights[tracker]->m_highlightedRanges); delete m_highlights[tracker]; m_highlights.remove(tracker); } } void CodeHighlighting::applyHighlighting(void* _highlighting) { CodeHighlighting::DocumentHighlighting* highlighting = static_cast(_highlighting); VERIFY_FOREGROUND_LOCKED QMutexLocker lock(&m_dataMutex); DocumentChangeTracker* tracker = ICore::self()->languageController()->backgroundParser()->trackerForUrl(highlighting->m_document); if(!tracker) { qCDebug(LANGUAGE) << "no document found for the planned highlighting of" << highlighting->m_document.str(); delete highlighting; return; } QVector< MovingRange* > oldHighlightedRanges; if(m_highlights.contains(tracker)) { oldHighlightedRanges = m_highlights[tracker]->m_highlightedRanges; delete m_highlights[tracker]; }else{ // we newly add this tracker, so add the connection // This can't use new style connect syntax since MovingInterface is not a QObject connect(tracker->document(), SIGNAL(aboutToInvalidateMovingInterfaceContent(KTextEditor::Document*)), this, SLOT(aboutToInvalidateMovingInterfaceContent(KTextEditor::Document*))); connect(tracker->document(), SIGNAL(aboutToRemoveText(KTextEditor::Range)), this, SLOT(aboutToRemoveText(KTextEditor::Range))); connect(tracker, &DocumentChangeTracker::destroyed, this, &CodeHighlighting::trackerDestroyed); } m_highlights[tracker] = highlighting; // Now create MovingRanges (match old ones with the incoming ranges) KTextEditor::Range tempRange; QVector::iterator movingIt = oldHighlightedRanges.begin(); QVector::iterator rangeIt = highlighting->m_waiting.begin(); while(rangeIt != highlighting->m_waiting.end()) { // Translate the range into the current revision KTextEditor::Range transformedRange = tracker->transformToCurrentRevision(rangeIt->range, highlighting->m_waitingRevision); while(movingIt != oldHighlightedRanges.end() && ((*movingIt)->start().line() < transformedRange.start().line() || ((*movingIt)->start().line() == transformedRange.start().line() && (*movingIt)->start().column() < transformedRange.start().column()))) { delete *movingIt; // Skip ranges that are in front of the current matched range ++movingIt; } tempRange = transformedRange; if(movingIt == oldHighlightedRanges.end() || transformedRange.start().line() != (*movingIt)->start().line() || transformedRange.start().column() != (*movingIt)->start().column() || transformedRange.end().line() != (*movingIt)->end().line() || transformedRange.end().column() != (*movingIt)->end().column()) { Q_ASSERT(rangeIt->attribute); // The moving range is behind or unequal, create a new range highlighting->m_highlightedRanges.push_back(tracker->documentMovingInterface()->newMovingRange(tempRange)); highlighting->m_highlightedRanges.back()->setAttribute(rangeIt->attribute); highlighting->m_highlightedRanges.back()->setZDepth(highlightingZDepth); } else { // Update the existing moving range (*movingIt)->setAttribute(rangeIt->attribute); (*movingIt)->setRange(tempRange); highlighting->m_highlightedRanges.push_back(*movingIt); ++movingIt; } ++rangeIt; } for(; movingIt != oldHighlightedRanges.end(); ++movingIt) delete *movingIt; // Delete unmatched moving ranges behind } void CodeHighlighting::trackerDestroyed(QObject* object) { // Called when a document is destroyed VERIFY_FOREGROUND_LOCKED QMutexLocker lock(&m_dataMutex); DocumentChangeTracker* tracker = static_cast(object); Q_ASSERT(m_highlights.contains(tracker)); delete m_highlights[tracker]; // No need to care about the individual ranges, as the document is being destroyed m_highlights.remove(tracker); } void CodeHighlighting::aboutToInvalidateMovingInterfaceContent(Document* doc) { clearHighlightingForDocument(IndexedString(doc->url())); } void CodeHighlighting::aboutToRemoveText( const KTextEditor::Range& range ) { if (range.onSingleLine()) // don't try to optimize this return; VERIFY_FOREGROUND_LOCKED QMutexLocker lock(&m_dataMutex); Q_ASSERT(dynamic_cast(sender())); KTextEditor::Document* doc = static_cast(sender()); DocumentChangeTracker* tracker = ICore::self()->languageController()->backgroundParser() ->trackerForUrl(IndexedString(doc->url())); if(m_highlights.contains(tracker)) { QVector& ranges = m_highlights.value(tracker)->m_highlightedRanges; QVector::iterator it = ranges.begin(); while(it != ranges.end()) { if (range.contains((*it)->toRange())) { delete (*it); it = ranges.erase(it); } else { ++it; } } } } } // kate: space-indent on; indent-width 2; replace-trailing-space-save on; show-tabs on; tab-indents on; tab-width 2; diff --git a/language/highlighting/colorcache.cpp b/language/highlighting/colorcache.cpp index 5494be1383..e2729f2a14 100644 --- a/language/highlighting/colorcache.cpp +++ b/language/highlighting/colorcache.cpp @@ -1,340 +1,345 @@ /* * This file is part of KDevelop * * Copyright 2009 Milian Wolff * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Library General Public License as * published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public * License along with this program; if not, write to the * Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "colorcache.h" #include "configurablecolors.h" #include #include "../../interfaces/icore.h" #include "../../interfaces/ilanguagecontroller.h" #include "../../interfaces/icompletionsettings.h" #include "../../interfaces/idocument.h" #include "../../interfaces/idocumentcontroller.h" #include "../interfaces/ilanguagesupport.h" #include "../duchain/duchain.h" #include "../duchain/duchainlock.h" #include "util/debug.h" #include #include #include #include #define ifDebug(x) // ######### start interpolation static const uint totalColorInterpolationStepCount = 6; static const uint interpolationWaypoints[] = {0xff0000, 0xff9900, 0x00ff00, 0x00aaff, 0x0000ff, 0xaa00ff}; //Do less steps when interpolating to/from green: Green is very dominant, and different mixed green tones are hard to distinguish(and always seem green). static const uint interpolationLengths[] = {0xff, 0xff, 0xbb, 0xbb, 0xbb, 0xff}; static const uint totalGeneratedColors = 10; uint totalColorInterpolationSteps() { uint ret = 0; for(uint a = 0; a < totalColorInterpolationStepCount; ++a) ret += interpolationLengths[a]; return ret; } ///Generates a color from the color wheel. @param step Step-number, one of totalColorInterpolationSteps QColor interpolate(uint step) { uint waypoint = 0; while(step > interpolationLengths[waypoint]) { step -= interpolationLengths[waypoint]; ++waypoint; } uint nextWaypoint = (waypoint + 1) % totalColorInterpolationStepCount; return KColorUtils::mix( QColor(interpolationWaypoints[waypoint]), QColor(interpolationWaypoints[nextWaypoint]), float(step) / float(interpolationLengths[waypoint]) ); } // ######### end interpolation namespace KDevelop { ColorCache* ColorCache::m_self = 0; ColorCache::ColorCache(QObject* parent) : QObject(parent), m_defaultColors(0), m_validColorCount(0), m_colorOffset(0), - m_localColorRatio(0), m_globalColorRatio(0) + m_localColorRatio(0), m_globalColorRatio(0), m_boldDeclarations(true) { Q_ASSERT(m_self == 0); updateColorsFromScheme(); // default / fallback updateColorsFromSettings(); connect(ICore::self()->languageController()->completionSettings(), &ICompletionSettings::settingsChanged, this, &ColorCache::updateColorsFromSettings, Qt::QueuedConnection); connect(ICore::self()->documentController(), &IDocumentController::documentActivated, this, &ColorCache::slotDocumentActivated); bool hadDoc = tryActiveDocument(); updateInternal(); m_self = this; if (!hadDoc) { // try to update later on again QMetaObject::invokeMethod(this, "tryActiveDocument", Qt::QueuedConnection); } } bool ColorCache::tryActiveDocument() { KTextEditor::View* view = ICore::self()->documentController()->activeTextDocumentView(); if ( view ) { updateColorsFromView(view); return true; } return false; } ColorCache::~ColorCache() { m_self = 0; delete m_defaultColors; m_defaultColors = 0; } ColorCache* ColorCache::self() { if (!m_self) { m_self = new ColorCache; } return m_self; } void ColorCache::generateColors() { if ( m_defaultColors ) { delete m_defaultColors; } m_defaultColors = new CodeHighlightingColors(this); m_colors.clear(); uint step = totalColorInterpolationSteps() / totalGeneratedColors; uint currentPos = m_colorOffset; ifDebug(qCDebug(LANGUAGE) << "text color:" << m_foregroundColor;) for(uint a = 0; a < totalGeneratedColors; ++a) { m_colors.append( blendLocalColor( interpolate( currentPos ) ) ); ifDebug(qCDebug(LANGUAGE) << "color" << a << "interpolated from" << currentPos << " < " << totalColorInterpolationSteps() << ":" << (void*) m_colors.last().rgb();) currentPos += step; } m_validColorCount = m_colors.count(); m_colors.append(m_foregroundColor); } void ColorCache::slotDocumentActivated() { KTextEditor::View* view = ICore::self()->documentController()->activeTextDocumentView(); ifDebug(qCDebug(LANGUAGE) << "doc activated:" << doc;) if ( view ) { updateColorsFromView(view); } } void ColorCache::slotViewSettingsChanged() { KTextEditor::View* view = qobject_cast(sender()); Q_ASSERT(view); ifDebug(qCDebug(LANGUAGE) << "settings changed" << view;) updateColorsFromView(view); } void ColorCache::updateColorsFromView(KTextEditor::View* view) { if ( !view ) { // yeah, the HighlightInterface methods returning an Attribute // require a View... kill me for that mess return; } QColor foreground(QColor::Invalid); QColor background(QColor::Invalid); KTextEditor::Attribute::Ptr style = view->defaultStyleAttribute(KTextEditor::dsNormal); foreground = style->foreground().color(); if (style->hasProperty(QTextFormat::BackgroundBrush)) { background = style->background().color(); } // FIXME: this is in kateview // qCDebug(LANGUAGE) << "got foreground:" << foreground.name() << "old is:" << m_foregroundColor.name(); //NOTE: this slot is defined in KatePart > 4.4, see ApiDocs of the ConfigInterface // the signal is not defined in ConfigInterface, but according to the docs it should be // can't use new signal slot syntax here, since ConfigInterface is not a QObject if ( KTextEditor::View* view = m_view.data() ) { Q_ASSERT(qobject_cast(view)); // we only listen to a single view, i.e. the active one disconnect(view, SIGNAL(configChanged()), this, SLOT(slotViewSettingsChanged())); } Q_ASSERT(qobject_cast(view)); connect(view, SIGNAL(configChanged()), this, SLOT(slotViewSettingsChanged())); m_view = view; if ( !foreground.isValid() ) { // fallback to colorscheme variant ifDebug(qCDebug(LANGUAGE) << "updating from scheme";) updateColorsFromScheme(); } else if ( m_foregroundColor != foreground || m_backgroundColor != background ) { m_foregroundColor = foreground; m_backgroundColor = background; ifDebug(qCDebug(LANGUAGE) << "updating from document";) update(); } } void ColorCache::updateColorsFromScheme() { KColorScheme scheme(QPalette::Normal, KColorScheme::View); QColor foreground = scheme.foreground(KColorScheme::NormalText).color(); QColor background = scheme.background(KColorScheme::NormalBackground).color(); if ( foreground != m_foregroundColor || background != m_backgroundColor ) { m_foregroundColor = foreground; m_backgroundColor = background; update(); } } void ColorCache::updateColorsFromSettings() { int localRatio = ICore::self()->languageController()->completionSettings()->localColorizationLevel(); int globalRatio = ICore::self()->languageController()->completionSettings()->globalColorizationLevel(); + bool boldDeclartions = ICore::self()->languageController()->completionSettings()->boldDeclarations(); if ( localRatio != m_localColorRatio || globalRatio != m_globalColorRatio ) { m_localColorRatio = localRatio; m_globalColorRatio = globalRatio; update(); } + if (boldDeclartions != m_boldDeclarations) { + m_boldDeclarations = boldDeclartions; + update(); + } } void ColorCache::update() { if ( !m_self ) { ifDebug(qCDebug(LANGUAGE) << "not updating - still initializating";) // don't update on startup, updateInternal is called directly there return; } QMetaObject::invokeMethod(this, "updateInternal", Qt::QueuedConnection); } void ColorCache::updateInternal() { ifDebug(qCDebug(LANGUAGE) << "update internal" << m_self;) generateColors(); if ( !m_self ) { // don't do anything else fancy on startup return; } emit colorsGotChanged(); // rehighlight open documents foreach (IDocument* doc, ICore::self()->documentController()->openDocuments()) { foreach (auto lang, ICore::self()->languageController()->languagesForUrl(doc->url())) { ReferencedTopDUContext top; { DUChainReadLocker lock; top = lang->standardContext(doc->url()); } if(top) { if ( ICodeHighlighting* highlighting = lang->codeHighlighting() ) { highlighting->highlightDUChain(top); } } } } } QColor ColorCache::blend(QColor color, uchar ratio) const { Q_ASSERT(m_backgroundColor.isValid()); Q_ASSERT(m_foregroundColor.isValid()); if ( KColorUtils::luma(m_foregroundColor) > KColorUtils::luma(m_backgroundColor) ) { // for dark color schemes, produce a fitting color first color = KColorUtils::tint(m_foregroundColor, color, 0.5); } // adapt contrast return KColorUtils::mix( m_foregroundColor, color, float(ratio) / float(0xff) ); } QColor ColorCache::blendBackground(QColor color, uchar ratio) const { /* if ( KColorUtils::luma(m_foregroundColor) > KColorUtils::luma(m_backgroundColor) ) { // for dark color schemes, produce a fitting color first color = KColorUtils::tint(m_foregroundColor, color, 0.5).rgb(); }*/ // adapt contrast return KColorUtils::mix( m_backgroundColor, color, float(ratio) / float(0xff) ); } QColor ColorCache::blendGlobalColor(QColor color) const { return blend(color, m_globalColorRatio); } QColor ColorCache::blendLocalColor(QColor color) const { return blend(color, m_localColorRatio); } CodeHighlightingColors* ColorCache::defaultColors() const { Q_ASSERT(m_defaultColors); return m_defaultColors; } QColor ColorCache::generatedColor(uint num) const { return m_colors[num]; } uint ColorCache::validColorCount() const { return m_validColorCount; } QColor ColorCache::foregroundColor() const { return m_foregroundColor; } } // kate: space-indent on; indent-width 2; replace-trailing-space-save on; show-tabs on; tab-indents on; tab-width 2; diff --git a/language/highlighting/colorcache.h b/language/highlighting/colorcache.h index d021fd2671..d04dfc5c90 100644 --- a/language/highlighting/colorcache.h +++ b/language/highlighting/colorcache.h @@ -1,164 +1,167 @@ /* * This file is part of KDevelop * * Copyright 2009 Milian Wolff * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Library General Public License as * published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public * License along with this program; if not, write to the * Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef KDEVPLATFORM_COLORCACHE_H #define KDEVPLATFORM_COLORCACHE_H #include #include #include #include #include namespace KTextEditor { class Document; class View; } namespace KDevelop { class CodeHighlightingColors; class IDocument; /** * A singleton which holds the global default colors, adapted to the current color scheme */ class KDEVPLATFORMLANGUAGE_EXPORT ColorCache : public QObject { Q_OBJECT public: ~ColorCache(); /// access the global color cache static ColorCache* self(); /// adapt a given foreground color to the current color scheme /// @p ratio between 0 and 255 where 0 gives @see m_foregroundColor /// and 255 gives @p color /// /// @note if you are looking for a background color, simply setting an alpha /// value should work. QColor blend(QColor color, uchar ratio) const; /// adapt a given background color to the current color scheme /// @p ratio between 0 and 255 where 0 gives @see m_foregroundColor /// and 255 gives @p color /// /// @note if you are looking for a background color, simply setting an alpha /// value should work. QColor blendBackground(QColor color, uchar ratio) const; /// blend a color for local colorization according to the user settings /// @see blend() QColor blendLocalColor(QColor color) const; /// blend a color for global colorization according to the user settings /// @see blend() QColor blendGlobalColor(QColor color) const; /// access the default colors CodeHighlightingColors* defaultColors() const; /// access the generated colors /// @see validColorCount() QColor generatedColor(uint num) const; /// returns the number of valid generated colors /// @see generatedColor() uint validColorCount() const; /// access the foreground color QColor foregroundColor() const; signals: /// will be emitted whenever the colors got changed /// @see update() void colorsGotChanged(); private slots: /// if necessary, adapt to the colors of this document void slotDocumentActivated(); /// settings got changed, update to the settings of the sender void slotViewSettingsChanged(); /// will regenerate colors from global KDE color scheme void updateColorsFromScheme(); /// will regenerate colors with the proper intensity settings void updateColorsFromSettings(); /// regenerate colors and emits @p colorsGotChanged() /// and finally triggers a rehighlight of the opened documents void updateInternal(); bool tryActiveDocument(); private: ColorCache(QObject *parent = 0); static ColorCache* m_self; /// get @p totalGeneratedColors colors from the color wheel and adapt them to the current color scheme void generateColors(); /// calls @c updateInternal() delayed to prevent double loading of language plugins. void update(); /// try to access the KatePart settings for the given doc or fallback to the global KDE scheme /// and update the colors if necessary /// @see generateColors(), updateColorsFromScheme() void updateColorsFromView(KTextEditor::View* view); /// the default colors for the different types CodeHighlightingColors* m_defaultColors; /// the generated colors QList m_colors; /// Must always be m_colors.count()-1, because the last color must be the fallback text color uint m_validColorCount; /// Maybe make this configurable: An offset where to start stepping through the color wheel uint m_colorOffset; /// the text color for the current color scheme QColor m_foregroundColor; /// the editor background color color for the current color scheme QColor m_backgroundColor; /// How generated colors for local variables should be mixed with the foreground color. /// Between 0 and 255, where 255 means only foreground color, and 0 only the chosen color. uchar m_localColorRatio; /// How global colors (i.e. for types, uses, etc.) should be mixed with the foreground color. /// Between 0 and 255, where 255 means only foreground color, and 0 only the chosen color. uchar m_globalColorRatio; + /// Whether declarations have to be rendered with a bold style or not. + bool m_boldDeclarations; + /// The view we are listening to for setting changes. QPointer m_view; }; } #endif // KDEVPLATFORM_COLORCACHE_H // kate: space-indent on; indent-width 2; replace-trailing-space-save on; show-tabs on; tab-indents on; tab-width 2; diff --git a/shell/completionsettings.cpp b/shell/completionsettings.cpp index 0440ca71c8..89cf68b46e 100644 --- a/shell/completionsettings.cpp +++ b/shell/completionsettings.cpp @@ -1,103 +1,108 @@ /*************************************************************************** * Copyright 2008 David Nolden * * Copyright 2013 Vlas Puhov * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU Library General Public License as * * published by the Free Software Foundation; either version 2 of the * * License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU Library General Public * * License along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * ***************************************************************************/ #include "completionsettings.h" #include namespace KDevelop { static QString completionLevelToString(ICompletionSettings::CompletionLevel l) { if (l < 0 || l >= ICompletionSettings::LAST_LEVEL) { return QString(); } const static QString levels[ICompletionSettings::LAST_LEVEL] = {"Minimal", "MinimalWhenAutomatic", "AlwaysFull"}; return levels[l]; } CompletionSettings& CompletionSettings::self() { static CompletionSettings settings; return settings; } QStringList CompletionSettings::todoMarkerWords() const { const QString markers = m_languageGroup.readEntry("todoMarkerWords", m_todoMarkerWords); return KShell::splitArgs(markers); } int CompletionSettings::minFilesForSimplifiedParsing() const { return m_languageGroup.readEntry("minFilesForSimplifiedParsing", m_minFilesForSimplifiedParsing); } bool CompletionSettings::showMultiLineSelectionInformation() const { return m_languageGroup.readEntry("showMultiLineSelectionInformation", m_showMultiLineInformation); } bool CompletionSettings::highlightProblematicLines() const { return m_languageGroup.readEntry("highlightProblematicLines", m_highlightProblematicLines); } bool CompletionSettings::highlightSemanticProblems() const { return m_languageGroup.readEntry("highlightSemanticProblems", m_highlightSemanticProblems); } +bool CompletionSettings::boldDeclarations() const +{ + return m_languageGroup.readEntry("boldDeclarations", m_boldDeclarations); +} + int CompletionSettings::globalColorizationLevel() const { return m_languageGroup.readEntry("globalColorization", m_globalColorizationLevel); } int CompletionSettings::localColorizationLevel() const { return m_languageGroup.readEntry("localColorization", m_localColorizationLevel); } bool CompletionSettings::automaticCompletionEnabled() const { return m_languageGroup.readEntry("Automatic Invocation", m_automatic); } ICompletionSettings::CompletionLevel CompletionSettings::completionLevel() const { const QString level = m_languageGroup.readEntry("completionDetail", completionLevelToString(m_level)); for (int i = 0; i < ICompletionSettings::LAST_LEVEL; i++) { if (completionLevelToString(static_cast(i)) == level) { return static_cast(i); } } return m_level; } CompletionSettings::CompletionSettings() : m_level(MinimalWhenAutomatic), m_automatic(true), m_highlightSemanticProblems(true), m_highlightProblematicLines(false), m_showMultiLineInformation(false), - m_localColorizationLevel(170), m_globalColorizationLevel(255), m_minFilesForSimplifiedParsing(100000), - m_todoMarkerWords("TODO FIXME"), + m_boldDeclarations(true), m_localColorizationLevel(170), m_globalColorizationLevel(255), + m_minFilesForSimplifiedParsing(100000), m_todoMarkerWords("TODO FIXME"), m_languageGroup(KSharedConfig::openConfig(), "Language Support"){} } diff --git a/shell/completionsettings.h b/shell/completionsettings.h index e4413195d2..05f166b432 100644 --- a/shell/completionsettings.h +++ b/shell/completionsettings.h @@ -1,68 +1,74 @@ /*************************************************************************** * Copyright 2008 David Nolden * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU Library General Public License as * * published by the Free Software Foundation; either version 2 of the * * License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU Library General Public * * License along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * ***************************************************************************/ #ifndef KDEVPLATFORM_COMPLETIONSETTINGS_H #define KDEVPLATFORM_COMPLETIONSETTINGS_H #include #include #include namespace KDevelop { class CompletionSettings : public KDevelop::ICompletionSettings { public: virtual CompletionLevel completionLevel() const override; virtual bool automaticCompletionEnabled() const override; void emitChanged() { emit settingsChanged(this); } virtual int localColorizationLevel() const override; virtual int globalColorizationLevel() const override; virtual bool highlightSemanticProblems() const override; virtual bool highlightProblematicLines() const override; + virtual bool boldDeclarations() const override; + virtual bool showMultiLineSelectionInformation() const override; virtual int minFilesForSimplifiedParsing() const override; virtual QStringList todoMarkerWords() const override; static CompletionSettings& self(); private: CompletionSettings(); const CompletionLevel m_level; - const bool m_automatic, m_highlightSemanticProblems, m_highlightProblematicLines, m_showMultiLineInformation; + const bool m_automatic; + const bool m_highlightSemanticProblems; + const bool m_highlightProblematicLines; + const bool m_showMultiLineInformation; + const bool m_boldDeclarations; const int m_localColorizationLevel; const int m_globalColorizationLevel; const int m_minFilesForSimplifiedParsing; const QString m_todoMarkerWords; const KConfigGroup m_languageGroup; }; } #endif diff --git a/shell/settings/ccconfig.kcfg b/shell/settings/ccconfig.kcfg index 1cd72a4b3c..624d8da975 100644 --- a/shell/settings/ccconfig.kcfg +++ b/shell/settings/ccconfig.kcfg @@ -1,41 +1,44 @@ true true false + + true + false 170 255 100000 TODO FIXME MinimalWhenAutomatic diff --git a/shell/settings/ccpreferences.ui b/shell/settings/ccpreferences.ui index fa4559e63a..48bd90f44f 100644 --- a/shell/settings/ccpreferences.ui +++ b/shell/settings/ccpreferences.ui @@ -1,319 +1,334 @@ CCPreferences 0 0 599 592 Code Completion If disabled, the code completion widget will never show automatically. Choose whether to display additional information for the currently selected code completion item. <p>The code completion UI has a minimal mode and a detailed mode.<br>Choose in what cases full code completion will be displayed.</p> 1 Never When Invoked Manually Always <p>The code completion UI has a minimal mode and a detailed mode.<br>Choose in what cases full code completion will be displayed.</p> Detailed completion: If disabled, the code completion widget will never show automatically. Enable automatic invocation: Choose whether to display additional information for the currently selected codecompletion item. Additional information for current item: Semantic Code Highlighting QFormLayout::ExpandingFieldsGrow <p>This setting decides about the intensity of colors for local variables, for example function arguments, variables and the like.</p> Local colorization intensity: kcfg_localColorization <p>This setting decides about the intensity of colors for local variables, for example function arguments, variables and the like.</p> 255 3 25 170 Qt::Horizontal + + + + <p>This settings lets you change the intensity of globally accessible types, for example classes, methods, functions etc.</p> + + + Global colorization intensity: + + + kcfg_localColorization + + + + + + + <p>This settings lets you change the intensity of globally accessible types, for example classes, methods, functions etc.</p> + + + 255 + + + 3 + + + 25 + + + 255 + + + Qt::Horizontal + + + <p>Highlight semantic problems, such as non-existent or inaccessible declarations.</p> Highlight semantic problems: <p>Highlight semantic problems, such as non-existent or inaccessible declarations.</p> <p>When enabled, lines with errors will get additionally highlighted and their positions get marked in the scrollbar.</p> Highlight problematic lines: <p>When enabled, lines with errors will get additionally highlighted and their positions get marked in the scrollbar.</p> Space-separated list of words that make a comment represent a TODO item TODO marker words: Space-separated list of words that make a comment represent a TODO item. - - - - <p>This settings lets you change the intensity of globally accessible types, for example classes, methods, functions etc.</p> - - - 255 - - - 3 - - - 25 - - - 255 - - - Qt::Horizontal - - - - - + + - <p>This settings lets you change the intensity of globally accessible types, for example classes, methods, functions etc.</p> + <html><head/><body><p>Use bold font for declarations such as classes, functions, local variables, etc.</p></body></html> - Global colorization intensity: - - - kcfg_localColorization + Bold font for declarations: + + + kcfg_localColorization label_4 kcfg_highlightSemanticProblems label_5 kcfg_highlightProblematicLines label_3 kcfg_todoMarkerWords kcfg_globalColorization globalColorizationLabel localColorizationLabel + boldDeclarationsLabel + kcfg_boldDeclarations Project Parsing QFormLayout::ExpandingFieldsGrow <p>When a project contains more files than this number, the project will be parsed in simplified mode, increasing the efficiency by gathering less information. Global code navigation and quickopen capabilities will be reduced.</p> Minimum project size for simplified parsing: 100 0 0 0 <p>When a project contains more files than this number, the project will be parsed in simplified mode, increasing the efficiency by gathering less information. Global code navigation and quickopen capabilities will be reduced.</p> files 99999999 1000 Qt::Vertical 20 40