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
11namespace Lexilla {
12
13enum class EncodingType { eightBit, unicode, dbcs };
14
15class LexAccessor {
16private:
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
50public:
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
198struct LexicalClass {
199 int value;
200 const char *name;
201 const char *tags;
202 const char *description;
203};
204
205}
206
207#endif
208