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 | |
30 | namespace 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 | */ |
37 | class 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 | */ |
443 | typedef QSharedPointer<TextLineData> TextLine; |
444 | |
445 | } |
446 | |
447 | #endif |
448 | |