File indexing completed on 2024-04-21 03:57:19

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_TEXTLINE_H
0008 #define KATE_TEXTLINE_H
0009 
0010 #include <KSyntaxHighlighting/State>
0011 
0012 #include <QList>
0013 #include <QString>
0014 
0015 namespace Kate
0016 {
0017 /**
0018  * Class representing a single text line.
0019  * For efficiency reasons, not only pure text is stored here, but also additional data.
0020  */
0021 class TextLine
0022 {
0023 public:
0024     /**
0025      * Attribute storage
0026      */
0027     class Attribute
0028     {
0029     public:
0030         /**
0031          * Attribute constructor
0032          * @param _offset offset
0033          * @param _length length
0034          * @param _attributeValue attribute value
0035          */
0036         explicit Attribute(int _offset = 0, int _length = 0, int _attributeValue = 0)
0037             : offset(_offset)
0038             , length(_length)
0039             , attributeValue(_attributeValue)
0040         {
0041         }
0042 
0043         /**
0044          * offset
0045          */
0046         int offset;
0047 
0048         /**
0049          * length
0050          */
0051         int length;
0052 
0053         /**
0054          * attribute value (to encode type of this range)
0055          */
0056         int attributeValue;
0057     };
0058 
0059     /**
0060      * Flags of TextLine
0061      */
0062     enum Flags { flagAutoWrapped = 1, flagFoldingStartAttribute = 2, flagFoldingEndAttribute = 4, flagLineModified = 8, flagLineSavedOnDisk = 16 };
0063 
0064     /**
0065      * Construct an empty text line.
0066      */
0067     TextLine() = default;
0068 
0069     /**
0070      * Construct an text line with given text.
0071      * @param text text to use for this line
0072      */
0073     explicit TextLine(const QString &text)
0074         : m_text(text)
0075         , m_flags(0)
0076     {
0077     }
0078 
0079     /**
0080      * Accessor to the text contained in this line.
0081      * @return text of this line as constant reference
0082      */
0083     const QString &text() const
0084     {
0085         return m_text;
0086     }
0087 
0088     /**
0089      * Accessor to the text contained in this line.
0090      * @return text of this line as reference
0091      */
0092     QString &text()
0093     {
0094         return m_text;
0095     }
0096 
0097     /**
0098      * Returns the position of the first non-whitespace character
0099      * @return position of first non-whitespace char or -1 if there is none
0100      */
0101     int firstChar() const;
0102 
0103     /**
0104      * Returns the position of the last non-whitespace character
0105      * @return position of last non-whitespace char or -1 if there is none
0106      */
0107     int lastChar() const;
0108 
0109     /**
0110      * Find the position of the next char that is not a space.
0111      * @param pos Column of the character which is examined first.
0112      * @return True if the specified or a following character is not a space
0113      *          Otherwise false.
0114      */
0115     int nextNonSpaceChar(int pos) const;
0116 
0117     /**
0118      * Find the position of the previous char that is not a space.
0119      * @param pos Column of the character which is examined first.
0120      * @return The position of the first non-whitespace character preceding pos,
0121      *   or -1 if none is found.
0122      */
0123     int previousNonSpaceChar(int pos) const;
0124 
0125     /**
0126      * Returns the character at the given \e column. If \e column is out of
0127      * range, the return value is QChar().
0128      * @param column column you want char for
0129      * @return char at given column or QChar()
0130      */
0131     inline QChar at(int column) const
0132     {
0133         if (column >= 0 && column < m_text.length()) {
0134             return m_text.at(column);
0135         }
0136 
0137         return QChar();
0138     }
0139 
0140     inline void markAsModified(bool modified)
0141     {
0142         if (modified) {
0143             m_flags |= flagLineModified;
0144             m_flags &= (~flagLineSavedOnDisk);
0145         } else {
0146             m_flags &= (~flagLineModified);
0147         }
0148     }
0149 
0150     inline bool markedAsModified() const
0151     {
0152         return m_flags & flagLineModified;
0153     }
0154 
0155     inline void markAsSavedOnDisk(bool savedOnDisk)
0156     {
0157         if (savedOnDisk) {
0158             m_flags |= flagLineSavedOnDisk;
0159             m_flags &= (~flagLineModified);
0160         } else {
0161             m_flags &= (~flagLineSavedOnDisk);
0162         }
0163     }
0164 
0165     inline bool markedAsSavedOnDisk() const
0166     {
0167         return m_flags & flagLineSavedOnDisk;
0168     }
0169 
0170     /**
0171      * Clear folding start and end status.
0172      */
0173     void clearMarkedAsFoldingStartAndEnd()
0174     {
0175         m_flags &= ~flagFoldingStartAttribute;
0176         m_flags &= ~flagFoldingEndAttribute;
0177     }
0178 
0179     /**
0180      * Is on this line a folding start per attribute?
0181      * @return folding start line per attribute? or not?
0182      */
0183     bool markedAsFoldingStartAttribute() const
0184     {
0185         return m_flags & flagFoldingStartAttribute;
0186     }
0187 
0188     /**
0189      * Mark as folding start line of an attribute based folding.
0190      */
0191     void markAsFoldingStartAttribute()
0192     {
0193         m_flags |= flagFoldingStartAttribute;
0194     }
0195 
0196     /**
0197      * Is on this line a folding end per attribute?
0198      * @return folding end line per attribute? or not?
0199      */
0200     bool markedAsFoldingEndAttribute() const
0201     {
0202         return m_flags & flagFoldingEndAttribute;
0203     }
0204 
0205     /**
0206      * Mark as folding end line of an attribute based folding.
0207      */
0208     void markAsFoldingEndAttribute()
0209     {
0210         m_flags |= flagFoldingEndAttribute;
0211     }
0212 
0213     /**
0214      * Returns the line's length.
0215      */
0216     int length() const
0217     {
0218         return m_text.length();
0219     }
0220 
0221     /**
0222      * Returns \e true, if the line was automagically wrapped, otherwise returns
0223      * \e false.
0224      * @return was this line auto-wrapped?
0225      */
0226     bool isAutoWrapped() const
0227     {
0228         return m_flags & flagAutoWrapped;
0229     }
0230 
0231     /**
0232      * Returns the substring with \e length beginning at the given \e column.
0233      * @param column start column of text to return
0234      * @param length length of text to return
0235      * @return wanted part of text
0236      */
0237     QString string(int column, int length) const
0238     {
0239         return m_text.mid(column, length);
0240     }
0241 
0242     /**
0243      * Leading whitespace of this line
0244      * @return leading whitespace of this line
0245      */
0246     QString leadingWhitespace() const;
0247 
0248     /**
0249      * Returns the indentation depth with each tab expanded into \e tabWidth characters.
0250      */
0251     int indentDepth(int tabWidth) const;
0252 
0253     /**
0254      * Returns the \e column with each tab expanded into \e tabWidth characters.
0255      */
0256     int toVirtualColumn(int column, int tabWidth) const;
0257 
0258     /**
0259      * Returns the "real" column where each tab only counts one character.
0260      * The conversion calculates with \e tabWidth characters for each tab.
0261      */
0262     int fromVirtualColumn(int column, int tabWidth) const;
0263 
0264     /**
0265      * Returns the text length with each tab expanded into \e tabWidth characters.
0266      */
0267     int virtualLength(int tabWidth) const;
0268 
0269     /**
0270      * Returns \e true, if \e match equals to the text at position \e column,
0271      * otherwise returns \e false.
0272      */
0273     bool matchesAt(int column, const QString &match) const;
0274 
0275     /**
0276      * Returns \e true, if the line starts with \e match, otherwise returns \e false.
0277      */
0278     bool startsWith(const QString &match) const
0279     {
0280         return m_text.startsWith(match);
0281     }
0282 
0283     /**
0284      * Returns \e true, if the line ends with \e match, otherwise returns \e false.
0285      */
0286     bool endsWith(const QString &match) const
0287     {
0288         return m_text.endsWith(match);
0289     }
0290 
0291     /**
0292      * context stack
0293      * @return context stack
0294      */
0295     const KSyntaxHighlighting::State &highlightingState() const
0296     {
0297         return m_highlightingState;
0298     }
0299 
0300     /**
0301      * Sets the syntax highlight context number
0302      * @param val new context array
0303      */
0304     void setHighlightingState(const KSyntaxHighlighting::State &val)
0305     {
0306         m_highlightingState = val;
0307     }
0308 
0309     /**
0310      * Add attribute to this line.
0311      * @param attribute new attribute to append
0312      */
0313     void addAttribute(const Attribute &attribute);
0314 
0315     /**
0316      * Clear attributes and foldings of this line
0317      */
0318     void clearAttributes()
0319     {
0320         m_attributesList.clear();
0321     }
0322 
0323     /**
0324      * Accessor to attributes
0325      * @return attributes of this line
0326      */
0327     const QList<Attribute> &attributesList() const
0328     {
0329         return m_attributesList;
0330     }
0331 
0332     /**
0333      * Gets the attribute at the given position
0334      * use KRenderer::attributes  to get the KTextAttribute for this.
0335      *
0336      * @param pos position of attribute requested
0337      * @return value of attribute
0338      */
0339     int attribute(int pos) const;
0340 
0341     /**
0342      * set auto-wrapped property
0343      * @param wrapped line was wrapped?
0344      */
0345     void setAutoWrapped(bool wrapped)
0346     {
0347         if (wrapped) {
0348             m_flags = m_flags | flagAutoWrapped;
0349         } else {
0350             m_flags = m_flags & ~flagAutoWrapped;
0351         }
0352     }
0353 
0354 private:
0355     /**
0356      * text of this line
0357      */
0358     QString m_text;
0359 
0360     /**
0361      * attributes of this line
0362      */
0363     QList<Attribute> m_attributesList;
0364 
0365     /**
0366      * current highlighting state
0367      */
0368     KSyntaxHighlighting::State m_highlightingState;
0369 
0370     /**
0371      * flags of this line
0372      */
0373     unsigned int m_flags = 0;
0374 };
0375 }
0376 
0377 #endif