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 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 length for @p line
238  * @param line wanted line number
239  * @return length of the line
240  */
241  int lineLength(int line) const
242  {
243  // get block, this will assert on invalid line
244  int blockIndex = blockForLine(line);
245 
246  // get line length
247  return m_blocks.at(blockIndex)->lineLength(line);
248  }
249 
250  /**
251  * Retrieve text of complete buffer.
252  * @return text for this buffer, lines separated by '\n'
253  */
254  QString text() const;
255 
256  /**
257  * Start an editing transaction, the wrapLine/unwrapLine/insertText and removeText functions
258  * are only allowed to be called inside a editing transaction.
259  * Editing transactions can stack. The number of startEdit and endEdit calls must match.
260  * @return returns true, if no transaction was already running
261  * Virtual, can be overwritten.
262  */
263  virtual bool startEditing();
264 
265  /**
266  * Finish an editing transaction. Only allowed to be called if editing transaction is started.
267  * @return returns true, if this finished last running transaction
268  * Virtual, can be overwritten.
269  */
270  virtual bool finishEditing();
271 
272  /**
273  * Query the number of editing transactions running atm.
274  * @return number of running transactions
275  */
277  {
278  return m_editingTransactions;
279  }
280 
281  /**
282  * Query the revision of this buffer before the ongoing editing transactions.
283  * @return revision of buffer before current editing transaction altered it
284  */
285  qint64 editingLastRevision() const
286  {
287  return m_editingLastRevision;
288  }
289 
290  /**
291  * Query the number of lines of this buffer before the ongoing editing transactions.
292  * @return number of lines of buffer before current editing transaction altered it
293  */
294  int editingLastLines() const
295  {
296  return m_editingLastLines;
297  }
298 
299  /**
300  * Query information from the last editing transaction: was the content of the buffer changed?
301  * This is checked by comparing the editingLastRevision() with the current revision().
302  * @return content of buffer was changed in last transaction?
303  */
304  bool editingChangedBuffer() const
305  {
306  return editingLastRevision() != revision();
307  }
308 
309  /**
310  * Query information from the last editing transaction: was the number of lines of the buffer changed?
311  * This is checked by comparing the editingLastLines() with the current lines().
312  * @return content of buffer was changed in last transaction?
313  */
315  {
316  return editingLastLines() != lines();
317  }
318 
319  /**
320  * Get minimal 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_editingMinimalLineChanged;
326  }
327 
328  /**
329  * Get maximal line number changed by last editing transaction
330  * @return maximal line number changed by last editing transaction, or -1, if none changed
331  */
333  {
334  return m_editingMaximalLineChanged;
335  }
336 
337  /**
338  * Wrap line at given cursor position.
339  * @param position line/column as cursor where to wrap
340  * Virtual, can be overwritten.
341  */
342  virtual void wrapLine(const KTextEditor::Cursor position);
343 
344  /**
345  * Unwrap given line.
346  * @param line line to unwrap
347  * Virtual, can be overwritten.
348  */
349  virtual void unwrapLine(int line);
350 
351  /**
352  * Insert text at given cursor position. Does nothing if text is empty, beside some consistency checks.
353  * @param position position where to insert text
354  * @param text text to insert
355  * Virtual, can be overwritten.
356  */
357  virtual void insertText(const KTextEditor::Cursor position, const QString &text);
358 
359  /**
360  * Remove text at given range. Does nothing if range is empty, beside some consistency checks.
361  * @param range range of text to remove, must be on one line only.
362  * Virtual, can be overwritten.
363  */
364  virtual void removeText(KTextEditor::Range range);
365 
366  /**
367  * TextHistory of this buffer
368  * @return text history for this buffer
369  */
371  {
372  return m_history;
373  }
374 
375 Q_SIGNALS:
376  /**
377  * Buffer got cleared. This is emitted when constructor or load have called clear() internally,
378  * or when the user of the buffer has called clear() itself.
379  */
380  void cleared();
381 
382  /**
383  * Buffer loaded successfully a file
384  * @param filename file which was loaded
385  * @param encodingErrors were there problems occurred while decoding the file?
386  */
387  void loaded(const QString &filename, bool encodingErrors);
388 
389  /**
390  * Buffer saved successfully a file
391  * @param filename file which was saved
392  */
393  void saved(const QString &filename);
394 
395  /**
396  * Editing transaction has started.
397  */
398  void editingStarted();
399 
400  /**
401  * Editing transaction has finished.
402  */
403  void editingFinished();
404 
405  /**
406  * A line got wrapped.
407  * @param position position where the wrap occurred
408  */
409  void lineWrapped(const KTextEditor::Cursor position);
410 
411  /**
412  * A line got unwrapped.
413  * @param line line where the unwrap occurred
414  */
415  void lineUnwrapped(int line);
416 
417  /**
418  * Text got inserted.
419  * @param position position where the insertion occurred
420  * @param text inserted text
421  */
422  void textInserted(const KTextEditor::Cursor position, const QString &text);
423 
424  /**
425  * Text got removed.
426  * @param range range where the removal occurred
427  * @param text removed text
428  */
429  void textRemoved(KTextEditor::Range range, const QString &text);
430 
431 private:
432  /**
433  * Save result which indicates an abstract reason why the operation has
434  * failed
435  */
436  enum class SaveResult { Failed = 0, MissingPermissions, Success };
437 
438  /**
439  * Find block containing given line.
440  * @param line we want to find block for this line
441  * @return index of found block
442  */
443  int blockForLine(int line) const;
444 
445  /**
446  * Fix start lines of all blocks after the given one
447  * @param startBlock index of block from which we start to fix
448  */
449  void fixStartLines(int startBlock);
450 
451  /**
452  * Balance the given block. Look if it is too small or too large.
453  * @param index block to balance
454  */
455  void balanceBlock(int index);
456 
457  /**
458  * Block for given index in block list.
459  * @param index block index
460  * @return block matching this index
461  */
462  TextBlock *blockForIndex(int index)
463  {
464  return m_blocks[index];
465  }
466 
467  /**
468  * A range changed, notify the views, in case of attributes or feedback.
469  * @param view which view is affected? nullptr for all views
470  * @param lineRange line range that the change spans
471  * @param needsRepaint do we need to trigger repaints? e.g. if ranges with attributes change
472  */
473  void notifyAboutRangeChange(KTextEditor::View *view, KTextEditor::LineRange lineRange, bool needsRepaint);
474 
475  /**
476  * Mark all modified lines as lines saved on disk (modified line system).
477  */
478  void markModifiedLinesAsSaved();
479 
480  /**
481  * Save the current buffer content to the given already opened device
482  *
483  * @param filename path name for display/debugging purposes
484  * @param saveFile open device to write the buffer to
485  */
486  bool saveBuffer(const QString &filename, KCompressionDevice &saveFile);
487 
488  /**
489  * Attempt to save the buffer content in the given filename location using
490  * current privileges.
491  */
492  SaveResult saveBufferUnprivileged(const QString &filename);
493 
494  /**
495  * Attempt to save the buffer content in the given filename location using
496  * escalated privileges.
497  */
498  bool saveBufferEscalated(const QString &filename);
499 
500 public:
501  /**
502  * Gets the document to which this buffer is bound.
503  * \return a pointer to the document
504  */
505  KTextEditor::DocumentPrivate *document() const
506  {
507  return m_document;
508  }
509 
510  /**
511  * Debug output, print whole buffer content with line numbers and line length
512  * @param title title for this output
513  */
514  void debugPrint(const QString &title) const;
515 
516  /**
517  * Return the ranges which affect the given line.
518  * @param line line to look at
519  * @param view only return ranges associated with given view
520  * @param rangesWithAttributeOnly only return ranges which have a attribute set
521  * @return list of ranges affecting this line
522  */
523  QVector<TextRange *> rangesForLine(int line, KTextEditor::View *view, bool rangesWithAttributeOnly) const
524  {
525  // get block, this will assert on invalid line
526  const int blockIndex = blockForLine(line);
527  return m_blocks.at(blockIndex)->rangesForLine(line, view, rangesWithAttributeOnly);
528  }
529 
530  /**
531  * Check if the given range pointer is still valid.
532  * @return range pointer still belongs to range for this buffer
533  */
534  bool rangePointerValid(TextRange *range) const
535  {
536  return m_ranges.contains(range);
537  }
538 
539  /**
540  * Invalidate all ranges in this buffer.
541  */
542  void invalidateRanges();
543 
544  //
545  // checksum handling
546  //
547 public:
548  /**
549  * Checksum of the document on disk, set either through file loading
550  * in openFile() or in KTextEditor::DocumentPrivate::saveFile()
551  * @return git compatible sha1 checksum for this document
552  */
553  const QByteArray &digest() const;
554 
555  /**
556  * Set the checksum of this buffer. Make sure this checksum is up-to-date
557  * when reading digest().
558  * @param checksum git compatible sha1 digest for the document on disk
559  */
560  void setDigest(const QByteArray &checksum);
561 
562 private:
563  QByteArray m_digest;
564 
565 private:
566  /**
567  * parent document
568  */
569  KTextEditor::DocumentPrivate *m_document;
570 
571  /**
572  * text history
573  */
574  TextHistory m_history;
575 
576  /**
577  * block size in lines the buffer will try to hold
578  */
579  const int m_blockSize;
580 
581  /**
582  * List of blocks which contain the lines of this buffer
583  */
584  std::vector<TextBlock *> m_blocks;
585 
586  /**
587  * Number of lines in buffer
588  */
589  int m_lines;
590 
591  /**
592  * Last used block in the buffer. Is used for speeding up blockForLine.
593  * May contain invalid index, must be checked before using.
594  */
595  mutable int m_lastUsedBlock;
596 
597  /**
598  * Revision of the buffer.
599  */
600  qint64 m_revision;
601 
602  /**
603  * Current number of running edit transactions
604  */
605  int m_editingTransactions;
606 
607  /**
608  * Revision remembered at start of current editing transaction
609  */
610  qint64 m_editingLastRevision;
611 
612  /**
613  * Number of lines remembered at start of current editing transaction
614  */
615  int m_editingLastLines;
616 
617  /**
618  * minimal line number changed by last editing transaction
619  */
620  int m_editingMinimalLineChanged;
621 
622  /**
623  * maximal line number changed by last editing transaction
624  */
625  int m_editingMaximalLineChanged;
626 
627  /**
628  * Set of invalid cursors for this whole buffer.
629  * Valid cursors are inside the block the belong to.
630  */
631  QSet<TextCursor *> m_invalidCursors;
632 
633  /**
634  * Set of ranges of this whole buffer.
635  */
636  QSet<TextRange *> m_ranges;
637 
638  /**
639  * Encoding prober type to use
640  */
641  KEncodingProber::ProberType m_encodingProberType;
642 
643  /**
644  * Fallback text codec to use
645  */
646  QTextCodec *m_fallbackTextCodec;
647 
648  /**
649  * Text codec to use
650  */
651  QTextCodec *m_textCodec;
652 
653  /**
654  * Mime-Type used for transparent compression/decompression support
655  * Set by load(), reset by clear()
656  */
657  QString m_mimeTypeForFilterDev;
658 
659  /**
660  * Should byte order mark be created?
661  */
662  bool m_generateByteOrderMark;
663 
664  /**
665  * End of line mode, default is Unix
666  */
667  EndOfLineMode m_endOfLineMode;
668 
669  /**
670  * Insert newline character at the end of the file?
671  */
672  bool m_newLineAtEof;
673 
674  /**
675  * Limit for line length, longer lines will be wrapped on load
676  */
677  int m_lineLengthLimit;
678 
679  /**
680  * For unit-testing purposes only.
681  */
682  bool m_alwaysUseKAuthForSave;
683 
684  /**
685  * For copying QBuffer -> QTemporaryFile while saving document in privileged mode
686  */
687  static const qint64 bufferLength = 4096;
688 };
689 
690 }
691 
692 #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:22
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.
int lineLength(int line) const
Retrieve length for line.
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:40
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-2022 The KDE developers.
Generated on Mon Jan 24 2022 22:50:50 by doxygen 1.8.11 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.