KTextEditor

katetextbuffer.h
1/*
2 SPDX-FileCopyrightText: 2010 Christoph Cullmann <cullmann@kde.org>
3
4 SPDX-License-Identifier: LGPL-2.0-or-later
5*/
6#ifndef KATE_TEXTBUFFER_H
7#define KATE_TEXTBUFFER_H
8
9#include <QList>
10#include <QObject>
11#include <QSet>
12#include <QString>
13
14#include "katetextblock.h"
15#include "katetexthistory.h"
16#include <ktexteditor_export.h>
17
18// encoding prober
19#include <KEncodingProber>
20
21namespace KTextEditor
22{
23class DocumentPrivate;
24}
25
27
28namespace Kate
29{
30class TextRange;
31class TextCursor;
32class TextBlock;
33
34constexpr int BufferBlockSize = 64;
35
36/**
37 * Class representing a text buffer.
38 * The interface is line based, internally the text will be stored in blocks of text lines.
39 */
40class KTEXTEDITOR_EXPORT TextBuffer : public QObject
41{
42 friend class TextCursor;
43 friend class TextRange;
44 friend class TextBlock;
45
46 Q_OBJECT
47
48public:
49 /**
50 * End of line mode
51 */
52 enum EndOfLineMode { eolUnknown = -1, eolUnix = 0, eolDos = 1, eolMac = 2 };
53
54 /**
55 * Construct an empty text buffer.
56 * Empty means one empty line in one block.
57 * @param parent parent qobject
58 */
59 explicit TextBuffer(KTextEditor::DocumentPrivate *parent, bool alwaysUseKAuth = false);
60
61 /**
62 * Destruct the text buffer
63 * Virtual, we allow inheritance
64 */
65 ~TextBuffer() override;
66
67 /**
68 * Clears the buffer, reverts to initial empty state.
69 * Empty means one empty line in one block.
70 * Virtual, can be overwritten.
71 */
72 virtual void clear();
73
74 /**
75 * Set encoding prober type for this buffer to use for load.
76 * @param proberType prober type to use for encoding
77 */
78 void setEncodingProberType(KEncodingProber::ProberType proberType)
79 {
80 m_encodingProberType = proberType;
81 }
82
83 /**
84 * Get encoding prober type for this buffer
85 * @return currently in use prober type of this buffer
86 */
87 KEncodingProber::ProberType encodingProberType() const
88 {
89 return m_encodingProberType;
90 }
91
92 /**
93 * Set fallback codec for this buffer to use for load.
94 * @param codec fallback to use for encoding
95 */
96 void setFallbackTextCodec(const QString &codec)
97 {
98 m_fallbackTextCodec = codec;
99 }
100
101 /**
102 * Get fallback codec for this buffer
103 * @return currently in use fallback codec of this buffer
104 */
106 {
107 return m_fallbackTextCodec;
108 }
109
110 /**
111 * Set codec for this buffer to use for load/save.
112 * Loading might overwrite this, if it encounters problems and finds a better codec.
113 * Might change BOM setting.
114 * @param codec to use for encoding
115 */
116 void setTextCodec(const QString &codec);
117
118 /**
119 * Get codec for this buffer
120 * @return currently in use codec of this buffer
121 */
123 {
124 return m_textCodec;
125 }
126
127 /**
128 * Generate byte order mark on save.
129 * Loading might overwrite this setting, if there is a BOM found inside the file.
130 * @param generateByteOrderMark should BOM be generated?
131 */
132 void setGenerateByteOrderMark(bool generateByteOrderMark)
133 {
134 m_generateByteOrderMark = generateByteOrderMark;
135 }
136
137 /**
138 * Generate byte order mark on save?
139 * @return should BOM be generated?
140 */
142 {
143 return m_generateByteOrderMark;
144 }
145
146 /**
147 * Set end of line mode for this buffer, not allowed to be set to unknown.
148 * Loading might overwrite this setting, if there is a eol found inside the file.
149 * @param endOfLineMode new eol mode
150 */
151 void setEndOfLineMode(EndOfLineMode endOfLineMode)
152 {
153 Q_ASSERT(endOfLineMode != eolUnknown);
154 m_endOfLineMode = endOfLineMode;
155 }
156
157 /**
158 * Get end of line mode
159 * @return end of line mode
160 */
162 {
163 return m_endOfLineMode;
164 }
165
166 /**
167 * Set line length limit
168 * @param lineLengthLimit new line length limit
169 */
170 void setLineLengthLimit(int lineLengthLimit)
171 {
172 m_lineLengthLimit = lineLengthLimit;
173 }
174
175 /**
176 * Load the given file. This will first clear the buffer and then load the file.
177 * Even on error during loading the buffer will still be cleared.
178 * Before calling this, setTextCodec must have been used to set codec!
179 * @param filename file to open
180 * @param encodingErrors were there problems occurred while decoding the file?
181 * @param tooLongLinesWrapped were too long lines found and wrapped?
182 * @param longestLineLoaded the longest line in the file (before wrapping)
183 * @param enforceTextCodec enforce to use only the set text codec
184 * @return success, the file got loaded, perhaps with encoding errors
185 * Virtual, can be overwritten.
186 */
187 virtual bool load(const QString &filename, bool &encodingErrors, bool &tooLongLinesWrapped, int &longestLineLoaded, bool enforceTextCodec);
188
189 /**
190 * Save the current buffer content to the given file.
191 * Before calling this, setTextCodec and setFallbackTextCodec must have been used to set codec!
192 * @param filename file to save
193 * @return success
194 * Virtual, can be overwritten.
195 */
196 virtual bool save(const QString &filename);
197
198 /**
199 * Lines currently stored in this buffer.
200 * This is never 0, even clear will let one empty line remain.
201 */
202 int lines() const
203 {
204 Q_ASSERT(m_lines > 0);
205 return m_lines;
206 }
207
208 /**
209 * Revision of this buffer. Is set to 0 on construction, clear() (load will trigger clear()).
210 * Is incremented on each change to the buffer.
211 * @return current revision
212 */
213 qint64 revision() const
214 {
215 return m_revision;
216 }
217
218 /**
219 * Retrieve a text line.
220 * @param line wanted line number
221 * @return text line
222 */
223 TextLine line(int line) const;
224
225 /**
226 * Transfer all non text attributes for the given line from the given text line to the one in the buffer.
227 * @param line line number to set attributes
228 * @param textLine line reference to get attributes from
229 */
230 void setLineMetaData(int line, const TextLine &textLine);
231
232 /**
233 * Retrieve length for @p line
234 * @param line wanted line number
235 * @return length of the line
236 */
237 int lineLength(int line) const
238 {
239 // get block, this will assert on invalid line
240 int blockIndex = blockForLine(line);
241
242 // get line length
243 return m_blocks.at(blockIndex)->lineLength(line);
244 }
245
246 /**
247 * Retrieve offset in text for the given cursor position
248 */
249 int cursorToOffset(KTextEditor::Cursor c) const;
250
251 /**
252 * Retrieve cursor in text for the given offset
253 */
254 KTextEditor::Cursor offsetToCursor(int offset) const;
255
256 /**
257 * Retrieve text of complete buffer.
258 * @return text for this buffer, lines separated by '\n'
259 */
260 QString text() const;
261
262 /**
263 * Start an editing transaction, the wrapLine/unwrapLine/insertText and removeText functions
264 * are only allowed to be called inside a editing transaction.
265 * Editing transactions can stack. The number of startEdit and endEdit calls must match.
266 * @return returns true, if no transaction was already running
267 * Virtual, can be overwritten.
268 */
269 virtual bool startEditing();
270
271 /**
272 * Finish an editing transaction. Only allowed to be called if editing transaction is started.
273 * @return returns true, if this finished last running transaction
274 * Virtual, can be overwritten.
275 */
276 virtual bool finishEditing();
277
278 /**
279 * Query the number of editing transactions running atm.
280 * @return number of running transactions
281 */
283 {
284 return m_editingTransactions;
285 }
286
287 /**
288 * Query the revision of this buffer before the ongoing editing transactions.
289 * @return revision of buffer before current editing transaction altered it
290 */
291 qint64 editingLastRevision() const
292 {
293 return m_editingLastRevision;
294 }
295
296 /**
297 * Query the number of lines of this buffer before the ongoing editing transactions.
298 * @return number of lines of buffer before current editing transaction altered it
299 */
301 {
302 return m_editingLastLines;
303 }
304
305 /**
306 * Query information from the last editing transaction: was the content of the buffer changed?
307 * This is checked by comparing the editingLastRevision() with the current revision().
308 * @return content of buffer was changed in last transaction?
309 */
311 {
312 return editingLastRevision() != revision();
313 }
314
315 /**
316 * Query information from the last editing transaction: was the number of lines of the buffer changed?
317 * This is checked by comparing the editingLastLines() with the current lines().
318 * @return content of buffer was changed in last transaction?
319 */
321 {
322 return editingLastLines() != lines();
323 }
324
325 /**
326 * Get minimal line number changed by last editing transaction
327 * @return maximal line number changed by last editing transaction, or -1, if none changed
328 */
330 {
331 return m_editingMinimalLineChanged;
332 }
333
334 /**
335 * Get maximal line number changed by last editing transaction
336 * @return maximal line number changed by last editing transaction, or -1, if none changed
337 */
339 {
340 return m_editingMaximalLineChanged;
341 }
342
343 /**
344 * Wrap line at given cursor position.
345 * @param position line/column as cursor where to wrap
346 * Virtual, can be overwritten.
347 */
348 virtual void wrapLine(const KTextEditor::Cursor position);
349
350 /**
351 * Unwrap given line.
352 * @param line line to unwrap
353 * Virtual, can be overwritten.
354 */
355 virtual void unwrapLine(int line);
356
357 /**
358 * Insert text at given cursor position. Does nothing if text is empty, beside some consistency checks.
359 * @param position position where to insert text
360 * @param text text to insert
361 * Virtual, can be overwritten.
362 */
363 virtual void insertText(const KTextEditor::Cursor position, const QString &text);
364
365 /**
366 * Remove text at given range. Does nothing if range is empty, beside some consistency checks.
367 * @param range range of text to remove, must be on one line only.
368 * Virtual, can be overwritten.
369 */
370 virtual void removeText(KTextEditor::Range range);
371
372 /**
373 * TextHistory of this buffer
374 * @return text history for this buffer
375 */
377 {
378 return m_history;
379 }
380
381Q_SIGNALS:
382 /**
383 * Buffer got cleared. This is emitted when constructor or load have called clear() internally,
384 * or when the user of the buffer has called clear() itself.
385 */
386 void cleared();
387
388 /**
389 * Buffer loaded successfully a file
390 * @param filename file which was loaded
391 * @param encodingErrors were there problems occurred while decoding the file?
392 */
393 void loaded(const QString &filename, bool encodingErrors);
394
395 /**
396 * Buffer saved successfully a file
397 * @param filename file which was saved
398 */
399 void saved(const QString &filename);
400
401private:
402 /**
403 * Save result which indicates an abstract reason why the operation has
404 * failed
405 */
406 enum class SaveResult { Failed = 0, MissingPermissions, Success };
407
408 /**
409 * Find block containing given line.
410 * @param line we want to find block for this line
411 * @return index of found block
412 */
413 int blockForLine(int line) const;
414 // exported for movingrange_test
415
416 /**
417 * Fix start lines of all blocks after the given one
418 * @param startBlock index of block from which we start to fix
419 */
420 KTEXTEDITOR_NO_EXPORT
421 void fixStartLines(int startBlock);
422
423 /**
424 * Balance the given block. Look if it is too small or too large.
425 * @param index block to balance
426 */
427 KTEXTEDITOR_NO_EXPORT
428 void balanceBlock(int index);
429
430 /**
431 * A range changed, notify the views, in case of attributes or feedback.
432 * @param view which view is affected? nullptr for all views
433 * @param lineRange line range that the change spans
434 * @param needsRepaint do we need to trigger repaints? e.g. if ranges with attributes change
435 */
436 KTEXTEDITOR_NO_EXPORT
437 void notifyAboutRangeChange(KTextEditor::View *view, KTextEditor::LineRange lineRange, bool needsRepaint);
438
439 /**
440 * Mark all modified lines as lines saved on disk (modified line system).
441 */
442 KTEXTEDITOR_NO_EXPORT
443 void markModifiedLinesAsSaved();
444
445 /**
446 * Save the current buffer content to the given already opened device
447 *
448 * @param filename path name for display/debugging purposes
449 * @param saveFile open device to write the buffer to
450 */
451 KTEXTEDITOR_NO_EXPORT
452 bool saveBuffer(const QString &filename, KCompressionDevice &saveFile);
453
454 /**
455 * Attempt to save the buffer content in the given filename location using
456 * current privileges.
457 */
458 KTEXTEDITOR_NO_EXPORT
459 SaveResult saveBufferUnprivileged(const QString &filename);
460
461 /**
462 * Attempt to save the buffer content in the given filename location using
463 * escalated privileges.
464 */
465 KTEXTEDITOR_NO_EXPORT
466 bool saveBufferEscalated(const QString &filename);
467
468public:
469 /**
470 * Gets the document to which this buffer is bound.
471 * \return a pointer to the document
472 */
473 KTextEditor::DocumentPrivate *document() const
474 {
475 return m_document;
476 }
477
478 /**
479 * Debug output, print whole buffer content with line numbers and line length
480 * @param title title for this output
481 */
482 void debugPrint(const QString &title) const;
483
484 /**
485 * Return the ranges which affect the given line.
486 * @param line line to look at
487 * @param view only return ranges associated with given view
488 * @param rangesWithAttributeOnly only return ranges which have a attribute set
489 * @return list of ranges affecting this line
490 */
491 QList<TextRange *> rangesForLine(int line, KTextEditor::View *view, bool rangesWithAttributeOnly) const
492 {
493 // get block, this will assert on invalid line
494 const int blockIndex = blockForLine(line);
495 return m_blocks.at(blockIndex)->rangesForLine(line, view, rangesWithAttributeOnly);
496 }
497
498 void rangesForLine(int line, KTextEditor::View *view, bool rangesWithAttributeOnly, QList<TextRange *> &outRanges) const
499 {
500 // get block, this will assert on invalid line
501 const int blockIndex = blockForLine(line);
502 return m_blocks.at(blockIndex)->rangesForLine(line, view, rangesWithAttributeOnly, outRanges);
503 }
504
505 /**
506 * Check if the given range pointer is still valid.
507 * @return range pointer still belongs to range for this buffer
508 */
509 bool rangePointerValid(TextRange *range) const
510 {
511 return m_ranges.contains(range);
512 }
513
514 /**
515 * Invalidate all ranges in this buffer.
516 */
517 void invalidateRanges();
518
519 //
520 // checksum handling
521 //
522public:
523 /**
524 * Checksum of the document on disk, set either through file loading
525 * in openFile() or in KTextEditor::DocumentPrivate::saveFile()
526 * @return git compatible sha1 checksum for this document
527 */
528 const QByteArray &digest() const;
529
530 /**
531 * Set the checksum of this buffer. Make sure this checksum is up-to-date
532 * when reading digest().
533 * @param checksum git compatible sha1 digest for the document on disk
534 */
535 void setDigest(const QByteArray &checksum);
536
537private:
538 QByteArray m_digest;
539
540private:
541 /**
542 * parent document
543 */
544 KTextEditor::DocumentPrivate *m_document;
545
546 /**
547 * text history
548 */
549 TextHistory m_history;
550
551 /**
552 * List of blocks which contain the lines of this buffer
553 */
554 std::vector<TextBlock *> m_blocks;
555
556 /**
557 * Number of lines in buffer
558 */
559 int m_lines;
560
561 /**
562 * Revision of the buffer.
563 */
564 qint64 m_revision;
565
566 /**
567 * Current number of running edit transactions
568 */
569 int m_editingTransactions;
570
571 /**
572 * Revision remembered at start of current editing transaction
573 */
574 qint64 m_editingLastRevision;
575
576 /**
577 * Number of lines remembered at start of current editing transaction
578 */
579 int m_editingLastLines;
580
581 /**
582 * minimal line number changed by last editing transaction
583 */
584 int m_editingMinimalLineChanged;
585
586 /**
587 * maximal line number changed by last editing transaction
588 */
589 int m_editingMaximalLineChanged;
590
591 /**
592 * Set of invalid cursors for this whole buffer.
593 * Valid cursors are inside the block the belong to.
594 */
595 QSet<TextCursor *> m_invalidCursors;
596
597 /**
598 * Set of ranges of this whole buffer.
599 */
600 QSet<TextRange *> m_ranges;
601
602 /**
603 * Encoding prober type to use
604 */
605 KEncodingProber::ProberType m_encodingProberType;
606
607 /**
608 * Fallback text codec to use
609 */
610 QString m_fallbackTextCodec;
611
612 /**
613 * Text codec to use
614 */
615 QString m_textCodec;
616
617 /**
618 * Mime-Type used for transparent compression/decompression support
619 * Set by load(), reset by clear()
620 */
621 QString m_mimeTypeForFilterDev;
622
623 /**
624 * Should byte order mark be created?
625 */
626 bool m_generateByteOrderMark;
627
628 /**
629 * End of line mode, default is Unix
630 */
631 EndOfLineMode m_endOfLineMode;
632
633 /**
634 * Limit for line length, longer lines will be wrapped on load
635 */
636 int m_lineLengthLimit;
637
638 /**
639 * For unit-testing purposes only.
640 */
641 bool m_alwaysUseKAuthForSave;
642
643 /**
644 * For copying QBuffer -> QTemporaryFile while saving document in privileged mode
645 */
646 static const qint64 bufferLength = 4096;
647};
648
649}
650
651#endif
The Cursor represents a position in a Document.
Definition cursor.h:75
An object representing lines from a start line to an end line.
Definition linerange.h:41
An object representing a section of text, from one Cursor to another.
A text widget with KXMLGUIClient that represents a Document.
Definition view.h:244
Class representing a text block.
Class representing a text buffer.
void setEncodingProberType(KEncodingProber::ProberType proberType)
Set encoding prober type for this buffer to use for load.
qint64 editingLastRevision() const
Query the revision of this buffer before the ongoing editing transactions.
KEncodingProber::ProberType encodingProberType() const
Get encoding prober type for this buffer.
QList< TextRange * > rangesForLine(int line, KTextEditor::View *view, bool rangesWithAttributeOnly) const
Return the ranges which affect the given line.
void setLineLengthLimit(int lineLengthLimit)
Set line length limit.
QString fallbackTextCodec() const
Get fallback codec for this buffer.
bool rangePointerValid(TextRange *range) const
Check if the given range pointer is still valid.
void cleared()
Buffer got cleared.
int editingMaximalLineChanged() const
Get maximal line number changed by last editing transaction.
void setFallbackTextCodec(const QString &codec)
Set fallback codec for this buffer to use for load.
bool editingChangedNumberOfLines() const
Query information from the last editing transaction: was the number of lines of the buffer changed?...
int lineLength(int line) const
Retrieve length for line.
bool editingChangedBuffer() const
Query information from the last editing transaction: was the content of the buffer changed?...
qint64 revision() const
Revision of this buffer.
int lines() const
Lines currently stored in this buffer.
EndOfLineMode endOfLineMode() const
Get end of line mode.
bool generateByteOrderMark() const
Generate byte order mark on save?
QString textCodec() const
Get codec for this buffer.
void setEndOfLineMode(EndOfLineMode endOfLineMode)
Set end of line mode for this buffer, not allowed to be set to unknown.
void loaded(const QString &filename, bool encodingErrors)
Buffer loaded successfully a file.
void saved(const QString &filename)
Buffer saved successfully a file.
int editingTransactions() const
Query the number of editing transactions running atm.
EndOfLineMode
End of line mode.
KTextEditor::DocumentPrivate * document() const
Gets the document to which this buffer is bound.
int editingMinimalLineChanged() const
Get minimal line number changed by last editing transaction.
TextHistory & history()
TextHistory of this buffer.
void setGenerateByteOrderMark(bool generateByteOrderMark)
Generate byte order mark on save.
int editingLastLines() const
Query the number of lines of this buffer before the ongoing editing transactions.
Class representing a 'clever' text cursor.
Class representing the editing history of a TextBuffer.
Class representing a single text line.
Class representing a 'clever' text range.
The KTextEditor namespace contains all the public API that is required to use the KTextEditor compone...
This file is part of the KDE documentation.
Documentation copyright © 1996-2024 The KDE developers.
Generated on Sun Feb 25 2024 18:42:02 by doxygen 1.10.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.