File indexing completed on 2024-05-19 04:00:02

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