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 <QtCore/QVector>
25#include <QtCore/QString>
26#include <QtCore/QSharedPointer>
27
28#include "katepartprivate_export.h"
29
30namespace Kate {
31
32/**
33 * Class representing a single text line.
34 * For efficience reasons, not only pure text is stored here, but also additional data.
35 * Will be only accessed over shared pointers.
36 */
37class KATEPART_TESTS_EXPORT TextLineData {
38 /**
39 * TexBlock is a friend class, only one allowed to touch the text content.
40 */
41 friend class TextBlock;
42
43 public:
44 /**
45 * Context stack
46 */
47 typedef QVector<short> ContextStack;
48
49 /**
50 * Attribute storage
51 */
52 class Attribute {
53 public:
54 /**
55 * Attribute constructor
56 * @param _offset offset
57 * @param _length length
58 * @param _attributeValue attribute value
59 * @param _foldingValue folding value
60 */
61 Attribute (int _offset = 0, int _length = 0, short _attributeValue = 0, short _foldingValue = 0)
62 : offset (_offset)
63 , length (_length)
64 , attributeValue (_attributeValue)
65 , foldingValue (_foldingValue)
66 {
67 }
68
69 /**
70 * offset
71 */
72 int offset;
73
74 /**
75 * length
76 */
77 int length;
78
79 /**
80 * attribute value (to encode type of this range)
81 */
82 short attributeValue;
83
84 /**
85 * folding value (begin/end type)
86 */
87 short foldingValue;
88 };
89
90 /**
91 * Flags of TextLineData
92 */
93 enum Flags
94 {
95 flagHlContinue = 1,
96 flagAutoWrapped = 2,
97 flagFoldingStartAttribute = 4,
98 flagFoldingStartIndentation = 8,
99 flagLineModified = 16,
100 flagLineSavedOnDisk = 32
101 };
102
103 /**
104 * Construct an empty text line.
105 */
106 TextLineData ();
107
108 /**
109 * Construct an text line with given text.
110 * @param text text to use for this line
111 */
112 TextLineData (const QString &text);
113
114 /**
115 * Destruct the text line
116 */
117 ~TextLineData ();
118
119 /**
120 * Accessor to the text contained in this line.
121 * @return text of this line as constant reference
122 */
123 const QString &text () const { return m_text; }
124
125 /**
126 * Returns the position of the first non-whitespace character
127 * @return position of first non-whitespace char or -1 if there is none
128 */
129 int firstChar() const;
130
131 /**
132 * Returns the position of the last non-whitespace character
133 * @return position of last non-whitespace char or -1 if there is none
134 */
135 int lastChar() const;
136
137 /**
138 * Find the position of the next char that is not a space.
139 * @param pos Column of the character which is examined first.
140 * @return True if the specified or a following character is not a space
141 * Otherwise false.
142 */
143 int nextNonSpaceChar(int pos) const;
144
145 /**
146 * Find the position of the previous char that is not a space.
147 * @param pos Column of the character which is examined first.
148 * @return The position of the first non-whitespace character preceding pos,
149 * or -1 if none is found.
150 */
151 int previousNonSpaceChar(int pos) const;
152
153 /**
154 * Returns the character at the given \e column. If \e column is out of
155 * range, the return value is QChar().
156 * @param column column you want char for
157 * @return char at given column or QChar()
158 */
159 inline QChar at (int column) const
160 {
161 if (column >= 0 && column < m_text.length())
162 return m_text[column];
163
164 return QChar();
165 }
166
167 /**
168 * Same as at().
169 * @param column column you want char for
170 * @return char at given column or QChar()
171 */
172 inline QChar operator[](int column) const
173 {
174 if (column >= 0 && column < m_text.length())
175 return m_text[column];
176
177 return QChar();
178 }
179
180 inline void markAsModified(bool modified)
181 {
182 if (modified) {
183 m_flags |= flagLineModified;
184 m_flags &= (~flagLineSavedOnDisk);
185 } else {
186 m_flags &= (~flagLineModified);
187 }
188 }
189
190 inline bool markedAsModified() const
191 {
192 return m_flags & flagLineModified;
193 }
194
195 inline void markAsSavedOnDisk(bool savedOnDisk)
196 {
197 if (savedOnDisk) {
198 m_flags |= flagLineSavedOnDisk;
199 m_flags &= (~flagLineModified);
200 } else {
201 m_flags &= (~flagLineSavedOnDisk);
202 }
203 }
204
205 inline bool markedAsSavedOnDisk() const
206 {
207 return m_flags & flagLineSavedOnDisk;
208 }
209
210 /**
211 * Is on this line a folding start?
212 * @return folding start line or not?
213 */
214 bool markedAsFoldingStart() const
215 {
216 return m_flags & (flagFoldingStartAttribute | flagFoldingStartIndentation);
217 }
218
219 /**
220 * Clear folding start status.
221 */
222 void clearMarkedAsFoldingStart ()
223 {
224 m_flags &= ~(flagFoldingStartAttribute | flagFoldingStartIndentation);
225 }
226
227 /**
228 * Is on this line a folding start per attribute?
229 * @return folding start line per attribute? or not?
230 */
231 bool markedAsFoldingStartAttribute() const
232 {
233 return m_flags & flagFoldingStartAttribute;
234 }
235
236 /**
237 * Is on this line a folding start per indentation?
238 * @return folding start line per indentation? or not?
239 */
240 bool markedAsFoldingStartIndentation() const
241 {
242 return m_flags & flagFoldingStartIndentation;
243 }
244
245 /**
246 * Mark as folding start line of an attribute based folding.
247 */
248 void markAsFoldingStartAttribute ()
249 {
250 clearMarkedAsFoldingStart ();
251 m_flags |= flagFoldingStartAttribute;
252 }
253
254 /**
255 * Mark as folding start line of an indentation based folding.
256 */
257 void markAsFoldingStartIndentation ()
258 {
259 clearMarkedAsFoldingStart ();
260 m_flags |= flagFoldingStartIndentation;
261 }
262
263 /**
264 * Returns the line's length.
265 */
266 int length() const { return m_text.length(); }
267
268 /**
269 * Returns \e true, if the line's hl-continue flag is set, otherwise returns
270 * \e false. The hl-continue flag is set in the hl-definition files.
271 * @return hl-continue flag is set
272 */
273 bool hlLineContinue () const { return m_flags & flagHlContinue; }
274
275 /**
276 * Returns \e true, if the line was automagically wrapped, otherwise returns
277 * \e false.
278 * @return was this line auto-wrapped?
279 */
280 bool isAutoWrapped () const { return m_flags & flagAutoWrapped; }
281
282 /**
283 * Returns the complete text line (as a QString reference).
284 * @return text of this line, read-only
285 */
286 const QString& string() const { return m_text; }
287
288 /**
289 * Returns the substring with \e length beginning at the given \e column.
290 * @param column start column of text to return
291 * @param length length of text to return
292 * @return wanted part of text
293 */
294 QString string (int column, int length) const
295 { return m_text.mid(column, length); }
296
297 /**
298 * Leading whitespace of this line
299 * @return leading whitespace of this line
300 */
301 QString leadingWhitespace() const;
302
303 /**
304 * Returns the indentation depth with each tab expanded into \e tabWidth characters.
305 */
306 int indentDepth (int tabWidth) const;
307
308 /**
309 * Returns the \e column with each tab expanded into \e tabWidth characters.
310 */
311 int toVirtualColumn (int column, int tabWidth) const;
312
313 /**
314 * Returns the "real" column where each tab only counts one character.
315 * The conversion calculates with \e tabWidth characters for each tab.
316 */
317 int fromVirtualColumn (int column, int tabWidth) const;
318
319 /**
320 * Returns the text length with each tab expanded into \e tabWidth characters.
321 */
322 int virtualLength (int tabWidth) const;
323
324 /**
325 * Returns \e true, if \e match equals to the text at position \e column,
326 * otherwise returns \e false.
327 */
328 bool matchesAt(int column, const QString& match) const;
329
330 /**
331 * Returns \e true, if the line starts with \e match, otherwise returns \e false.
332 */
333 bool startsWith(const QString& match) const { return m_text.startsWith (match); }
334
335 /**
336 * Returns \e true, if the line ends with \e match, otherwise returns \e false.
337 */
338 bool endsWith(const QString& match) const { return m_text.endsWith (match); }
339
340 /**
341 * context stack
342 * @return context stack
343 */
344 const ContextStack &contextStack () const { return m_contextStack; }
345
346 /**
347 * Sets the syntax highlight context number
348 * @param val new context array
349 */
350 void setContextStack (const ContextStack &val) { m_contextStack = val; }
351
352 /**
353 * Add attribute to this line.
354 * @param attribute new attribute to append
355 */
356 void addAttribute (const Attribute &attribute);
357
358 /**
359 * Clear attributes of this line
360 */
361 void clearAttributes () { m_attributesList.clear (); }
362
363 /**
364 * Accessor to attributes
365 * @return attributes of this line
366 */
367 const QVector<Attribute> &attributesList () const { return m_attributesList; }
368
369 /**
370 * Gets the attribute at the given position
371 * use KRenderer::attributes to get the KTextAttribute for this.
372 *
373 * @param pos position of attribute requested
374 * @return value of attribute
375 */
376 short attribute (int pos) const
377 {
378 for (int i=0; i < m_attributesList.size(); ++i)
379 {
380 if (pos >= m_attributesList[i].offset && pos < (m_attributesList[i].offset + m_attributesList[i].length))
381 return m_attributesList[i].attributeValue;
382
383 if (pos < m_attributesList[i].offset)
384 break;
385 }
386
387 return 0;
388 }
389
390 /**
391 * set hl continue flag
392 * @param cont continue flag?
393 */
394 void setHlLineContinue (bool cont)
395 {
396 if (cont) m_flags = m_flags | flagHlContinue;
397 else m_flags = m_flags & ~ flagHlContinue;
398 }
399
400 /**
401 * set auto-wrapped property
402 * @param wrapped line was wrapped?
403 */
404 void setAutoWrapped (bool wrapped)
405 {
406 if (wrapped) m_flags = m_flags | flagAutoWrapped;
407 else m_flags = m_flags & ~ flagAutoWrapped;
408 }
409
410 private:
411 /**
412 * Accessor to the text contained in this line.
413 * This accessor is private, only the friend class text buffer/block is allowed to access the text read/write.
414 * @return text of this line
415 */
416 QString &textReadWrite () { return m_text; }
417
418 private:
419 /**
420 * text of this line
421 */
422 QString m_text;
423
424 /**
425 * attributes of this line
426 */
427 QVector<Attribute> m_attributesList;
428
429 /**
430 * context stack of this line
431 */
432 ContextStack m_contextStack;
433
434 /**
435 * flags of this line
436 */
437 unsigned int m_flags;
438};
439
440/**
441 * The normal world only accesses the text lines with shared pointers.
442 */
443typedef QSharedPointer<TextLineData> TextLine;
444
445}
446
447#endif
448