]> git.saurik.com Git - wxWidgets.git/blob - src/stc/scintilla/src/LexCSS.cxx
11daa142388d83d3080f53c7b878d8a3b4a1a281
[wxWidgets.git] / src / stc / scintilla / src / LexCSS.cxx
1 // Scintilla source code edit control
2 /** @file LexCSS.cxx
3 ** Lexer for Cascade Style Sheets
4 ** Written by Jakub Vrána
5 **/
6 // Copyright 1998-2002 by Neil Hodgson <neilh@scintilla.org>
7 // The License.txt file describes the conditions under which this software may be distributed.
8
9 #include <stdlib.h>
10 #include <string.h>
11 #include <ctype.h>
12 #include <stdio.h>
13 #include <stdarg.h>
14
15 #include "Platform.h"
16
17 #include "PropSet.h"
18 #include "Accessor.h"
19 #include "StyleContext.h"
20 #include "KeyWords.h"
21 #include "Scintilla.h"
22 #include "SciLexer.h"
23
24 static inline bool IsAWordChar(const unsigned int ch) {
25 return (isalnum(ch) || ch == '-' || ch == '_' || ch >= 161); // _ is not in fact correct CSS word-character
26 }
27
28 inline bool IsCssOperator(const char ch) {
29 if (!isalnum(ch) && (ch == '{' || ch == '}' || ch == ':' || ch == ',' || ch == ';' || ch == '.' || ch == '#' || ch == '!' || ch == '@'))
30 return true;
31 return false;
32 }
33
34 static void ColouriseCssDoc(unsigned int startPos, int length, int initStyle, WordList *keywordlists[], Accessor &styler) {
35 WordList &keywords = *keywordlists[0];
36 WordList &pseudoClasses = *keywordlists[1];
37
38 StyleContext sc(startPos, length, initStyle, styler);
39
40 int lastState = -1; // before operator
41 int lastStateC = -1; // before comment
42 int op = ' '; // last operator
43
44 for (; sc.More(); sc.Forward()) {
45 if (sc.state == SCE_CSS_COMMENT && sc.Match('*', '/')) {
46 if (lastStateC == -1) {
47 // backtrack to get last state
48 unsigned int i = startPos;
49 for (; i > 0; i--) {
50 if ((lastStateC = styler.StyleAt(i-1)) != SCE_CSS_COMMENT) {
51 if (lastStateC == SCE_CSS_OPERATOR) {
52 op = styler.SafeGetCharAt(i-1);
53 while (--i) {
54 lastState = styler.StyleAt(i-1);
55 if (lastState != SCE_CSS_OPERATOR && lastState != SCE_CSS_COMMENT)
56 break;
57 }
58 if (i == 0)
59 lastState = SCE_CSS_DEFAULT;
60 }
61 break;
62 }
63 }
64 if (i == 0)
65 lastStateC = SCE_CSS_DEFAULT;
66 }
67 sc.Forward();
68 sc.ForwardSetState(lastStateC);
69 }
70
71 if (sc.state == SCE_CSS_COMMENT)
72 continue;
73
74 if (sc.state == SCE_CSS_DOUBLESTRING || sc.state == SCE_CSS_SINGLESTRING) {
75 if (sc.ch != (sc.state == SCE_CSS_DOUBLESTRING ? '\"' : '\''))
76 continue;
77 unsigned int i = sc.currentPos;
78 while (i && styler[i-1] == '\\')
79 i--;
80 if ((sc.currentPos - i) % 2 == 1)
81 continue;
82 sc.ForwardSetState(SCE_CSS_VALUE);
83 }
84
85 if (sc.state == SCE_CSS_OPERATOR) {
86 if (op == ' ') {
87 unsigned int i = startPos;
88 op = styler.SafeGetCharAt(i-1);
89 while (--i) {
90 lastState = styler.StyleAt(i-1);
91 if (lastState != SCE_CSS_OPERATOR && lastState != SCE_CSS_COMMENT)
92 break;
93 }
94 }
95 switch (op) {
96 case '@':
97 if (lastState == SCE_CSS_DEFAULT)
98 sc.SetState(SCE_CSS_DIRECTIVE);
99 break;
100 case '{':
101 if (lastState == SCE_CSS_DIRECTIVE)
102 sc.SetState(SCE_CSS_DEFAULT);
103 else if (lastState == SCE_CSS_TAG)
104 sc.SetState(SCE_CSS_IDENTIFIER);
105 break;
106 case '}':
107 if (lastState == SCE_CSS_DEFAULT || lastState == SCE_CSS_VALUE || lastState == SCE_CSS_IMPORTANT || lastState == SCE_CSS_IDENTIFIER)
108 sc.SetState(SCE_CSS_DEFAULT);
109 break;
110 case ':':
111 if (lastState == SCE_CSS_TAG || lastState == SCE_CSS_PSEUDOCLASS || lastState == SCE_CSS_DEFAULT ||
112 lastState == SCE_CSS_CLASS || lastState == SCE_CSS_ID || lastState == SCE_CSS_UNKNOWN_PSEUDOCLASS)
113 sc.SetState(SCE_CSS_PSEUDOCLASS);
114 else if (lastState == SCE_CSS_IDENTIFIER || lastState == SCE_CSS_UNKNOWN_IDENTIFIER)
115 sc.SetState(SCE_CSS_VALUE);
116 break;
117 case '.':
118 if (lastState == SCE_CSS_TAG || lastState == SCE_CSS_DEFAULT)
119 sc.SetState(SCE_CSS_CLASS);
120 break;
121 case '#':
122 if (lastState == SCE_CSS_TAG || lastState == SCE_CSS_DEFAULT)
123 sc.SetState(SCE_CSS_ID);
124 break;
125 case ',':
126 if (lastState == SCE_CSS_TAG)
127 sc.SetState(SCE_CSS_DEFAULT);
128 break;
129 case ';':
130 if (lastState == SCE_CSS_DIRECTIVE)
131 sc.SetState(SCE_CSS_DEFAULT);
132 else if (lastState == SCE_CSS_VALUE || lastState == SCE_CSS_IMPORTANT)
133 sc.SetState(SCE_CSS_IDENTIFIER);
134 break;
135 case '!':
136 if (lastState == SCE_CSS_VALUE)
137 sc.SetState(SCE_CSS_IMPORTANT);
138 break;
139 }
140 }
141
142 if (IsAWordChar(sc.ch)) {
143 if (sc.state == SCE_CSS_DEFAULT)
144 sc.SetState(SCE_CSS_TAG);
145 continue;
146 }
147
148 if (IsAWordChar(sc.chPrev) && (
149 sc.state == SCE_CSS_IDENTIFIER || sc.state == SCE_CSS_UNKNOWN_IDENTIFIER
150 || sc.state == SCE_CSS_PSEUDOCLASS || sc.state == SCE_CSS_UNKNOWN_PSEUDOCLASS
151 || sc.state == SCE_CSS_IMPORTANT
152 )) {
153 char s[100];
154 sc.GetCurrentLowered(s, sizeof(s));
155 char *s2 = s;
156 while (*s2 && !IsAWordChar(*s2))
157 s2++;
158 switch (sc.state) {
159 case SCE_CSS_IDENTIFIER:
160 if (!keywords.InList(s2))
161 sc.ChangeState(SCE_CSS_UNKNOWN_IDENTIFIER);
162 break;
163 case SCE_CSS_UNKNOWN_IDENTIFIER:
164 if (keywords.InList(s2))
165 sc.ChangeState(SCE_CSS_IDENTIFIER);
166 break;
167 case SCE_CSS_PSEUDOCLASS:
168 if (!pseudoClasses.InList(s2))
169 sc.ChangeState(SCE_CSS_UNKNOWN_PSEUDOCLASS);
170 break;
171 case SCE_CSS_UNKNOWN_PSEUDOCLASS:
172 if (pseudoClasses.InList(s2))
173 sc.ChangeState(SCE_CSS_PSEUDOCLASS);
174 break;
175 case SCE_CSS_IMPORTANT:
176 if (strcmp(s2, "important") != 0)
177 sc.ChangeState(SCE_CSS_VALUE);
178 break;
179 }
180 }
181
182 if (sc.ch != '.' && sc.ch != ':' && sc.ch != '#' && (sc.state == SCE_CSS_CLASS || sc.state == SCE_CSS_PSEUDOCLASS || sc.state == SCE_CSS_UNKNOWN_PSEUDOCLASS || sc.state == SCE_CSS_ID))
183 sc.SetState(SCE_CSS_TAG);
184
185 if (sc.Match('/', '*')) {
186 lastStateC = sc.state;
187 sc.SetState(SCE_CSS_COMMENT);
188 sc.Forward();
189 } else if (sc.state == SCE_CSS_VALUE && (sc.ch == '\"' || sc.ch == '\'')) {
190 sc.SetState((sc.ch == '\"' ? SCE_CSS_DOUBLESTRING : SCE_CSS_SINGLESTRING));
191 } else if (IsCssOperator(static_cast<char>(sc.ch))
192 && (sc.state != SCE_CSS_VALUE || sc.ch == ';' || sc.ch == '}' || sc.ch == '!')
193 && (sc.state != SCE_CSS_DIRECTIVE || sc.ch == ';' || sc.ch == '{')
194 ) {
195 if (sc.state != SCE_CSS_OPERATOR)
196 lastState = sc.state;
197 sc.SetState(SCE_CSS_OPERATOR);
198 op = sc.ch;
199 }
200 }
201
202 sc.Complete();
203 }
204
205 static void FoldCSSDoc(unsigned int startPos, int length, int, WordList *[], Accessor &styler) {
206 bool foldComment = styler.GetPropertyInt("fold.comment") != 0;
207 bool foldCompact = styler.GetPropertyInt("fold.compact", 1) != 0;
208 unsigned int endPos = startPos + length;
209 int visibleChars = 0;
210 int lineCurrent = styler.GetLine(startPos);
211 int levelPrev = styler.LevelAt(lineCurrent) & SC_FOLDLEVELNUMBERMASK;
212 int levelCurrent = levelPrev;
213 char chNext = styler[startPos];
214 bool inComment = (styler.StyleAt(startPos-1) == SCE_CSS_COMMENT);
215 for (unsigned int i = startPos; i < endPos; i++) {
216 char ch = chNext;
217 chNext = styler.SafeGetCharAt(i + 1);
218 int style = styler.StyleAt(i);
219 bool atEOL = (ch == '\r' && chNext != '\n') || (ch == '\n');
220 if (foldComment) {
221 if (!inComment && (style == SCE_CSS_COMMENT))
222 levelCurrent++;
223 else if (inComment && (style != SCE_CSS_COMMENT))
224 levelCurrent--;
225 inComment = (style == SCE_CSS_COMMENT);
226 }
227 if (style == SCE_CSS_OPERATOR) {
228 if (ch == '{') {
229 levelCurrent++;
230 } else if (ch == '}') {
231 levelCurrent--;
232 }
233 }
234 if (atEOL) {
235 int lev = levelPrev;
236 if (visibleChars == 0 && foldCompact)
237 lev |= SC_FOLDLEVELWHITEFLAG;
238 if ((levelCurrent > levelPrev) && (visibleChars > 0))
239 lev |= SC_FOLDLEVELHEADERFLAG;
240 if (lev != styler.LevelAt(lineCurrent)) {
241 styler.SetLevel(lineCurrent, lev);
242 }
243 lineCurrent++;
244 levelPrev = levelCurrent;
245 visibleChars = 0;
246 }
247 if (!isspacechar(ch))
248 visibleChars++;
249 }
250 // Fill in the real level of the next line, keeping the current flags as they will be filled in later
251 int flagsNext = styler.LevelAt(lineCurrent) & ~SC_FOLDLEVELNUMBERMASK;
252 styler.SetLevel(lineCurrent, levelPrev | flagsNext);
253 }
254
255 static const char * const cssWordListDesc[] = {
256 "Keywords",
257 "Pseudo classes",
258 0
259 };
260
261 LexerModule lmCss(SCLEX_CSS, ColouriseCssDoc, "css", FoldCSSDoc, cssWordListDesc);