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