File indexing completed on 2024-04-28 15:30:47

0001 /*
0002     SPDX-FileCopyrightText: 2001, 2002 Joseph Wenninger <jowenn@kde.org>
0003     SPDX-FileCopyrightText: 2001 Christoph Cullmann <cullmann@kde.org>
0004     SPDX-FileCopyrightText: 1999 Jochen Wilhelmy <digisnap@cs.tu-berlin.de>
0005 
0006     SPDX-License-Identifier: LGPL-2.0-or-later
0007 */
0008 
0009 #ifndef KATE_HIGHLIGHT_H
0010 #define KATE_HIGHLIGHT_H
0011 
0012 #include <KSyntaxHighlighting/AbstractHighlighter>
0013 #include <KSyntaxHighlighting/Definition>
0014 #include <KSyntaxHighlighting/FoldingRegion>
0015 #include <KSyntaxHighlighting/Format>
0016 #include <KSyntaxHighlighting/Theme>
0017 
0018 #include "kateextendedattribute.h"
0019 #include "range.h"
0020 #include "spellcheck/prefixstore.h"
0021 
0022 #include <QHash>
0023 #include <QVector>
0024 
0025 #include <QRegularExpression>
0026 #include <QStringList>
0027 
0028 #include <unordered_map>
0029 
0030 namespace KTextEditor
0031 {
0032 class DocumentPrivate;
0033 }
0034 namespace Kate
0035 {
0036 class TextLineData;
0037 }
0038 
0039 /**
0040  * convert from KSyntaxHighlighting => KTextEditor type
0041  * special handle non-1:1 things
0042  */
0043 static inline KTextEditor::DefaultStyle textStyleToDefaultStyle(const KSyntaxHighlighting::Theme::TextStyle textStyle)
0044 {
0045     // handle deviations
0046     if (textStyle == KSyntaxHighlighting::Theme::Error) {
0047         return KTextEditor::dsError;
0048     }
0049     if (textStyle == KSyntaxHighlighting::Theme::Others) {
0050         return KTextEditor::dsOthers;
0051     }
0052 
0053     // else: simple cast
0054     return static_cast<KTextEditor::DefaultStyle>(textStyle);
0055 }
0056 
0057 /**
0058  * convert from KTextEditor => KSyntaxHighlighting type
0059  * special handle non-1:1 things
0060  */
0061 static inline KSyntaxHighlighting::Theme::TextStyle defaultStyleToTextStyle(const KTextEditor::DefaultStyle textStyle)
0062 {
0063     // handle deviations
0064     if (textStyle == KTextEditor::dsError) {
0065         return KSyntaxHighlighting::Theme::Error;
0066     }
0067     if (textStyle == KTextEditor::dsOthers) {
0068         return KSyntaxHighlighting::Theme::Others;
0069     }
0070 
0071     // else: simple cast
0072     return static_cast<KSyntaxHighlighting::Theme::TextStyle>(textStyle);
0073 }
0074 
0075 class KateHighlighting : private KSyntaxHighlighting::AbstractHighlighter
0076 {
0077 public:
0078     explicit KateHighlighting(const KSyntaxHighlighting::Definition &def);
0079 
0080 protected:
0081     /**
0082      * Reimplement this to apply formats to your output. The provided @p format
0083      * is valid for the interval [@p offset, @p offset + @p length).
0084      *
0085      * @param offset The start column of the interval for which @p format matches
0086      * @param length The length of the matching text
0087      * @param format The Format that applies to the range [offset, offset + length)
0088      *
0089      * @note Make sure to set a valid Definition, otherwise the parameter
0090      *       @p format is invalid for the entire line passed to highlightLine()
0091      *       (cf. Format::isValid()).
0092      *
0093      * @see applyFolding(), highlightLine()
0094      */
0095     void applyFormat(int offset, int length, const KSyntaxHighlighting::Format &format) override;
0096 
0097     /**
0098      * Reimplement this to apply folding to your output. The provided
0099      * FoldingRegion @p region either stars or ends a code folding region in the
0100      * interval [@p offset, @p offset + @p length).
0101      *
0102      * @param offset The start column of the FoldingRegion
0103      * @param length The length of the matching text that starts / ends a
0104      *       folding region
0105      * @param region The FoldingRegion that applies to the range [offset, offset + length)
0106      *
0107      * @note The FoldingRegion @p region is @e always either of type
0108      *       FoldingRegion::Type::Begin or FoldingRegion::Type::End.
0109      *
0110      * @see applyFormat(), highlightLine(), FoldingRegion
0111      */
0112     void applyFolding(int offset, int length, KSyntaxHighlighting::FoldingRegion region) override;
0113 
0114 public:
0115     /**
0116      * Parse the text and fill in the context array and folding list array
0117      *
0118      * @param prevLine The previous line, the context array is picked up from that if present.
0119      * @param textLine The text line to parse
0120      * @param ctxChanged will be set to reflect if the context changed
0121      */
0122     void doHighlight(const Kate::TextLineData *prevLine, Kate::TextLineData *textLine, bool &ctxChanged);
0123 
0124     const QString &name() const
0125     {
0126         return iName;
0127     }
0128     const QString &section() const
0129     {
0130         return iSection;
0131     }
0132     bool hidden() const
0133     {
0134         return iHidden;
0135     }
0136     const QString &style() const
0137     {
0138         return iStyle;
0139     }
0140     const QString &getIdentifier() const
0141     {
0142         return identifier;
0143     }
0144 
0145     /**
0146      * @return true if the character @p c is not a deliminator character
0147      *     for the corresponding highlight.
0148      */
0149     bool isInWord(QChar c, int attrib = 0) const;
0150 
0151     /**
0152      * @return true if the character @p c is a wordwrap deliminator as specified
0153      * in the general keyword section of the xml file.
0154      */
0155     bool canBreakAt(QChar c, int attrib = 0) const;
0156     /**
0157      *
0158      */
0159     const QVector<QRegularExpression> &emptyLines(int attribute = 0) const;
0160 
0161     bool isEmptyLine(const Kate::TextLineData *textline) const;
0162 
0163     /**
0164      * @return true if @p beginAttr and @p endAttr are members of the same
0165      * highlight, and there are comment markers of either type in that.
0166      */
0167     bool canComment(int startAttr, int endAttr) const;
0168 
0169     /**
0170      * @return the mulitiline comment start marker for the highlight
0171      * corresponding to @p attrib.
0172      */
0173     QString getCommentStart(int attrib = 0) const;
0174 
0175     /**
0176      * @return the muiltiline comment end marker for the highlight corresponding
0177      * to @p attrib.
0178      */
0179     QString getCommentEnd(int attrib = 0) const;
0180 
0181     /**
0182      * @return the single comment marker for the highlight corresponding
0183      * to @p attrib.
0184      */
0185     QString getCommentSingleLineStart(int attrib = 0) const;
0186 
0187     const QHash<QString, QChar> &characterEncodings(int attrib = 0) const;
0188 
0189     /**
0190      * @return the single comment marker position for the highlight corresponding
0191      * to @p attrib.
0192      */
0193     KSyntaxHighlighting::CommentPosition getCommentSingleLinePosition(int attrib = 0) const;
0194 
0195     bool attributeRequiresSpellchecking(int attr);
0196 
0197     /**
0198      * map attribute to its name
0199      * @return name of the attribute
0200      */
0201     QString nameForAttrib(int attrib) const;
0202 
0203     /**
0204      * Get attribute for the given cursor position.
0205      * @param doc document to use
0206      * @param cursor cursor position in the given document
0207      * @return attribute valid at that location, default is 0
0208      */
0209     int attributeForLocation(KTextEditor::DocumentPrivate *doc, const KTextEditor::Cursor cursor);
0210 
0211     /**
0212      * Get all keywords valid for the given cursor position.
0213      * @param doc document to use
0214      * @param cursor cursor position in the given document
0215      * @return all keywords valid at that location
0216      */
0217     QStringList keywordsForLocation(KTextEditor::DocumentPrivate *doc, const KTextEditor::Cursor cursor);
0218 
0219     /**
0220      * Is spellchecking required for the tiven cursor position?
0221      * @param doc document to use
0222      * @param cursor cursor position in the given document
0223      * @return spell checking required?
0224      */
0225     bool spellCheckingRequiredForLocation(KTextEditor::DocumentPrivate *doc, const KTextEditor::Cursor cursor);
0226 
0227     /**
0228      * Get highlighting mode for the given cursor position.
0229      * @param doc document to use
0230      * @param cursor cursor position in the given document
0231      * @return mode valid at that location
0232      */
0233     QString higlightingModeForLocation(KTextEditor::DocumentPrivate *doc, const KTextEditor::Cursor cursor);
0234 
0235     KTextEditor::DefaultStyle defaultStyleForAttribute(int attr) const;
0236 
0237     void clearAttributeArrays();
0238 
0239     QVector<KTextEditor::Attribute::Ptr> attributes(const QString &schema);
0240 
0241     inline bool noHighlighting() const
0242     {
0243         return noHl;
0244     }
0245 
0246     /**
0247      * Indentation mode, e.g. c-style, ....
0248      * @return indentation mode
0249      */
0250     const QString &indentation() const
0251     {
0252         return m_indentation;
0253     }
0254 
0255     const QHash<QString, QChar> &getCharacterEncodings(int attrib) const;
0256     const KatePrefixStore &getCharacterEncodingsPrefixStore(int attrib) const;
0257     const QHash<QChar, QString> &getReverseCharacterEncodings(int attrib) const;
0258 
0259     /**
0260      * Returns a list of names of embedded modes.
0261      */
0262     QStringList getEmbeddedHighlightingModes() const;
0263 
0264     /**
0265      * create list of attributes from internal formats with properties as defined in syntax file
0266      * @param schema The id of the chosen schema
0267      * @return attributes list with attributes as defined in syntax file
0268      */
0269     QVector<KTextEditor::Attribute::Ptr> attributesForDefinition(const QString &schema) const;
0270 
0271     /**
0272      * Retrieve all formats for this highlighting.
0273      * @return all formats for the highlighting definition of this highlighting includes included formats
0274      */
0275     const std::vector<KSyntaxHighlighting::Format> &formats() const
0276     {
0277         return m_formats;
0278     }
0279 
0280 private:
0281     int sanitizeFormatIndex(int attrib) const;
0282 
0283 private:
0284     QStringList embeddedHighlightingModes;
0285 
0286     bool noHl = true;
0287     bool folding = false;
0288 
0289     QString iName;
0290     QString iSection;
0291     bool iHidden = false;
0292     QString identifier;
0293     QString iStyle;
0294 
0295     /**
0296      * Indentation mode, e.g. c-style, ....
0297      */
0298     QString m_indentation;
0299 
0300     bool m_foldingIndentationSensitive = false;
0301 
0302     // map schema name to attributes...
0303     QHash<QString, QVector<KTextEditor::Attribute::Ptr>> m_attributeArrays;
0304 
0305     /**
0306      * This class holds the additional properties for one highlight
0307      * definition, such as comment strings, deliminators etc.
0308      */
0309     class HighlightPropertyBag
0310     {
0311     public:
0312         KSyntaxHighlighting::Definition definition;
0313         QString singleLineCommentMarker;
0314         QString multiLineCommentStart;
0315         QString multiLineCommentEnd;
0316         KSyntaxHighlighting::CommentPosition singleLineCommentPosition;
0317         QVector<QRegularExpression> emptyLines;
0318         QHash<QString, QChar> characterEncodings;
0319         KatePrefixStore characterEncodingsPrefixStore;
0320         QHash<QChar, QString> reverseCharacterEncodings;
0321     };
0322 
0323 public:
0324     inline bool foldingIndentationSensitive()
0325     {
0326         return m_foldingIndentationSensitive;
0327     }
0328     inline bool allowsFolding()
0329     {
0330         return folding;
0331     }
0332 
0333     /**
0334      * Highlight properties for this definition and each included highlight definition.
0335      */
0336     std::vector<HighlightPropertyBag> m_properties;
0337 
0338     /**
0339      * all formats for the highlighting definition of this highlighting
0340      * includes included formats
0341      */
0342     std::vector<KSyntaxHighlighting::Format> m_formats;
0343 
0344     /**
0345      * for each format, pointer to the matching HighlightPropertyBag in m_properties
0346      */
0347     std::vector<const HighlightPropertyBag *> m_propertiesForFormat;
0348 
0349     /**
0350      * mapping of format id => index into m_formats
0351      */
0352     std::unordered_map<quint16, short> m_formatsIdToIndex;
0353 
0354     /**
0355      * textline to do updates on during doHighlight
0356      */
0357     Kate::TextLineData *m_textLineToHighlight = nullptr;
0358 
0359     /**
0360      * check if the folding begin/ends are balanced!
0361      * updated during doHighlight
0362      */
0363     QHash<int, int> m_foldingStartToCount;
0364 };
0365 
0366 #endif