Warning, file /frameworks/ktexteditor/src/buffer/katetextbuffer.h was not indexed or was modified since last indexation (in which case cross-reference links may be missing, inaccurate or erroneous).

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