File indexing completed on 2024-04-21 15:03:32

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