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