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
11namespace 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
17class 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
43public:
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