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 | |