File indexing completed on 2024-12-01 03:42:33
0001 /* 0002 SPDX-FileCopyrightText: 2010 Christoph Cullmann <cullmann@kde.org> 0003 0004 SPDX-License-Identifier: LGPL-2.0-or-later 0005 */ 0006 #ifndef KATE_TEXTBUFFER_H 0007 #define KATE_TEXTBUFFER_H 0008 0009 #include <QList> 0010 #include <QObject> 0011 #include <QSet> 0012 #include <QString> 0013 0014 #include "katetextblock.h" 0015 #include "katetexthistory.h" 0016 #include <ktexteditor_export.h> 0017 0018 // encoding prober 0019 #include <KEncodingProber> 0020 0021 namespace KTextEditor 0022 { 0023 class DocumentPrivate; 0024 } 0025 0026 class KCompressionDevice; 0027 0028 namespace Kate 0029 { 0030 class TextRange; 0031 class TextCursor; 0032 class TextBlock; 0033 0034 constexpr int BufferBlockSize = 64; 0035 0036 /** 0037 * Class representing a text buffer. 0038 * The interface is line based, internally the text will be stored in blocks of text lines. 0039 */ 0040 class KTEXTEDITOR_EXPORT TextBuffer : public QObject 0041 { 0042 friend class TextCursor; 0043 friend class TextRange; 0044 friend class TextBlock; 0045 0046 Q_OBJECT 0047 0048 public: 0049 /** 0050 * End of line mode 0051 */ 0052 enum EndOfLineMode { eolUnknown = -1, eolUnix = 0, eolDos = 1, eolMac = 2 }; 0053 0054 /** 0055 * Construct an empty text buffer. 0056 * Empty means one empty line in one block. 0057 * @param parent parent qobject 0058 */ 0059 explicit TextBuffer(KTextEditor::DocumentPrivate *parent, bool alwaysUseKAuth = false); 0060 0061 /** 0062 * Destruct the text buffer 0063 * Virtual, we allow inheritance 0064 */ 0065 ~TextBuffer() override; 0066 0067 /** 0068 * Clears the buffer, reverts to initial empty state. 0069 * Empty means one empty line in one block. 0070 * Virtual, can be overwritten. 0071 */ 0072 virtual void clear(); 0073 0074 /** 0075 * Set encoding prober type for this buffer to use for load. 0076 * @param proberType prober type to use for encoding 0077 */ 0078 void setEncodingProberType(KEncodingProber::ProberType proberType) 0079 { 0080 m_encodingProberType = proberType; 0081 } 0082 0083 /** 0084 * Get encoding prober type for this buffer 0085 * @return currently in use prober type of this buffer 0086 */ 0087 KEncodingProber::ProberType encodingProberType() const 0088 { 0089 return m_encodingProberType; 0090 } 0091 0092 /** 0093 * Set fallback codec for this buffer to use for load. 0094 * @param codec fallback to use for encoding 0095 */ 0096 void setFallbackTextCodec(const QString &codec) 0097 { 0098 m_fallbackTextCodec = codec; 0099 } 0100 0101 /** 0102 * Get fallback codec for this buffer 0103 * @return currently in use fallback codec of this buffer 0104 */ 0105 QString fallbackTextCodec() const 0106 { 0107 return m_fallbackTextCodec; 0108 } 0109 0110 /** 0111 * Set codec for this buffer to use for load/save. 0112 * Loading might overwrite this, if it encounters problems and finds a better codec. 0113 * Might change BOM setting. 0114 * @param codec to use for encoding 0115 */ 0116 void setTextCodec(const QString &codec); 0117 0118 /** 0119 * Get codec for this buffer 0120 * @return currently in use codec of this buffer 0121 */ 0122 QString textCodec() const 0123 { 0124 return m_textCodec; 0125 } 0126 0127 /** 0128 * Generate byte order mark on save. 0129 * Loading might overwrite this setting, if there is a BOM found inside the file. 0130 * @param generateByteOrderMark should BOM be generated? 0131 */ 0132 void setGenerateByteOrderMark(bool generateByteOrderMark) 0133 { 0134 m_generateByteOrderMark = generateByteOrderMark; 0135 } 0136 0137 /** 0138 * Generate byte order mark on save? 0139 * @return should BOM be generated? 0140 */ 0141 bool generateByteOrderMark() const 0142 { 0143 return m_generateByteOrderMark; 0144 } 0145 0146 /** 0147 * Set end of line mode for this buffer, not allowed to be set to unknown. 0148 * Loading might overwrite this setting, if there is a eol found inside the file. 0149 * @param endOfLineMode new eol mode 0150 */ 0151 void setEndOfLineMode(EndOfLineMode endOfLineMode) 0152 { 0153 Q_ASSERT(endOfLineMode != eolUnknown); 0154 m_endOfLineMode = endOfLineMode; 0155 } 0156 0157 /** 0158 * Get end of line mode 0159 * @return end of line mode 0160 */ 0161 EndOfLineMode endOfLineMode() const 0162 { 0163 return m_endOfLineMode; 0164 } 0165 0166 /** 0167 * Set line length limit 0168 * @param lineLengthLimit new line length limit 0169 */ 0170 void setLineLengthLimit(int lineLengthLimit) 0171 { 0172 m_lineLengthLimit = lineLengthLimit; 0173 } 0174 0175 /** 0176 * Load the given file. This will first clear the buffer and then load the file. 0177 * Even on error during loading the buffer will still be cleared. 0178 * Before calling this, setTextCodec must have been used to set codec! 0179 * @param filename file to open 0180 * @param encodingErrors were there problems occurred while decoding the file? 0181 * @param tooLongLinesWrapped were too long lines found and wrapped? 0182 * @param longestLineLoaded the longest line in the file (before wrapping) 0183 * @param enforceTextCodec enforce to use only the set text codec 0184 * @return success, the file got loaded, perhaps with encoding errors 0185 * Virtual, can be overwritten. 0186 */ 0187 virtual bool load(const QString &filename, bool &encodingErrors, bool &tooLongLinesWrapped, int &longestLineLoaded, bool enforceTextCodec); 0188 0189 /** 0190 * Save the current buffer content to the given file. 0191 * Before calling this, setTextCodec and setFallbackTextCodec must have been used to set codec! 0192 * @param filename file to save 0193 * @return success 0194 * Virtual, can be overwritten. 0195 */ 0196 virtual bool save(const QString &filename); 0197 0198 /** 0199 * Lines currently stored in this buffer. 0200 * This is never 0, even clear will let one empty line remain. 0201 */ 0202 int lines() const 0203 { 0204 Q_ASSERT(m_lines > 0); 0205 return m_lines; 0206 } 0207 0208 /** 0209 * Revision of this buffer. Is set to 0 on construction, clear() (load will trigger clear()). 0210 * Is incremented on each change to the buffer. 0211 * @return current revision 0212 */ 0213 qint64 revision() const 0214 { 0215 return m_revision; 0216 } 0217 0218 /** 0219 * Retrieve a text line. 0220 * @param line wanted line number 0221 * @return text line 0222 */ 0223 TextLine line(int line) const; 0224 0225 /** 0226 * Transfer all non text attributes for the given line from the given text line to the one in the buffer. 0227 * @param line line number to set attributes 0228 * @param textLine line reference to get attributes from 0229 */ 0230 void setLineMetaData(int line, const TextLine &textLine); 0231 0232 /** 0233 * Retrieve length for @p line 0234 * @param line wanted line number 0235 * @return length of the line 0236 */ 0237 int lineLength(int line) const 0238 { 0239 // get block, this will assert on invalid line 0240 int blockIndex = blockForLine(line); 0241 0242 // get line length 0243 return m_blocks.at(blockIndex)->lineLength(line); 0244 } 0245 0246 /** 0247 * Retrieve offset in text for the given cursor position 0248 */ 0249 int cursorToOffset(KTextEditor::Cursor c) const; 0250 0251 /** 0252 * Retrieve cursor in text for the given offset 0253 */ 0254 KTextEditor::Cursor offsetToCursor(int offset) const; 0255 0256 /** 0257 * Retrieve text of complete buffer. 0258 * @return text for this buffer, lines separated by '\n' 0259 */ 0260 QString text() const; 0261 0262 /** 0263 * Start an editing transaction, the wrapLine/unwrapLine/insertText and removeText functions 0264 * are only allowed to be called inside a editing transaction. 0265 * Editing transactions can stack. The number of startEdit and endEdit calls must match. 0266 * @return returns true, if no transaction was already running 0267 * Virtual, can be overwritten. 0268 */ 0269 virtual bool startEditing(); 0270 0271 /** 0272 * Finish an editing transaction. Only allowed to be called if editing transaction is started. 0273 * @return returns true, if this finished last running transaction 0274 * Virtual, can be overwritten. 0275 */ 0276 virtual bool finishEditing(); 0277 0278 /** 0279 * Query the number of editing transactions running atm. 0280 * @return number of running transactions 0281 */ 0282 int editingTransactions() const 0283 { 0284 return m_editingTransactions; 0285 } 0286 0287 /** 0288 * Query the revision of this buffer before the ongoing editing transactions. 0289 * @return revision of buffer before current editing transaction altered it 0290 */ 0291 qint64 editingLastRevision() const 0292 { 0293 return m_editingLastRevision; 0294 } 0295 0296 /** 0297 * Query the number of lines of this buffer before the ongoing editing transactions. 0298 * @return number of lines of buffer before current editing transaction altered it 0299 */ 0300 int editingLastLines() const 0301 { 0302 return m_editingLastLines; 0303 } 0304 0305 /** 0306 * Query information from the last editing transaction: was the content of the buffer changed? 0307 * This is checked by comparing the editingLastRevision() with the current revision(). 0308 * @return content of buffer was changed in last transaction? 0309 */ 0310 bool editingChangedBuffer() const 0311 { 0312 return editingLastRevision() != revision(); 0313 } 0314 0315 /** 0316 * Query information from the last editing transaction: was the number of lines of the buffer changed? 0317 * This is checked by comparing the editingLastLines() with the current lines(). 0318 * @return content of buffer was changed in last transaction? 0319 */ 0320 bool editingChangedNumberOfLines() const 0321 { 0322 return editingLastLines() != lines(); 0323 } 0324 0325 /** 0326 * Get minimal line number changed by last editing transaction 0327 * @return maximal line number changed by last editing transaction, or -1, if none changed 0328 */ 0329 int editingMinimalLineChanged() const 0330 { 0331 return m_editingMinimalLineChanged; 0332 } 0333 0334 /** 0335 * Get maximal line number changed by last editing transaction 0336 * @return maximal line number changed by last editing transaction, or -1, if none changed 0337 */ 0338 int editingMaximalLineChanged() const 0339 { 0340 return m_editingMaximalLineChanged; 0341 } 0342 0343 /** 0344 * Wrap line at given cursor position. 0345 * @param position line/column as cursor where to wrap 0346 * Virtual, can be overwritten. 0347 */ 0348 virtual void wrapLine(const KTextEditor::Cursor position); 0349 0350 /** 0351 * Unwrap given line. 0352 * @param line line to unwrap 0353 * Virtual, can be overwritten. 0354 */ 0355 virtual void unwrapLine(int line); 0356 0357 /** 0358 * Insert text at given cursor position. Does nothing if text is empty, beside some consistency checks. 0359 * @param position position where to insert text 0360 * @param text text to insert 0361 * Virtual, can be overwritten. 0362 */ 0363 virtual void insertText(const KTextEditor::Cursor position, const QString &text); 0364 0365 /** 0366 * Remove text at given range. Does nothing if range is empty, beside some consistency checks. 0367 * @param range range of text to remove, must be on one line only. 0368 * Virtual, can be overwritten. 0369 */ 0370 virtual void removeText(KTextEditor::Range range); 0371 0372 /** 0373 * TextHistory of this buffer 0374 * @return text history for this buffer 0375 */ 0376 TextHistory &history() 0377 { 0378 return m_history; 0379 } 0380 0381 Q_SIGNALS: 0382 /** 0383 * Buffer got cleared. This is emitted when constructor or load have called clear() internally, 0384 * or when the user of the buffer has called clear() itself. 0385 */ 0386 void cleared(); 0387 0388 /** 0389 * Buffer loaded successfully a file 0390 * @param filename file which was loaded 0391 * @param encodingErrors were there problems occurred while decoding the file? 0392 */ 0393 void loaded(const QString &filename, bool encodingErrors); 0394 0395 /** 0396 * Buffer saved successfully a file 0397 * @param filename file which was saved 0398 */ 0399 void saved(const QString &filename); 0400 0401 private: 0402 /** 0403 * Save result which indicates an abstract reason why the operation has 0404 * failed 0405 */ 0406 enum class SaveResult { Failed = 0, MissingPermissions, Success }; 0407 0408 /** 0409 * Find block containing given line. 0410 * @param line we want to find block for this line 0411 * @return index of found block 0412 */ 0413 int blockForLine(int line) const; 0414 // exported for movingrange_test 0415 0416 /** 0417 * Fix start lines of all blocks after the given one 0418 * @param startBlock index of block from which we start to fix 0419 */ 0420 KTEXTEDITOR_NO_EXPORT 0421 void fixStartLines(int startBlock); 0422 0423 /** 0424 * Balance the given block. Look if it is too small or too large. 0425 * @param index block to balance 0426 */ 0427 KTEXTEDITOR_NO_EXPORT 0428 void balanceBlock(int index); 0429 0430 /** 0431 * A range changed, notify the views, in case of attributes or feedback. 0432 * @param view which view is affected? nullptr for all views 0433 * @param lineRange line range that the change spans 0434 * @param needsRepaint do we need to trigger repaints? e.g. if ranges with attributes change 0435 */ 0436 KTEXTEDITOR_NO_EXPORT 0437 void notifyAboutRangeChange(KTextEditor::View *view, KTextEditor::LineRange lineRange, bool needsRepaint); 0438 0439 /** 0440 * Mark all modified lines as lines saved on disk (modified line system). 0441 */ 0442 KTEXTEDITOR_NO_EXPORT 0443 void markModifiedLinesAsSaved(); 0444 0445 /** 0446 * Save the current buffer content to the given already opened device 0447 * 0448 * @param filename path name for display/debugging purposes 0449 * @param saveFile open device to write the buffer to 0450 */ 0451 KTEXTEDITOR_NO_EXPORT 0452 bool saveBuffer(const QString &filename, KCompressionDevice &saveFile); 0453 0454 /** 0455 * Attempt to save the buffer content in the given filename location using 0456 * current privileges. 0457 */ 0458 KTEXTEDITOR_NO_EXPORT 0459 SaveResult saveBufferUnprivileged(const QString &filename); 0460 0461 /** 0462 * Attempt to save the buffer content in the given filename location using 0463 * escalated privileges. 0464 */ 0465 KTEXTEDITOR_NO_EXPORT 0466 bool saveBufferEscalated(const QString &filename); 0467 0468 public: 0469 /** 0470 * Gets the document to which this buffer is bound. 0471 * \return a pointer to the document 0472 */ 0473 KTextEditor::DocumentPrivate *document() const 0474 { 0475 return m_document; 0476 } 0477 0478 /** 0479 * Debug output, print whole buffer content with line numbers and line length 0480 * @param title title for this output 0481 */ 0482 void debugPrint(const QString &title) const; 0483 0484 /** 0485 * Return the ranges which affect the given line. 0486 * @param line line to look at 0487 * @param view only return ranges associated with given view 0488 * @param rangesWithAttributeOnly only return ranges which have a attribute set 0489 * @return list of ranges affecting this line 0490 */ 0491 QList<TextRange *> rangesForLine(int line, KTextEditor::View *view, bool rangesWithAttributeOnly) const 0492 { 0493 // get block, this will assert on invalid line 0494 const int blockIndex = blockForLine(line); 0495 return m_blocks.at(blockIndex)->rangesForLine(line, view, rangesWithAttributeOnly); 0496 } 0497 0498 void rangesForLine(int line, KTextEditor::View *view, bool rangesWithAttributeOnly, QList<TextRange *> &outRanges) const 0499 { 0500 // get block, this will assert on invalid line 0501 const int blockIndex = blockForLine(line); 0502 return m_blocks.at(blockIndex)->rangesForLine(line, view, rangesWithAttributeOnly, outRanges); 0503 } 0504 0505 /** 0506 * Check if the given range pointer is still valid. 0507 * @return range pointer still belongs to range for this buffer 0508 */ 0509 bool rangePointerValid(TextRange *range) const 0510 { 0511 return m_ranges.contains(range); 0512 } 0513 0514 /** 0515 * Invalidate all ranges in this buffer. 0516 */ 0517 void invalidateRanges(); 0518 0519 // 0520 // checksum handling 0521 // 0522 public: 0523 /** 0524 * Checksum of the document on disk, set either through file loading 0525 * in openFile() or in KTextEditor::DocumentPrivate::saveFile() 0526 * @return git compatible sha1 checksum for this document 0527 */ 0528 const QByteArray &digest() const; 0529 0530 /** 0531 * Set the checksum of this buffer. Make sure this checksum is up-to-date 0532 * when reading digest(). 0533 * @param checksum git compatible sha1 digest for the document on disk 0534 */ 0535 void setDigest(const QByteArray &checksum); 0536 0537 private: 0538 QByteArray m_digest; 0539 0540 private: 0541 /** 0542 * parent document 0543 */ 0544 KTextEditor::DocumentPrivate *m_document; 0545 0546 /** 0547 * text history 0548 */ 0549 TextHistory m_history; 0550 0551 /** 0552 * List of blocks which contain the lines of this buffer 0553 */ 0554 std::vector<TextBlock *> m_blocks; 0555 0556 /** 0557 * Number of lines in buffer 0558 */ 0559 int m_lines; 0560 0561 /** 0562 * Revision of the buffer. 0563 */ 0564 qint64 m_revision; 0565 0566 /** 0567 * Current number of running edit transactions 0568 */ 0569 int m_editingTransactions; 0570 0571 /** 0572 * Revision remembered at start of current editing transaction 0573 */ 0574 qint64 m_editingLastRevision; 0575 0576 /** 0577 * Number of lines remembered at start of current editing transaction 0578 */ 0579 int m_editingLastLines; 0580 0581 /** 0582 * minimal line number changed by last editing transaction 0583 */ 0584 int m_editingMinimalLineChanged; 0585 0586 /** 0587 * maximal line number changed by last editing transaction 0588 */ 0589 int m_editingMaximalLineChanged; 0590 0591 /** 0592 * Set of invalid cursors for this whole buffer. 0593 * Valid cursors are inside the block the belong to. 0594 */ 0595 QSet<TextCursor *> m_invalidCursors; 0596 0597 /** 0598 * Set of ranges of this whole buffer. 0599 */ 0600 QSet<TextRange *> m_ranges; 0601 0602 /** 0603 * Encoding prober type to use 0604 */ 0605 KEncodingProber::ProberType m_encodingProberType; 0606 0607 /** 0608 * Fallback text codec to use 0609 */ 0610 QString m_fallbackTextCodec; 0611 0612 /** 0613 * Text codec to use 0614 */ 0615 QString m_textCodec; 0616 0617 /** 0618 * Mime-Type used for transparent compression/decompression support 0619 * Set by load(), reset by clear() 0620 */ 0621 QString m_mimeTypeForFilterDev; 0622 0623 /** 0624 * Should byte order mark be created? 0625 */ 0626 bool m_generateByteOrderMark; 0627 0628 /** 0629 * End of line mode, default is Unix 0630 */ 0631 EndOfLineMode m_endOfLineMode; 0632 0633 /** 0634 * Limit for line length, longer lines will be wrapped on load 0635 */ 0636 int m_lineLengthLimit; 0637 0638 /** 0639 * For unit-testing purposes only. 0640 */ 0641 bool m_alwaysUseKAuthForSave; 0642 0643 /** 0644 * For copying QBuffer -> QTemporaryFile while saving document in privileged mode 0645 */ 0646 static const qint64 bufferLength = 4096; 0647 }; 0648 0649 } 0650 0651 #endif