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