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