1 // Scintilla source code edit control
2 //Author: instanton (email: soft_share<at>126<dot>com)
3 // The License.txt file describes the conditions under which this software may be distributed.
4 
5 #include <stdlib.h>
6 #include <string.h>
7 #include <stdio.h>
8 #include <stdarg.h>
9 #include <assert.h>
10 
11 #include "ILexer.h"
12 #include "Scintilla.h"
13 #include "SciLexer.h"
14 
15 #include "WordList.h"
16 #include "LexAccessor.h"
17 #include "Accessor.h"
18 #include "StyleContext.h"
19 #include "CharacterSet.h"
20 #include "LexerModule.h"
21 
22 using namespace Scintilla;
23 
ColouriseAsyDoc(Sci_PositionU startPos,Sci_Position length,int initStyle,WordList * keywordlists[],Accessor & styler)24 static void ColouriseAsyDoc(Sci_PositionU startPos, Sci_Position length, int initStyle,
25 		WordList *keywordlists[], Accessor &styler) {
26 
27 	WordList &keywords = *keywordlists[0];
28 	WordList &keywords2 = *keywordlists[1];
29 
30 	CharacterSet setWordStart(CharacterSet::setAlpha, "_", 0x80, true);
31 	CharacterSet setWord(CharacterSet::setAlphaNum, "._", 0x80, true);
32 
33 	int visibleChars = 0;
34 
35 	StyleContext sc(startPos, length, initStyle, styler);
36 
37 	for (; sc.More(); sc.Forward()) {
38 
39 		if (sc.atLineStart) {
40 			if (sc.state == SCE_ASY_STRING) {
41 				sc.SetState(SCE_ASY_STRING);
42 			}
43 			visibleChars = 0;
44 		}
45 
46 		if (sc.ch == '\\') {
47 			if (sc.chNext == '\n' || sc.chNext == '\r') {
48 				sc.Forward();
49 				if (sc.ch == '\r' && sc.chNext == '\n') {
50 					sc.Forward();
51 				}
52 //				continuationLine = true;
53 				continue;
54 			}
55 		}
56 
57 		// Determine if the current state should terminate.
58 		switch (sc.state) {
59 			case SCE_ASY_OPERATOR:
60 				sc.SetState(SCE_ASY_DEFAULT);
61 				break;
62 			case SCE_ASY_NUMBER:
63 				if (!setWord.Contains(sc.ch)) {
64 					sc.SetState(SCE_ASY_DEFAULT);
65 				}
66 				break;
67 			case SCE_ASY_IDENTIFIER:
68 				if (!setWord.Contains(sc.ch) || (sc.ch == '.')) {
69 					char s[1000];
70 					sc.GetCurrentLowered(s, sizeof(s));
71 					if (keywords.InList(s)) {
72 						sc.ChangeState(SCE_ASY_WORD);
73 					} else if (keywords2.InList(s)) {
74 						sc.ChangeState(SCE_ASY_WORD2);
75 					}
76 					sc.SetState(SCE_ASY_DEFAULT);
77 				}
78 				break;
79 			case SCE_ASY_COMMENT:
80 				if (sc.Match('*', '/')) {
81 					sc.Forward();
82 					sc.ForwardSetState(SCE_ASY_DEFAULT);
83 				}
84 				break;
85 			case SCE_ASY_COMMENTLINE:
86 				if (sc.atLineStart) {
87 					sc.SetState(SCE_ASY_DEFAULT);
88 				}
89 				break;
90 			case SCE_ASY_STRING:
91 				if (sc.atLineEnd) {
92 					sc.ChangeState(SCE_ASY_STRINGEOL);
93 				} else if (sc.ch == '\\') {
94 					if (sc.chNext == '\"' || sc.chNext == '\'' || sc.chNext == '\\') {
95 						sc.Forward();
96 					}
97 				} else if (sc.ch == '\"') {
98 					sc.ForwardSetState(SCE_ASY_DEFAULT);
99 				}
100 				break;
101 			case SCE_ASY_CHARACTER:
102 				if (sc.atLineEnd) {
103 					sc.ChangeState(SCE_ASY_STRINGEOL);
104 				} else 	if (sc.ch == '\\') {
105 					if (sc.chNext == '\"' || sc.chNext == '\'' || sc.chNext == '\\') {
106 						sc.Forward();
107 					}
108 				} else if (sc.ch == '\'') {
109 					sc.ForwardSetState(SCE_ASY_DEFAULT);
110 				}
111 				break;
112 		}
113 
114 		// Determine if a new state should be entered.
115 		if (sc.state == SCE_ASY_DEFAULT) {
116 			if (setWordStart.Contains(sc.ch) || (sc.ch == '@')) {
117 				sc.SetState(SCE_ASY_IDENTIFIER);
118 			} else if (sc.Match('/', '*')) {
119 				sc.SetState(SCE_ASY_COMMENT);
120 				sc.Forward();	//
121 			} else if (sc.Match('/', '/')) {
122 				sc.SetState(SCE_ASY_COMMENTLINE);
123 			} else if (sc.ch == '\"') {
124 				sc.SetState(SCE_ASY_STRING);
125 			} else if (sc.ch == '\'') {
126 				sc.SetState(SCE_ASY_CHARACTER);
127 			} else if (sc.ch == '#' && visibleChars == 0) {
128 				do {
129 					sc.Forward();
130 				} while ((sc.ch == ' ' || sc.ch == '\t') && sc.More());
131 				if (sc.atLineEnd) {
132 					sc.SetState(SCE_ASY_DEFAULT);
133 				}
134 			} else if (isoperator(static_cast<char>(sc.ch))) {
135 				sc.SetState(SCE_ASY_OPERATOR);
136 			}
137 		}
138 
139 	}
140 	sc.Complete();
141 }
142 
IsAsyCommentStyle(int style)143 static bool IsAsyCommentStyle(int style) {
144 	return style == SCE_ASY_COMMENT;
145 }
146 
147 
isASYidentifier(int ch)148 static inline bool isASYidentifier(int ch) {
149 	return
150       ((ch >= 'a') && (ch <= 'z')) || ((ch >= 'A') && (ch <= 'Z')) ;
151 }
152 
ParseASYWord(Sci_PositionU pos,Accessor & styler,char * word)153 static int ParseASYWord(Sci_PositionU pos, Accessor &styler, char *word)
154 {
155   int length=0;
156   char ch=styler.SafeGetCharAt(pos);
157   *word=0;
158 
159   while(isASYidentifier(ch) && length<100){
160           word[length]=ch;
161           length++;
162           ch=styler.SafeGetCharAt(pos+length);
163   }
164   word[length]=0;
165   return length;
166 }
167 
IsASYDrawingLine(Sci_Position line,Accessor & styler)168 static bool IsASYDrawingLine(Sci_Position line, Accessor &styler) {
169 	Sci_Position pos = styler.LineStart(line);
170 	Sci_Position eol_pos = styler.LineStart(line + 1) - 1;
171 
172 	Sci_Position startpos = pos;
173 	char buffer[100]="";
174 
175 	while (startpos<eol_pos){
176 		char ch = styler[startpos];
177 		ParseASYWord(startpos,styler,buffer);
178 		bool drawcommands = strncmp(buffer,"draw",4)==0||
179 			strncmp(buffer,"pair",4)==0||strncmp(buffer,"label",5)==0;
180 		if (!drawcommands && ch!=' ') return false;
181 		else if (drawcommands) return true;
182 		startpos++;
183 	}
184 	return false;
185 }
186 
FoldAsyDoc(Sci_PositionU startPos,Sci_Position length,int initStyle,WordList * [],Accessor & styler)187 static void FoldAsyDoc(Sci_PositionU startPos, Sci_Position length, int initStyle,
188 					   WordList *[], Accessor &styler) {
189 	bool foldComment = styler.GetPropertyInt("fold.comment") != 0;
190 	bool foldCompact = styler.GetPropertyInt("fold.compact", 1) != 0;
191 	bool foldAtElse = styler.GetPropertyInt("fold.at.else", 0) != 0;
192 	Sci_PositionU endPos = startPos + length;
193 	int visibleChars = 0;
194 	Sci_Position lineCurrent = styler.GetLine(startPos);
195 	int levelCurrent = SC_FOLDLEVELBASE;
196 	if (lineCurrent > 0)
197 		levelCurrent = styler.LevelAt(lineCurrent-1) >> 16;
198 	int levelMinCurrent = levelCurrent;
199 	int levelNext = levelCurrent;
200 	char chNext = styler[startPos];
201 	int styleNext = styler.StyleAt(startPos);
202 	int style = initStyle;
203 	for (Sci_PositionU i = startPos; i < endPos; i++) {
204 		char ch = chNext;
205 		chNext = styler.SafeGetCharAt(i + 1);
206 		int stylePrev = style;
207 		style = styleNext;
208 		styleNext = styler.StyleAt(i + 1);
209 		bool atEOL = (ch == '\r' && chNext != '\n') || (ch == '\n');
210 		if (foldComment && IsAsyCommentStyle(style)) {
211 			if (!IsAsyCommentStyle(stylePrev) && (stylePrev != SCE_ASY_COMMENTLINEDOC)) {
212 				levelNext++;
213 			} else if (!IsAsyCommentStyle(styleNext) && (styleNext != SCE_ASY_COMMENTLINEDOC) && !atEOL) {
214 				levelNext--;
215 			}
216 		}
217 		if (style == SCE_ASY_OPERATOR) {
218 			if (ch == '{') {
219 				if (levelMinCurrent > levelNext) {
220 					levelMinCurrent = levelNext;
221 				}
222 				levelNext++;
223 			} else if (ch == '}') {
224 				levelNext--;
225 			}
226 		}
227 
228 		if (atEOL && IsASYDrawingLine(lineCurrent, styler)){
229 			if (lineCurrent==0 && IsASYDrawingLine(lineCurrent + 1, styler))
230 				levelNext++;
231 			else if (lineCurrent!=0 && !IsASYDrawingLine(lineCurrent - 1, styler)
232 				&& IsASYDrawingLine(lineCurrent + 1, styler)
233 				)
234 				levelNext++;
235 			else if (lineCurrent!=0 && IsASYDrawingLine(lineCurrent - 1, styler) &&
236 				!IsASYDrawingLine(lineCurrent+1, styler))
237 				levelNext--;
238 		}
239 
240 		if (atEOL) {
241 			int levelUse = levelCurrent;
242 			if (foldAtElse) {
243 				levelUse = levelMinCurrent;
244 			}
245 			int lev = levelUse | levelNext << 16;
246 			if (visibleChars == 0 && foldCompact)
247 				lev |= SC_FOLDLEVELWHITEFLAG;
248 			if (levelUse < levelNext)
249 				lev |= SC_FOLDLEVELHEADERFLAG;
250 			if (lev != styler.LevelAt(lineCurrent)) {
251 				styler.SetLevel(lineCurrent, lev);
252 			}
253 			lineCurrent++;
254 			levelCurrent = levelNext;
255 			levelMinCurrent = levelCurrent;
256 			visibleChars = 0;
257 		}
258 		if (!IsASpace(ch))
259 			visibleChars++;
260 	}
261 }
262 
263 static const char * const asyWordLists[] = {
264             "Primary keywords and identifiers",
265             "Secondary keywords and identifiers",
266             0,
267         };
268 
269 LexerModule lmASY(SCLEX_ASYMPTOTE, ColouriseAsyDoc, "asy", FoldAsyDoc, asyWordLists);
270