KTextEditor

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

KDE's Doxygen guidelines are available online.