File indexing completed on 2024-05-19 04:00:03
0001 /* 0002 SPDX-FileCopyrightText: 2003-2005 Hamish Rodda <rodda@kde.org> 0003 SPDX-FileCopyrightText: 2001-2005 Christoph Cullmann <cullmann@kde.org> 0004 SPDX-FileCopyrightText: 2002 Christian Couder <christian@kdevelop.org> 0005 SPDX-FileCopyrightText: 2001 Joseph Wenninger <jowenn@kde.org> 0006 SPDX-FileCopyrightText: 1999 Jochen Wilhelmy <digisnap@cs.tu-berlin.de> 0007 0008 SPDX-License-Identifier: LGPL-2.0-or-later 0009 */ 0010 0011 #ifndef KTEXTEDITOR_RANGE_H 0012 #define KTEXTEDITOR_RANGE_H 0013 0014 #include <ktexteditor_export.h> 0015 0016 #include <ktexteditor/cursor.h> 0017 #include <ktexteditor/linerange.h> 0018 0019 #include <QtGlobal> 0020 0021 class QDebug; 0022 class QString; 0023 class QStringView; 0024 0025 namespace KTextEditor 0026 { 0027 /** 0028 * \class Range range.h <KTextEditor/Range> 0029 * 0030 * \short An object representing a section of text, from one Cursor to another. 0031 * 0032 * A Range is a basic class which represents a range of text with two Cursors, 0033 * from a start() position to an end() position. 0034 * 0035 * For simplicity and convenience, ranges always maintain their start position to 0036 * be before or equal to their end position. Attempting to set either the 0037 * start or end of the range beyond the respective end or start will result in 0038 * both values being set to the specified position. In the constructor, the 0039 * start and end will be swapped if necessary. 0040 * 0041 * If you want additional functionality such as the ability to maintain position 0042 * in a document, see MovingRange. 0043 * 0044 * \sa MovingRange 0045 * 0046 * \author Hamish Rodda \<rodda@kde.org\> 0047 */ 0048 class KTEXTEDITOR_EXPORT Range 0049 { 0050 public: 0051 /** 0052 * Default constructor. Creates a valid range from position (0, 0) to 0053 * position (0, 0). 0054 */ 0055 constexpr Range() noexcept = default; 0056 0057 /** 0058 * Constructor which creates a range from \e start to \e end. 0059 * If start is after end, they will be swapped. 0060 * 0061 * \param start start position 0062 * \param end end position 0063 */ 0064 constexpr Range(Cursor start, Cursor end) noexcept 0065 : m_start(qMin(start, end)) 0066 , m_end(qMax(start, end)) 0067 { 0068 } 0069 0070 /** 0071 * Constructor which creates a single-line range from \p start, 0072 * extending \p width characters along the same line. 0073 * 0074 * \param start start position 0075 * \param width width of this range in columns along the same line 0076 */ 0077 constexpr Range(Cursor start, int width) noexcept 0078 : m_start(qMin(start, Cursor(start.line(), start.column() + width))) 0079 , m_end(qMax(start, Cursor(start.line(), start.column() + width))) 0080 { 0081 } 0082 0083 /** 0084 * Constructor which creates a range from \p start, to \p endLine, \p endColumn. 0085 * 0086 * \param start start position 0087 * \param endLine end line 0088 * \param endColumn end column 0089 */ 0090 constexpr Range(Cursor start, int endLine, int endColumn) noexcept 0091 : m_start(qMin(start, Cursor(endLine, endColumn))) 0092 , m_end(qMax(start, Cursor(endLine, endColumn))) 0093 { 0094 } 0095 0096 /** 0097 * Constructor which creates a range from \e startLine, \e startColumn to \e endLine, \e endColumn. 0098 * 0099 * \param startLine start line 0100 * \param startColumn start column 0101 * \param endLine end line 0102 * \param endColumn end column 0103 */ 0104 constexpr Range(int startLine, int startColumn, int endLine, int endColumn) noexcept 0105 : m_start(qMin(Cursor(startLine, startColumn), Cursor(endLine, endColumn))) 0106 , m_end(qMax(Cursor(startLine, startColumn), Cursor(endLine, endColumn))) 0107 { 0108 } 0109 0110 /** 0111 * Validity check. In the base class, returns true unless the range starts before (0,0). 0112 */ 0113 constexpr bool isValid() const noexcept 0114 { 0115 return start().isValid() && end().isValid(); 0116 } 0117 0118 /** 0119 * Returns an invalid range. 0120 */ 0121 constexpr static Range invalid() noexcept 0122 { 0123 return Range(Cursor::invalid(), Cursor::invalid()); 0124 } 0125 0126 /** 0127 * Returns the cursor position as string in the format 0128 * "start-line:start-column,endl-line:end-column". 0129 * \see fromString() 0130 */ 0131 QString toString() const; 0132 0133 /** 0134 * Returns a Range created from the string \p str containing the format 0135 * "[(start-line, start-column), (endl-line:end-column)]". 0136 * In case the string cannot be parsed, an Range::invalid() is returned. 0137 * \see toString() 0138 */ 0139 static Range fromString(QStringView str) noexcept; 0140 0141 /** 0142 * \name Position 0143 * 0144 * The following functions provide access to, and manipulation of, the range's position. 0145 * \{ 0146 */ 0147 0148 /** 0149 * Get the start position of this range. This will always be <= end(). 0150 * 0151 * \returns const reference to the start position of this range. 0152 */ 0153 constexpr Cursor start() const noexcept 0154 { 0155 return m_start; 0156 } 0157 0158 /** 0159 * Get the end position of this range. This will always be >= start(). 0160 * 0161 * \returns const reference to the end position of this range. 0162 */ 0163 constexpr Cursor end() const noexcept 0164 { 0165 return m_end; 0166 } 0167 0168 /** 0169 * Convert this Range to a LineRange 0170 * 0171 * @return LineRange from the start line to the end line of this range. 0172 */ 0173 constexpr LineRange toLineRange() const noexcept 0174 { 0175 return {start().line(), end().line()}; 0176 } 0177 0178 /** 0179 * Convenience function. Set the start and end lines to \p line. 0180 * 0181 * \param line the line number to assign to start() and end() 0182 */ 0183 void setBothLines(int line) noexcept; 0184 0185 /** 0186 * Convenience function. Set the start and end columns to \p column. 0187 * 0188 * \param column the column number to assign to start() and end() 0189 */ 0190 void setBothColumns(int column) noexcept; 0191 0192 /** 0193 * Set the start and end cursors to \e range.start() and \e range.end() respectively. 0194 * 0195 * \param range range to assign to this range 0196 */ 0197 void setRange(Range range) noexcept; 0198 0199 /** 0200 * \overload 0201 * \n \n 0202 * Set the start and end cursors to \e start and \e end respectively. 0203 * 0204 * \note If \e start is after \e end, they will be reversed. 0205 * 0206 * \param start start cursor 0207 * \param end end cursor 0208 */ 0209 void setRange(Cursor start, Cursor end) noexcept; 0210 0211 /** 0212 * Set the start cursor to \e start. 0213 * 0214 * \note If \e start is after current end, start and end will be set to new start value. 0215 * 0216 * \param start new start cursor 0217 */ 0218 void setStart(Cursor start) noexcept 0219 { 0220 if (start > end()) { 0221 setRange(start, start); 0222 } else { 0223 setRange(start, end()); 0224 } 0225 } 0226 0227 /** 0228 * Set the end cursor to \e end. 0229 * 0230 * \note If \e end is in front of current start, start and end will be set to new end value. 0231 * 0232 * \param end new end cursor 0233 */ 0234 void setEnd(Cursor end) noexcept 0235 { 0236 if (end < start()) { 0237 setRange(end, end); 0238 } else { 0239 setRange(start(), end); 0240 } 0241 } 0242 0243 /** 0244 * Expand this range if necessary to contain \p range. 0245 * 0246 * \param range range which this range should contain 0247 * 0248 * \return \e true if expansion occurred, \e false otherwise 0249 */ 0250 bool expandToRange(Range range) noexcept; 0251 0252 /** 0253 * Confine this range if necessary to fit within \p range. 0254 * 0255 * \param range range which should contain this range 0256 * 0257 * \return \e true if confinement occurred, \e false otherwise 0258 */ 0259 bool confineToRange(Range range) noexcept; 0260 0261 /** 0262 * Check whether this range is wholly contained within one line, ie. if 0263 * the start() and end() positions are on the same line. 0264 * 0265 * \return \e true if both the start and end positions are on the same 0266 * line, otherwise \e false 0267 */ 0268 constexpr bool onSingleLine() const noexcept 0269 { 0270 return start().line() == end().line(); 0271 } 0272 0273 /** 0274 * Returns the number of lines separating the start() and end() positions. 0275 * 0276 * \return the number of lines separating the start() and end() positions; 0277 * 0 if the start and end lines are the same. 0278 */ 0279 constexpr int numberOfLines() const noexcept 0280 { 0281 return end().line() - start().line(); 0282 } 0283 0284 /** 0285 * Returns the number of columns separating the start() and end() positions. 0286 * 0287 * \return the number of columns separating the start() and end() positions; 0288 * 0 if the start and end columns are the same. 0289 */ 0290 constexpr int columnWidth() const noexcept 0291 { 0292 return end().column() - start().column(); 0293 } 0294 0295 /** 0296 * Returns true if this range contains no characters, ie. the start() and 0297 * end() positions are the same. 0298 * 0299 * \returns \e true if the range contains no characters, otherwise \e false 0300 */ 0301 constexpr bool isEmpty() const noexcept 0302 { 0303 return start() == end(); 0304 } 0305 0306 // BEGIN comparison functions 0307 /** 0308 * \} 0309 * 0310 * \name Comparison 0311 * 0312 * The following functions perform checks against this range in comparison 0313 * to other lines, columns, cursors, and ranges. 0314 * \{ 0315 */ 0316 /** 0317 * Check whether the this range wholly encompasses \e range. 0318 * 0319 * \param range range to check 0320 * 0321 * \return \e true, if this range contains \e range, otherwise \e false 0322 */ 0323 constexpr bool contains(Range range) const noexcept 0324 { 0325 return range.start() >= start() && range.end() <= end(); 0326 } 0327 0328 /** 0329 * Check to see if \p cursor is contained within this range, ie >= start() and \< end(). 0330 * 0331 * \param cursor the position to test for containment 0332 * 0333 * \return \e true if the cursor is contained within this range, otherwise \e false. 0334 */ 0335 constexpr bool contains(Cursor cursor) const noexcept 0336 { 0337 return cursor >= start() && cursor < end(); 0338 } 0339 0340 /** 0341 * Returns true if this range wholly encompasses \p line. 0342 * 0343 * \param line line to check 0344 * 0345 * \return \e true if the line is wholly encompassed by this range, otherwise \e false. 0346 */ 0347 constexpr bool containsLine(int line) const noexcept 0348 { 0349 return (line > start().line() || (line == start().line() && !start().column())) && line < end().line(); 0350 } 0351 0352 /** 0353 * Check whether the range contains \e column. 0354 * 0355 * \param column column to check 0356 * 0357 * \return \e true if the range contains \e column, otherwise \e false 0358 */ 0359 constexpr bool containsColumn(int column) const noexcept 0360 { 0361 return column >= start().column() && column < end().column(); 0362 } 0363 0364 /** 0365 * Check whether the this range overlaps with \e range. 0366 * 0367 * \param range range to check against 0368 * 0369 * \return \e true, if this range overlaps with \e range, otherwise \e false 0370 */ 0371 constexpr bool overlaps(Range range) const noexcept 0372 { 0373 return (range.start() <= start()) ? (range.end() > start()) : (range.end() >= end()) ? (range.start() < end()) : contains(range); 0374 } 0375 0376 /** 0377 * Check whether the range overlaps at least part of \e line. 0378 * 0379 * \param line line to check 0380 * 0381 * \return \e true, if the range overlaps at least part of \e line, otherwise \e false 0382 */ 0383 constexpr bool overlapsLine(int line) const noexcept 0384 { 0385 return line >= start().line() && line <= end().line(); 0386 } 0387 0388 /** 0389 * Check to see if this range overlaps \p column; that is, if \p column is 0390 * between start().column() and end().column(). This function is most likely 0391 * to be useful in relation to block text editing. 0392 * 0393 * \param column the column to test 0394 * 0395 * \return \e true if the column is between the range's starting and ending 0396 * columns, otherwise \e false. 0397 */ 0398 constexpr bool overlapsColumn(int column) const noexcept 0399 { 0400 return start().column() <= column && end().column() > column; 0401 } 0402 0403 /** 0404 * Check whether \p cursor is located at either of the start() or end() 0405 * boundaries. 0406 * 0407 * \param cursor cursor to check 0408 * 0409 * \return \e true if the cursor is equal to \p start() or \p end(), 0410 * otherwise \e false. 0411 */ 0412 constexpr bool boundaryAtCursor(Cursor cursor) const noexcept 0413 { 0414 return cursor == start() || cursor == end(); 0415 } 0416 //!\} 0417 // END 0418 0419 /** 0420 * Intersects this range with another, returning the shared area of 0421 * the two ranges. 0422 * 0423 * \param range other range to intersect with this 0424 * 0425 * \return the intersection of this range and the supplied \a range. 0426 */ 0427 constexpr Range intersect(Range range) const noexcept 0428 { 0429 return ((!isValid() || !range.isValid() || *this > range || *this < range)) ? invalid() : Range(qMax(start(), range.start()), qMin(end(), range.end())); 0430 } 0431 0432 /** 0433 * Returns the smallest range which encompasses this range and the 0434 * supplied \a range. 0435 * 0436 * \param range other range to encompass 0437 * 0438 * \return the smallest range which contains this range and the supplied \a range. 0439 */ 0440 constexpr Range encompass(Range range) const noexcept 0441 { 0442 return (!isValid()) ? (range.isValid() ? range : invalid()) 0443 : (!range.isValid()) ? (*this) 0444 : Range(qMin(start(), range.start()), qMax(end(), range.end())); 0445 } 0446 0447 /** 0448 * Addition operator. Takes two ranges and returns their summation. 0449 * 0450 * \param r1 the first range 0451 * \param r2 the second range 0452 * 0453 * \return a the summation of the two input ranges 0454 */ 0455 constexpr friend Range operator+(Range r1, Range r2) noexcept 0456 { 0457 return Range(r1.start() + r2.start(), r1.end() + r2.end()); 0458 } 0459 0460 /** 0461 * Addition assignment operator. Adds \p r2 to this range. 0462 * 0463 * \param r1 the first range 0464 * \param r2 the second range 0465 * 0466 * \return a reference to the cursor which has just been added to 0467 */ 0468 friend Range &operator+=(Range &r1, Range r2) noexcept 0469 { 0470 r1.setRange(r1.start() + r2.start(), r1.end() + r2.end()); 0471 return r1; 0472 } 0473 0474 /** 0475 * Subtraction operator. Takes two ranges and returns the subtraction 0476 * of \p r2 from \p r1. 0477 * 0478 * \param r1 the first range 0479 * \param r2 the second range 0480 * 0481 * \return a range representing the subtraction of \p r2 from \p r1 0482 */ 0483 constexpr friend Range operator-(Range r1, Range r2) noexcept 0484 { 0485 return Range(r1.start() - r2.start(), r1.end() - r2.end()); 0486 } 0487 0488 /** 0489 * Subtraction assignment operator. Subtracts \p r2 from \p r1. 0490 * 0491 * \param r1 the first range 0492 * \param r2 the second range 0493 * 0494 * \return a reference to the range which has just been subtracted from 0495 */ 0496 friend Range &operator-=(Range &r1, Range r2) noexcept 0497 { 0498 r1.setRange(r1.start() - r2.start(), r1.end() - r2.end()); 0499 return r1; 0500 } 0501 0502 /** 0503 * Intersects \a r1 and \a r2. 0504 * 0505 * \param r1 the first range 0506 * \param r2 the second range 0507 * 0508 * \return the intersected range, invalid() if there is no overlap 0509 */ 0510 constexpr friend Range operator&(Range r1, Range r2) noexcept 0511 { 0512 return r1.intersect(r2); 0513 } 0514 0515 /** 0516 * Intersects \a r1 with \a r2 and assigns the result to \a r1. 0517 * 0518 * \param r1 the range to assign the intersection to 0519 * \param r2 the range to intersect \a r1 with 0520 * 0521 * \return a reference to this range, after the intersection has taken place 0522 */ 0523 friend Range &operator&=(Range &r1, Range r2) noexcept 0524 { 0525 r1.setRange(r1.intersect(r2)); 0526 return r1; 0527 } 0528 0529 /** 0530 * Equality operator. 0531 * 0532 * \param r1 first range to compare 0533 * \param r2 second range to compare 0534 * 0535 * \return \e true if \e r1 and \e r2 equal, otherwise \e false 0536 */ 0537 constexpr friend bool operator==(Range r1, Range r2) noexcept 0538 { 0539 return r1.start() == r2.start() && r1.end() == r2.end(); 0540 } 0541 0542 /** 0543 * Inequality operator. 0544 * 0545 * \param r1 first range to compare 0546 * \param r2 second range to compare 0547 * 0548 * \return \e true if \e r1 and \e r2 do \e not equal, otherwise \e false 0549 */ 0550 constexpr friend bool operator!=(Range r1, Range r2) noexcept 0551 { 0552 return r1.start() != r2.start() || r1.end() != r2.end(); 0553 } 0554 0555 /** 0556 * Greater than operator. Looks only at the position of the two ranges, 0557 * does not consider their size. 0558 * 0559 * \param r1 first range to compare 0560 * \param r2 second range to compare 0561 * 0562 * \return \e true if \e r1 starts after where \e r2 ends, otherwise \e false 0563 */ 0564 constexpr friend bool operator>(Range r1, Range r2) noexcept 0565 { 0566 return r1.start() > r2.end(); 0567 } 0568 0569 /** 0570 * Less than operator. Looks only at the position of the two ranges, 0571 * does not consider their size. 0572 * 0573 * \param r1 first range to compare 0574 * \param r2 second range to compare 0575 * 0576 * \return \e true if \e r1 ends before \e r2 begins, otherwise \e false 0577 */ 0578 constexpr friend bool operator<(Range r1, Range r2) noexcept 0579 { 0580 return r1.end() < r2.start(); 0581 } 0582 0583 private: 0584 /** 0585 * This range's start cursor pointer. 0586 * 0587 * \internal 0588 */ 0589 Cursor m_start; 0590 0591 /** 0592 * This range's end cursor pointer. 0593 * 0594 * \internal 0595 */ 0596 Cursor m_end; 0597 }; 0598 0599 /** 0600 * QHash function for KTextEditor::Range. 0601 * Returns the hash value for @p range. 0602 */ 0603 KTEXTEDITOR_EXPORT size_t qHash(KTextEditor::Range range, size_t seed = 0) noexcept; 0604 } 0605 0606 Q_DECLARE_TYPEINFO(KTextEditor::Range, Q_RELOCATABLE_TYPE); 0607 0608 /** 0609 * qDebug() stream operator. Writes this range to the debug output in a nicely formatted way. 0610 */ 0611 KTEXTEDITOR_EXPORT QDebug operator<<(QDebug s, KTextEditor::Range range); 0612 0613 namespace QTest 0614 { 0615 // forward declaration of template in qtestcase.h 0616 template<typename T> 0617 char *toString(const T &); 0618 0619 /** 0620 * QTestLib integration to have nice output in e.g. QCOMPARE failures. 0621 */ 0622 template<> 0623 KTEXTEDITOR_EXPORT char *toString(const KTextEditor::Range &range); 0624 } 0625 0626 #endif