File indexing completed on 2024-05-12 15:45:40

0001 /*
0002     SPDX-FileCopyrightText: 2003-2005 Hamish Rodda <rodda@kde.org>
0003     SPDX-FileCopyrightText: 2001-2005 Christoph Cullmann <cullmann@kde.org>
0004     SPDX-FileCopyrightText: 2014 Dominik Haumann <dhaumann@kde.org>
0005     SPDX-FileCopyrightText: 2002 Christian Couder <christian@kdevelop.org>
0006     SPDX-FileCopyrightText: 2001 Joseph Wenninger <jowenn@kde.org>
0007     SPDX-FileCopyrightText: 1999 Jochen Wilhelmy <digisnap@cs.tu-berlin.de>
0008 
0009     SPDX-License-Identifier: LGPL-2.0-or-later
0010 */
0011 
0012 #ifndef KTEXTEDITOR_CURSOR_H
0013 #define KTEXTEDITOR_CURSOR_H
0014 
0015 #include <ktexteditor_export.h>
0016 
0017 #include <QDebug>
0018 #include <QtGlobal>
0019 
0020 namespace KTextEditor
0021 {
0022 class Document;
0023 class Range;
0024 
0025 /**
0026  * \class Cursor cursor.h <KTextEditor/Cursor>
0027  *
0028  * \short The Cursor represents a position in a Document.
0029  *
0030  * \section kte_cursor_intro Introduction
0031  * A Cursor represents a position in a Document through a tuple
0032  * of two int%s, namely the line() and column(). A Cursor maintains
0033  * no affiliation with a particular Document, meaning that it remains
0034  * constant if not changed through the Cursor API.
0035  *
0036  * \section kte_cursor_notes Important Notes
0037  *
0038  * Working with a cursor, one should be aware of the following notes:
0039  * - Lines and columns start a 0.
0040  * - The Cursor class is designed to be passed by value (only 8 Bytes).
0041  * - Think of cursors as having their position at the start of a character,
0042  *   not in the middle of one.
0043  * - invalid() Cursor%s are located at (-1, -1). In addition, a Cursor
0044  *   is invalid(), if either its line() and/or its column() is arbitrarily
0045  *   negative, i.e. < 0.
0046  * - All Cursor%s with line() >= 0 and column() >= 0 are valid. In this case
0047  *   isValid() returns \e true.
0048  * - A Cursor has a non-virtual destructor. Hence, you cannot derive from Cursor.
0049  *
0050  * \section kte_cursor_properties Cursor Efficiency
0051  *
0052  * The Cursor consists of just two int%s, the line() and the column().
0053  * Therefore, a Cursor instance takes 8 Bytes of memory. Further, a Cursor
0054  * is a non-virtual class, turning it into a primitive old data type (POD).
0055  * Thus, it can be moved and copied very efficiently.
0056  *
0057  * \section kte_cursor_more Additional Concepts
0058  *
0059  * In addition to the Cursor, the KTextEditor API provides advanced concepts:
0060  * - The DocumentCursor is a Cursor bound to a specific Document. In addition
0061  *   to the Cursor API, it provides convenience functions like
0062  *   DocumentCursor::isValidTextPosition() or DocumentCursor::move().
0063  *   The DocumentCursor does not maintain its position, though.
0064  * - The MovingCursor is also bound to a specific Document. In addition to the
0065  *   DocumentCursor, the MovingCursor maintains its position, meaning that
0066  *   whenever the Document changes, the MovingCursor moves, too.
0067  * - The Cursor forms the basis for the Range.
0068  *
0069  * \sa DocumentCursor, MovingCursor, Range
0070  */
0071 class KTEXTEDITOR_EXPORT Cursor
0072 {
0073 public:
0074     /**
0075      * The default constructor creates a cursor at position (0, 0).
0076      */
0077     Q_DECL_CONSTEXPR Cursor() Q_DECL_NOEXCEPT
0078     {
0079     }
0080 
0081     /**
0082      * This constructor creates a cursor initialized with \p line
0083      * and \p column.
0084      * \param line line for cursor
0085      * \param column column for cursor
0086      */
0087     Q_DECL_CONSTEXPR Cursor(int line, int column) Q_DECL_NOEXCEPT : m_line(line), m_column(column)
0088     {
0089     }
0090 
0091     /**
0092      * Returns whether the current position of this cursor is a valid position
0093      * (line + column must both be >= 0).
0094      *
0095      * @note If you want to check, whether a cursor position is a valid
0096      *       \e text-position, use DocumentCursor::isValidTextPosition(),
0097      *       or Document::isValidTextPosition().
0098      */
0099     Q_DECL_CONSTEXPR inline bool isValid() const Q_DECL_NOEXCEPT
0100     {
0101         return m_line >= 0 && m_column >= 0;
0102     }
0103 
0104     /**
0105      * Returns an invalid cursor.
0106      * The returned cursor position is set to (-1, -1).
0107      * \see isValid()
0108      */
0109     Q_DECL_CONSTEXPR static Cursor invalid() Q_DECL_NOEXCEPT
0110     {
0111         return Cursor(-1, -1);
0112     }
0113 
0114     /**
0115      * Returns a cursor representing the start of any document - i.e., line 0, column 0.
0116      */
0117     Q_DECL_CONSTEXPR static Cursor start() Q_DECL_NOEXCEPT
0118     {
0119         return Cursor();
0120     }
0121 
0122     /**
0123      * Returns the cursor position as string in the format "(line, column)".
0124      * \see fromString()
0125      */
0126     QString toString() const
0127     {
0128         return QLatin1Char('(') + QString::number(m_line) + QLatin1String(", ") + QString::number(m_column) + QLatin1Char(')');
0129     }
0130 
0131     /**
0132      * Returns a Cursor created from the string \p str containing the format
0133      * "(line, column)". In case the string cannot be parsed, Cursor::invalid()
0134      * is returned.
0135      * \see toString()
0136      */
0137     // TODO KF6: Remove this overload in favor of fromString(QStringView).
0138     static Cursor fromString(const QString &str) Q_DECL_NOEXCEPT
0139     {
0140         return fromString(str.leftRef(-1));
0141     }
0142 
0143     /**
0144      * Returns a Cursor created from the string \p str containing the format
0145      * "(line, column)". In case the string cannot be parsed, Cursor::invalid()
0146      * is returned.
0147      * \see toString()
0148      */
0149     // TODO KF6: Remove this overload in favor of fromString(QStringView).
0150     static Cursor fromString(const QStringRef &str) Q_DECL_NOEXCEPT;
0151 
0152     /**
0153      * Returns a Cursor created from the string \p str containing the format
0154      * "(line, column)". In case the string cannot be parsed, Cursor::invalid()
0155      * is returned.
0156      * \see toString()
0157      */
0158     static Cursor fromString(QStringView str) Q_DECL_NOEXCEPT;
0159 
0160     /**
0161      * \name Position
0162      *
0163      * The following functions provide access to, and manipulation of, the cursor's position.
0164      * \{
0165      */
0166     /**
0167      * Set the current cursor position to \e position.
0168      *
0169      * \param position new cursor position
0170      */
0171     inline void setPosition(const Cursor &position) Q_DECL_NOEXCEPT
0172     {
0173         m_line = position.m_line;
0174         m_column = position.m_column;
0175     }
0176 
0177     /**
0178      * \overload
0179      *
0180      * Set the cursor position to \e line and \e column.
0181      *
0182      * \param line new cursor line
0183      * \param column new cursor column
0184      */
0185     inline void setPosition(int line, int column) Q_DECL_NOEXCEPT
0186     {
0187         m_line = line;
0188         m_column = column;
0189     }
0190 
0191     /**
0192      * Retrieve the line on which this cursor is situated.
0193      * \return line number, where 0 is the first line.
0194      */
0195     Q_DECL_CONSTEXPR inline int line() const Q_DECL_NOEXCEPT
0196     {
0197         return m_line;
0198     }
0199 
0200     /**
0201      * Set the cursor line to \e line.
0202      * \param line new cursor line
0203      */
0204     inline void setLine(int line) Q_DECL_NOEXCEPT
0205     {
0206         m_line = line;
0207     }
0208 
0209     /**
0210      * Retrieve the column on which this cursor is situated.
0211      * \return column number, where 0 is the first column.
0212      */
0213     Q_DECL_CONSTEXPR inline int column() const Q_DECL_NOEXCEPT
0214     {
0215         return m_column;
0216     }
0217 
0218     /**
0219      * Set the cursor column to \e column.
0220      * \param column new cursor column
0221      */
0222     inline void setColumn(int column) Q_DECL_NOEXCEPT
0223     {
0224         m_column = column;
0225     }
0226 
0227     /**
0228      * Determine if this cursor is located at the start of a line (= at column 0).
0229      * \return \e true if the cursor is situated at the start of the line, \e false if it isn't.
0230      */
0231     Q_DECL_CONSTEXPR inline bool atStartOfLine() const Q_DECL_NOEXCEPT
0232     {
0233         return m_column == 0;
0234     }
0235 
0236     /**
0237      * Determine if this cursor is located at the start of a document (= at position (0, 0)).
0238      * \return \e true if the cursor is situated at the start of the document, \e false if it isn't.
0239      */
0240     Q_DECL_CONSTEXPR inline bool atStartOfDocument() const Q_DECL_NOEXCEPT
0241     {
0242         return m_line == 0 && m_column == 0;
0243     }
0244 
0245     /**
0246      * Get both the line and column of the cursor position.
0247      * \param line will be filled with current cursor line
0248      * \param column will be filled with current cursor column
0249      */
0250     inline void position(int &line, int &column) const Q_DECL_NOEXCEPT
0251     {
0252         line = m_line;
0253         column = m_column;
0254     }
0255     //!\}
0256 
0257     /**
0258      * Addition operator. Takes two cursors and returns their summation.
0259      * \param c1 the first position
0260      * \param c2 the second position
0261      * \return a the summation of the two input cursors
0262      */
0263     Q_DECL_CONSTEXPR inline friend Cursor operator+(const Cursor &c1, const Cursor &c2) Q_DECL_NOEXCEPT
0264     {
0265         return Cursor(c1.line() + c2.line(), c1.column() + c2.column());
0266     }
0267 
0268     /**
0269      * Addition assignment operator. Adds \p c2 to this cursor.
0270      * \param c1 the cursor being added to
0271      * \param c2 the position to add
0272      * \return a reference to the cursor which has just been added to
0273      */
0274     inline friend Cursor &operator+=(Cursor &c1, const Cursor &c2) Q_DECL_NOEXCEPT
0275     {
0276         c1.setPosition(c1.line() + c2.line(), c1.column() + c2.column());
0277         return c1;
0278     }
0279 
0280     /**
0281      * Subtraction operator. Takes two cursors and returns the subtraction
0282      * of \p c2 from \p c1.
0283      *
0284      * \param c1 the first position
0285      * \param c2 the second position
0286      * \return a cursor representing the subtraction of \p c2 from \p c1
0287      */
0288     Q_DECL_CONSTEXPR inline friend Cursor operator-(const Cursor &c1, const Cursor &c2) Q_DECL_NOEXCEPT
0289     {
0290         return Cursor(c1.line() - c2.line(), c1.column() - c2.column());
0291     }
0292 
0293     /**
0294      * Subtraction assignment operator. Subtracts \p c2 from \p c1.
0295      * \param c1 the cursor being subtracted from
0296      * \param c2 the position to subtract
0297      * \return a reference to the cursor which has just been subtracted from
0298      */
0299     inline friend Cursor &operator-=(Cursor &c1, const Cursor &c2) Q_DECL_NOEXCEPT
0300     {
0301         c1.setPosition(c1.line() - c2.line(), c1.column() - c2.column());
0302         return c1;
0303     }
0304 
0305     /**
0306      * Equality operator.
0307      *
0308      * \note comparison between two invalid cursors is undefined.
0309      *       comparison between and invalid and a valid cursor will always be \e false.
0310      *
0311      * \param c1 first cursor to compare
0312      * \param c2 second cursor to compare
0313      * \return \e true, if c1's and c2's line and column are \e equal.
0314      */
0315     Q_DECL_CONSTEXPR inline friend bool operator==(const Cursor &c1, const Cursor &c2) Q_DECL_NOEXCEPT
0316     {
0317         return c1.line() == c2.line() && c1.column() == c2.column();
0318     }
0319 
0320     /**
0321      * Inequality operator.
0322      * \param c1 first cursor to compare
0323      * \param c2 second cursor to compare
0324      * \return \e true, if c1's and c2's line and column are \e not equal.
0325      */
0326     Q_DECL_CONSTEXPR inline friend bool operator!=(const Cursor &c1, const Cursor &c2) Q_DECL_NOEXCEPT
0327     {
0328         return !(c1 == c2);
0329     }
0330 
0331     /**
0332      * Greater than operator.
0333      * \param c1 first cursor to compare
0334      * \param c2 second cursor to compare
0335      * \return \e true, if c1's position is greater than c2's position,
0336      *         otherwise \e false.
0337      */
0338     Q_DECL_CONSTEXPR inline friend bool operator>(const Cursor &c1, const Cursor &c2) Q_DECL_NOEXCEPT
0339     {
0340         return c1.line() > c2.line() || (c1.line() == c2.line() && c1.m_column > c2.m_column);
0341     }
0342 
0343     /**
0344      * Greater than or equal to operator.
0345      * \param c1 first cursor to compare
0346      * \param c2 second cursor to compare
0347      * \return \e true, if c1's position is greater than or equal to c2's
0348      *         position, otherwise \e false.
0349      */
0350     Q_DECL_CONSTEXPR inline friend bool operator>=(const Cursor &c1, const Cursor &c2) Q_DECL_NOEXCEPT
0351     {
0352         return c1.line() > c2.line() || (c1.line() == c2.line() && c1.m_column >= c2.m_column);
0353     }
0354 
0355     /**
0356      * Less than operator.
0357      * \param c1 first cursor to compare
0358      * \param c2 second cursor to compare
0359      * \return \e true, if c1's position is greater than or equal to c2's
0360      *         position, otherwise \e false.
0361      */
0362     Q_DECL_CONSTEXPR inline friend bool operator<(const Cursor &c1, const Cursor &c2) Q_DECL_NOEXCEPT
0363     {
0364         return !(c1 >= c2);
0365     }
0366 
0367     /**
0368      * Less than or equal to operator.
0369      * \param c1 first cursor to compare
0370      * \param c2 second cursor to compare
0371      * \return \e true, if c1's position is lesser than or equal to c2's
0372      *         position, otherwise \e false.
0373      */
0374     Q_DECL_CONSTEXPR inline friend bool operator<=(const Cursor &c1, const Cursor &c2) Q_DECL_NOEXCEPT
0375     {
0376         return !(c1 > c2);
0377     }
0378 
0379     /**
0380      * qDebug() stream operator.  Writes this cursor to the debug output in a nicely formatted way.
0381      */
0382     inline friend QDebug operator<<(QDebug s, const Cursor &cursor)
0383     {
0384         s.nospace() << "(" << cursor.line() << ", " << cursor.column() << ")";
0385         return s.space();
0386     }
0387 
0388 private:
0389     /**
0390      * \internal
0391      *
0392      * Cursor line
0393      */
0394     int m_line = 0;
0395 
0396     /**
0397      * \internal
0398      *
0399      * Cursor column
0400      */
0401     int m_column = 0;
0402 };
0403 
0404 } // namespace KTextEditor
0405 
0406 Q_DECLARE_TYPEINFO(KTextEditor::Cursor, Q_MOVABLE_TYPE);
0407 Q_DECLARE_METATYPE(KTextEditor::Cursor)
0408 
0409 /**
0410  * QHash function for KTextEditor::Cursor.
0411  * Returns the hash value for @p cursor.
0412  */
0413 inline uint qHash(const KTextEditor::Cursor &cursor, uint seed = 0) Q_DECL_NOTHROW
0414 {
0415     return qHash(qMakePair(cursor.line(), cursor.column()), seed);
0416 }
0417 
0418 namespace QTest
0419 {
0420 // forward declaration of template in qtestcase.h
0421 template<typename T>
0422 char *toString(const T &);
0423 
0424 /**
0425  * QTestLib integration to have nice output in e.g. QCOMPARE failures.
0426  */
0427 template<>
0428 KTEXTEDITOR_EXPORT char *toString(const KTextEditor::Cursor &cursor);
0429 }
0430 
0431 #endif