1/*
2 SPDX-FileCopyrightText: 2001, 2002 Joseph Wenninger <jowenn@kde.org>
3 SPDX-FileCopyrightText: 2001 Christoph Cullmann <cullmann@kde.org>
4 SPDX-FileCopyrightText: 1999 Jochen Wilhelmy <digisnap@cs.tu-berlin.de>
5
6 SPDX-License-Identifier: LGPL-2.0-or-later
7*/
8
9#ifndef KATE_HIGHLIGHT_H
10#define KATE_HIGHLIGHT_H
11
12#include <KSyntaxHighlighting/AbstractHighlighter>
13#include <KSyntaxHighlighting/Definition>
14#include <KSyntaxHighlighting/FoldingRegion>
15#include <KSyntaxHighlighting/Format>
16#include <KSyntaxHighlighting/Theme>
17
18#include <KTextEditor/Attribute>
19#include <KTextEditor/Range>
20
21#include "spellcheck/prefixstore.h"
22
23#include <QHash>
24#include <QList>
25
26#include <QRegularExpression>
27#include <QStringList>
28
29#include <unordered_map>
30#include <vector>
31
32namespace KTextEditor
33{
34class DocumentPrivate;
35}
36namespace Kate
37{
38class TextLine;
39}
40
41class KateHighlighting : private KSyntaxHighlighting::AbstractHighlighter
42{
43public:
44 explicit KateHighlighting(const KSyntaxHighlighting::Definition &def);
45
46 /**
47 * Folding storage
48 */
49 class Folding
50 {
51 public:
52 /**
53 * Construct folding.
54 * @param _offset offset of the folding start
55 * @param _length length of the folding
56 * @param _foldingRegion folding region, includes if we start or end a region and the id
57 */
58 Folding(int _offset, int _length, KSyntaxHighlighting::FoldingRegion _foldingRegion)
59 : offset(_offset)
60 , length(_length)
61 , foldingRegion(_foldingRegion)
62 {
63 }
64
65 /**
66 * offset
67 */
68 int offset = 0;
69
70 /**
71 * length
72 */
73 int length = 0;
74
75 /**
76 * folding region, includes if we start or end a region and the id
77 */
78 KSyntaxHighlighting::FoldingRegion foldingRegion;
79 };
80
81 /**
82 * Folding vector used to pass out folding knowledge
83 */
84 typedef std::vector<Folding> Foldings;
85
86protected:
87 /**
88 * Reimplement this to apply formats to your output. The provided @p format
89 * is valid for the interval [@p offset, @p offset + @p length).
90 *
91 * @param offset The start column of the interval for which @p format matches
92 * @param length The length of the matching text
93 * @param format The Format that applies to the range [offset, offset + length)
94 *
95 * @note Make sure to set a valid Definition, otherwise the parameter
96 * @p format is invalid for the entire line passed to highlightLine()
97 * (cf. Format::isValid()).
98 *
99 * @see applyFolding(), highlightLine()
100 */
101 void applyFormat(int offset, int length, const KSyntaxHighlighting::Format &format) override;
102
103 /**
104 * Reimplement this to apply folding to your output. The provided
105 * FoldingRegion @p region either stars or ends a code folding region in the
106 * interval [@p offset, @p offset + @p length).
107 *
108 * @param offset The start column of the FoldingRegion
109 * @param length The length of the matching text that starts / ends a
110 * folding region
111 * @param region The FoldingRegion that applies to the range [offset, offset + length)
112 *
113 * @note The FoldingRegion @p region is @e always either of type
114 * FoldingRegion::Type::Begin or FoldingRegion::Type::End.
115 *
116 * @see applyFormat(), highlightLine(), FoldingRegion
117 */
118 void applyFolding(int offset, int length, KSyntaxHighlighting::FoldingRegion region) override;
119
120public:
121 /**
122 * Parse the text and fill in the context array and folding list array
123 *
124 * @param prevLine The previous line, the context array is picked up from that if present.
125 * @param textLine The text line to parse
126 * @param ctxChanged will be set to reflect if the context changed
127 * @param foldings foldings vector to fill, if that is wanted
128 */
129 void doHighlight(const Kate::TextLine *prevLine, Kate::TextLine *textLine, bool &ctxChanged, Foldings *foldings = nullptr);
130
131 const QString &name() const
132 {
133 return iName;
134 }
135 const QString &section() const
136 {
137 return iSection;
138 }
139 bool hidden() const
140 {
141 return iHidden;
142 }
143 const QString &style() const
144 {
145 return iStyle;
146 }
147 const QString &getIdentifier() const
148 {
149 return identifier;
150 }
151
152 /**
153 * @return true if the character @p c is not a deliminator character
154 * for the corresponding highlight.
155 */
156 bool isInWord(QChar c, int attrib = 0) const;
157
158 /**
159 * @return true if the character @p c is a wordwrap deliminator as specified
160 * in the general keyword section of the xml file.
161 */
162 bool canBreakAt(QChar c, int attrib = 0) const;
163 /**
164 *
165 */
166 const QList<QRegularExpression> &emptyLines(int attribute = 0) const;
167
168 bool isEmptyLine(const Kate::TextLine *textline) const;
169
170 /**
171 * @return true if @p beginAttr and @p endAttr are members of the same
172 * highlight, and there are comment markers of either type in that.
173 */
174 bool canComment(int startAttr, int endAttr) const;
175
176 /**
177 * @return the mulitiline comment start marker for the highlight
178 * corresponding to @p attrib.
179 */
180 QString getCommentStart(int attrib = 0) const;
181
182 /**
183 * @return the muiltiline comment end marker for the highlight corresponding
184 * to @p attrib.
185 */
186 QString getCommentEnd(int attrib = 0) const;
187
188 /**
189 * @return the single comment marker for the highlight corresponding
190 * to @p attrib.
191 */
192 QString getCommentSingleLineStart(int attrib = 0) const;
193
194 const QHash<QString, QChar> &characterEncodings(int attrib = 0) const;
195
196 /**
197 * @return the single comment marker position for the highlight corresponding
198 * to @p attrib.
199 */
200 KSyntaxHighlighting::CommentPosition getCommentSingleLinePosition(int attrib = 0) const;
201
202 bool attributeRequiresSpellchecking(int attr);
203
204 /**
205 * map attribute to its name
206 * @return name of the attribute
207 */
208 QString nameForAttrib(int attrib) const;
209
210 /**
211 * Get attribute for the given cursor position.
212 * @param doc document to use
213 * @param cursor cursor position in the given document
214 * @return attribute valid at that location, default is 0
215 */
216 int attributeForLocation(KTextEditor::DocumentPrivate *doc, const KTextEditor::Cursor cursor);
217
218 /**
219 * Get all keywords valid for the given cursor position.
220 * @param doc document to use
221 * @param cursor cursor position in the given document
222 * @return all keywords valid at that location
223 */
224 QStringList keywordsForLocation(KTextEditor::DocumentPrivate *doc, const KTextEditor::Cursor cursor);
225
226 /**
227 * Is spellchecking required for the tiven cursor position?
228 * @param doc document to use
229 * @param cursor cursor position in the given document
230 * @return spell checking required?
231 */
232 bool spellCheckingRequiredForLocation(KTextEditor::DocumentPrivate *doc, const KTextEditor::Cursor cursor);
233
234 /**
235 * Get highlighting mode for the given cursor position.
236 * @param doc document to use
237 * @param cursor cursor position in the given document
238 * @return mode valid at that location
239 */
240 QString higlightingModeForLocation(KTextEditor::DocumentPrivate *doc, const KTextEditor::Cursor cursor);
241
242 KSyntaxHighlighting::Theme::TextStyle defaultStyleForAttribute(int attr) const;
243
244 void clearAttributeArrays();
245
246 QList<KTextEditor::Attribute::Ptr> attributes(const QString &schema);
247
248 inline bool noHighlighting() const
249 {
250 return noHl;
251 }
252
253 /**
254 * Indentation mode, e.g. c-style, ....
255 * @return indentation mode
256 */
257 const QString &indentation() const
258 {
259 return m_indentation;
260 }
261
262 const QHash<QString, QChar> &getCharacterEncodings(int attrib) const;
263 const KatePrefixStore &getCharacterEncodingsPrefixStore(int attrib) const;
264 const QHash<QChar, QString> &getReverseCharacterEncodings(int attrib) const;
265
266 /**
267 * Returns a list of names of embedded modes.
268 */
269 QStringList getEmbeddedHighlightingModes() const;
270
271 /**
272 * create list of attributes from internal formats with properties as defined in syntax file
273 * @param schema The id of the chosen schema
274 * @return attributes list with attributes as defined in syntax file
275 */
276 QList<KTextEditor::Attribute::Ptr> attributesForDefinition(const QString &schema) const;
277
278 /**
279 * Retrieve all formats for this highlighting.
280 * @return all formats for the highlighting definition of this highlighting includes included formats
281 */
282 const std::vector<KSyntaxHighlighting::Format> &formats() const
283 {
284 return m_formats;
285 }
286
287private:
288 int sanitizeFormatIndex(int attrib) const;
289
290private:
291 QStringList embeddedHighlightingModes;
292
293 bool noHl = true;
294 bool folding = false;
295
296 QString iName;
297 QString iSection;
298 bool iHidden = false;
299 QString identifier;
300 QString iStyle;
301
302 /**
303 * Indentation mode, e.g. c-style, ....
304 */
305 QString m_indentation;
306
307 bool m_foldingIndentationSensitive = false;
308
309 // map schema name to attributes...
310 QHash<QString, QList<KTextEditor::Attribute::Ptr>> m_attributeArrays;
311
312 /**
313 * This class holds the additional properties for one highlight
314 * definition, such as comment strings, deliminators etc.
315 */
316 class HighlightPropertyBag
317 {
318 public:
319 KSyntaxHighlighting::Definition definition;
320 QString singleLineCommentMarker;
321 QString multiLineCommentStart;
322 QString multiLineCommentEnd;
323 KSyntaxHighlighting::CommentPosition singleLineCommentPosition;
324 QList<QRegularExpression> emptyLines;
325 QHash<QString, QChar> characterEncodings;
326 KatePrefixStore characterEncodingsPrefixStore;
327 QHash<QChar, QString> reverseCharacterEncodings;
328 };
329
330public:
331 inline bool foldingIndentationSensitive()
332 {
333 return m_foldingIndentationSensitive;
334 }
335 inline bool allowsFolding()
336 {
337 return folding;
338 }
339
340 /**
341 * Highlight properties for this definition and each included highlight definition.
342 */
343 std::vector<HighlightPropertyBag> m_properties;
344
345 /**
346 * all formats for the highlighting definition of this highlighting
347 * includes included formats
348 */
349 std::vector<KSyntaxHighlighting::Format> m_formats;
350
351 /**
352 * for each format, pointer to the matching HighlightPropertyBag in m_properties
353 */
354 std::vector<const HighlightPropertyBag *> m_propertiesForFormat;
355
356 /**
357 * mapping of format id => index into m_formats
358 */
359 std::unordered_map<int, int> m_formatsIdToIndex;
360
361 /**
362 * textline to do updates on during doHighlight
363 */
364 Kate::TextLine *m_textLineToHighlight = nullptr;
365
366 /**
367 * foldings vector to do updates on during doHighlight
368 * might not be set, then we ignor that
369 */
370 Foldings *m_foldings = nullptr;
371
372 /**
373 * check if the folding begin/ends are balanced!
374 * updated during doHighlight
375 */
376 QHash<int, int> m_foldingStartToCount;
377};
378
379#endif
380

source code of ktexteditor/src/syntax/katehighlight.h