| 1 | // Scintilla source code edit control |
| 2 | /** @file LexAccessor.h |
| 3 | ** Interfaces between Scintilla and lexers. |
| 4 | **/ |
| 5 | // Copyright 1998-2010 by Neil Hodgson <neilh@scintilla.org> |
| 6 | // The License.txt file describes the conditions under which this software may be distributed. |
| 7 | |
| 8 | #ifndef LEXACCESSOR_H |
| 9 | #define LEXACCESSOR_H |
| 10 | |
| 11 | namespace Lexilla { |
| 12 | |
| 13 | enum class EncodingType { eightBit, unicode, dbcs }; |
| 14 | |
| 15 | class LexAccessor { |
| 16 | private: |
| 17 | Scintilla::IDocument *pAccess; |
| 18 | enum {extremePosition=0x7FFFFFFF}; |
| 19 | /** @a bufferSize is a trade off between time taken to copy the characters |
| 20 | * and retrieval overhead. |
| 21 | * @a slopSize positions the buffer before the desired position |
| 22 | * in case there is some backtracking. */ |
| 23 | enum {bufferSize=4000, slopSize=bufferSize/8}; |
| 24 | char buf[bufferSize+1]; |
| 25 | Sci_Position startPos; |
| 26 | Sci_Position endPos; |
| 27 | int codePage; |
| 28 | enum EncodingType encodingType; |
| 29 | Sci_Position lenDoc; |
| 30 | char styleBuf[bufferSize]; |
| 31 | Sci_Position validLen; |
| 32 | Sci_PositionU startSeg; |
| 33 | Sci_Position startPosStyling; |
| 34 | int documentVersion; |
| 35 | |
| 36 | void Fill(Sci_Position position) { |
| 37 | startPos = position - slopSize; |
| 38 | if (startPos + bufferSize > lenDoc) |
| 39 | startPos = lenDoc - bufferSize; |
| 40 | if (startPos < 0) |
| 41 | startPos = 0; |
| 42 | endPos = startPos + bufferSize; |
| 43 | if (endPos > lenDoc) |
| 44 | endPos = lenDoc; |
| 45 | |
| 46 | pAccess->GetCharRange(buf, startPos, endPos-startPos); |
| 47 | buf[endPos-startPos] = '\0'; |
| 48 | } |
| 49 | |
| 50 | public: |
| 51 | explicit LexAccessor(Scintilla::IDocument *pAccess_) : |
| 52 | pAccess(pAccess_), startPos(extremePosition), endPos(0), |
| 53 | codePage(pAccess->CodePage()), |
| 54 | encodingType(EncodingType::eightBit), |
| 55 | lenDoc(pAccess->Length()), |
| 56 | validLen(0), |
| 57 | startSeg(0), startPosStyling(0), |
| 58 | documentVersion(pAccess->Version()) { |
| 59 | // Prevent warnings by static analyzers about uninitialized buf and styleBuf. |
| 60 | buf[0] = 0; |
| 61 | styleBuf[0] = 0; |
| 62 | switch (codePage) { |
| 63 | case 65001: |
| 64 | encodingType = EncodingType::unicode; |
| 65 | break; |
| 66 | case 932: |
| 67 | case 936: |
| 68 | case 949: |
| 69 | case 950: |
| 70 | case 1361: |
| 71 | encodingType = EncodingType::dbcs; |
| 72 | } |
| 73 | } |
| 74 | char operator[](Sci_Position position) { |
| 75 | if (position < startPos || position >= endPos) { |
| 76 | Fill(position); |
| 77 | } |
| 78 | return buf[position - startPos]; |
| 79 | } |
| 80 | Scintilla::IDocument *MultiByteAccess() const noexcept { |
| 81 | return pAccess; |
| 82 | } |
| 83 | /** Safe version of operator[], returning a defined value for invalid position. */ |
| 84 | char SafeGetCharAt(Sci_Position position, char chDefault=' ') { |
| 85 | if (position < startPos || position >= endPos) { |
| 86 | Fill(position); |
| 87 | if (position < startPos || position >= endPos) { |
| 88 | // Position is outside range of document |
| 89 | return chDefault; |
| 90 | } |
| 91 | } |
| 92 | return buf[position - startPos]; |
| 93 | } |
| 94 | bool IsLeadByte(char ch) const { |
| 95 | return |
| 96 | (static_cast<unsigned char>(ch) >= 0x80) && // non-ASCII |
| 97 | (encodingType == EncodingType::dbcs) && // IsDBCSLeadByte only for DBCS |
| 98 | pAccess->IsDBCSLeadByte(ch); |
| 99 | } |
| 100 | EncodingType Encoding() const noexcept { |
| 101 | return encodingType; |
| 102 | } |
| 103 | bool Match(Sci_Position pos, const char *s) { |
| 104 | for (int i=0; *s; i++) { |
| 105 | if (*s != SafeGetCharAt(pos+i)) |
| 106 | return false; |
| 107 | s++; |
| 108 | } |
| 109 | return true; |
| 110 | } |
| 111 | bool MatchIgnoreCase(Sci_Position pos, const char *s); |
| 112 | |
| 113 | // Get first len - 1 characters in range [startPos_, endPos_). |
| 114 | void GetRange(Sci_PositionU startPos_, Sci_PositionU endPos_, char *s, Sci_PositionU len); |
| 115 | void GetRangeLowered(Sci_PositionU startPos_, Sci_PositionU endPos_, char *s, Sci_PositionU len); |
| 116 | // Get all characters in range [startPos_, endPos_). |
| 117 | std::string GetRange(Sci_PositionU startPos_, Sci_PositionU endPos_); |
| 118 | std::string GetRangeLowered(Sci_PositionU startPos_, Sci_PositionU endPos_); |
| 119 | |
| 120 | char StyleAt(Sci_Position position) const { |
| 121 | return pAccess->StyleAt(position); |
| 122 | } |
| 123 | Sci_Position GetLine(Sci_Position position) const { |
| 124 | return pAccess->LineFromPosition(position); |
| 125 | } |
| 126 | Sci_Position LineStart(Sci_Position line) const { |
| 127 | return pAccess->LineStart(line); |
| 128 | } |
| 129 | Sci_Position LineEnd(Sci_Position line) const { |
| 130 | return pAccess->LineEnd(line); |
| 131 | } |
| 132 | int LevelAt(Sci_Position line) const { |
| 133 | return pAccess->GetLevel(line); |
| 134 | } |
| 135 | Sci_Position Length() const { |
| 136 | return lenDoc; |
| 137 | } |
| 138 | void Flush() { |
| 139 | if (validLen > 0) { |
| 140 | pAccess->SetStyles(validLen, styleBuf); |
| 141 | startPosStyling += validLen; |
| 142 | validLen = 0; |
| 143 | } |
| 144 | } |
| 145 | int GetLineState(Sci_Position line) const { |
| 146 | return pAccess->GetLineState(line); |
| 147 | } |
| 148 | int SetLineState(Sci_Position line, int state) { |
| 149 | return pAccess->SetLineState(line, state); |
| 150 | } |
| 151 | // Style setting |
| 152 | void StartAt(Sci_PositionU start) { |
| 153 | pAccess->StartStyling(start); |
| 154 | startPosStyling = start; |
| 155 | } |
| 156 | Sci_PositionU GetStartSegment() const { |
| 157 | return startSeg; |
| 158 | } |
| 159 | void StartSegment(Sci_PositionU pos) { |
| 160 | startSeg = pos; |
| 161 | } |
| 162 | void ColourTo(Sci_PositionU pos, int chAttr) { |
| 163 | // Only perform styling if non empty range |
| 164 | if (pos != startSeg - 1) { |
| 165 | assert(pos >= startSeg); |
| 166 | if (pos < startSeg) { |
| 167 | return; |
| 168 | } |
| 169 | |
| 170 | if (validLen + (pos - startSeg + 1) >= bufferSize) |
| 171 | Flush(); |
| 172 | const char attr = static_cast<char>(chAttr); |
| 173 | if (validLen + (pos - startSeg + 1) >= bufferSize) { |
| 174 | // Too big for buffer so send directly |
| 175 | pAccess->SetStyleFor(pos - startSeg + 1, attr); |
| 176 | } else { |
| 177 | for (Sci_PositionU i = startSeg; i <= pos; i++) { |
| 178 | assert((startPosStyling + validLen) < Length()); |
| 179 | styleBuf[validLen++] = attr; |
| 180 | } |
| 181 | } |
| 182 | } |
| 183 | startSeg = pos+1; |
| 184 | } |
| 185 | void SetLevel(Sci_Position line, int level) { |
| 186 | pAccess->SetLevel(line, level); |
| 187 | } |
| 188 | void IndicatorFill(Sci_Position start, Sci_Position end, int indicator, int value) { |
| 189 | pAccess->DecorationSetCurrentIndicator(indicator); |
| 190 | pAccess->DecorationFillRange(start, value, end - start); |
| 191 | } |
| 192 | |
| 193 | void ChangeLexerState(Sci_Position start, Sci_Position end) { |
| 194 | pAccess->ChangeLexerState(start, end); |
| 195 | } |
| 196 | }; |
| 197 | |
| 198 | struct LexicalClass { |
| 199 | int value; |
| 200 | const char *name; |
| 201 | const char *tags; |
| 202 | const char *description; |
| 203 | }; |
| 204 | |
| 205 | } |
| 206 | |
| 207 | #endif |
| 208 | |