diff --git a/src/syntax/katehighlight.cpp b/src/syntax/katehighlight.cpp index 1bfdd4ec..a0ce0f29 100644 --- a/src/syntax/katehighlight.cpp +++ b/src/syntax/katehighlight.cpp @@ -1,671 +1,673 @@ /* This file is part of the KDE libraries Copyright (C) 2007 Mirko Stocker Copyright (C) 2007 Matthew Woehlke Copyright (C) 2003, 2004 Anders Lund Copyright (C) 2003 Hamish Rodda Copyright (C) 2001,2002 Joseph Wenninger Copyright (C) 2001 Christoph Cullmann Copyright (C) 1999 Jochen Wilhelmy This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License version 2 as published by the Free Software Foundation. This library 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 Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ //BEGIN INCLUDES #include "katehighlight.h" #include "katetextline.h" #include "katedocument.h" #include "katerenderer.h" #include "kateglobal.h" #include "kateschema.h" #include "kateconfig.h" #include "kateextendedattribute.h" #include "katepartdebug.h" #include "katedefaultcolors.h" #include #include #include #include #include #include #include #include #include //END //BEGIN STATICS namespace { /** * convert from KSyntaxHighlighting => KTextEditor type * special handle non-1:1 things */ inline KTextEditor::DefaultStyle textStyleToDefaultStyle(const KSyntaxHighlighting::Theme::TextStyle textStyle) { // handle deviations if (textStyle == KSyntaxHighlighting::Theme::Error) { return KTextEditor::dsError; } if (textStyle == KSyntaxHighlighting::Theme::Others) { return KTextEditor::dsOthers; } // else: simple cast return static_cast(textStyle); } } //END //BEGIN KateHighlighting KateHighlighting::KateHighlighting(const KSyntaxHighlighting::Definition &def) { /** * get name and section, always works */ iName = def.name(); iSection = def.translatedSection(); /** * handle the "no highlighting" case */ if (!def.isValid()) { - // dummy properties + // dummy properties + formats m_properties.resize(1); m_propertiesForFormat.push_back(&m_properties[0]); + m_formats.resize(1); + m_formatsIdToIndex.insert(std::make_pair(m_formats[0].id(), 0)); // be done, all below is just for the real highlighting variants return; } /** * handle the real highlighting case */ noHl = false; iHidden = def.isHidden(); identifier = def.filePath(); iStyle = def.style(); m_indentation = def.indenter(); folding = def.foldingEnabled(); m_foldingIndentationSensitive = def.indentationBasedFoldingEnabled(); /** * tell the AbstractHighlighter the definition it shall use */ setDefinition(def); /** * get all included definitions, e.g. PHP for HTML highlighting */ auto definitions = definition().includedDefinitions(); /** * first: handle only really included definitions */ for (const auto &includedDefinition : definitions) embeddedHighlightingModes.push_back(includedDefinition.name()); /** * now: handle all, including this definition itself * create the format => attributes mapping * collect embedded highlightings, too * * we start with our definition as we want to have the default format * of the initial definition as attribute with index == 0 * * we collect additional properties in the m_properties and * map the formats to the right properties in m_propertiesForFormat */ definitions.push_front(definition()); m_properties.resize(definitions.size()); size_t propertiesIndex = 0; for (const auto & includedDefinition : definitions) { auto &properties = m_properties[propertiesIndex]; properties.definition = includedDefinition; for (const auto &emptyLine : includedDefinition.foldingIgnoreList()) properties.emptyLines.push_back(QRegularExpression(emptyLine)); properties.singleLineCommentMarker = includedDefinition.singleLineCommentMarker(); properties.singleLineCommentPosition = includedDefinition.singleLineCommentPosition(); const auto multiLineComment = includedDefinition.multiLineCommentMarker(); properties.multiLineCommentStart = multiLineComment.first; properties.multiLineCommentEnd = multiLineComment.second; // collect character characters for (const auto &enc : includedDefinition.characterEncodings()) { properties.characterEncodingsPrefixStore.addPrefix(enc.second); properties.characterEncodings[enc.second] = enc.first; properties.reverseCharacterEncodings[enc.first] = enc.second; } // collect formats for (const auto & format : includedDefinition.formats()) { // register format id => internal attributes, we want no clashs const auto nextId = m_formats.size(); - m_formatsIdToIndex.insert(std::make_pair(format.id(), nextId)).second; + m_formatsIdToIndex.insert(std::make_pair(format.id(), nextId)); m_formats.push_back(format); m_propertiesForFormat.push_back(&properties); } // advance to next properties ++propertiesIndex; } } void KateHighlighting::doHighlight(const Kate::TextLineData *prevLine, Kate::TextLineData *textLine, const Kate::TextLineData *nextLine, bool &ctxChanged, int tabWidth) { // default: no context change ctxChanged = false; // no text line => nothing to do if (!textLine) { return; } // in all cases, remove old hl, or we will grow to infinite ;) textLine->clearAttributesAndFoldings(); // reset folding start textLine->clearMarkedAsFoldingStart(); // no hl set, nothing to do more than the above cleaning ;) if (noHl) { return; } /** * ensure we arrive in clean state */ Q_ASSERT(!m_textLineToHighlight); Q_ASSERT(!m_foldingStartToCount); /** * highlight the given line via the abstract highlighter * a bit ugly: we set the line to highlight as member to be able to update its stats in the applyFormat and applyFolding member functions */ m_textLineToHighlight = textLine; const KSyntaxHighlighting::State initialState (!prevLine ? KSyntaxHighlighting::State() : prevLine->highlightingState()); const KSyntaxHighlighting::State endOfLineState = highlightLine(textLine->string(), initialState); m_textLineToHighlight = nullptr; /** * update highlighting state if needed */ if (textLine->highlightingState() != endOfLineState) { textLine->setHighlightingState(endOfLineState); ctxChanged = true; } /** * handle folding info computed and cleanup hash again, if there * check if folding is not balanced and we have more starts then ends * then this line is a possible folding start! */ if (m_foldingStartToCount) { /** * possible folding start, if imbalanced, aka hash not empty! */ if (!m_foldingStartToCount->isEmpty()) { textLine->markAsFoldingStartAttribute(); } /** * kill hash */ delete m_foldingStartToCount; m_foldingStartToCount = nullptr; } /** * check for indentation based folding */ if (m_foldingIndentationSensitive && (tabWidth > 0) && !textLine->markedAsFoldingStartAttribute()) { /** * compute if we increase indentation in next line */ if (endOfLineState.indentationBasedFoldingEnabled() && !isEmptyLine(textLine) && !isEmptyLine(nextLine) && (textLine->indentDepth(tabWidth) < nextLine->indentDepth(tabWidth))) { textLine->markAsFoldingStartIndentation(); } } } void KateHighlighting::applyFormat(int offset, int length, const KSyntaxHighlighting::Format &format) { // WE ATM assume ascending offset order Q_ASSERT(m_textLineToHighlight); Q_ASSERT(format.isValid()); // get internal attribute, must exist const auto it = m_formatsIdToIndex.find(format.id()); Q_ASSERT(it != m_formatsIdToIndex.end()); // remember highlighting info in our textline m_textLineToHighlight->addAttribute(Kate::TextLineData::Attribute(offset, length, it->second)); } void KateHighlighting::applyFolding(int offset, int, KSyntaxHighlighting::FoldingRegion region) { // WE ATM assume ascending offset order and don't care for length Q_ASSERT(m_textLineToHighlight); Q_ASSERT(region.isValid()); const int foldingValue = (region.type() == KSyntaxHighlighting::FoldingRegion::Begin) ? int(region.id()) : -int(region.id()); m_textLineToHighlight->addFolding(offset, foldingValue); /** * for each end region, decrement counter for that type, erase if count reaches 0! */ if ((foldingValue < 0) && m_foldingStartToCount) { QHash::iterator end = m_foldingStartToCount->find(foldingValue); if (end != m_foldingStartToCount->end()) { if (end.value() > 1) { --(end.value()); } else { m_foldingStartToCount->erase(end); } } } /** * increment counter for each begin region! */ if (foldingValue > 0) { // construct on demand! if (!m_foldingStartToCount) { m_foldingStartToCount = new QHash (); } ++(*m_foldingStartToCount)[foldingValue]; } } void KateHighlighting::getKateExtendedAttributeList(const QString &schema, QList &list, KConfig *cfg) { KConfigGroup config(cfg ? cfg : KateHlManager::self()->getKConfig(), QLatin1String("Highlighting ") + iName + QLatin1String(" - Schema ") + schema); list = attributesForDefinition(); foreach (KTextEditor::Attribute::Ptr p, list) { Q_ASSERT(p); QStringList s = config.readEntry(p->name(), QStringList()); // qCDebug(LOG_KTE)<name< 0) { while (s.count() < 10) { s << QString(); } QString name = p->name(); bool spellCheck = !p->skipSpellChecking(); p->clear(); p->setName(name); p->setSkipSpellChecking(!spellCheck); QString tmp = s[0]; if (!tmp.isEmpty()) { p->setDefaultStyle(static_cast (tmp.toInt())); } QRgb col; tmp = s[1]; if (!tmp.isEmpty()) { col = tmp.toUInt(nullptr, 16); p->setForeground(QColor(col)); } tmp = s[2]; if (!tmp.isEmpty()) { col = tmp.toUInt(nullptr, 16); p->setSelectedForeground(QColor(col)); } tmp = s[3]; if (!tmp.isEmpty()) { p->setFontBold(tmp != QLatin1String("0")); } tmp = s[4]; if (!tmp.isEmpty()) { p->setFontItalic(tmp != QLatin1String("0")); } tmp = s[5]; if (!tmp.isEmpty()) { p->setFontStrikeOut(tmp != QLatin1String("0")); } tmp = s[6]; if (!tmp.isEmpty()) { p->setFontUnderline(tmp != QLatin1String("0")); } tmp = s[7]; if (!tmp.isEmpty()) { col = tmp.toUInt(nullptr, 16); p->setBackground(QColor(col)); } tmp = s[8]; if (!tmp.isEmpty()) { col = tmp.toUInt(nullptr, 16); p->setSelectedBackground(QColor(col)); } tmp = s[9]; if (!tmp.isEmpty() && tmp != QLatin1String("---")) { p->setFontFamily(tmp); } } } } void KateHighlighting::getKateExtendedAttributeListCopy(const QString &schema, QList< KTextEditor::Attribute::Ptr > &list, KConfig *cfg) { QList attributes; getKateExtendedAttributeList(schema, attributes, cfg); list.clear(); foreach (const KTextEditor::Attribute::Ptr &attribute, attributes) { list.append(KTextEditor::Attribute::Ptr(new KTextEditor::Attribute(*attribute.data()))); } } void KateHighlighting::setKateExtendedAttributeList(const QString &schema, QList &list, KConfig *cfg, bool writeDefaultsToo) { KConfigGroup config(cfg ? cfg : KateHlManager::self()->getKConfig(), QLatin1String("Highlighting ") + iName + QLatin1String(" - Schema ") + schema); QStringList settings; KateAttributeList defList; KateHlManager::self()->getDefaults(schema, defList); foreach (const KTextEditor::Attribute::Ptr &p, list) { Q_ASSERT(p); settings.clear(); KTextEditor::DefaultStyle defStyle = p->defaultStyle(); KTextEditor::Attribute::Ptr a(defList[defStyle]); settings << QString::number(p->defaultStyle(), 10); settings << (p->hasProperty(QTextFormat::ForegroundBrush) ? QString::number(p->foreground().color().rgb(), 16) : (writeDefaultsToo ? QString::number(a->foreground().color().rgb(), 16) : QString())); settings << (p->hasProperty(SelectedForeground) ? QString::number(p->selectedForeground().color().rgb(), 16) : (writeDefaultsToo ? QString::number(a->selectedForeground().color().rgb(), 16) : QString())); settings << (p->hasProperty(QTextFormat::FontWeight) ? (p->fontBold() ? QStringLiteral("1") : QStringLiteral("0")) : (writeDefaultsToo ? (a->fontBold() ? QStringLiteral("1") : QStringLiteral("0")) : QString())); settings << (p->hasProperty(QTextFormat::FontItalic) ? (p->fontItalic() ? QStringLiteral("1") : QStringLiteral("0")) : (writeDefaultsToo ? (a->fontItalic() ? QStringLiteral("1") : QStringLiteral("0")) : QString())); settings << (p->hasProperty(QTextFormat::FontStrikeOut) ? (p->fontStrikeOut() ? QStringLiteral("1") : QStringLiteral("0")) : (writeDefaultsToo ? (a->fontStrikeOut() ? QStringLiteral("1") : QStringLiteral("0")) : QString())); settings << (p->hasProperty(QTextFormat::FontUnderline) ? (p->fontUnderline() ? QStringLiteral("1") : QStringLiteral("0")) : (writeDefaultsToo ? (a->fontUnderline() ? QStringLiteral("1") : QStringLiteral("0")) : QString())); settings << (p->hasProperty(QTextFormat::BackgroundBrush) ? QString::number(p->background().color().rgb(), 16) : ((writeDefaultsToo && a->hasProperty(QTextFormat::BackgroundBrush)) ? QString::number(a->background().color().rgb(), 16) : QString())); settings << (p->hasProperty(SelectedBackground) ? QString::number(p->selectedBackground().color().rgb(), 16) : ((writeDefaultsToo && a->hasProperty(SelectedBackground)) ? QString::number(a->selectedBackground().color().rgb(), 16) : QString())); settings << (p->hasProperty(QTextFormat::FontFamily) ? (p->fontFamily()) : (writeDefaultsToo ? a->fontFamily() : QString())); settings << QStringLiteral("---"); config.writeEntry(p->name(), settings); } } +int KateHighlighting::sanitizeFormatIndex(int attrib) const +{ + // sanitize, e.g. one could have old hl info with now invalid attribs + if (attrib < 0 || size_t(attrib) >= m_formats.size()) { + return 0; + } + return attrib; + +} + const QHash &KateHighlighting::getCharacterEncodings(int attrib) const { - return m_propertiesForFormat.at(attrib)->characterEncodings; + return m_propertiesForFormat.at(sanitizeFormatIndex(attrib))->characterEncodings; } const KatePrefixStore &KateHighlighting::getCharacterEncodingsPrefixStore(int attrib) const { - return m_propertiesForFormat.at(attrib)->characterEncodingsPrefixStore; + return m_propertiesForFormat.at(sanitizeFormatIndex(attrib))->characterEncodingsPrefixStore; } const QHash &KateHighlighting::getReverseCharacterEncodings(int attrib) const { - return m_propertiesForFormat.at(attrib)->reverseCharacterEncodings; + return m_propertiesForFormat.at(sanitizeFormatIndex(attrib))->reverseCharacterEncodings; } bool KateHighlighting::attributeRequiresSpellchecking(int attr) { - if (attr >= 0 && attr < static_cast(m_formats.size())) { - return m_formats[attr].spellCheck(); - } - return true; + return m_formats[sanitizeFormatIndex(attr)].spellCheck(); } KTextEditor::DefaultStyle KateHighlighting::defaultStyleForAttribute(int attr) const { - if (attr >= 0 && attr < static_cast(m_formats.size())) { - return textStyleToDefaultStyle(m_formats[attr].textStyle()); - } - return KTextEditor::dsNormal; + return textStyleToDefaultStyle(m_formats[sanitizeFormatIndex(attr)].textStyle()); } QString KateHighlighting::nameForAttrib(int attrib) const { - return m_propertiesForFormat.at(attrib)->definition.name() + QLatin1Char(':') + m_formats.at(attrib).name(); + const auto &format = m_formats.at(sanitizeFormatIndex(attrib)); + return m_propertiesForFormat.at(sanitizeFormatIndex(attrib))->definition.name() + QLatin1Char(':') + QString(format.isValid() ? format.name() : QLatin1String("Normal")); } bool KateHighlighting::isInWord(QChar c, int attrib) const { - return !m_propertiesForFormat.at(attrib)->definition.isWordDelimiter(c) + return !m_propertiesForFormat.at(sanitizeFormatIndex(attrib))->definition.isWordDelimiter(c) && !c.isSpace() && c != QLatin1Char('"') && c != QLatin1Char('\'') && c != QLatin1Char('`'); } bool KateHighlighting::canBreakAt(QChar c, int attrib) const { - return m_propertiesForFormat.at(attrib)->definition.isWordWrapDelimiter(c) && c != QLatin1Char('"') && c != QLatin1Char('\''); + return m_propertiesForFormat.at(sanitizeFormatIndex(attrib))->definition.isWordWrapDelimiter(c) && c != QLatin1Char('"') && c != QLatin1Char('\''); } const QVector &KateHighlighting::emptyLines(int attrib) const { - return m_propertiesForFormat.at(attrib)->emptyLines; + return m_propertiesForFormat.at(sanitizeFormatIndex(attrib))->emptyLines; } bool KateHighlighting::canComment(int startAttrib, int endAttrib) const { - const auto startProperties = m_propertiesForFormat.at(startAttrib); - const auto endProperties = m_propertiesForFormat.at(endAttrib); + const auto startProperties = m_propertiesForFormat.at(sanitizeFormatIndex(startAttrib)); + const auto endProperties = m_propertiesForFormat.at(sanitizeFormatIndex(endAttrib)); return (startProperties == endProperties && ((!startProperties->multiLineCommentStart.isEmpty() && !startProperties->multiLineCommentEnd.isEmpty()) || !startProperties->singleLineCommentMarker.isEmpty())); } QString KateHighlighting::getCommentStart(int attrib) const { - return m_propertiesForFormat.at(attrib)->multiLineCommentStart; + return m_propertiesForFormat.at(sanitizeFormatIndex(attrib))->multiLineCommentStart; } QString KateHighlighting::getCommentEnd(int attrib) const { - return m_propertiesForFormat.at(attrib)->multiLineCommentEnd; + return m_propertiesForFormat.at(sanitizeFormatIndex(attrib))->multiLineCommentEnd; } QString KateHighlighting::getCommentSingleLineStart(int attrib) const { - return m_propertiesForFormat.at(attrib)->singleLineCommentMarker; + return m_propertiesForFormat.at(sanitizeFormatIndex(attrib))->singleLineCommentMarker; } KSyntaxHighlighting::CommentPosition KateHighlighting::getCommentSingleLinePosition(int attrib) const { - return m_propertiesForFormat.at(attrib)->singleLineCommentPosition; + return m_propertiesForFormat.at(sanitizeFormatIndex(attrib))->singleLineCommentPosition; } const QHash &KateHighlighting::characterEncodings(int attrib) const { - return m_propertiesForFormat.at(attrib)->characterEncodings; + return m_propertiesForFormat.at(sanitizeFormatIndex(attrib))->characterEncodings; } void KateHighlighting::clearAttributeArrays() { // just clear the hashed attributes, we create them lazy again m_attributeArrays.clear(); } QList KateHighlighting::attributesForDefinition() { /** * create list of all known things */ QList array; - if (m_formats.empty()) { - KTextEditor::Attribute::Ptr newAttribute(new KTextEditor::Attribute(iName + QLatin1Char(':') + QLatin1String("Normal"), KTextEditor::dsNormal)); - array.append(newAttribute); - } else { - for (const auto &format : m_formats) { - /** - * FIXME: atm we just set some theme here for later color generation - */ - setTheme(KateHlManager::self()->repository().defaultTheme(KSyntaxHighlighting::Repository::LightTheme)); - - /** - * create a KTextEditor attribute matching the given format - */ - KTextEditor::Attribute::Ptr newAttribute(new KTextEditor::Attribute(nameForAttrib(array.size()), textStyleToDefaultStyle(format.textStyle()))); - - if (format.hasTextColor(theme())) { - newAttribute->setForeground(format.textColor(theme())); - newAttribute->setSelectedForeground(format.selectedTextColor(theme())); - } + for (const auto &format : m_formats) { + /** + * FIXME: atm we just set some theme here for later color generation + */ + setTheme(KateHlManager::self()->repository().defaultTheme(KSyntaxHighlighting::Repository::LightTheme)); - if (format.hasBackgroundColor(theme())) { - newAttribute->setBackground(format.backgroundColor(theme())); - newAttribute->setSelectedBackground(format.selectedBackgroundColor(theme())); - } + /** + * create a KTextEditor attribute matching the given format + */ + KTextEditor::Attribute::Ptr newAttribute(new KTextEditor::Attribute(nameForAttrib(array.size()), textStyleToDefaultStyle(format.textStyle()))); - if (format.isBold(theme())) { - newAttribute->setFontBold(true); - } + if (format.hasTextColor(theme())) { + newAttribute->setForeground(format.textColor(theme())); + newAttribute->setSelectedForeground(format.selectedTextColor(theme())); + } - if (format.isItalic(theme())) { - newAttribute->setFontItalic(true); - } + if (format.hasBackgroundColor(theme())) { + newAttribute->setBackground(format.backgroundColor(theme())); + newAttribute->setSelectedBackground(format.selectedBackgroundColor(theme())); + } - if (format.isUnderline(theme())) { - newAttribute->setFontUnderline(true); - } + if (format.isBold(theme())) { + newAttribute->setFontBold(true); + } - if (format.isStrikeThrough(theme())) { - newAttribute->setFontStrikeOut(true); - } + if (format.isItalic(theme())) { + newAttribute->setFontItalic(true); + } - newAttribute->setSkipSpellChecking(format.spellCheck()); + if (format.isUnderline(theme())) { + newAttribute->setFontUnderline(true); + } - array.append(newAttribute); + if (format.isStrikeThrough(theme())) { + newAttribute->setFontStrikeOut(true); } + + newAttribute->setSkipSpellChecking(format.spellCheck()); + + array.append(newAttribute); } return array; } QList KateHighlighting::attributes(const QString &schema) { // found it, already floating around if (m_attributeArrays.contains(schema)) { return m_attributeArrays[schema]; } // k, schema correct, let create the data QList array; KateAttributeList defaultStyleList; KateHlManager::self()->getDefaults(schema, defaultStyleList); QList itemDataList; getKateExtendedAttributeList(schema, itemDataList); uint nAttribs = itemDataList.count(); for (uint z = 0; z < nAttribs; z++) { KTextEditor::Attribute::Ptr itemData = itemDataList.at(z); KTextEditor::Attribute::Ptr newAttribute(new KTextEditor::Attribute(*defaultStyleList.at(itemData->defaultStyle()))); if (itemData && itemData->hasAnyProperty()) { *newAttribute += *itemData; } array.append(newAttribute); } m_attributeArrays.insert(schema, array); return array; } QStringList KateHighlighting::getEmbeddedHighlightingModes() const { return embeddedHighlightingModes; } bool KateHighlighting::isEmptyLine(const Kate::TextLineData *textline) const { const QString &txt = textline->string(); if (txt.isEmpty()) { return true; } const auto &l = emptyLines(textline->attribute(0)); if (l.isEmpty()) { return false; } foreach (const QRegularExpression &re, l) { const QRegularExpressionMatch match = re.match (txt, 0, QRegularExpression::NormalMatch, QRegularExpression::AnchoredMatchOption); if (match.hasMatch() && match.capturedLength() == txt.length()) { return true; } } return false; } int KateHighlighting::attributeForLocation(KTextEditor::DocumentPrivate* doc, const KTextEditor::Cursor& cursor) { // Validate parameters to prevent out of range access if (cursor.line() < 0 || cursor.line() >= doc->lines() || cursor.column() < 0) { return 0; } // get highlighted line Kate::TextLine tl = doc->kateTextLine(cursor.line()); // make sure the textline is a valid pointer if (!tl) { return 0; } /** * either get char attribute or attribute of context still active at end of line */ if (cursor.column() < tl->length()) { - return tl->attribute(cursor.column()); + return sanitizeFormatIndex(tl->attribute(cursor.column())); } else if (cursor.column() >= tl->length()) { if (!tl->attributesList().isEmpty()) { - return tl->attributesList().back().attributeValue; + return sanitizeFormatIndex(tl->attributesList().back().attributeValue); } } return 0; } QStringList KateHighlighting::keywordsForLocation(KTextEditor::DocumentPrivate* doc, const KTextEditor::Cursor& cursor) { // FIXME-SYNTAX: was before more precise, aka context level const auto &def = m_propertiesForFormat.at(attributeForLocation(doc, cursor))->definition; QStringList keywords; for (const auto &keylist : def.keywordLists()) { keywords += def.keywordList(keylist); } return keywords; } bool KateHighlighting::spellCheckingRequiredForLocation(KTextEditor::DocumentPrivate* doc, const KTextEditor::Cursor& cursor) { return m_formats.at(attributeForLocation(doc, cursor)).spellCheck(); } QString KateHighlighting::higlightingModeForLocation(KTextEditor::DocumentPrivate* doc, const KTextEditor::Cursor& cursor) { return m_propertiesForFormat.at(attributeForLocation(doc, cursor))->definition.name(); } //END diff --git a/src/syntax/katehighlight.h b/src/syntax/katehighlight.h index 9ee85168..06fd44d8 100644 --- a/src/syntax/katehighlight.h +++ b/src/syntax/katehighlight.h @@ -1,352 +1,354 @@ /* This file is part of the KDE libraries Copyright (C) 2001,2002 Joseph Wenninger Copyright (C) 2001 Christoph Cullmann Copyright (C) 1999 Jochen Wilhelmy * * This library 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 library 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 * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public License * along with this library; see the file COPYING.LIB. If not, write to * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #ifndef __KATE_HIGHLIGHT_H__ #define __KATE_HIGHLIGHT_H__ #include #include #include #include #include "katetextline.h" #include "kateextendedattribute.h" #include "katesyntaxmanager.h" #include "spellcheck/prefixstore.h" #include "range.h" #include #include #include #include #include #include #include #include #include #include class KConfig; namespace KTextEditor { class DocumentPrivate; } class KateHighlighting : private KSyntaxHighlighting::AbstractHighlighter { public: KateHighlighting(const KSyntaxHighlighting::Definition &def); protected: /** * Reimplement this to apply formats to your output. The provided @p format * is valid for the interval [@p offset, @p offset + @p length). * * @param offset The start column of the interval for which @p format matches * @param length The length of the matching text * @param format The Format that applies to the range [offset, offset + length) * * @note Make sure to set a valid Definition, otherwise the parameter * @p format is invalid for the entire line passed to highlightLine() * (cf. Format::isValid()). * * @see applyFolding(), highlightLine() */ virtual void applyFormat(int offset, int length, const KSyntaxHighlighting::Format &format) override; /** * Reimplement this to apply folding to your output. The provided * FoldingRegion @p region either stars or ends a code folding region in the * interval [@p offset, @p offset + @p length). * * @param offset The start column of the FoldingRegion * @param length The length of the matching text that starts / ends a * folding region * @param region The FoldingRegion that applies to the range [offset, offset + length) * * @note The FoldingRegion @p region is @e always either of type * FoldingRegion::Type::Begin or FoldingRegion::Type::End. * * @see applyFormat(), highlightLine(), FoldingRegion */ virtual void applyFolding(int offset, int length, KSyntaxHighlighting::FoldingRegion region) override; public: /** * Parse the text and fill in the context array and folding list array * * @param prevLine The previous line, the context array is picked up from that if present. * @param textLine The text line to parse * @param nextLine The next line, to check if indentation changed for indentation based folding. * @param ctxChanged will be set to reflect if the context changed * @param tabWidth tab width for indentation based folding, if wanted, else 0 */ void doHighlight(const Kate::TextLineData *prevLine, Kate::TextLineData *textLine, const Kate::TextLineData *nextLine, bool &ctxChanged, int tabWidth = 0); /** * Saves the attribute definitions to the config file. * * @param schema The id of the schema group to save * @param list QList containing the data to be used */ void setKateExtendedAttributeList(const QString &schema, QList &list, KConfig *cfg = nullptr /*if 0 standard kate config*/, bool writeDefaultsToo = false); const QString &name() const { return iName; } const QString §ion() const { return iSection; } bool hidden() const { return iHidden; } const QString &style() const { return iStyle; } const QString &getIdentifier() const { return identifier; } /** * @return true if the character @p c is not a deliminator character * for the corresponding highlight. */ bool isInWord(QChar c, int attrib = 0) const; /** * @return true if the character @p c is a wordwrap deliminator as specified * in the general keyword section of the xml file. */ bool canBreakAt(QChar c, int attrib = 0) const; /** * */ const QVector &emptyLines(int attribute = 0) const; bool isEmptyLine(const Kate::TextLineData *textline) const; /** * @return true if @p beginAttr and @p endAttr are members of the same * highlight, and there are comment markers of either type in that. */ bool canComment(int startAttr, int endAttr) const; /** * @return the mulitiline comment start marker for the highlight * corresponding to @p attrib. */ QString getCommentStart(int attrib = 0) const; /** * @return the muiltiline comment end marker for the highlight corresponding * to @p attrib. */ QString getCommentEnd(int attrib = 0) const; /** * @return the single comment marker for the highlight corresponding * to @p attrib. */ QString getCommentSingleLineStart(int attrib = 0) const; const QHash &characterEncodings(int attrib = 0) const; /** * @return the single comment marker position for the highlight corresponding * to @p attrib. */ KSyntaxHighlighting::CommentPosition getCommentSingleLinePosition(int attrib = 0) const; bool attributeRequiresSpellchecking(int attr); /** * map attribute to its name * @return name of the attribute */ QString nameForAttrib(int attrib) const; /** * Get attribute for the given cursor position. * @param doc document to use * @param cursor cursor position in the given document * @return attribute valid at that location, default is 0 */ int attributeForLocation(KTextEditor::DocumentPrivate* doc, const KTextEditor::Cursor& cursor); /** * Get all keywords valid for the given cursor position. * @param doc document to use * @param cursor cursor position in the given document * @return all keywords valid at that location */ QStringList keywordsForLocation(KTextEditor::DocumentPrivate* doc, const KTextEditor::Cursor& cursor); /** * Is spellchecking required for the tiven cursor position? * @param doc document to use * @param cursor cursor position in the given document * @return spell checking required? */ bool spellCheckingRequiredForLocation(KTextEditor::DocumentPrivate* doc, const KTextEditor::Cursor& cursor); /** * Get highlighting mode for the given cursor position. * @param doc document to use * @param cursor cursor position in the given document * @return mode valid at that location */ QString higlightingModeForLocation(KTextEditor::DocumentPrivate* doc, const KTextEditor::Cursor& cursor); KTextEditor::DefaultStyle defaultStyleForAttribute(int attr) const; void clearAttributeArrays(); QList attributes(const QString &schema); inline bool noHighlighting() const { return noHl; } /** * Indentation mode, e.g. c-style, .... * @return indentation mode */ const QString &indentation() const { return m_indentation; } void getKateExtendedAttributeList(const QString &schema, QList &, KConfig *cfg = nullptr); void getKateExtendedAttributeListCopy(const QString &schema, QList &, KConfig *cfg = nullptr); const QHash &getCharacterEncodings(int attrib) const; const KatePrefixStore &getCharacterEncodingsPrefixStore(int attrib) const; const QHash &getReverseCharacterEncodings(int attrib) const; /** * Returns a list of names of embedded modes. */ QStringList getEmbeddedHighlightingModes() const; private: /** * create list of attributes from internal formats with properties as defined in syntax file * @return attributes list with attributes as defined in syntax file */ QList attributesForDefinition(); + int sanitizeFormatIndex(int attrib) const; + private: QStringList embeddedHighlightingModes; bool noHl = true; bool folding = false; QString iName; QString iSection; bool iHidden = false; QString identifier; QString iStyle; /** * Indentation mode, e.g. c-style, .... */ QString m_indentation; bool m_foldingIndentationSensitive = false; // map schema name to attributes... QHash< QString, QList > m_attributeArrays; /** * This class holds the additional properties for one highlight * definition, such as comment strings, deliminators etc. */ class HighlightPropertyBag { public: KSyntaxHighlighting::Definition definition; QString singleLineCommentMarker; QString multiLineCommentStart; QString multiLineCommentEnd; KSyntaxHighlighting::CommentPosition singleLineCommentPosition; QVector emptyLines; QHash characterEncodings; KatePrefixStore characterEncodingsPrefixStore; QHash reverseCharacterEncodings; }; public: inline bool foldingIndentationSensitive() { return m_foldingIndentationSensitive; } inline bool allowsFolding() { return folding; } /** * Highlight properties for this definition and each included highlight definition. */ std::vector m_properties; /** * all formats for the highlighting definition of this highlighting * includes included formats */ std::vector m_formats; /** * for each format, pointer to the matching HighlightPropertyBag in m_properties */ std::vector m_propertiesForFormat; /** * mapping of format id => index into m_formats */ std::unordered_map m_formatsIdToIndex; /** * textline to do updates on during doHighlight */ Kate::TextLineData *m_textLineToHighlight = nullptr; /** * check if the folding begin/ends are balanced! * constructed on demand! */ QHash *m_foldingStartToCount = nullptr; }; #endif