1/*
2 SPDX-FileCopyrightText: 2010 Christoph Cullmann <cullmann@kde.org>
3
4 SPDX-License-Identifier: LGPL-2.0-or-later
5*/
6
7#ifndef KATE_TEXTBLOCK_H
8#define KATE_TEXTBLOCK_H
9
10#include "katetextline.h"
11
12#include <QList>
13#include <QSet>
14#include <QVarLengthArray>
15
16#include <ktexteditor/cursor.h>
17#include <ktexteditor_export.h>
18
19namespace KTextEditor
20{
21class View;
22}
23
24namespace Kate
25{
26class TextBuffer;
27class TextCursor;
28class TextRange;
29
30/**
31 * Class representing a text block.
32 * This is used to build up a Kate::TextBuffer.
33 * This class should only be used by TextBuffer/Cursor/Range.
34 */
35class TextBlock
36{
37public:
38 /**
39 * Construct an empty text block.
40 * @param buffer parent text buffer
41 * @param startLine start line of this block
42 */
43 TextBlock(TextBuffer *buffer, int startLine);
44
45 /**
46 * Destruct the text block
47 */
48 ~TextBlock();
49
50 /**
51 * Start line of this block.
52 * @return start line of this block
53 */
54 int startLine() const
55 {
56 return m_startLine;
57 }
58
59 /**
60 * Set start line of this block.
61 * @param startLine new start line of this block
62 */
63 void setStartLine(int startLine);
64
65 /**
66 * Retrieve a text line.
67 * @param line wanted line number
68 * @return text line
69 */
70 TextLine line(int line) const;
71
72 /**
73 * Transfer all non text attributes for the given line from the given text line to the one in the block.
74 * @param line line number to set attributes
75 * @param textLine line reference to get attributes from
76 */
77 void setLineMetaData(int line, const TextLine &textLine);
78
79 /**
80 * Retrieve length for @p line.
81 * @param line wanted line number
82 * @return length of line
83 */
84 int lineLength(int line) const
85 {
86 Q_ASSERT(line >= startLine() && (line - startLine()) < lines());
87 return m_lines[line - startLine()].length();
88 }
89
90 /**
91 * Append a new line with given text.
92 * @param textOfLine text of the line to append
93 */
94 void appendLine(const QString &textOfLine);
95
96 /**
97 * Clear the lines.
98 */
99 void clearLines();
100
101 /**
102 * Number of lines in this block.
103 * @return number of lines
104 */
105 int lines() const
106 {
107 return static_cast<int>(m_lines.size());
108 }
109
110 /**
111 * Retrieve text of block.
112 * @param text for this block, lines separated by '\n'
113 */
114 void text(QString &text) const;
115
116 /**
117 * Wrap line at given cursor position.
118 * @param position line/column as cursor where to wrap
119 * @param fixStartLinesStartIndex start index to fix start lines, normally this is this block
120 */
121 void wrapLine(const KTextEditor::Cursor position, int fixStartLinesStartIndex);
122
123 /**
124 * Unwrap given line.
125 * @param line line to unwrap
126 * @param previousBlock previous block, if any, if we unwrap first line in block, we need to have this
127 * @param fixStartLinesStartIndex start index to fix start lines, normally this is this block or the previous one
128 */
129 void unwrapLine(int line, TextBlock *previousBlock, int fixStartLinesStartIndex);
130
131 /**
132 * Insert text at given cursor position.
133 * @param position position where to insert text
134 * @param text text to insert
135 */
136 void insertText(const KTextEditor::Cursor position, const QString &text);
137
138 /**
139 * Remove text at given range.
140 * @param range range of text to remove, must be on one line only.
141 * @param removedText will be filled with removed text
142 */
143 void removeText(KTextEditor::Range range, QString &removedText);
144
145 /**
146 * Debug output, print whole block content with line numbers and line length
147 * @param blockIndex index of this block in buffer
148 */
149 void debugPrint(int blockIndex) const;
150
151 /**
152 * Split given block. A new block will be created and all lines starting from the given index will
153 * be moved to it, together with the cursors belonging to it.
154 * @param fromLine line from which to split
155 * @return new block containing the lines + cursors removed from this one
156 */
157 TextBlock *splitBlock(int fromLine);
158
159 /**
160 * Merge this block with given one, the given one must be a direct predecessor.
161 * @param targetBlock block to merge with
162 */
163 void mergeBlock(TextBlock *targetBlock);
164
165 /**
166 * Delete the block content, delete all lines and delete all cursors not bound to ranges.
167 * This is used in destructor of TextBuffer, for fast cleanup. Only stuff remaining afterwards are cursors which are
168 * part of a range, TextBuffer will delete them itself...
169 */
170 void deleteBlockContent();
171
172 /**
173 * Clear the block content, delete all lines, move all cursors not bound to range to given block at 0,0.
174 * This is used by clear() of TextBuffer.
175 * @param targetBlock empty target block for cursors
176 */
177 void clearBlockContent(TextBlock *targetBlock);
178
179 /**
180 * Return all ranges in this block which might intersect the given line.
181 * @param line line to check intersection
182 * @param view only return ranges associated with given view
183 * @param rangesWithAttributeOnly ranges with attributes only?
184 * @return list of possible candidate ranges
185 */
186 KTEXTEDITOR_EXPORT QList<TextRange *> rangesForLine(int line, KTextEditor::View *view, bool rangesWithAttributeOnly) const;
187
188 KTEXTEDITOR_NO_EXPORT void rangesForLine(int line, KTextEditor::View *view, bool rangesWithAttributeOnly, QList<TextRange *> &outRanges) const;
189
190 /**
191 * Is the given range contained in this block?
192 * @param range range to check for
193 * @return contained in this blocks mapping?
194 */
195 bool containsRange(TextRange *range) const
196 {
197 return m_cachedLineForRanges.find(key: range) != m_cachedLineForRanges.end() || m_uncachedRanges.contains(t: range);
198 }
199
200 /**
201 * Flag all modified text lines as saved on disk.
202 */
203 void markModifiedLinesAsSaved();
204
205 /**
206 * Insert cursor into this block.
207 * @param cursor cursor to insert
208 */
209 void insertCursor(Kate::TextCursor *cursor)
210 {
211 m_cursors.insert(value: cursor);
212 }
213
214 /**
215 * Remove cursor from this block.
216 * @param cursor cursor to remove
217 */
218 void removeCursor(Kate::TextCursor *cursor)
219 {
220 m_cursors.remove(value: cursor);
221 }
222
223 /**
224 * Update a range from this block.
225 * Will move the range to right set, either cached for one-line ranges or not.
226 * @param range range to update
227 */
228 void updateRange(TextRange *range);
229
230 /**
231 * Remove a range from this block.
232 * @param range range to remove
233 */
234 void removeRange(TextRange *range);
235
236 /**
237 * Returns the size of this block i.e.,
238 * the count of QChars it has + number of new lines
239 */
240 int blockSize() const
241 {
242 return m_blockSize + m_lines.size();
243 }
244
245private:
246 /**
247 * Return all ranges in this block which might intersect the given line and only span one line.
248 * For them an internal fast lookup cache is hold.
249 * @param line line to check intersection
250 * @return set of ranges
251 */
252 const QVarLengthArray<TextRange *, 6> *cachedRangesForLine(int line) const
253 {
254 line -= m_startLine;
255 if (line >= 0 && (size_t)line < m_cachedRangesForLine.size()) {
256 return &m_cachedRangesForLine[line];
257 } else {
258 return nullptr;
259 }
260 }
261
262private:
263 /**
264 * parent text buffer
265 */
266 TextBuffer *m_buffer;
267
268 /**
269 * Lines contained in this buffer.
270 * We need no sharing, use STL.
271 */
272 std::vector<Kate::TextLine> m_lines;
273
274 /**
275 * Startline of this block
276 */
277 int m_startLine;
278
279 /**
280 * size of block i.e., number of QChars
281 */
282 int m_blockSize = 0;
283
284 /**
285 * Set of cursors for this block.
286 * using QSet is better than unordered_set for perf reasons
287 */
288 QSet<TextCursor *> m_cursors;
289
290 /**
291 * Contains for each line-offset the ranges that were cached into it.
292 * These ranges are fully contained by the line.
293 */
294 std::vector<QVarLengthArray<TextRange *, 6>> m_cachedRangesForLine;
295
296 /**
297 * Maps for each cached range the line into which the range was cached.
298 */
299 QHash<TextRange *, int> m_cachedLineForRanges;
300
301 /**
302 * This contains all the ranges that are not cached.
303 */
304 QVarLengthArray<TextRange *, 1> m_uncachedRanges;
305};
306
307}
308
309#endif
310

source code of ktexteditor/src/buffer/katetextblock.h