File indexing completed on 2025-04-27 03:44:20
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