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