1 // Scintilla source code edit control
2 // Copyright 1998-2002 by Neil Hodgson <neilh@scintilla.org>
3 // @file LexGui4Cli.cxx
4 /*
5 This is the Lexer for Gui4Cli, included in SciLexer.dll
6 - by d. Keletsekis, 2/10/2003
7 
8 To add to SciLexer.dll:
9 1. Add the values below to INCLUDE\Scintilla.iface
10 2. Run the scripts/HFacer.py script
11 3. Run the scripts/LexGen.py script
12 
13 val SCE_GC_DEFAULT=0
14 val SCE_GC_COMMENTLINE=1
15 val SCE_GC_COMMENTBLOCK=2
16 val SCE_GC_GLOBAL=3
17 val SCE_GC_EVENT=4
18 val SCE_GC_ATTRIBUTE=5
19 val SCE_GC_CONTROL=6
20 val SCE_GC_COMMAND=7
21 val SCE_GC_STRING=8
22 val SCE_GC_OPERATOR=9
23 */
24 
25 #include <stdlib.h>
26 #include <string.h>
27 #include <stdio.h>
28 #include <stdarg.h>
29 #include <assert.h>
30 #include <ctype.h>
31 
32 #include "ILexer.h"
33 #include "Scintilla.h"
34 #include "SciLexer.h"
35 
36 #include "WordList.h"
37 #include "LexAccessor.h"
38 #include "Accessor.h"
39 #include "StyleContext.h"
40 #include "CharacterSet.h"
41 #include "LexerModule.h"
42 
43 using namespace Scintilla;
44 
45 #define debug Platform::DebugPrintf
46 
IsAWordChar(const int ch)47 static inline bool IsAWordChar(const int ch) {
48 	return (ch < 0x80) && (isalnum(ch) || ch == '.' || ch == '_' || ch =='\\');
49 }
50 
isGCOperator(int ch)51 inline bool isGCOperator(int ch)
52 {	if (isalnum(ch))
53 		return false;
54 	// '.' left out as it is used to make up numbers
55 	if (ch == '*' || ch == '/' || ch == '-' || ch == '+' ||
56 		 ch == '(' || ch == ')' || ch == '=' || ch == '%' ||
57 		 ch == '[' || ch == ']' || ch == '<' || ch == '>' ||
58 		 ch == ',' || ch == ';' || ch == ':')
59 		return true;
60 	return false;
61 }
62 
63 #define isSpace(x)		((x)==' ' || (x)=='\t')
64 #define isNL(x)			((x)=='\n' || (x)=='\r')
65 #define isSpaceOrNL(x)  (isSpace(x) || isNL(x))
66 #define BUFFSIZE 500
67 #define isFoldPoint(x)  ((styler.LevelAt(x) & SC_FOLDLEVELNUMBERMASK) == 1024)
68 
colorFirstWord(WordList * keywordlists[],Accessor & styler,StyleContext * sc,char * buff,Sci_Position length,Sci_Position)69 static void colorFirstWord(WordList *keywordlists[], Accessor &styler,
70 									StyleContext *sc, char *buff, Sci_Position length, Sci_Position)
71 {
72 	Sci_Position c = 0;
73 	while (sc->More() && isSpaceOrNL(sc->ch))
74 	{	sc->Forward();
75 	}
76 	styler.ColourTo(sc->currentPos - 1, sc->state);
77 
78 	if (!IsAWordChar(sc->ch)) // comment, marker, etc..
79 		return;
80 
81 	while (sc->More() && !isSpaceOrNL(sc->ch) && (c < length-1) && !isGCOperator(sc->ch))
82 	{	buff[c] = static_cast<char>(sc->ch);
83 		++c; sc->Forward();
84 	}
85 	buff[c] = '\0';
86 	char *p = buff;
87 	while (*p)	// capitalize..
88 	{	if (islower(*p)) *p = static_cast<char>(toupper(*p));
89 		++p;
90 	}
91 
92 	WordList &kGlobal		= *keywordlists[0];	// keyword lists set by the user
93 	WordList &kEvent		= *keywordlists[1];
94 	WordList &kAttribute	= *keywordlists[2];
95 	WordList &kControl	= *keywordlists[3];
96 	WordList &kCommand	= *keywordlists[4];
97 
98 	int state = 0;
99 	// int level = styler.LevelAt(line) & SC_FOLDLEVELNUMBERMASK;
100 	// debug ("line = %d, level = %d", line, level);
101 
102 	if	     (kGlobal.InList(buff))		state = SCE_GC_GLOBAL;
103 	else if (kAttribute.InList(buff))	state = SCE_GC_ATTRIBUTE;
104 	else if (kControl.InList(buff))		state = SCE_GC_CONTROL;
105 	else if (kCommand.InList(buff))		state = SCE_GC_COMMAND;
106 	else if (kEvent.InList(buff))			state = SCE_GC_EVENT;
107 
108 	if (state)
109 	{	sc->ChangeState(state);
110 		styler.ColourTo(sc->currentPos - 1, sc->state);
111 		sc->ChangeState(SCE_GC_DEFAULT);
112 	}
113 	else
114 	{	sc->ChangeState(SCE_GC_DEFAULT);
115 		styler.ColourTo(sc->currentPos - 1, sc->state);
116 	}
117 }
118 
119 // Main colorizing function called by Scintilla
120 static void
ColouriseGui4CliDoc(Sci_PositionU startPos,Sci_Position length,int initStyle,WordList * keywordlists[],Accessor & styler)121 ColouriseGui4CliDoc(Sci_PositionU startPos, Sci_Position length, int initStyle,
122                     WordList *keywordlists[], Accessor &styler)
123 {
124 	styler.StartAt(startPos);
125 
126 	Sci_Position currentline = styler.GetLine(startPos);
127 	int quotestart = 0, oldstate;
128 	styler.StartSegment(startPos);
129 	bool noforward;
130 	char buff[BUFFSIZE+1];	// buffer for command name
131 
132 	StyleContext sc(startPos, length, initStyle, styler);
133 	buff[0] = '\0'; // cbuff = 0;
134 
135 	if (sc.state != SCE_GC_COMMENTBLOCK) // colorize 1st word..
136 		colorFirstWord(keywordlists, styler, &sc, buff, BUFFSIZE, currentline);
137 
138 	while (sc.More())
139 	{	noforward = 0;
140 
141 		switch (sc.ch)
142 		{
143 			case '/':
144 				if (sc.state == SCE_GC_COMMENTBLOCK || sc.state == SCE_GC_STRING)
145 					break;
146 				if (sc.chNext == '/')	// line comment
147 				{	sc.SetState (SCE_GC_COMMENTLINE);
148 					sc.Forward();
149 					styler.ColourTo(sc.currentPos, sc.state);
150 				}
151 				else if (sc.chNext == '*')	// block comment
152 				{	sc.SetState(SCE_GC_COMMENTBLOCK);
153 					sc.Forward();
154 					styler.ColourTo(sc.currentPos, sc.state);
155 				}
156 				else
157 					styler.ColourTo(sc.currentPos, sc.state);
158 				break;
159 
160 			case '*':	// end of comment block, or operator..
161 				if (sc.state == SCE_GC_STRING)
162 					break;
163 				if (sc.state == SCE_GC_COMMENTBLOCK && sc.chNext == '/')
164 				{	sc.Forward();
165 					styler.ColourTo(sc.currentPos, sc.state);
166 					sc.ChangeState (SCE_GC_DEFAULT);
167 				}
168 				else
169 					styler.ColourTo(sc.currentPos, sc.state);
170 				break;
171 
172 			case '\'':	case '\"': // strings..
173 				if (sc.state == SCE_GC_COMMENTBLOCK || sc.state == SCE_GC_COMMENTLINE)
174 					break;
175 				if (sc.state == SCE_GC_STRING)
176 				{	if (sc.ch == quotestart)	// match same quote char..
177 					{	styler.ColourTo(sc.currentPos, sc.state);
178 						sc.ChangeState(SCE_GC_DEFAULT);
179 						quotestart = 0;
180 				}	}
181 				else
182 				{	styler.ColourTo(sc.currentPos - 1, sc.state);
183 					sc.ChangeState(SCE_GC_STRING);
184 					quotestart = sc.ch;
185 				}
186 				break;
187 
188 			case ';':	// end of commandline character
189 				if (sc.state != SCE_GC_COMMENTBLOCK && sc.state != SCE_GC_COMMENTLINE &&
190 					 sc.state != SCE_GC_STRING)
191 				{
192 					styler.ColourTo(sc.currentPos - 1, sc.state);
193 					styler.ColourTo(sc.currentPos, SCE_GC_OPERATOR);
194 					sc.ChangeState(SCE_GC_DEFAULT);
195 					sc.Forward();
196 					colorFirstWord(keywordlists, styler, &sc, buff, BUFFSIZE, currentline);
197 					noforward = 1; // don't move forward - already positioned at next char..
198 				}
199 				break;
200 
201 			case '+': case '-': case '=':	case '!':	// operators..
202 			case '<': case '>': case '&': case '|': case '$':
203 				if (sc.state != SCE_GC_COMMENTBLOCK && sc.state != SCE_GC_COMMENTLINE &&
204 					 sc.state != SCE_GC_STRING)
205 				{
206 					styler.ColourTo(sc.currentPos - 1, sc.state);
207 					styler.ColourTo(sc.currentPos, SCE_GC_OPERATOR);
208 					sc.ChangeState(SCE_GC_DEFAULT);
209 				}
210 				break;
211 
212 			case '\\':	// escape - same as operator, but also mark in strings..
213 				if (sc.state != SCE_GC_COMMENTBLOCK && sc.state != SCE_GC_COMMENTLINE)
214 				{
215 					oldstate = sc.state;
216 					styler.ColourTo(sc.currentPos - 1, sc.state);
217 					sc.Forward(); // mark also the next char..
218 					styler.ColourTo(sc.currentPos, SCE_GC_OPERATOR);
219 					sc.ChangeState(oldstate);
220 				}
221 				break;
222 
223 			case '\n': case '\r':
224 				++currentline;
225 				if (sc.state == SCE_GC_COMMENTLINE)
226 				{	styler.ColourTo(sc.currentPos, sc.state);
227 					sc.ChangeState (SCE_GC_DEFAULT);
228 				}
229 				else if (sc.state != SCE_GC_COMMENTBLOCK)
230 				{	colorFirstWord(keywordlists, styler, &sc, buff, BUFFSIZE, currentline);
231 					noforward = 1; // don't move forward - already positioned at next char..
232 				}
233 				break;
234 
235 //			case ' ': case '\t':
236 //			default :
237 		}
238 
239 		if (!noforward) sc.Forward();
240 
241 	}
242 	sc.Complete();
243 }
244 
245 // Main folding function called by Scintilla - (based on props (.ini) files function)
FoldGui4Cli(Sci_PositionU startPos,Sci_Position length,int,WordList * [],Accessor & styler)246 static void FoldGui4Cli(Sci_PositionU startPos, Sci_Position length, int,
247 								WordList *[], Accessor &styler)
248 {
249 	bool foldCompact = styler.GetPropertyInt("fold.compact", 1) != 0;
250 
251 	Sci_PositionU endPos = startPos + length;
252 	int visibleChars = 0;
253 	Sci_Position lineCurrent = styler.GetLine(startPos);
254 
255 	char chNext = styler[startPos];
256 	int styleNext = styler.StyleAt(startPos);
257 	bool headerPoint = false;
258 
259 	for (Sci_PositionU i = startPos; i < endPos; i++)
260 	{
261 		char ch = chNext;
262 		chNext = styler[i+1];
263 
264 		int style = styleNext;
265 		styleNext = styler.StyleAt(i + 1);
266 		bool atEOL = (ch == '\r' && chNext != '\n') || (ch == '\n');
267 
268 		if (style == SCE_GC_EVENT || style == SCE_GC_GLOBAL)
269 		{	headerPoint = true; // fold at events and globals
270 		}
271 
272 		if (atEOL)
273 		{	int lev = SC_FOLDLEVELBASE+1;
274 
275 			if (headerPoint)
276 				lev = SC_FOLDLEVELBASE;
277 
278 			if (visibleChars == 0 && foldCompact)
279 				lev |= SC_FOLDLEVELWHITEFLAG;
280 
281 			if (headerPoint)
282 				lev |= SC_FOLDLEVELHEADERFLAG;
283 
284 			if (lev != styler.LevelAt(lineCurrent)) // set level, if not already correct
285 			{	styler.SetLevel(lineCurrent, lev);
286 			}
287 
288 			lineCurrent++;		// re-initialize our flags
289 			visibleChars = 0;
290 			headerPoint = false;
291 		}
292 
293 		if (!(isspacechar(ch))) // || (style == SCE_GC_COMMENTLINE) || (style != SCE_GC_COMMENTBLOCK)))
294 			visibleChars++;
295 	}
296 
297 	int lev = headerPoint ? SC_FOLDLEVELBASE : SC_FOLDLEVELBASE+1;
298 	int flagsNext = styler.LevelAt(lineCurrent) & ~SC_FOLDLEVELNUMBERMASK;
299 	styler.SetLevel(lineCurrent, lev | flagsNext);
300 }
301 
302 // I have no idea what these are for.. probably accessible by some message.
303 static const char * const gui4cliWordListDesc[] = {
304 	"Globals", "Events", "Attributes", "Control", "Commands",
305 	0
306 };
307 
308 // Declare language & pass our function pointers to Scintilla
309 LexerModule lmGui4Cli(SCLEX_GUI4CLI, ColouriseGui4CliDoc, "gui4cli", FoldGui4Cli, gui4cliWordListDesc);
310 
311 #undef debug
312 
313