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

source code of ktexteditor/src/include/ktexteditor/cursor.h