KTextEditor

include/ktexteditor/range.h
1/*
2 SPDX-FileCopyrightText: 2003-2005 Hamish Rodda <rodda@kde.org>
3 SPDX-FileCopyrightText: 2001-2005 Christoph Cullmann <cullmann@kde.org>
4 SPDX-FileCopyrightText: 2002 Christian Couder <christian@kdevelop.org>
5 SPDX-FileCopyrightText: 2001 Joseph Wenninger <jowenn@kde.org>
6 SPDX-FileCopyrightText: 1999 Jochen Wilhelmy <digisnap@cs.tu-berlin.de>
7
8 SPDX-License-Identifier: LGPL-2.0-or-later
9*/
10
11#ifndef KTEXTEDITOR_RANGE_H
12#define KTEXTEDITOR_RANGE_H
13
14#include <ktexteditor_export.h>
15
16#include <ktexteditor/cursor.h>
17#include <ktexteditor/linerange.h>
18
19#include <QtGlobal>
20
21class QDebug;
22class QString;
23class QStringView;
24
25namespace KTextEditor
26{
27/**
28 * \class Range range.h <KTextEditor/Range>
29 *
30 * \short An object representing a section of text, from one Cursor to another.
31 *
32 * A Range is a basic class which represents a range of text with two Cursors,
33 * from a start() position to an end() position.
34 *
35 * For simplicity and convenience, ranges always maintain their start position to
36 * be before or equal to their end position. Attempting to set either the
37 * start or end of the range beyond the respective end or start will result in
38 * both values being set to the specified position. In the constructor, the
39 * start and end will be swapped if necessary.
40 *
41 * If you want additional functionality such as the ability to maintain position
42 * in a document, see MovingRange.
43 *
44 * \sa MovingRange
45 *
46 * \author Hamish Rodda <rodda@kde.org>
47 */
48class KTEXTEDITOR_EXPORT Range
49{
50public:
51 /**
52 * Default constructor. Creates a valid range from position (0, 0) to
53 * position (0, 0).
54 */
55 constexpr Range() noexcept = default;
56
57 /**
58 * Constructor which creates a range from \e start to \e end.
59 * If start is after end, they will be swapped.
60 *
61 * \param start start position
62 * \param end end position
63 */
64 constexpr Range(Cursor start, Cursor end) noexcept
65 : m_start(qMin(start, end))
66 , m_end(qMax(start, end))
67 {
68 }
69
70 /**
71 * Constructor which creates a single-line range from \p start,
72 * extending \p width characters along the same line.
73 *
74 * \param start start position
75 * \param width width of this range in columns along the same line
76 */
77 constexpr Range(Cursor start, int width) noexcept
78 : m_start(qMin(start, Cursor(start.line(), start.column() + width)))
79 , m_end(qMax(start, Cursor(start.line(), start.column() + width)))
80 {
81 }
82
83 /**
84 * Constructor which creates a range from \p start, to \p endLine, \p endColumn.
85 *
86 * \param start start position
87 * \param endLine end line
88 * \param endColumn end column
89 */
90 constexpr Range(Cursor start, int endLine, int endColumn) noexcept
91 : m_start(qMin(start, Cursor(endLine, endColumn)))
92 , m_end(qMax(start, Cursor(endLine, endColumn)))
93 {
94 }
95
96 /**
97 * Constructor which creates a range from \e startLine, \e startColumn to \e endLine, \e endColumn.
98 *
99 * \param startLine start line
100 * \param startColumn start column
101 * \param endLine end line
102 * \param endColumn end column
103 */
104 constexpr Range(int startLine, int startColumn, int endLine, int endColumn) noexcept
105 : m_start(qMin(Cursor(startLine, startColumn), Cursor(endLine, endColumn)))
106 , m_end(qMax(Cursor(startLine, startColumn), Cursor(endLine, endColumn)))
107 {
108 }
109
110 /**
111 * Validity check. In the base class, returns true unless the range starts before (0,0).
112 */
113 constexpr bool isValid() const noexcept
114 {
115 return start().isValid() && end().isValid();
116 }
117
118 /**
119 * Returns an invalid range.
120 */
121 constexpr static Range invalid() noexcept
122 {
123 return Range(Cursor::invalid(), Cursor::invalid());
124 }
125
126 /**
127 * Returns the cursor position as string in the format
128 * "start-line:start-column,endl-line:end-column".
129 * \see fromString()
130 */
131 QString toString() const;
132
133 /**
134 * Returns a Range created from the string \p str containing the format
135 * "[(start-line, start-column), (endl-line:end-column)]".
136 * In case the string cannot be parsed, an Range::invalid() is returned.
137 * \see toString()
138 */
139 static Range fromString(QStringView str) noexcept;
140
141 /**
142 * \name Position
143 *
144 * The following functions provide access to, and manipulation of, the range's position.
145 * \{
146 */
147
148 /**
149 * Get the start position of this range. This will always be <= end().
150 *
151 * \returns const reference to the start position of this range.
152 */
153 constexpr Cursor start() const noexcept
154 {
155 return m_start;
156 }
157
158 /**
159 * Get the end position of this range. This will always be >= start().
160 *
161 * \returns const reference to the end position of this range.
162 */
163 constexpr Cursor end() const noexcept
164 {
165 return m_end;
166 }
167
168 /**
169 * Convert this Range to a LineRange
170 *
171 * @return LineRange from the start line to the end line of this range.
172 */
173 constexpr LineRange toLineRange() const noexcept
174 {
175 return {start().line(), end().line()};
176 }
177
178 /**
179 * Convenience function. Set the start and end lines to \p line.
180 *
181 * \param line the line number to assign to start() and end()
182 */
183 void setBothLines(int line) noexcept;
184
185 /**
186 * Convenience function. Set the start and end columns to \p column.
187 *
188 * \param column the column number to assign to start() and end()
189 */
190 void setBothColumns(int column) noexcept;
191
192 /**
193 * Set the start and end cursors to \e range.start() and \e range.end() respectively.
194 *
195 * \param range range to assign to this range
196 */
197 void setRange(Range range) noexcept;
198
199 /**
200 * \overload
201 * \n \n
202 * Set the start and end cursors to \e start and \e end respectively.
203 *
204 * \note If \e start is after \e end, they will be reversed.
205 *
206 * \param start start cursor
207 * \param end end cursor
208 */
209 void setRange(Cursor start, Cursor end) noexcept;
210
211 /**
212 * Set the start cursor to \e start.
213 *
214 * \note If \e start is after current end, start and end will be set to new start value.
215 *
216 * \param start new start cursor
217 */
218 void setStart(Cursor start) noexcept
219 {
220 if (start > end()) {
221 setRange(start, start);
222 } else {
223 setRange(start, end());
224 }
225 }
226
227 /**
228 * Set the end cursor to \e end.
229 *
230 * \note If \e end is in front of current start, start and end will be set to new end value.
231 *
232 * \param end new end cursor
233 */
234 void setEnd(Cursor end) noexcept
235 {
236 if (end < start()) {
237 setRange(end, end);
238 } else {
239 setRange(start(), end);
240 }
241 }
242
243 /**
244 * Expand this range if necessary to contain \p range.
245 *
246 * \param range range which this range should contain
247 *
248 * \return \e true if expansion occurred, \e false otherwise
249 */
250 bool expandToRange(Range range) noexcept;
251
252 /**
253 * Confine this range if necessary to fit within \p range.
254 *
255 * \param range range which should contain this range
256 *
257 * \return \e true if confinement occurred, \e false otherwise
258 */
259 bool confineToRange(Range range) noexcept;
260
261 /**
262 * Check whether this range is wholly contained within one line, ie. if
263 * the start() and end() positions are on the same line.
264 *
265 * \return \e true if both the start and end positions are on the same
266 * line, otherwise \e false
267 */
268 constexpr bool onSingleLine() const noexcept
269 {
270 return start().line() == end().line();
271 }
272
273 /**
274 * Returns the number of lines separating the start() and end() positions.
275 *
276 * \return the number of lines separating the start() and end() positions;
277 * 0 if the start and end lines are the same.
278 */
279 constexpr int numberOfLines() const noexcept
280 {
281 return end().line() - start().line();
282 }
283
284 /**
285 * Returns the number of columns separating the start() and end() positions.
286 *
287 * \return the number of columns separating the start() and end() positions;
288 * 0 if the start and end columns are the same.
289 */
290 constexpr int columnWidth() const noexcept
291 {
292 return end().column() - start().column();
293 }
294
295 /**
296 * Returns true if this range contains no characters, ie. the start() and
297 * end() positions are the same.
298 *
299 * \returns \e true if the range contains no characters, otherwise \e false
300 */
301 constexpr bool isEmpty() const noexcept
302 {
303 return start() == end();
304 }
305
306 // BEGIN comparison functions
307 /**
308 * \}
309 *
310 * \name Comparison
311 *
312 * The following functions perform checks against this range in comparison
313 * to other lines, columns, cursors, and ranges.
314 * \{
315 */
316 /**
317 * Check whether the this range wholly encompasses \e range.
318 *
319 * \param range range to check
320 *
321 * \return \e true, if this range contains \e range, otherwise \e false
322 */
323 constexpr bool contains(Range range) const noexcept
324 {
325 return range.start() >= start() && range.end() <= end();
326 }
327
328 /**
329 * Check to see if \p cursor is contained within this range, ie >= start() and < end().
330 *
331 * \param cursor the position to test for containment
332 *
333 * \return \e true if the cursor is contained within this range, otherwise \e false.
334 */
335 constexpr bool contains(Cursor cursor) const noexcept
336 {
337 return cursor >= start() && cursor < end();
338 }
339
340 /**
341 * Returns true if this range wholly encompasses \p line.
342 *
343 * \param line line to check
344 *
345 * \return \e true if the line is wholly encompassed by this range, otherwise \e false.
346 */
347 constexpr bool containsLine(int line) const noexcept
348 {
349 return (line > start().line() || (line == start().line() && !start().column())) && line < end().line();
350 }
351
352 /**
353 * Check whether the range contains \e column.
354 *
355 * \param column column to check
356 *
357 * \return \e true if the range contains \e column, otherwise \e false
358 */
359 constexpr bool containsColumn(int column) const noexcept
360 {
361 return column >= start().column() && column < end().column();
362 }
363
364 /**
365 * Check whether the this range overlaps with \e range.
366 *
367 * \param range range to check against
368 *
369 * \return \e true, if this range overlaps with \e range, otherwise \e false
370 */
371 constexpr bool overlaps(Range range) const noexcept
372 {
373 return (range.start() <= start()) ? (range.end() > start()) : (range.end() >= end()) ? (range.start() < end()) : contains(range);
374 }
375
376 /**
377 * Check whether the range overlaps at least part of \e line.
378 *
379 * \param line line to check
380 *
381 * \return \e true, if the range overlaps at least part of \e line, otherwise \e false
382 */
383 constexpr bool overlapsLine(int line) const noexcept
384 {
385 return line >= start().line() && line <= end().line();
386 }
387
388 /**
389 * Check to see if this range overlaps \p column; that is, if \p column is
390 * between start().column() and end().column(). This function is most likely
391 * to be useful in relation to block text editing.
392 *
393 * \param column the column to test
394 *
395 * \return \e true if the column is between the range's starting and ending
396 * columns, otherwise \e false.
397 */
398 constexpr bool overlapsColumn(int column) const noexcept
399 {
400 return start().column() <= column && end().column() > column;
401 }
402
403 /**
404 * Check whether \p cursor is located at either of the start() or end()
405 * boundaries.
406 *
407 * \param cursor cursor to check
408 *
409 * \return \e true if the cursor is equal to \p start() or \p end(),
410 * otherwise \e false.
411 */
412 constexpr bool boundaryAtCursor(Cursor cursor) const noexcept
413 {
414 return cursor == start() || cursor == end();
415 }
416 //!\}
417 // END
418
419 /**
420 * Intersects this range with another, returning the shared area of
421 * the two ranges.
422 *
423 * \param range other range to intersect with this
424 *
425 * \return the intersection of this range and the supplied \a range.
426 */
427 constexpr Range intersect(Range range) const noexcept
428 {
429 return ((!isValid() || !range.isValid() || *this > range || *this < range)) ? invalid() : Range(qMax(start(), range.start()), qMin(end(), range.end()));
430 }
431
432 /**
433 * Returns the smallest range which encompasses this range and the
434 * supplied \a range.
435 *
436 * \param range other range to encompass
437 *
438 * \return the smallest range which contains this range and the supplied \a range.
439 */
440 constexpr Range encompass(Range range) const noexcept
441 {
442 return (!isValid()) ? (range.isValid() ? range : invalid())
443 : (!range.isValid()) ? (*this)
444 : Range(qMin(start(), range.start()), qMax(end(), range.end()));
445 }
446
447 /**
448 * Addition operator. Takes two ranges and returns their summation.
449 *
450 * \param r1 the first range
451 * \param r2 the second range
452 *
453 * \return a the summation of the two input ranges
454 */
455 constexpr friend Range operator+(Range r1, Range r2) noexcept
456 {
457 return Range(r1.start() + r2.start(), r1.end() + r2.end());
458 }
459
460 /**
461 * Addition assignment operator. Adds \p r2 to this range.
462 *
463 * \param r1 the first range
464 * \param r2 the second range
465 *
466 * \return a reference to the cursor which has just been added to
467 */
468 friend Range &operator+=(Range &r1, Range r2) noexcept
469 {
470 r1.setRange(r1.start() + r2.start(), r1.end() + r2.end());
471 return r1;
472 }
473
474 /**
475 * Subtraction operator. Takes two ranges and returns the subtraction
476 * of \p r2 from \p r1.
477 *
478 * \param r1 the first range
479 * \param r2 the second range
480 *
481 * \return a range representing the subtraction of \p r2 from \p r1
482 */
483 constexpr friend Range operator-(Range r1, Range r2) noexcept
484 {
485 return Range(r1.start() - r2.start(), r1.end() - r2.end());
486 }
487
488 /**
489 * Subtraction assignment operator. Subtracts \p r2 from \p r1.
490 *
491 * \param r1 the first range
492 * \param r2 the second range
493 *
494 * \return a reference to the range which has just been subtracted from
495 */
496 friend Range &operator-=(Range &r1, Range r2) noexcept
497 {
498 r1.setRange(r1.start() - r2.start(), r1.end() - r2.end());
499 return r1;
500 }
501
502 /**
503 * Intersects \a r1 and \a r2.
504 *
505 * \param r1 the first range
506 * \param r2 the second range
507 *
508 * \return the intersected range, invalid() if there is no overlap
509 */
510 constexpr friend Range operator&(Range r1, Range r2) noexcept
511 {
512 return r1.intersect(r2);
513 }
514
515 /**
516 * Intersects \a r1 with \a r2 and assigns the result to \a r1.
517 *
518 * \param r1 the range to assign the intersection to
519 * \param r2 the range to intersect \a r1 with
520 *
521 * \return a reference to this range, after the intersection has taken place
522 */
523 friend Range &operator&=(Range &r1, Range r2) noexcept
524 {
525 r1.setRange(r1.intersect(r2));
526 return r1;
527 }
528
529 /**
530 * Equality operator.
531 *
532 * \param r1 first range to compare
533 * \param r2 second range to compare
534 *
535 * \return \e true if \e r1 and \e r2 equal, otherwise \e false
536 */
537 constexpr friend bool operator==(Range r1, Range r2) noexcept
538 {
539 return r1.start() == r2.start() && r1.end() == r2.end();
540 }
541
542 /**
543 * Inequality operator.
544 *
545 * \param r1 first range to compare
546 * \param r2 second range to compare
547 *
548 * \return \e true if \e r1 and \e r2 do \e not equal, otherwise \e false
549 */
550 constexpr friend bool operator!=(Range r1, Range r2) noexcept
551 {
552 return r1.start() != r2.start() || r1.end() != r2.end();
553 }
554
555 /**
556 * Greater than operator. Looks only at the position of the two ranges,
557 * does not consider their size.
558 *
559 * \param r1 first range to compare
560 * \param r2 second range to compare
561 *
562 * \return \e true if \e r1 starts after where \e r2 ends, otherwise \e false
563 */
564 constexpr friend bool operator>(Range r1, Range r2) noexcept
565 {
566 return r1.start() > r2.end();
567 }
568
569 /**
570 * Less than operator. Looks only at the position of the two ranges,
571 * does not consider their size.
572 *
573 * \param r1 first range to compare
574 * \param r2 second range to compare
575 *
576 * \return \e true if \e r1 ends before \e r2 begins, otherwise \e false
577 */
578 constexpr friend bool operator<(Range r1, Range r2) noexcept
579 {
580 return r1.end() < r2.start();
581 }
582
583private:
584 /**
585 * This range's start cursor pointer.
586 *
587 * \internal
588 */
589 Cursor m_start;
590
591 /**
592 * This range's end cursor pointer.
593 *
594 * \internal
595 */
596 Cursor m_end;
597};
598
599/**
600 * QHash function for KTextEditor::Range.
601 * Returns the hash value for @p range.
602 */
603KTEXTEDITOR_EXPORT size_t qHash(KTextEditor::Range range, size_t seed = 0) noexcept;
604}
605
606Q_DECLARE_TYPEINFO(KTextEditor::Range, Q_RELOCATABLE_TYPE);
607
608/**
609 * qDebug() stream operator. Writes this range to the debug output in a nicely formatted way.
610 */
611KTEXTEDITOR_EXPORT QDebug operator<<(QDebug s, KTextEditor::Range range);
612
613namespace QTest
614{
615// forward declaration of template in qtestcase.h
616template<typename T>
617char *toString(const T &);
618
619/**
620 * QTestLib integration to have nice output in e.g. QCOMPARE failures.
621 */
622template<>
623KTEXTEDITOR_EXPORT char *toString(const KTextEditor::Range &range);
624}
625
626#endif
The Cursor represents a position in a Document.
Definition cursor.h:75
An object representing lines from a start line to an end line.
Definition linerange.h:41
An object representing a section of text, from one Cursor to another.
constexpr LineRange toLineRange() const noexcept
Convert this Range to a LineRange.
constexpr Cursor end() const noexcept
Get the end position of this range.
constexpr Cursor start() const noexcept
Get the start position of this range.
void setEnd(Cursor end) noexcept
Set the end cursor to end.
constexpr bool contains(Cursor cursor) const noexcept
Check to see if cursor is contained within this range, ie >= start() and < end().
constexpr friend Range operator&(Range r1, Range r2) noexcept
Intersects r1 and r2.
constexpr bool isEmpty() const noexcept
Returns true if this range contains no characters, ie.
constexpr Range(int startLine, int startColumn, int endLine, int endColumn) noexcept
Constructor which creates a range from startLine, startColumn to endLine, endColumn.
constexpr friend bool operator>(Range r1, Range r2) noexcept
Greater than operator.
constexpr bool overlaps(Range range) const noexcept
Check whether the this range overlaps with range.
constexpr int columnWidth() const noexcept
Returns the number of columns separating the start() and end() positions.
constexpr bool onSingleLine() const noexcept
Check whether this range is wholly contained within one line, ie.
constexpr friend bool operator<(Range r1, Range r2) noexcept
Less than operator.
static constexpr Range invalid() noexcept
Returns an invalid range.
constexpr friend Range operator-(Range r1, Range r2) noexcept
Subtraction operator.
constexpr bool isValid() const noexcept
Validity check.
friend Range & operator&=(Range &r1, Range r2) noexcept
Intersects r1 with r2 and assigns the result to r1.
constexpr friend bool operator!=(Range r1, Range r2) noexcept
Inequality operator.
constexpr Range(Cursor start, int width) noexcept
Constructor which creates a single-line range from start, extending width characters along the same l...
constexpr bool containsLine(int line) const noexcept
Returns true if this range wholly encompasses line.
constexpr Range() noexcept=default
Default constructor.
constexpr Range(Cursor start, int endLine, int endColumn) noexcept
Constructor which creates a range from start, to endLine, endColumn.
constexpr bool contains(Range range) const noexcept
Check whether the this range wholly encompasses range.
constexpr bool overlapsLine(int line) const noexcept
Check whether the range overlaps at least part of line.
friend Range & operator-=(Range &r1, Range r2) noexcept
Subtraction assignment operator.
constexpr Range intersect(Range range) const noexcept
Intersects this range with another, returning the shared area of the two ranges.
friend Range & operator+=(Range &r1, Range r2) noexcept
Addition assignment operator.
constexpr bool overlapsColumn(int column) const noexcept
Check to see if this range overlaps column; that is, if column is between start()....
constexpr bool containsColumn(int column) const noexcept
Check whether the range contains column.
constexpr int numberOfLines() const noexcept
Returns the number of lines separating the start() and end() positions.
constexpr bool boundaryAtCursor(Cursor cursor) const noexcept
Check whether cursor is located at either of the start() or end() boundaries.
constexpr friend Range operator+(Range r1, Range r2) noexcept
Addition operator.
constexpr friend bool operator==(Range r1, Range r2) noexcept
Equality operator.
void setStart(Cursor start) noexcept
Set the start cursor to start.
constexpr Range encompass(Range range) const noexcept
Returns the smallest range which encompasses this range and the supplied range.
Q_SCRIPTABLE Q_NOREPLY void start()
The KTextEditor namespace contains all the public API that is required to use the KTextEditor compone...
KTEXTEDITOR_EXPORT size_t qHash(KTextEditor::Cursor cursor, size_t seed=0) noexcept
QHash function for KTextEditor::Cursor.
This file is part of the KDE documentation.
Documentation copyright © 1996-2024 The KDE developers.
Generated on Tue Mar 26 2024 11:15:44 by doxygen 1.10.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.