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 Scintilla {
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 	IDocumentWithLineEnd *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 
GetNextChar()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 lineStartNext;
48 	bool atLineStart;
49 	bool atLineEnd;
50 	int state;
51 	int chPrev;
52 	int ch;
53 	Sci_Position width;
54 	int chNext;
55 	Sci_Position widthNext;
56 
57 	StyleContext(Sci_PositionU startPos, Sci_PositionU length,
58                         int initStyle, LexAccessor &styler_, char chMask='\377') :
styler(styler_)59 		styler(styler_),
60 		multiByteAccess(nullptr),
61 		endPos(startPos + length),
62 		posRelative(0),
63 		currentPosLastRelative(0x7FFFFFFF),
64 		offsetRelative(0),
65 		currentPos(startPos),
66 		currentLine(-1),
67 		lineStartNext(-1),
68 		atLineEnd(false),
69 		state(initStyle & chMask), // Mask off all bits which aren't in the chMask.
70 		chPrev(0),
71 		ch(0),
72 		width(0),
73 		chNext(0),
74 		widthNext(1) {
75 		if (styler.Encoding() != enc8bit) {
76 			multiByteAccess = styler.MultiByteAccess();
77 		}
78 		styler.StartAt(startPos /*, chMask*/);
79 		styler.StartSegment(startPos);
80 		currentLine = styler.GetLine(startPos);
81 		lineStartNext = styler.LineStart(currentLine+1);
82 		lengthDocument = static_cast<Sci_PositionU>(styler.Length());
83 		if (endPos == lengthDocument)
84 			endPos++;
85 		lineDocEnd = styler.GetLine(lengthDocument);
86 		atLineStart = static_cast<Sci_PositionU>(styler.LineStart(currentLine)) == startPos;
87 
88 		// Variable width is now 0 so GetNextChar gets the char at currentPos into chNext/widthNext
89 		width = 0;
90 		GetNextChar();
91 		ch = chNext;
92 		width = widthNext;
93 
94 		GetNextChar();
95 	}
96 	// Deleted so StyleContext objects can not be copied.
97 	StyleContext(const StyleContext &) = delete;
98 	StyleContext &operator=(const StyleContext &) = delete;
Complete()99 	void Complete() {
100 		styler.ColourTo(currentPos - ((currentPos > lengthDocument) ? 2 : 1), state);
101 		styler.Flush();
102 	}
More()103 	bool More() const {
104 		return currentPos < endPos;
105 	}
Forward()106 	void Forward() {
107 		if (currentPos < endPos) {
108 			atLineStart = atLineEnd;
109 			if (atLineStart) {
110 				currentLine++;
111 				lineStartNext = styler.LineStart(currentLine+1);
112 			}
113 			chPrev = ch;
114 			currentPos += width;
115 			ch = chNext;
116 			width = widthNext;
117 			GetNextChar();
118 		} else {
119 			atLineStart = false;
120 			chPrev = ' ';
121 			ch = ' ';
122 			chNext = ' ';
123 			atLineEnd = true;
124 		}
125 	}
Forward(Sci_Position nb)126 	void Forward(Sci_Position nb) {
127 		for (Sci_Position i = 0; i < nb; i++) {
128 			Forward();
129 		}
130 	}
ForwardBytes(Sci_Position nb)131 	void ForwardBytes(Sci_Position nb) {
132 		const Sci_PositionU forwardPos = currentPos + nb;
133 		while (forwardPos > currentPos) {
134 			const Sci_PositionU currentPosStart = currentPos;
135 			Forward();
136 			if (currentPos == currentPosStart) {
137 				// Reached end
138 				return;
139 			}
140 		}
141 	}
ChangeState(int state_)142 	void ChangeState(int state_) {
143 		state = state_;
144 	}
SetState(int state_)145 	void SetState(int state_) {
146 		styler.ColourTo(currentPos - ((currentPos > lengthDocument) ? 2 : 1), state);
147 		state = state_;
148 	}
ForwardSetState(int state_)149 	void ForwardSetState(int state_) {
150 		Forward();
151 		styler.ColourTo(currentPos - ((currentPos > lengthDocument) ? 2 : 1), state);
152 		state = state_;
153 	}
LengthCurrent()154 	Sci_Position LengthCurrent() const {
155 		return currentPos - styler.GetStartSegment();
156 	}
GetRelative(Sci_Position n)157 	int GetRelative(Sci_Position n) {
158 		return static_cast<unsigned char>(styler.SafeGetCharAt(currentPos+n, 0));
159 	}
GetRelativeCharacter(Sci_Position n)160 	int GetRelativeCharacter(Sci_Position n) {
161 		if (n == 0)
162 			return ch;
163 		if (multiByteAccess) {
164 			if ((currentPosLastRelative != currentPos) ||
165 				((n > 0) && ((offsetRelative < 0) || (n < offsetRelative))) ||
166 				((n < 0) && ((offsetRelative > 0) || (n > offsetRelative)))) {
167 				posRelative = currentPos;
168 				offsetRelative = 0;
169 			}
170 			const Sci_Position diffRelative = n - offsetRelative;
171 			const Sci_Position posNew = multiByteAccess->GetRelativePosition(posRelative, diffRelative);
172 			const int chReturn = multiByteAccess->GetCharacterAndWidth(posNew, nullptr);
173 			posRelative = posNew;
174 			currentPosLastRelative = currentPos;
175 			offsetRelative = n;
176 			return chReturn;
177 		} else {
178 			// fast version for single byte encodings
179 			return static_cast<unsigned char>(styler.SafeGetCharAt(currentPos + n, 0));
180 		}
181 	}
Match(char ch0)182 	bool Match(char ch0) const {
183 		return ch == static_cast<unsigned char>(ch0);
184 	}
Match(char ch0,char ch1)185 	bool Match(char ch0, char ch1) const {
186 		return (ch == static_cast<unsigned char>(ch0)) && (chNext == static_cast<unsigned char>(ch1));
187 	}
Match(const char * s)188 	bool Match(const char *s) {
189 		if (ch != static_cast<unsigned char>(*s))
190 			return false;
191 		s++;
192 		if (!*s)
193 			return true;
194 		if (chNext != static_cast<unsigned char>(*s))
195 			return false;
196 		s++;
197 		for (int n=2; *s; n++) {
198 			if (*s != styler.SafeGetCharAt(currentPos+n, 0))
199 				return false;
200 			s++;
201 		}
202 		return true;
203 	}
204 	// Non-inline
205 	bool MatchIgnoreCase(const char *s);
206 	void GetCurrent(char *s, Sci_PositionU len);
207 	void GetCurrentLowered(char *s, Sci_PositionU len);
208 };
209 
210 }
211 
212 #endif
213