1 | /* This file is part of the Kate project. |
2 | * |
3 | * Copyright (C) 2010 Christoph Cullmann <cullmann@kde.org> |
4 | * |
5 | * This library is free software; you can redistribute it and/or |
6 | * modify it under the terms of the GNU Library General Public |
7 | * License as published by the Free Software Foundation; either |
8 | * version 2 of the License, or (at your option) any later version. |
9 | * |
10 | * This library is distributed in the hope that it will be useful, |
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
13 | * Library General Public License for more details. |
14 | * |
15 | * You should have received a copy of the GNU Library General Public License |
16 | * along with this library; see the file COPYING.LIB. If not, write to |
17 | * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, |
18 | * Boston, MA 02110-1301, USA. |
19 | */ |
20 | |
21 | #ifndef KATE_TEXTLINE_H |
22 | #define KATE_TEXTLINE_H |
23 | |
24 | #include <QVector> |
25 | #include <QString> |
26 | #include <QSharedPointer> |
27 | |
28 | #include <ktexteditor_export.h> |
29 | |
30 | #include <KSyntaxHighlighting/State> |
31 | |
32 | namespace Kate |
33 | { |
34 | |
35 | /** |
36 | * Class representing a single text line. |
37 | * For efficiency reasons, not only pure text is stored here, but also additional data. |
38 | * Will be only accessed over shared pointers. |
39 | */ |
40 | class KTEXTEDITOR_EXPORT TextLineData |
41 | { |
42 | /** |
43 | * TexBlock is a friend class, only one allowed to touch the text content. |
44 | */ |
45 | friend class TextBlock; |
46 | |
47 | public: |
48 | /** |
49 | * Attribute storage |
50 | */ |
51 | class Attribute |
52 | { |
53 | public: |
54 | /** |
55 | * Attribute constructor |
56 | * @param _offset offset |
57 | * @param _length length |
58 | * @param _attributeValue attribute value |
59 | */ |
60 | explicit Attribute(int _offset = 0, int _length = 0, short _attributeValue = 0) |
61 | : offset(_offset) |
62 | , length(_length) |
63 | , attributeValue(_attributeValue) |
64 | { |
65 | } |
66 | |
67 | /** |
68 | * offset |
69 | */ |
70 | int offset; |
71 | |
72 | /** |
73 | * length |
74 | */ |
75 | int length; |
76 | |
77 | /** |
78 | * attribute value (to encode type of this range) |
79 | */ |
80 | short attributeValue; |
81 | }; |
82 | |
83 | /** |
84 | * Folding storage |
85 | */ |
86 | class Folding |
87 | { |
88 | public: |
89 | /** |
90 | * Construct folding. |
91 | * @param _offset offset of the folding start |
92 | * @param _foldingValue positive ones start foldings, negative ones end them |
93 | */ |
94 | Folding(int _offset, int _foldingValue) |
95 | : offset(_offset) |
96 | , foldingValue(_foldingValue) |
97 | { |
98 | } |
99 | |
100 | /** |
101 | * offset |
102 | */ |
103 | int offset = 0; |
104 | |
105 | /** |
106 | * positive ones start foldings, negative ones end them |
107 | */ |
108 | int foldingValue = 0; |
109 | }; |
110 | |
111 | /** |
112 | * Flags of TextLineData |
113 | */ |
114 | enum Flags { |
115 | flagAutoWrapped = 1, |
116 | flagFoldingStartAttribute = 2, |
117 | flagFoldingStartIndentation = 4, |
118 | flagLineModified = 8, |
119 | flagLineSavedOnDisk = 16 |
120 | }; |
121 | |
122 | /** |
123 | * Construct an empty text line. |
124 | */ |
125 | TextLineData(); |
126 | |
127 | /** |
128 | * Construct an text line with given text. |
129 | * @param text text to use for this line |
130 | */ |
131 | explicit TextLineData(const QString &text); |
132 | |
133 | /** |
134 | * Destruct the text line |
135 | */ |
136 | ~TextLineData(); |
137 | |
138 | /** |
139 | * Accessor to the text contained in this line. |
140 | * @return text of this line as constant reference |
141 | */ |
142 | const QString &text() const |
143 | { |
144 | return m_text; |
145 | } |
146 | |
147 | /** |
148 | * Returns the position of the first non-whitespace character |
149 | * @return position of first non-whitespace char or -1 if there is none |
150 | */ |
151 | int firstChar() const; |
152 | |
153 | /** |
154 | * Returns the position of the last non-whitespace character |
155 | * @return position of last non-whitespace char or -1 if there is none |
156 | */ |
157 | int lastChar() const; |
158 | |
159 | /** |
160 | * Find the position of the next char that is not a space. |
161 | * @param pos Column of the character which is examined first. |
162 | * @return True if the specified or a following character is not a space |
163 | * Otherwise false. |
164 | */ |
165 | int nextNonSpaceChar(int pos) const; |
166 | |
167 | /** |
168 | * Find the position of the previous char that is not a space. |
169 | * @param pos Column of the character which is examined first. |
170 | * @return The position of the first non-whitespace character preceding pos, |
171 | * or -1 if none is found. |
172 | */ |
173 | int previousNonSpaceChar(int pos) const; |
174 | |
175 | /** |
176 | * Returns the character at the given \e column. If \e column is out of |
177 | * range, the return value is QChar(). |
178 | * @param column column you want char for |
179 | * @return char at given column or QChar() |
180 | */ |
181 | inline QChar at(int column) const |
182 | { |
183 | if (column >= 0 && column < m_text.length()) { |
184 | return m_text[column]; |
185 | } |
186 | |
187 | return QChar(); |
188 | } |
189 | |
190 | /** |
191 | * Same as at(). |
192 | * @param column column you want char for |
193 | * @return char at given column or QChar() |
194 | */ |
195 | inline QChar operator[](int column) const |
196 | { |
197 | if (column >= 0 && column < m_text.length()) { |
198 | return m_text[column]; |
199 | } |
200 | |
201 | return QChar(); |
202 | } |
203 | |
204 | inline void markAsModified(bool modified) |
205 | { |
206 | if (modified) { |
207 | m_flags |= flagLineModified; |
208 | m_flags &= (~flagLineSavedOnDisk); |
209 | } else { |
210 | m_flags &= (~flagLineModified); |
211 | } |
212 | } |
213 | |
214 | inline bool markedAsModified() const |
215 | { |
216 | return m_flags & flagLineModified; |
217 | } |
218 | |
219 | inline void markAsSavedOnDisk(bool savedOnDisk) |
220 | { |
221 | if (savedOnDisk) { |
222 | m_flags |= flagLineSavedOnDisk; |
223 | m_flags &= (~flagLineModified); |
224 | } else { |
225 | m_flags &= (~flagLineSavedOnDisk); |
226 | } |
227 | } |
228 | |
229 | inline bool markedAsSavedOnDisk() const |
230 | { |
231 | return m_flags & flagLineSavedOnDisk; |
232 | } |
233 | |
234 | /** |
235 | * Is on this line a folding start? |
236 | * @return folding start line or not? |
237 | */ |
238 | bool markedAsFoldingStart() const |
239 | { |
240 | return m_flags & (flagFoldingStartAttribute | flagFoldingStartIndentation); |
241 | } |
242 | |
243 | /** |
244 | * Clear folding start status. |
245 | */ |
246 | void clearMarkedAsFoldingStart() |
247 | { |
248 | m_flags &= ~(flagFoldingStartAttribute | flagFoldingStartIndentation); |
249 | } |
250 | |
251 | /** |
252 | * Is on this line a folding start per attribute? |
253 | * @return folding start line per attribute? or not? |
254 | */ |
255 | bool markedAsFoldingStartAttribute() const |
256 | { |
257 | return m_flags & flagFoldingStartAttribute; |
258 | } |
259 | |
260 | /** |
261 | * Is on this line a folding start per indentation? |
262 | * @return folding start line per indentation? or not? |
263 | */ |
264 | bool markedAsFoldingStartIndentation() const |
265 | { |
266 | return m_flags & flagFoldingStartIndentation; |
267 | } |
268 | |
269 | /** |
270 | * Mark as folding start line of an attribute based folding. |
271 | */ |
272 | void markAsFoldingStartAttribute() |
273 | { |
274 | clearMarkedAsFoldingStart(); |
275 | m_flags |= flagFoldingStartAttribute; |
276 | } |
277 | |
278 | /** |
279 | * Mark as folding start line of an indentation based folding. |
280 | */ |
281 | void markAsFoldingStartIndentation() |
282 | { |
283 | clearMarkedAsFoldingStart(); |
284 | m_flags |= flagFoldingStartIndentation; |
285 | } |
286 | |
287 | /** |
288 | * Returns the line's length. |
289 | */ |
290 | int length() const |
291 | { |
292 | return m_text.length(); |
293 | } |
294 | |
295 | /** |
296 | * Returns \e true, if the line was automagically wrapped, otherwise returns |
297 | * \e false. |
298 | * @return was this line auto-wrapped? |
299 | */ |
300 | bool isAutoWrapped() const |
301 | { |
302 | return m_flags & flagAutoWrapped; |
303 | } |
304 | |
305 | /** |
306 | * Returns the complete text line (as a QString reference). |
307 | * @return text of this line, read-only |
308 | */ |
309 | const QString &string() const |
310 | { |
311 | return m_text; |
312 | } |
313 | |
314 | /** |
315 | * Returns the substring with \e length beginning at the given \e column. |
316 | * @param column start column of text to return |
317 | * @param length length of text to return |
318 | * @return wanted part of text |
319 | */ |
320 | QString string(int column, int length) const |
321 | { |
322 | return m_text.mid(column, length); |
323 | } |
324 | |
325 | /** |
326 | * Leading whitespace of this line |
327 | * @return leading whitespace of this line |
328 | */ |
329 | QString leadingWhitespace() const; |
330 | |
331 | /** |
332 | * Returns the indentation depth with each tab expanded into \e tabWidth characters. |
333 | */ |
334 | int indentDepth(int tabWidth) const; |
335 | |
336 | /** |
337 | * Returns the \e column with each tab expanded into \e tabWidth characters. |
338 | */ |
339 | int toVirtualColumn(int column, int tabWidth) const; |
340 | |
341 | /** |
342 | * Returns the "real" column where each tab only counts one character. |
343 | * The conversion calculates with \e tabWidth characters for each tab. |
344 | */ |
345 | int fromVirtualColumn(int column, int tabWidth) const; |
346 | |
347 | /** |
348 | * Returns the text length with each tab expanded into \e tabWidth characters. |
349 | */ |
350 | int virtualLength(int tabWidth) const; |
351 | |
352 | /** |
353 | * Returns \e true, if \e match equals to the text at position \e column, |
354 | * otherwise returns \e false. |
355 | */ |
356 | bool matchesAt(int column, const QString &match) const; |
357 | |
358 | /** |
359 | * Returns \e true, if the line starts with \e match, otherwise returns \e false. |
360 | */ |
361 | bool startsWith(const QString &match) const |
362 | { |
363 | return m_text.startsWith(match); |
364 | } |
365 | |
366 | /** |
367 | * Returns \e true, if the line ends with \e match, otherwise returns \e false. |
368 | */ |
369 | bool endsWith(const QString &match) const |
370 | { |
371 | return m_text.endsWith(match); |
372 | } |
373 | |
374 | /** |
375 | * context stack |
376 | * @return context stack |
377 | */ |
378 | const KSyntaxHighlighting::State &highlightingState() const |
379 | { |
380 | return m_highlightingState; |
381 | } |
382 | |
383 | /** |
384 | * Sets the syntax highlight context number |
385 | * @param val new context array |
386 | */ |
387 | void setHighlightingState(const KSyntaxHighlighting::State &val) |
388 | { |
389 | m_highlightingState = val; |
390 | } |
391 | |
392 | /** |
393 | * Add attribute to this line. |
394 | * @param attribute new attribute to append |
395 | */ |
396 | void addAttribute(const Attribute &attribute); |
397 | |
398 | /** |
399 | * Clear attributes and foldings of this line |
400 | */ |
401 | void clearAttributesAndFoldings() |
402 | { |
403 | m_attributesList.clear(); |
404 | m_foldings.clear(); |
405 | } |
406 | |
407 | /** |
408 | * Accessor to attributes |
409 | * @return attributes of this line |
410 | */ |
411 | const QVector<Attribute> &attributesList() const |
412 | { |
413 | return m_attributesList; |
414 | } |
415 | |
416 | /** |
417 | * Accessor to foldings |
418 | * @return foldings of this line |
419 | */ |
420 | const std::vector<Folding> &foldings() const |
421 | { |
422 | return m_foldings; |
423 | } |
424 | |
425 | /** |
426 | * Add new folding at end of foldings stored in this line |
427 | * @param offset offset of folding start |
428 | * @param folding folding to add, positive to open, negative to close |
429 | */ |
430 | void addFolding(int offset, int folding) |
431 | { |
432 | m_foldings.emplace_back(offset,folding); |
433 | } |
434 | |
435 | /** |
436 | * Gets the attribute at the given position |
437 | * use KRenderer::attributes to get the KTextAttribute for this. |
438 | * |
439 | * @param pos position of attribute requested |
440 | * @return value of attribute |
441 | */ |
442 | short attribute(int pos) const; |
443 | |
444 | /** |
445 | * set auto-wrapped property |
446 | * @param wrapped line was wrapped? |
447 | */ |
448 | void setAutoWrapped(bool wrapped) |
449 | { |
450 | if (wrapped) { |
451 | m_flags = m_flags | flagAutoWrapped; |
452 | } else { |
453 | m_flags = m_flags & ~ flagAutoWrapped; |
454 | } |
455 | } |
456 | |
457 | private: |
458 | /** |
459 | * Accessor to the text contained in this line. |
460 | * This accessor is private, only the friend class text buffer/block is allowed to access the text read/write. |
461 | * @return text of this line |
462 | */ |
463 | QString &textReadWrite() |
464 | { |
465 | return m_text; |
466 | } |
467 | |
468 | private: |
469 | /** |
470 | * text of this line |
471 | */ |
472 | QString m_text; |
473 | |
474 | /** |
475 | * attributes of this line |
476 | */ |
477 | QVector<Attribute> m_attributesList; |
478 | |
479 | /** |
480 | * foldings of this line |
481 | */ |
482 | std::vector<Folding> m_foldings; |
483 | |
484 | /** |
485 | * current highlighting state |
486 | */ |
487 | KSyntaxHighlighting::State m_highlightingState; |
488 | |
489 | /** |
490 | * flags of this line |
491 | */ |
492 | unsigned int m_flags = 0; |
493 | }; |
494 | |
495 | /** |
496 | * The normal world only accesses the text lines with shared pointers. |
497 | */ |
498 | typedef QSharedPointer<TextLineData> TextLine; |
499 | |
500 | } |
501 | |
502 | #endif |
503 | |