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
32namespace 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 */
40class 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
47public:
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
457private:
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
468private:
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 */
498typedef QSharedPointer<TextLineData> TextLine;
499
500}
501
502#endif
503