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  ~TextBuffer() override;
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 line length limit
170  * @param lineLengthLimit new line length limit
171  */
172  void setLineLengthLimit(int lineLengthLimit)
173  {
174  m_lineLengthLimit = lineLengthLimit;
175  }
176 
177  /**
178  * Load the given file. This will first clear the buffer and then load the file.
179  * Even on error during loading the buffer will still be cleared.
180  * Before calling this, setTextCodec must have been used to set codec!
181  * @param filename file to open
182  * @param encodingErrors were there problems occurred while decoding the file?
183  * @param tooLongLinesWrapped were too long lines found and wrapped?
184  * @param longestLineLoaded the longest line in the file (before wrapping)
185  * @param enforceTextCodec enforce to use only the set text codec
186  * @return success, the file got loaded, perhaps with encoding errors
187  * Virtual, can be overwritten.
188  */
189  virtual bool load(const QString &filename, bool &encodingErrors, bool &tooLongLinesWrapped, int &longestLineLoaded, bool enforceTextCodec);
190 
191  /**
192  * Save the current buffer content to the given file.
193  * Before calling this, setTextCodec and setFallbackTextCodec must have been used to set codec!
194  * @param filename file to save
195  * @return success
196  * Virtual, can be overwritten.
197  */
198  virtual bool save(const QString &filename);
199 
200  /**
201  * Lines currently stored in this buffer.
202  * This is never 0, even clear will let one empty line remain.
203  */
204  int lines() const
205  {
206  Q_ASSERT(m_lines > 0);
207  return m_lines;
208  }
209 
210  /**
211  * Revision of this buffer. Is set to 0 on construction, clear() (load will trigger clear()).
212  * Is incremented on each change to the buffer.
213  * @return current revision
214  */
215  qint64 revision() const
216  {
217  return m_revision;
218  }
219 
220  /**
221  * Retrieve a text line.
222  * @param line wanted line number
223  * @return text line
224  */
225  TextLine line(int line) const;
226 
227  /**
228  * Retrieve length for @p line
229  * @param line wanted line number
230  * @return length of the line
231  */
232  int lineLength(int line) const
233  {
234  // get block, this will assert on invalid line
235  int blockIndex = blockForLine(line);
236 
237  // get line length
238  return m_blocks.at(blockIndex)->lineLength(line);
239  }
240 
241  /**
242  * Retrieve text of complete buffer.
243  * @return text for this buffer, lines separated by '\n'
244  */
245  QString text() const;
246 
247  /**
248  * Start an editing transaction, the wrapLine/unwrapLine/insertText and removeText functions
249  * are only allowed to be called inside a editing transaction.
250  * Editing transactions can stack. The number of startEdit and endEdit calls must match.
251  * @return returns true, if no transaction was already running
252  * Virtual, can be overwritten.
253  */
254  virtual bool startEditing();
255 
256  /**
257  * Finish an editing transaction. Only allowed to be called if editing transaction is started.
258  * @return returns true, if this finished last running transaction
259  * Virtual, can be overwritten.
260  */
261  virtual bool finishEditing();
262 
263  /**
264  * Query the number of editing transactions running atm.
265  * @return number of running transactions
266  */
268  {
269  return m_editingTransactions;
270  }
271 
272  /**
273  * Query the revision of this buffer before the ongoing editing transactions.
274  * @return revision of buffer before current editing transaction altered it
275  */
276  qint64 editingLastRevision() const
277  {
278  return m_editingLastRevision;
279  }
280 
281  /**
282  * Query the number of lines of this buffer before the ongoing editing transactions.
283  * @return number of lines of buffer before current editing transaction altered it
284  */
285  int editingLastLines() const
286  {
287  return m_editingLastLines;
288  }
289 
290  /**
291  * Query information from the last editing transaction: was the content of the buffer changed?
292  * This is checked by comparing the editingLastRevision() with the current revision().
293  * @return content of buffer was changed in last transaction?
294  */
295  bool editingChangedBuffer() const
296  {
297  return editingLastRevision() != revision();
298  }
299 
300  /**
301  * Query information from the last editing transaction: was the number of lines of the buffer changed?
302  * This is checked by comparing the editingLastLines() with the current lines().
303  * @return content of buffer was changed in last transaction?
304  */
306  {
307  return editingLastLines() != lines();
308  }
309 
310  /**
311  * Get minimal line number changed by last editing transaction
312  * @return maximal line number changed by last editing transaction, or -1, if none changed
313  */
315  {
316  return m_editingMinimalLineChanged;
317  }
318 
319  /**
320  * Get maximal line number changed by last editing transaction
321  * @return maximal line number changed by last editing transaction, or -1, if none changed
322  */
324  {
325  return m_editingMaximalLineChanged;
326  }
327 
328  /**
329  * Wrap line at given cursor position.
330  * @param position line/column as cursor where to wrap
331  * Virtual, can be overwritten.
332  */
333  virtual void wrapLine(const KTextEditor::Cursor position);
334 
335  /**
336  * Unwrap given line.
337  * @param line line to unwrap
338  * Virtual, can be overwritten.
339  */
340  virtual void unwrapLine(int line);
341 
342  /**
343  * Insert text at given cursor position. Does nothing if text is empty, beside some consistency checks.
344  * @param position position where to insert text
345  * @param text text to insert
346  * Virtual, can be overwritten.
347  */
348  virtual void insertText(const KTextEditor::Cursor position, const QString &text);
349 
350  /**
351  * Remove text at given range. Does nothing if range is empty, beside some consistency checks.
352  * @param range range of text to remove, must be on one line only.
353  * Virtual, can be overwritten.
354  */
355  virtual void removeText(KTextEditor::Range range);
356 
357  /**
358  * TextHistory of this buffer
359  * @return text history for this buffer
360  */
362  {
363  return m_history;
364  }
365 
366 Q_SIGNALS:
367  /**
368  * Buffer got cleared. This is emitted when constructor or load have called clear() internally,
369  * or when the user of the buffer has called clear() itself.
370  */
371  void cleared();
372 
373  /**
374  * Buffer loaded successfully a file
375  * @param filename file which was loaded
376  * @param encodingErrors were there problems occurred while decoding the file?
377  */
378  void loaded(const QString &filename, bool encodingErrors);
379 
380  /**
381  * Buffer saved successfully a file
382  * @param filename file which was saved
383  */
384  void saved(const QString &filename);
385 
386  /**
387  * Editing transaction has started.
388  */
389  void editingStarted();
390 
391  /**
392  * Editing transaction has finished.
393  */
394  void editingFinished();
395 
396  /**
397  * A line got wrapped.
398  * @param position position where the wrap occurred
399  */
400  void lineWrapped(const KTextEditor::Cursor position);
401 
402  /**
403  * A line got unwrapped.
404  * @param line line where the unwrap occurred
405  */
406  void lineUnwrapped(int line);
407 
408  /**
409  * Text got inserted.
410  * @param position position where the insertion occurred
411  * @param text inserted text
412  */
413  void textInserted(const KTextEditor::Cursor position, const QString &text);
414 
415  /**
416  * Text got removed.
417  * @param range range where the removal occurred
418  * @param text removed text
419  */
420  void textRemoved(KTextEditor::Range range, const QString &text);
421 
422 private:
423  /**
424  * Save result which indicates an abstract reason why the operation has
425  * failed
426  */
427  enum class SaveResult { Failed = 0, MissingPermissions, Success };
428 
429  /**
430  * Find block containing given line.
431  * @param line we want to find block for this line
432  * @return index of found block
433  */
434  int blockForLine(int line) const;
435 
436  /**
437  * Fix start lines of all blocks after the given one
438  * @param startBlock index of block from which we start to fix
439  */
440  void fixStartLines(int startBlock);
441 
442  /**
443  * Balance the given block. Look if it is too small or too large.
444  * @param index block to balance
445  */
446  void balanceBlock(int index);
447 
448  /**
449  * Block for given index in block list.
450  * @param index block index
451  * @return block matching this index
452  */
453  TextBlock *blockForIndex(int index)
454  {
455  return m_blocks[index];
456  }
457 
458  /**
459  * A range changed, notify the views, in case of attributes or feedback.
460  * @param view which view is affected? nullptr for all views
461  * @param lineRange line range that the change spans
462  * @param needsRepaint do we need to trigger repaints? e.g. if ranges with attributes change
463  */
464  void notifyAboutRangeChange(KTextEditor::View *view, KTextEditor::LineRange lineRange, bool needsRepaint);
465 
466  /**
467  * Mark all modified lines as lines saved on disk (modified line system).
468  */
469  void markModifiedLinesAsSaved();
470 
471  /**
472  * Save the current buffer content to the given already opened device
473  *
474  * @param filename path name for display/debugging purposes
475  * @param saveFile open device to write the buffer to
476  */
477  bool saveBuffer(const QString &filename, KCompressionDevice &saveFile);
478 
479  /**
480  * Attempt to save the buffer content in the given filename location using
481  * current privileges.
482  */
483  SaveResult saveBufferUnprivileged(const QString &filename);
484 
485  /**
486  * Attempt to save the buffer content in the given filename location using
487  * escalated privileges.
488  */
489  bool saveBufferEscalated(const QString &filename);
490 
491 public:
492  /**
493  * Gets the document to which this buffer is bound.
494  * \return a pointer to the document
495  */
496  KTextEditor::DocumentPrivate *document() const
497  {
498  return m_document;
499  }
500 
501  /**
502  * Debug output, print whole buffer content with line numbers and line length
503  * @param title title for this output
504  */
505  void debugPrint(const QString &title) const;
506 
507  /**
508  * Return the ranges which affect the given line.
509  * @param line line to look at
510  * @param view only return ranges associated with given view
511  * @param rangesWithAttributeOnly only return ranges which have a attribute set
512  * @return list of ranges affecting this line
513  */
514  QVector<TextRange *> rangesForLine(int line, KTextEditor::View *view, bool rangesWithAttributeOnly) const
515  {
516  // get block, this will assert on invalid line
517  const int blockIndex = blockForLine(line);
518  return m_blocks.at(blockIndex)->rangesForLine(line, view, rangesWithAttributeOnly);
519  }
520 
521  /**
522  * Check if the given range pointer is still valid.
523  * @return range pointer still belongs to range for this buffer
524  */
525  bool rangePointerValid(TextRange *range) const
526  {
527  return m_ranges.contains(range);
528  }
529 
530  /**
531  * Invalidate all ranges in this buffer.
532  */
533  void invalidateRanges();
534 
535  //
536  // checksum handling
537  //
538 public:
539  /**
540  * Checksum of the document on disk, set either through file loading
541  * in openFile() or in KTextEditor::DocumentPrivate::saveFile()
542  * @return git compatible sha1 checksum for this document
543  */
544  const QByteArray &digest() const;
545 
546  /**
547  * Set the checksum of this buffer. Make sure this checksum is up-to-date
548  * when reading digest().
549  * @param checksum git compatible sha1 digest for the document on disk
550  */
551  void setDigest(const QByteArray &checksum);
552 
553 private:
554  QByteArray m_digest;
555 
556 private:
557  /**
558  * parent document
559  */
560  KTextEditor::DocumentPrivate *m_document;
561 
562  /**
563  * text history
564  */
565  TextHistory m_history;
566 
567  /**
568  * block size in lines the buffer will try to hold
569  */
570  const int m_blockSize;
571 
572  /**
573  * List of blocks which contain the lines of this buffer
574  */
575  std::vector<TextBlock *> m_blocks;
576 
577  /**
578  * Number of lines in buffer
579  */
580  int m_lines;
581 
582  /**
583  * Last used block in the buffer. Is used for speeding up blockForLine.
584  * May contain invalid index, must be checked before using.
585  */
586  mutable int m_lastUsedBlock;
587 
588  /**
589  * Revision of the buffer.
590  */
591  qint64 m_revision;
592 
593  /**
594  * Current number of running edit transactions
595  */
596  int m_editingTransactions;
597 
598  /**
599  * Revision remembered at start of current editing transaction
600  */
601  qint64 m_editingLastRevision;
602 
603  /**
604  * Number of lines remembered at start of current editing transaction
605  */
606  int m_editingLastLines;
607 
608  /**
609  * minimal line number changed by last editing transaction
610  */
611  int m_editingMinimalLineChanged;
612 
613  /**
614  * maximal line number changed by last editing transaction
615  */
616  int m_editingMaximalLineChanged;
617 
618  /**
619  * Set of invalid cursors for this whole buffer.
620  * Valid cursors are inside the block the belong to.
621  */
622  QSet<TextCursor *> m_invalidCursors;
623 
624  /**
625  * Set of ranges of this whole buffer.
626  */
627  QSet<TextRange *> m_ranges;
628 
629  /**
630  * Encoding prober type to use
631  */
632  KEncodingProber::ProberType m_encodingProberType;
633 
634  /**
635  * Fallback text codec to use
636  */
637  QTextCodec *m_fallbackTextCodec;
638 
639  /**
640  * Text codec to use
641  */
642  QTextCodec *m_textCodec;
643 
644  /**
645  * Mime-Type used for transparent compression/decompression support
646  * Set by load(), reset by clear()
647  */
648  QString m_mimeTypeForFilterDev;
649 
650  /**
651  * Should byte order mark be created?
652  */
653  bool m_generateByteOrderMark;
654 
655  /**
656  * End of line mode, default is Unix
657  */
658  EndOfLineMode m_endOfLineMode;
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
bool rangePointerValid(TextRange *range) const
Check if the given range pointer is still valid.
QTextCodec * textCodec() const
Get codec for this buffer.
void setFallbackTextCodec(QTextCodec *codec)
Set fallback codec for this buffer to use for load.
void setEncodingProberType(KEncodingProber::ProberType proberType)
Set encoding prober type for this buffer to use for load.
Class representing a 'clever' text cursor.
bool editingChangedBuffer() const
Query information from the last editing transaction: was the content of the buffer changed?...
Class representing a text buffer.
void setEndOfLineMode(EndOfLineMode endOfLineMode)
Set end of line mode for this buffer, not allowed to be set to unknown.
qint64 revision() const
Revision of this buffer.
An object representing lines from a start line to an end line.
Definition: linerange.h:37
An object representing a section of text, from one Cursor to another.
int editingLastLines() const
Query the number of lines of this buffer before the ongoing editing transactions.
int editingMaximalLineChanged() const
Get maximal line number changed by last editing transaction.
QVector< TextRange * > rangesForLine(int line, KTextEditor::View *view, bool rangesWithAttributeOnly) const
Return the ranges which affect the given line.
EndOfLineMode
End of line mode.
void setLineLengthLimit(int lineLengthLimit)
Set line length limit.
qint64 editingLastRevision() const
Query the revision of this buffer before the ongoing editing transactions.
The Cursor represents a position in a Document.
Definition: cursor.h:71
KEncodingProber::ProberType encodingProberType() const
Get encoding prober type for this buffer.
QTextCodec * fallbackTextCodec() const
Get fallback codec for this buffer.
A text widget with KXMLGUIClient that represents a Document.
Definition: view.h:146
bool generateByteOrderMark() const
Generate byte order mark on save?
KTextEditor::DocumentPrivate * document() const
Gets the document to which this buffer is bound.
int lineLength(int line) const
Retrieve length for line.
The KTextEditor namespace contains all the public API that is required to use the KTextEditor compone...
Definition: katetextblock.h:22
Class representing a 'clever' text range.
Definition: katetextrange.h:36
Class representing the editing history of a TextBuffer.
bool editingChangedNumberOfLines() const
Query information from the last editing transaction: was the number of lines of the buffer changed?...
int editingTransactions() const
Query the number of editing transactions running atm.
Class representing a text block.
Definition: katetextblock.h:40
int lines() const
Lines currently stored in this buffer.
EndOfLineMode endOfLineMode() const
Get end of line mode.
void setGenerateByteOrderMark(bool generateByteOrderMark)
Generate byte order mark on save.
int editingMinimalLineChanged() const
Get minimal line number changed by last editing transaction.
TextHistory & history()
TextHistory of this buffer.
This file is part of the KDE documentation.
Documentation copyright © 1996-2022 The KDE developers.
Generated on Wed Aug 17 2022 03:54:01 by doxygen 1.8.17 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.