File indexing completed on 2024-04-28 07:46:10

0001 /*
0002     SPDX-FileCopyrightText: 2010 Christoph Cullmann <cullmann@kde.org>
0003 
0004     SPDX-License-Identifier: LGPL-2.0-or-later
0005 */
0006 
0007 #ifndef KATE_TEXTBLOCK_H
0008 #define KATE_TEXTBLOCK_H
0009 
0010 #include "katetextline.h"
0011 
0012 #include <QList>
0013 #include <QSet>
0014 #include <QVarLengthArray>
0015 
0016 #include <ktexteditor/cursor.h>
0017 #include <ktexteditor_export.h>
0018 
0019 namespace KTextEditor
0020 {
0021 class View;
0022 }
0023 
0024 namespace Kate
0025 {
0026 class TextBuffer;
0027 class TextCursor;
0028 class TextRange;
0029 
0030 /**
0031  * Class representing a text block.
0032  * This is used to build up a Kate::TextBuffer.
0033  * This class should only be used by TextBuffer/Cursor/Range.
0034  */
0035 class TextBlock
0036 {
0037 public:
0038     /**
0039      * Construct an empty text block.
0040      * @param buffer parent text buffer
0041      * @param startLine start line of this block
0042      */
0043     TextBlock(TextBuffer *buffer, int startLine);
0044 
0045     /**
0046      * Destruct the text block
0047      */
0048     ~TextBlock();
0049 
0050     /**
0051      * Start line of this block.
0052      * @return start line of this block
0053      */
0054     int startLine() const
0055     {
0056         return m_startLine;
0057     }
0058 
0059     /**
0060      * Set start line of this block.
0061      * @param startLine new start line of this block
0062      */
0063     void setStartLine(int startLine);
0064 
0065     /**
0066      * Retrieve a text line.
0067      * @param line wanted line number
0068      * @return text line
0069      */
0070     TextLine line(int line) const;
0071 
0072     /**
0073      * Transfer all non text attributes for the given line from the given text line to the one in the block.
0074      * @param line line number to set attributes
0075      * @param textLine line reference to get attributes from
0076      */
0077     void setLineMetaData(int line, const TextLine &textLine);
0078 
0079     /**
0080      * Retrieve length for @p line.
0081      * @param line wanted line number
0082      * @return length of line
0083      */
0084     int lineLength(int line) const
0085     {
0086         Q_ASSERT(line >= startLine() && (line - startLine()) < lines());
0087         return m_lines[line - startLine()].length();
0088     }
0089 
0090     /**
0091      * Append a new line with given text.
0092      * @param textOfLine text of the line to append
0093      */
0094     void appendLine(const QString &textOfLine);
0095 
0096     /**
0097      * Clear the lines.
0098      */
0099     void clearLines();
0100 
0101     /**
0102      * Number of lines in this block.
0103      * @return number of lines
0104      */
0105     int lines() const
0106     {
0107         return static_cast<int>(m_lines.size());
0108     }
0109 
0110     /**
0111      * Retrieve text of block.
0112      * @param text for this block, lines separated by '\n'
0113      */
0114     void text(QString &text) const;
0115 
0116     /**
0117      * Wrap line at given cursor position.
0118      * @param position line/column as cursor where to wrap
0119      * @param fixStartLinesStartIndex start index to fix start lines, normally this is this block
0120      */
0121     void wrapLine(const KTextEditor::Cursor position, int fixStartLinesStartIndex);
0122 
0123     /**
0124      * Unwrap given line.
0125      * @param line line to unwrap
0126      * @param previousBlock previous block, if any, if we unwrap first line in block, we need to have this
0127      * @param fixStartLinesStartIndex start index to fix start lines, normally this is this block or the previous one
0128      */
0129     void unwrapLine(int line, TextBlock *previousBlock, int fixStartLinesStartIndex);
0130 
0131     /**
0132      * Insert text at given cursor position.
0133      * @param position position where to insert text
0134      * @param text text to insert
0135      */
0136     void insertText(const KTextEditor::Cursor position, const QString &text);
0137 
0138     /**
0139      * Remove text at given range.
0140      * @param range range of text to remove, must be on one line only.
0141      * @param removedText will be filled with removed text
0142      */
0143     void removeText(KTextEditor::Range range, QString &removedText);
0144 
0145     /**
0146      * Debug output, print whole block content with line numbers and line length
0147      * @param blockIndex index of this block in buffer
0148      */
0149     void debugPrint(int blockIndex) const;
0150 
0151     /**
0152      * Split given block. A new block will be created and all lines starting from the given index will
0153      * be moved to it, together with the cursors belonging to it.
0154      * @param fromLine line from which to split
0155      * @return new block containing the lines + cursors removed from this one
0156      */
0157     TextBlock *splitBlock(int fromLine);
0158 
0159     /**
0160      * Merge this block with given one, the given one must be a direct predecessor.
0161      * @param targetBlock block to merge with
0162      */
0163     void mergeBlock(TextBlock *targetBlock);
0164 
0165     /**
0166      * Delete the block content, delete all lines and delete all cursors not bound to ranges.
0167      * This is used in destructor of TextBuffer, for fast cleanup. Only stuff remaining afterwards are cursors which are
0168      * part of a range, TextBuffer will delete them itself...
0169      */
0170     void deleteBlockContent();
0171 
0172     /**
0173      * Clear the block content, delete all lines, move all cursors not bound to range to given block at 0,0.
0174      * This is used by clear() of TextBuffer.
0175      * @param targetBlock empty target block for cursors
0176      */
0177     void clearBlockContent(TextBlock *targetBlock);
0178 
0179     /**
0180      * Return all ranges in this block which might intersect the given line.
0181      * @param line                          line to check intersection
0182      * @param view                          only return ranges associated with given view
0183      * @param rangesWithAttributeOnly       ranges with attributes only?
0184      * @return list of possible candidate ranges
0185      */
0186     KTEXTEDITOR_EXPORT QList<TextRange *> rangesForLine(int line, KTextEditor::View *view, bool rangesWithAttributeOnly) const;
0187 
0188     KTEXTEDITOR_NO_EXPORT void rangesForLine(int line, KTextEditor::View *view, bool rangesWithAttributeOnly, QList<TextRange *> &outRanges) const;
0189 
0190     /**
0191      * Is the given range contained in this block?
0192      * @param range range to check for
0193      * @return contained in this blocks mapping?
0194      */
0195     bool containsRange(TextRange *range) const
0196     {
0197         return m_cachedLineForRanges.find(range) != m_cachedLineForRanges.end() || m_uncachedRanges.contains(range);
0198     }
0199 
0200     /**
0201      * Flag all modified text lines as saved on disk.
0202      */
0203     void markModifiedLinesAsSaved();
0204 
0205     /**
0206      * Insert cursor into this block.
0207      * @param cursor cursor to insert
0208      */
0209     void insertCursor(Kate::TextCursor *cursor)
0210     {
0211         m_cursors.insert(cursor);
0212     }
0213 
0214     /**
0215      * Remove cursor from this block.
0216      * @param cursor cursor to remove
0217      */
0218     void removeCursor(Kate::TextCursor *cursor)
0219     {
0220         m_cursors.remove(cursor);
0221     }
0222 
0223     /**
0224      * Update a range from this block.
0225      * Will move the range to right set, either cached for one-line ranges or not.
0226      * @param range range to update
0227      */
0228     void updateRange(TextRange *range);
0229 
0230     /**
0231      * Remove a range from this block.
0232      * @param range range to remove
0233      */
0234     void removeRange(TextRange *range);
0235 
0236     /**
0237      * Returns the size of this block i.e.,
0238      * the count of QChars it has + number of new lines
0239      */
0240     int blockSize() const
0241     {
0242         return m_blockSize + m_lines.size();
0243     }
0244 
0245 private:
0246     /**
0247      * Return all ranges in this block which might intersect the given line and only span one line.
0248      * For them an internal fast lookup cache is hold.
0249      * @param line line to check intersection
0250      * @return set of ranges
0251      */
0252     const QVarLengthArray<TextRange *, 6> *cachedRangesForLine(int line) const
0253     {
0254         line -= m_startLine;
0255         if (line >= 0 && (size_t)line < m_cachedRangesForLine.size()) {
0256             return &m_cachedRangesForLine[line];
0257         } else {
0258             return nullptr;
0259         }
0260     }
0261 
0262 private:
0263     /**
0264      * parent text buffer
0265      */
0266     TextBuffer *m_buffer;
0267 
0268     /**
0269      * Lines contained in this buffer.
0270      * We need no sharing, use STL.
0271      */
0272     std::vector<Kate::TextLine> m_lines;
0273 
0274     /**
0275      * Startline of this block
0276      */
0277     int m_startLine;
0278 
0279     /**
0280      * size of block i.e., number of QChars
0281      */
0282     int m_blockSize = 0;
0283 
0284     /**
0285      * Set of cursors for this block.
0286      * using QSet is better than unordered_set for perf reasons
0287      */
0288     QSet<TextCursor *> m_cursors;
0289 
0290     /**
0291      * Contains for each line-offset the ranges that were cached into it.
0292      * These ranges are fully contained by the line.
0293      */
0294     std::vector<QVarLengthArray<TextRange *, 6>> m_cachedRangesForLine;
0295 
0296     /**
0297      * Maps for each cached range the line into which the range was cached.
0298      */
0299     QHash<TextRange *, int> m_cachedLineForRanges;
0300 
0301     /**
0302      * This contains all the ranges that are not cached.
0303      */
0304     QVarLengthArray<TextRange *, 1> m_uncachedRanges;
0305 };
0306 
0307 }
0308 
0309 #endif