1/*
2 SPDX-FileCopyrightText: 2010 Christoph Cullmann <cullmann@kde.org>
3
4 Based on code of the SmartCursor/Range by:
5 SPDX-FileCopyrightText: 2003-2005 Hamish Rodda <rodda@kde.org>
6
7 SPDX-License-Identifier: LGPL-2.0-or-later
8*/
9
10#ifndef KATE_TEXTRANGE_H
11#define KATE_TEXTRANGE_H
12
13#include <ktexteditor/movingrange.h>
14
15#include "katetextcursor.h"
16
17namespace KTextEditor
18{
19class MovingRangeFeedback;
20class View;
21}
22
23namespace Kate
24{
25class TextBuffer;
26
27/**
28 * Class representing a 'clever' text range.
29 * It will automagically move if the text inside the buffer it belongs to is modified.
30 * By intention no subclass of KTextEditor::Range, must be converted manually.
31 * A TextRange is allowed to be empty. If you call setInvalidateIfEmpty(true),
32 * a TextRange will become automatically invalid as soon as start() == end()
33 * position holds.
34 */
35class TextRange final : public KTextEditor::MovingRange
36{
37 // this is a friend, block changes might invalidate ranges...
38 friend class TextBlock;
39
40public:
41 /**
42 * Construct a text range.
43 * A TextRange is not allowed to be empty, as soon as start == end position, it will become
44 * automatically invalid!
45 * @param buffer parent text buffer
46 * @param range The initial text range assumed by the new range.
47 * @param insertBehavior Define whether the range should expand when text is inserted adjacent to the range.
48 * @param emptyBehavior Define whether the range should invalidate itself on becoming empty.
49 */
50 TextRange(TextBuffer &buffer, KTextEditor::Range range, InsertBehaviors insertBehavior, EmptyBehavior emptyBehavior = AllowEmpty);
51
52 /**
53 * No copy constructor, don't allow this to be copied.
54 */
55 TextRange(const TextRange &) = delete;
56
57 /**
58 * Destruct the text block
59 */
60 ~TextRange() override;
61
62 /**
63 * No assignment operator, no copying around.
64 */
65 TextRange &operator=(const TextRange &) = delete;
66
67 /**
68 * Set insert behaviors.
69 * @param insertBehaviors new insert behaviors
70 */
71 void setInsertBehaviors(InsertBehaviors insertBehaviors) override;
72
73 /**
74 * Get current insert behaviors.
75 * @return current insert behaviors
76 */
77 InsertBehaviors insertBehaviors() const override;
78
79 /**
80 * Set if this range will invalidate itself if it becomes empty.
81 * @param emptyBehavior behavior on becoming empty
82 */
83 void setEmptyBehavior(EmptyBehavior emptyBehavior) override;
84
85 /**
86 * Will this range invalidate itself if it becomes empty?
87 * @return behavior on becoming empty
88 */
89 EmptyBehavior emptyBehavior() const override
90 {
91 return m_invalidateIfEmpty ? InvalidateIfEmpty : AllowEmpty;
92 }
93
94 /**
95 * Gets the document to which this range is bound.
96 * \return a pointer to the document
97 */
98 KTextEditor::Document *document() const override;
99
100 /**
101 * Set the range of this range.
102 * A TextRange is not allowed to be empty, as soon as start == end position, it will become
103 * automatically invalid!
104 * @param range new range for this clever range
105 */
106 void setRange(KTextEditor::Range range) override;
107
108 /**
109 * \overload
110 * Set the range of this range
111 * A TextRange is not allowed to be empty, as soon as start == end position, it will become
112 * automatically invalid!
113 * @param start new start for this clever range
114 * @param end new end for this clever range
115 */
116 void setRange(KTextEditor::Cursor start, KTextEditor::Cursor end)
117 {
118 KTextEditor::MovingRange::setRange(start, end);
119 }
120
121 /**
122 * Set the range of this range and the connected attribute.
123 * Avoids internal overhead of separate setting that.
124 *
125 * A TextRange is not allowed to be empty, as soon as start == end position, it will become
126 * automatically invalid!
127 *
128 * @param range new range for this clever range
129 * @param attribute Attribute to assign to this range. If null, simply removes the previous Attribute.
130 *
131 * @since 6.0
132 */
133 void setRange(KTextEditor::Range range, KTextEditor::Attribute::Ptr attribute) override;
134
135 /**
136 * Set the range of this range and the connected attribute and Z-depth.
137 * Avoids internal overhead of separate setting that.
138 *
139 * A TextRange is not allowed to be empty, as soon as start == end position, it will become
140 * automatically invalid!
141 *
142 * @param range new range for this clever range
143 * @param attribute Attribute to assign to this range. If null, simply removes the previous Attribute.
144 * @param zDepth new Z-depth of this range
145 *
146 * @since 6.0
147 */
148 void setRange(KTextEditor::Range range, KTextEditor::Attribute::Ptr attribute, qreal zDepth) override;
149
150 /**
151 * Retrieve start cursor of this range, read-only.
152 * @return start cursor
153 */
154 const KTextEditor::MovingCursor &start() const override
155 {
156 return m_start;
157 }
158
159 /**
160 * Non-virtual version of start(), which is faster.
161 * @return start cursor
162 */
163 const TextCursor &startInternal() const
164 {
165 return m_start;
166 }
167
168 /**
169 * Retrieve end cursor of this range, read-only.
170 * @return end cursor
171 */
172 const KTextEditor::MovingCursor &end() const override
173 {
174 return m_end;
175 }
176
177 /**
178 * Nonvirtual version of end(), which is faster.
179 * @return end cursor
180 */
181 const TextCursor &endInternal() const
182 {
183 return m_end;
184 }
185
186 /**
187 * Hides parent's impl of toLineRange() and uses non-virtual functions internally.
188 */
189 KTextEditor::LineRange toLineRange() const
190 {
191 return {startInternal().lineInternal(), endInternal().lineInternal()};
192 }
193
194 /**
195 * Convert this clever range into a dumb one.
196 * @return normal range
197 */
198 const KTextEditor::Range toRange() const
199 {
200 auto startCursor = KTextEditor::Cursor(startInternal().lineInternal(), startInternal().columnInternal());
201 auto endCursor = KTextEditor::Cursor(endInternal().lineInternal(), endInternal().columnInternal());
202 return KTextEditor::Range(startCursor, endCursor);
203 }
204
205 /**
206 * Convert this clever range into a dumb one. Equal to toRange, allowing to use implicit conversion.
207 * @return normal range
208 */
209 operator KTextEditor::Range() const
210 {
211 return toRange();
212 }
213
214 /**
215 * Gets the active view for this range. Might be already invalid, internally only used for pointer comparisons.
216 *
217 * \return a pointer to the active view
218 */
219 KTextEditor::View *view() const override
220 {
221 return m_view;
222 }
223
224 /**
225 * Sets the currently active view for this range.
226 * This will trigger update of the relevant view parts, if the view changed.
227 * Set view before the attribute, that will avoid not needed redraws.
228 *
229 * \param view View to assign to this range. If null, simply
230 * removes the previous view.
231 */
232 void setView(KTextEditor::View *view) override;
233
234 /**
235 * Gets the active Attribute for this range.
236 *
237 * \return a pointer to the active attribute
238 */
239 const KTextEditor::Attribute::Ptr &attribute() const override
240 {
241 return m_attribute;
242 }
243
244 /**
245 * \return whether a nonzero attribute is set. This is faster than checking attribute(),
246 * because the reference-counting is omitted.
247 */
248 bool hasAttribute() const
249 {
250 return m_attribute.constData();
251 }
252
253 /**
254 * Sets the currently active attribute for this range.
255 * This will trigger update of the relevant view parts.
256 *
257 * \param attribute Attribute to assign to this range. If null, simply
258 * removes the previous Attribute.
259 */
260 void setAttribute(KTextEditor::Attribute::Ptr attribute) override;
261
262 /**
263 * Gets the active MovingRangeFeedback for this range.
264 *
265 * \return a pointer to the active MovingRangeFeedback
266 */
267 KTextEditor::MovingRangeFeedback *feedback() const override
268 {
269 return m_feedback;
270 }
271
272 /**
273 * Sets the currently active MovingRangeFeedback for this range.
274 * This will trigger evaluation if feedback must be send again (for example if mouse is already inside range).
275 *
276 * \param feedback MovingRangeFeedback to assign to this range. If null, simply
277 * removes the previous MovingRangeFeedback.
278 */
279 void setFeedback(KTextEditor::MovingRangeFeedback *feedback) override;
280
281 /**
282 * Is this range's attribute only visible in views, not for example prints?
283 * Default is false.
284 * @return range visible only for views
285 */
286 bool attributeOnlyForViews() const override
287 {
288 return m_attributeOnlyForViews;
289 }
290
291 /**
292 * Set if this range's attribute is only visible in views, not for example prints.
293 * @param onlyForViews attribute only valid for views
294 */
295 void setAttributeOnlyForViews(bool onlyForViews) override;
296
297 /**
298 * Gets the current Z-depth of this range.
299 * Ranges with smaller Z-depth than others will win during rendering.
300 * Default is 0.0.
301 *
302 * \return current Z-depth of this range
303 */
304 qreal zDepth() const override
305 {
306 return m_zDepth;
307 }
308
309 /**
310 * Set the current Z-depth of this range.
311 * Ranges with smaller Z-depth than others will win during rendering.
312 * This will trigger update of the relevant view parts, if the depth changed.
313 * Set depth before the attribute, that will avoid not needed redraws.
314 * Default is 0.0.
315 *
316 * \param zDepth new Z-depth of this range
317 */
318 void setZDepth(qreal zDepth) override;
319
320private:
321 /**
322 * Check if range is valid, used by constructor and setRange.
323 * If at least one cursor is invalid, both will set to invalid.
324 * Same if range itself is invalid (start >= end).
325 *
326 * IMPORTANT: Notifications might need to deletion of this range!
327 *
328 * @param oldLineRange line range of this range before changing of cursors, needed to add/remove range from m_ranges in blocks, required!
329 * @param notifyAboutChange should feedback be emitted or not?
330 */
331 void checkValidity(KTextEditor::LineRange oldLineRange, bool notifyAboutChange = true);
332
333 /**
334 * Add/Remove range from the lookup m_ranges hash of each block
335 * @param oldLineRange old line range before changing of cursors, needed to add/remove range from m_ranges in blocks
336 * @param lineRange line range to start looking for the range to remove
337 */
338 void fixLookup(KTextEditor::LineRange oldLineRange, KTextEditor::LineRange lineRange);
339
340 /**
341 * Mark this range for later validity checking.
342 */
343 void setValidityCheckRequired()
344 {
345 m_isCheckValidityRequired = true;
346 }
347
348 /**
349 * Does this range need validity checking?
350 * @return is checking required?
351 */
352 bool isValidityCheckRequired() const
353 {
354 return m_isCheckValidityRequired;
355 }
356
357private:
358 /**
359 * parent text buffer
360 * is a reference, and no pointer, as this must always exist and can't change
361 */
362 TextBuffer &m_buffer;
363
364 /**
365 * Start cursor for this range, is a clever cursor
366 */
367 TextCursor m_start;
368
369 /**
370 * End cursor for this range, is a clever cursor
371 */
372 TextCursor m_end;
373
374 /**
375 * The view for which the attribute is valid, 0 means any view
376 */
377 KTextEditor::View *m_view;
378
379 /**
380 * This range's current attribute.
381 */
382 KTextEditor::Attribute::Ptr m_attribute;
383
384 /**
385 * pointer to the active MovingRangeFeedback
386 */
387 KTextEditor::MovingRangeFeedback *m_feedback;
388
389 /**
390 * Z-depth of this range for rendering
391 */
392 qreal m_zDepth;
393
394 /**
395 * Is this range's attribute only visible in views, not for example prints?
396 */
397 bool m_attributeOnlyForViews;
398
399 /**
400 * Will this range invalidate itself if it becomes empty?
401 */
402 bool m_invalidateIfEmpty;
403
404 /**
405 * Should this range be validated?
406 * Used by KateTextBlock to avoid multiple updates without costly hashing.
407 * Reset by checkValidity().
408 */
409 bool m_isCheckValidityRequired = false;
410};
411
412}
413
414#endif
415

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