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