1 | // Scintilla source code edit control |
2 | /** @file StyleContext.h |
3 | ** Lexer infrastructure. |
4 | **/ |
5 | // Copyright 1998-2004 by Neil Hodgson <neilh@scintilla.org> |
6 | // This file is in the public domain. |
7 | |
8 | #ifndef STYLECONTEXT_H |
9 | #define STYLECONTEXT_H |
10 | |
11 | namespace Lexilla { |
12 | |
13 | // All languages handled so far can treat all characters >= 0x80 as one class |
14 | // which just continues the current token or starts an identifier if in default. |
15 | // DBCS treated specially as the second character can be < 0x80 and hence |
16 | // syntactically significant. UTF-8 avoids this as all trail bytes are >= 0x80 |
17 | class StyleContext { |
18 | LexAccessor &styler; |
19 | Scintilla::IDocument *multiByteAccess; |
20 | Sci_PositionU endPos; |
21 | Sci_PositionU lengthDocument; |
22 | |
23 | // Used for optimizing GetRelativeCharacter |
24 | Sci_PositionU posRelative; |
25 | Sci_PositionU currentPosLastRelative; |
26 | Sci_Position offsetRelative; |
27 | |
28 | void GetNextChar() { |
29 | if (multiByteAccess) { |
30 | chNext = multiByteAccess->GetCharacterAndWidth(currentPos+width, &widthNext); |
31 | } else { |
32 | chNext = static_cast<unsigned char>(styler.SafeGetCharAt(currentPos+width, 0)); |
33 | widthNext = 1; |
34 | } |
35 | // End of line determined from line end position, allowing CR, LF, |
36 | // CRLF and Unicode line ends as set by document. |
37 | if (currentLine < lineDocEnd) |
38 | atLineEnd = static_cast<Sci_Position>(currentPos) >= (lineStartNext-1); |
39 | else // Last line |
40 | atLineEnd = static_cast<Sci_Position>(currentPos) >= lineStartNext; |
41 | } |
42 | |
43 | public: |
44 | Sci_PositionU currentPos; |
45 | Sci_Position currentLine; |
46 | Sci_Position lineDocEnd; |
47 | Sci_Position lineEnd; |
48 | Sci_Position lineStartNext; |
49 | bool atLineStart; |
50 | bool atLineEnd; |
51 | int state; |
52 | int chPrev; |
53 | int ch; |
54 | Sci_Position width; |
55 | int chNext; |
56 | Sci_Position widthNext; |
57 | |
58 | StyleContext(Sci_PositionU startPos, Sci_PositionU length, |
59 | int initStyle, LexAccessor &styler_, char chMask='\377') : |
60 | styler(styler_), |
61 | multiByteAccess(nullptr), |
62 | endPos(startPos + length), |
63 | posRelative(0), |
64 | currentPosLastRelative(0x7FFFFFFF), |
65 | offsetRelative(0), |
66 | currentPos(startPos), |
67 | currentLine(-1), |
68 | lineEnd(-1), |
69 | lineStartNext(-1), |
70 | atLineEnd(false), |
71 | state(initStyle & chMask), // Mask off all bits which aren't in the chMask. |
72 | chPrev(0), |
73 | ch(0), |
74 | width(0), |
75 | chNext(0), |
76 | widthNext(1) { |
77 | if (styler.Encoding() != EncodingType::eightBit) { |
78 | multiByteAccess = styler.MultiByteAccess(); |
79 | } |
80 | styler.StartAt(startPos /*, chMask*/); |
81 | styler.StartSegment(startPos); |
82 | currentLine = styler.GetLine(startPos); |
83 | lineEnd = styler.LineEnd(currentLine); |
84 | lineStartNext = styler.LineStart(currentLine+1); |
85 | lengthDocument = static_cast<Sci_PositionU>(styler.Length()); |
86 | if (endPos == lengthDocument) |
87 | endPos++; |
88 | lineDocEnd = styler.GetLine(lengthDocument); |
89 | atLineStart = static_cast<Sci_PositionU>(styler.LineStart(currentLine)) == startPos; |
90 | |
91 | // Variable width is now 0 so GetNextChar gets the char at currentPos into chNext/widthNext |
92 | width = 0; |
93 | GetNextChar(); |
94 | ch = chNext; |
95 | width = widthNext; |
96 | |
97 | GetNextChar(); |
98 | } |
99 | // Deleted so StyleContext objects can not be copied. |
100 | StyleContext(const StyleContext &) = delete; |
101 | StyleContext &operator=(const StyleContext &) = delete; |
102 | void Complete() { |
103 | styler.ColourTo(currentPos - ((currentPos > lengthDocument) ? 2 : 1), state); |
104 | styler.Flush(); |
105 | } |
106 | bool More() const noexcept { |
107 | return currentPos < endPos; |
108 | } |
109 | void Forward() { |
110 | if (currentPos < endPos) { |
111 | atLineStart = atLineEnd; |
112 | if (atLineStart) { |
113 | currentLine++; |
114 | lineEnd = styler.LineEnd(currentLine); |
115 | lineStartNext = styler.LineStart(currentLine+1); |
116 | } |
117 | chPrev = ch; |
118 | currentPos += width; |
119 | ch = chNext; |
120 | width = widthNext; |
121 | GetNextChar(); |
122 | } else { |
123 | atLineStart = false; |
124 | chPrev = ' '; |
125 | ch = ' '; |
126 | chNext = ' '; |
127 | atLineEnd = true; |
128 | } |
129 | } |
130 | void Forward(Sci_Position nb) { |
131 | for (Sci_Position i = 0; i < nb; i++) { |
132 | Forward(); |
133 | } |
134 | } |
135 | void ForwardBytes(Sci_Position nb) { |
136 | const Sci_PositionU forwardPos = currentPos + nb; |
137 | while (forwardPos > currentPos) { |
138 | const Sci_PositionU currentPosStart = currentPos; |
139 | Forward(); |
140 | if (currentPos == currentPosStart) { |
141 | // Reached end |
142 | return; |
143 | } |
144 | } |
145 | } |
146 | void ChangeState(int state_) noexcept { |
147 | state = state_; |
148 | } |
149 | void SetState(int state_) { |
150 | styler.ColourTo(currentPos - ((currentPos > lengthDocument) ? 2 : 1), state); |
151 | state = state_; |
152 | } |
153 | void ForwardSetState(int state_) { |
154 | Forward(); |
155 | styler.ColourTo(currentPos - ((currentPos > lengthDocument) ? 2 : 1), state); |
156 | state = state_; |
157 | } |
158 | Sci_Position LengthCurrent() const { |
159 | return currentPos - styler.GetStartSegment(); |
160 | } |
161 | int GetRelative(Sci_Position n, char chDefault='\0') { |
162 | return static_cast<unsigned char>(styler.SafeGetCharAt(currentPos+n, chDefault)); |
163 | } |
164 | int GetRelativeCharacter(Sci_Position n) { |
165 | if (n == 0) |
166 | return ch; |
167 | if (multiByteAccess) { |
168 | if ((currentPosLastRelative != currentPos) || |
169 | ((n > 0) && ((offsetRelative < 0) || (n < offsetRelative))) || |
170 | ((n < 0) && ((offsetRelative > 0) || (n > offsetRelative)))) { |
171 | posRelative = currentPos; |
172 | offsetRelative = 0; |
173 | } |
174 | const Sci_Position diffRelative = n - offsetRelative; |
175 | const Sci_Position posNew = multiByteAccess->GetRelativePosition(posRelative, diffRelative); |
176 | const int chReturn = multiByteAccess->GetCharacterAndWidth(posNew, nullptr); |
177 | posRelative = posNew; |
178 | currentPosLastRelative = currentPos; |
179 | offsetRelative = n; |
180 | return chReturn; |
181 | } else { |
182 | // fast version for single byte encodings |
183 | return static_cast<unsigned char>(styler.SafeGetCharAt(currentPos + n, 0)); |
184 | } |
185 | } |
186 | bool MatchLineEnd() const noexcept { |
187 | return static_cast<Sci_Position>(currentPos) == lineEnd; |
188 | } |
189 | bool Match(char ch0) const { |
190 | return ch == static_cast<unsigned char>(ch0); |
191 | } |
192 | bool Match(char ch0, char ch1) const { |
193 | return (ch == static_cast<unsigned char>(ch0)) && (chNext == static_cast<unsigned char>(ch1)); |
194 | } |
195 | bool Match(const char *s) { |
196 | if (ch != static_cast<unsigned char>(*s)) |
197 | return false; |
198 | s++; |
199 | if (!*s) |
200 | return true; |
201 | if (chNext != static_cast<unsigned char>(*s)) |
202 | return false; |
203 | s++; |
204 | for (int n=2; *s; n++) { |
205 | if (*s != styler.SafeGetCharAt(currentPos+n, 0)) |
206 | return false; |
207 | s++; |
208 | } |
209 | return true; |
210 | } |
211 | // Non-inline |
212 | bool MatchIgnoreCase(const char *s); |
213 | void GetCurrent(char *s, Sci_PositionU len); |
214 | void GetCurrentLowered(char *s, Sci_PositionU len); |
215 | }; |
216 | |
217 | } |
218 | |
219 | #endif |
220 | |