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 | |
32 | namespace KTextEditor |
33 | { |
34 | class DocumentPrivate; |
35 | } |
36 | namespace Kate |
37 | { |
38 | class TextLine; |
39 | } |
40 | |
41 | class KateHighlighting : private KSyntaxHighlighting::AbstractHighlighter |
42 | { |
43 | public: |
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 | |
86 | protected: |
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 | |
120 | public: |
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 §ion() 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 (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 (int attrib = 0) const; |
181 | |
182 | /** |
183 | * @return the muiltiline comment end marker for the highlight corresponding |
184 | * to @p attrib. |
185 | */ |
186 | QString (int attrib = 0) const; |
187 | |
188 | /** |
189 | * @return the single comment marker for the highlight corresponding |
190 | * to @p attrib. |
191 | */ |
192 | QString (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 (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 | |
287 | private: |
288 | int sanitizeFormatIndex(int attrib) const; |
289 | |
290 | private: |
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 ; |
321 | QString ; |
322 | QString ; |
323 | KSyntaxHighlighting::CommentPosition ; |
324 | QList<QRegularExpression> emptyLines; |
325 | QHash<QString, QChar> characterEncodings; |
326 | KatePrefixStore characterEncodingsPrefixStore; |
327 | QHash<QChar, QString> reverseCharacterEncodings; |
328 | }; |
329 | |
330 | public: |
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 | |