1/* This file is part of the KDE project
2 Copyright (C) 2003-2005 Hamish Rodda <rodda@kde.org>
3 Copyright (C) 2001-2005 Christoph Cullmann <cullmann@kde.org>
4 Copyright (C) 2014 Dominik Haumann <dhaumann@kde.org>
5 Copyright (C) 2002 Christian Couder <christian@kdevelop.org>
6 Copyright (C) 2001 Joseph Wenninger <jowenn@kde.org>
7 Copyright (C) 1999 Jochen Wilhelmy <digisnap@cs.tu-berlin.de>
8
9 This library is free software; you can redistribute it and/or
10 modify it under the terms of the GNU Library General Public
11 License as published by the Free Software Foundation; either
12 version 2 of the License, or (at your option) any later version.
13
14 This library is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 Library General Public License for more details.
18
19 You should have received a copy of the GNU Library General Public License
20 along with this library; see the file COPYING.LIB. If not, write to
21 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
22 Boston, MA 02110-1301, USA.
23*/
24
25#ifndef KTEXTEDITOR_CURSOR_H
26#define KTEXTEDITOR_CURSOR_H
27
28#include <ktexteditor_export.h>
29
30#include <QDebug>
31#include <QtGlobal>
32
33namespace KTextEditor
34{
35class Document;
36class Range;
37
38/**
39 * \short The Cursor represents a position in a Document.
40 *
41 * \section kte_cursor_intro Introduction
42 * A Cursor represents a position in a Document through a tuple
43 * of two int%s, namely the line() and column(). A Cursor maintains
44 * no affiliation with a particular Document, meaning that it remains
45 * constant if not changed through the Cursor API.
46 *
47 * \section kte_cursor_notes Important Notes
48 *
49 * Working with a cursor, one should be aware of the following notes:
50 * - Lines and columns start a 0.
51 * - The Cursor class is designed to be passed by value (only 8 Bytes).
52 * - Think of cursors as having their position at the start of a character,
53 * not in the middle of one.
54 * - invalid() Cursor%s are located at (-1, -1). In addition, a Cursor
55 * is invalid(), if either its line() and/or its column() is arbitrarily
56 * negative, i.e. < 0.
57 * - All Cursor%s with line() >= 0 and column() >= 0 are valid. In this case
58 * isValid() returns \e true.
59 * - A Cursor has a non-virtual destructor. Hence, you cannot derive from Cursor.
60 *
61 * \section kte_cursor_properties Cursor Efficiency
62 *
63 * The Cursor consists of just two int%s, the line() and the column().
64 * Therefore, a Cursor instance takes 8 Bytes of memory. Further, a Cursor
65 * is a non-virtual class, turning it into a primitive old data type (POD).
66 * Thus, it can be moved and copied very efficiently.
67 *
68 * \section kte_cursor_more Additional Concepts
69 *
70 * In addition to the Cursor, the KTextEditor API provides advanced concepts:
71 * - The DocumentCursor is a Cursor bound to a specific Document. In addition
72 * to the Cursor API, it provides convenience functions like
73 * DocumentCursor::isValidTextPosition() or DocumentCursor::move().
74 * The DocumentCursor does not maintain its position, though.
75 * - The MovingCursor is also bound to a specific Document. In addition to the
76 * DocumentCursor, the MovingCursor maintains its position, meaning that
77 * whenever the Document changes, the MovingCursor moves, too.
78 * - The Cursor forms the basis for the Range.
79 *
80 * \sa DocumentCursor, MovingCursor, Range
81 */
82class KTEXTEDITOR_EXPORT Cursor
83{
84public:
85 /**
86 * The default constructor creates a cursor at position (0, 0).
87 */
88 Q_DECL_CONSTEXPR Cursor() Q_DECL_NOEXCEPT
89 {
90 }
91
92 /**
93 * This constructor creates a cursor initialized with \p line
94 * and \p column.
95 * \param line line for cursor
96 * \param column column for cursor
97 */
98 Q_DECL_CONSTEXPR Cursor(int line, int column) Q_DECL_NOEXCEPT
99 : m_line(line)
100 , m_column(column)
101 {
102 }
103
104 /**
105 * Returns whether the current position of this cursor is a valid position
106 * (line + column must both be >= 0).
107 *
108 * @note If you want to check, whether a cursor position is a valid
109 * \e text-position, use DocumentCursor::isValidTextPosition(),
110 * or Document::isValidTextPosition().
111 */
112 Q_DECL_CONSTEXPR inline bool isValid() const Q_DECL_NOEXCEPT {
113 return m_line >= 0 && m_column >= 0;
114 }
115
116 /**
117 * Returns an invalid cursor.
118 * The returned cursor position is set to (-1, -1).
119 * \see isValid()
120 */
121 Q_DECL_CONSTEXPR static Cursor invalid() Q_DECL_NOEXCEPT {
122 return Cursor(-1, -1);
123 }
124
125 /**
126 * Returns a cursor representing the start of any document - i.e., line 0, column 0.
127 */
128 Q_DECL_CONSTEXPR static Cursor start() Q_DECL_NOEXCEPT {
129 return Cursor();
130 }
131
132 /**
133 * Returns the cursor position as string in the format "(line, column)".
134 * \see fromString()
135 */
136 QString toString() const {
137 return QLatin1Char('(') + QString::number(m_line)
138 + QStringLiteral(", ") + QString::number(m_column)
139 + QLatin1Char(')');
140 }
141
142 /**
143 * Returns a Cursor created from the string \p str containing the format
144 * "(line, column)". In case the string cannot be parsed, Cursor::invalid()
145 * is returned.
146 * \see toString()
147 */
148 static Cursor fromString(const QString& str) Q_DECL_NOEXCEPT {
149 return fromString(str.leftRef(-1));
150 }
151
152 /**
153 * Returns a Cursor created from the string \p str containing the format
154 * "(line, column)". In case the string cannot be parsed, Cursor::invalid()
155 * is returned.
156 * \see toString()
157 */
158 static Cursor fromString(const QStringRef& str) Q_DECL_NOEXCEPT;
159
160 /**
161 * \name Position
162 *
163 * The following functions provide access to, and manipulation of, the cursor's position.
164 * \{
165 */
166 /**
167 * Set the current cursor position to \e position.
168 *
169 * \param position new cursor position
170 */
171 inline void setPosition(const Cursor &position) Q_DECL_NOEXCEPT {
172 m_line = position.m_line;
173 m_column = position.m_column;
174 }
175
176 /**
177 * \overload
178 *
179 * Set the cursor position to \e line and \e column.
180 *
181 * \param line new cursor line
182 * \param column new cursor column
183 */
184 inline void setPosition(int line, int column) Q_DECL_NOEXCEPT {
185 m_line = line;
186 m_column = column;
187 }
188
189 /**
190 * Retrieve the line on which this cursor is situated.
191 * \return line number, where 0 is the first line.
192 */
193 Q_DECL_CONSTEXPR inline int line() const Q_DECL_NOEXCEPT {
194 return m_line;
195 }
196
197 /**
198 * Set the cursor line to \e line.
199 * \param line new cursor line
200 */
201 inline void setLine(int line) Q_DECL_NOEXCEPT {
202 m_line = line;
203 }
204
205 /**
206 * Retrieve the column on which this cursor is situated.
207 * \return column number, where 0 is the first column.
208 */
209 Q_DECL_CONSTEXPR inline int column() const Q_DECL_NOEXCEPT {
210 return m_column;
211 }
212
213 /**
214 * Set the cursor column to \e column.
215 * \param column new cursor column
216 */
217 inline void setColumn(int column) Q_DECL_NOEXCEPT {
218 m_column = column;
219 }
220
221 /**
222 * Determine if this cursor is located at the start of a line (= at column 0).
223 * \return \e true if the cursor is situated at the start of the line, \e false if it isn't.
224 */
225 Q_DECL_CONSTEXPR inline bool atStartOfLine() const Q_DECL_NOEXCEPT {
226 return m_column == 0;
227 }
228
229 /**
230 * Determine if this cursor is located at the start of a document (= at position (0, 0)).
231 * \return \e true if the cursor is situated at the start of the document, \e false if it isn't.
232 */
233 Q_DECL_CONSTEXPR inline bool atStartOfDocument() const Q_DECL_NOEXCEPT {
234 return m_line == 0 && m_column == 0;
235 }
236
237 /**
238 * Get both the line and column of the cursor position.
239 * \param line will be filled with current cursor line
240 * \param column will be filled with current cursor column
241 */
242 inline void position(int &line, int &column) const Q_DECL_NOEXCEPT {
243 line = m_line;
244 column = m_column;
245 }
246 //!\}
247
248 /**
249 * Addition operator. Takes two cursors and returns their summation.
250 * \param c1 the first position
251 * \param c2 the second position
252 * \return a the summation of the two input cursors
253 */
254 Q_DECL_CONSTEXPR inline friend Cursor operator+(const Cursor &c1, const Cursor &c2) Q_DECL_NOEXCEPT {
255 return Cursor(c1.line() + c2.line(), c1.column() + c2.column());
256 }
257
258 /**
259 * Addition assignment operator. Adds \p c2 to this cursor.
260 * \param c1 the cursor being added to
261 * \param c2 the position to add
262 * \return a reference to the cursor which has just been added to
263 */
264 inline friend Cursor &operator+=(Cursor &c1, const Cursor &c2) Q_DECL_NOEXCEPT {
265 c1.setPosition(c1.line() + c2.line(), c1.column() + c2.column());
266 return c1;
267 }
268
269 /**
270 * Subtraction operator. Takes two cursors and returns the subtraction
271 * of \p c2 from \p c1.
272 *
273 * \param c1 the first position
274 * \param c2 the second position
275 * \return a cursor representing the subtraction of \p c2 from \p c1
276 */
277 Q_DECL_CONSTEXPR inline friend Cursor operator-(const Cursor &c1, const Cursor &c2) Q_DECL_NOEXCEPT {
278 return Cursor(c1.line() - c2.line(), c1.column() - c2.column());
279 }
280
281 /**
282 * Subtraction assignment operator. Subtracts \p c2 from \p c1.
283 * \param c1 the cursor being subtracted from
284 * \param c2 the position to subtract
285 * \return a reference to the cursor which has just been subtracted from
286 */
287 inline friend Cursor &operator-=(Cursor &c1, const Cursor &c2) Q_DECL_NOEXCEPT {
288 c1.setPosition(c1.line() - c2.line(), c1.column() - c2.column());
289 return c1;
290 }
291
292 /**
293 * Equality operator.
294 *
295 * \note comparison between two invalid cursors is undefined.
296 * comparison between and invalid and a valid cursor will always be \e false.
297 *
298 * \param c1 first cursor to compare
299 * \param c2 second cursor to compare
300 * \return \e true, if c1's and c2's line and column are \e equal.
301 */
302 Q_DECL_CONSTEXPR inline friend bool operator==(const Cursor &c1, const Cursor &c2) Q_DECL_NOEXCEPT {
303 return c1.line() == c2.line() && c1.column() == c2.column();
304 }
305
306 /**
307 * Inequality operator.
308 * \param c1 first cursor to compare
309 * \param c2 second cursor to compare
310 * \return \e true, if c1's and c2's line and column are \e not equal.
311 */
312 Q_DECL_CONSTEXPR inline friend bool operator!=(const Cursor &c1, const Cursor &c2) Q_DECL_NOEXCEPT {
313 return !(c1 == c2);
314 }
315
316 /**
317 * Greater than operator.
318 * \param c1 first cursor to compare
319 * \param c2 second cursor to compare
320 * \return \e true, if c1's position is greater than c2's position,
321 * otherwise \e false.
322 */
323 Q_DECL_CONSTEXPR inline friend bool operator>(const Cursor &c1, const Cursor &c2) Q_DECL_NOEXCEPT {
324 return c1.line() > c2.line() || (c1.line() == c2.line() && c1.m_column > c2.m_column);
325 }
326
327 /**
328 * Greater than or equal to operator.
329 * \param c1 first cursor to compare
330 * \param c2 second cursor to compare
331 * \return \e true, if c1's position is greater than or equal to c2's
332 * position, otherwise \e false.
333 */
334 Q_DECL_CONSTEXPR inline friend bool operator>=(const Cursor &c1, const Cursor &c2) Q_DECL_NOEXCEPT{
335 return c1.line() > c2.line() || (c1.line() == c2.line() && c1.m_column >= c2.m_column);
336 }
337
338 /**
339 * Less than operator.
340 * \param c1 first cursor to compare
341 * \param c2 second cursor to compare
342 * \return \e true, if c1's position is greater than or equal to c2's
343 * position, otherwise \e false.
344 */
345 Q_DECL_CONSTEXPR inline friend bool operator<(const Cursor &c1, const Cursor &c2) Q_DECL_NOEXCEPT {
346 return !(c1 >= c2);
347 }
348
349 /**
350 * Less than or equal to operator.
351 * \param c1 first cursor to compare
352 * \param c2 second cursor to compare
353 * \return \e true, if c1's position is lesser than or equal to c2's
354 * position, otherwise \e false.
355 */
356 Q_DECL_CONSTEXPR inline friend bool operator<=(const Cursor &c1, const Cursor &c2) Q_DECL_NOEXCEPT {
357 return !(c1 > c2);
358 }
359
360 /**
361 * qDebug() stream operator. Writes this cursor to the debug output in a nicely formatted way.
362 */
363 inline friend QDebug operator<< (QDebug s, const Cursor &cursor) {
364 s.nospace() << "(" << cursor.line() << ", " << cursor.column() << ")";
365 return s.space();
366 }
367
368private:
369 /**
370 * \internal
371 *
372 * Cursor line
373 */
374 int m_line = 0;
375
376 /**
377 * \internal
378 *
379 * Cursor column
380 */
381 int m_column = 0;
382};
383
384} // namespace KTextEditor
385
386Q_DECLARE_TYPEINFO(KTextEditor::Cursor, Q_MOVABLE_TYPE);
387Q_DECLARE_METATYPE(KTextEditor::Cursor)
388
389/**
390 * QHash function for KTextEditor::Cursor.
391 * Returns the hash value for @p cursor.
392 */
393inline uint qHash(const KTextEditor::Cursor& cursor, uint seed = 0) Q_DECL_NOTHROW
394{
395 return qHash(qMakePair(cursor.line(), cursor.column()), seed);
396}
397
398namespace QTest
399{
400 // forward declaration of template in qtestcase.h
401 template<typename T> char* toString(const T&);
402
403 /**
404 * QTestLib integration to have nice output in e.g. QCOMPARE failures.
405 */
406 template<>
407 KTEXTEDITOR_EXPORT char *toString(const KTextEditor::Cursor &cursor);
408}
409
410#endif
411
412