1 // Scintilla source code edit control
2 /** @file LexLout.cxx
3 ** Lexer for the Basser Lout (>= version 3) typesetting language
4 **/
5 // Copyright 2003 by Kein-Hong Man <mkh@pl.jaring.my>
6 // The License.txt file describes the conditions under which this software may be distributed.
7
8 #include <stdlib.h>
9 #include <string.h>
10 #include <stdio.h>
11 #include <stdarg.h>
12 #include <assert.h>
13 #include <ctype.h>
14
15 #include "ILexer.h"
16 #include "Scintilla.h"
17 #include "SciLexer.h"
18
19 #include "WordList.h"
20 #include "LexAccessor.h"
21 #include "Accessor.h"
22 #include "StyleContext.h"
23 #include "CharacterSet.h"
24 #include "LexerModule.h"
25
26 using namespace Scintilla;
27
IsAWordChar(const int ch)28 static inline bool IsAWordChar(const int ch) {
29 return (ch < 0x80) && (isalpha(ch) || ch == '@' || ch == '_');
30 }
31
IsAnOther(const int ch)32 static inline bool IsAnOther(const int ch) {
33 return (ch < 0x80) && (ch == '{' || ch == '}' ||
34 ch == '!' || ch == '$' || ch == '%' || ch == '&' || ch == '\'' ||
35 ch == '(' || ch == ')' || ch == '*' || ch == '+' || ch == ',' ||
36 ch == '-' || ch == '.' || ch == '/' || ch == ':' || ch == ';' ||
37 ch == '<' || ch == '=' || ch == '>' || ch == '?' || ch == '[' ||
38 ch == ']' || ch == '^' || ch == '`' || ch == '|' || ch == '~');
39 }
40
ColouriseLoutDoc(Sci_PositionU startPos,Sci_Position length,int initStyle,WordList * keywordlists[],Accessor & styler)41 static void ColouriseLoutDoc(Sci_PositionU startPos, Sci_Position length, int initStyle,
42 WordList *keywordlists[], Accessor &styler) {
43
44 WordList &keywords = *keywordlists[0];
45 WordList &keywords2 = *keywordlists[1];
46 WordList &keywords3 = *keywordlists[2];
47
48 int visibleChars = 0;
49 int firstWordInLine = 0;
50 int leadingAtSign = 0;
51
52 StyleContext sc(startPos, length, initStyle, styler);
53
54 for (; sc.More(); sc.Forward()) {
55
56 if (sc.atLineStart && (sc.state == SCE_LOUT_STRING)) {
57 // Prevent SCE_LOUT_STRINGEOL from leaking back to previous line
58 sc.SetState(SCE_LOUT_STRING);
59 }
60
61 // Determine if the current state should terminate.
62 if (sc.state == SCE_LOUT_COMMENT) {
63 if (sc.atLineEnd) {
64 sc.SetState(SCE_LOUT_DEFAULT);
65 visibleChars = 0;
66 }
67 } else if (sc.state == SCE_LOUT_NUMBER) {
68 if (!IsADigit(sc.ch) && sc.ch != '.') {
69 sc.SetState(SCE_LOUT_DEFAULT);
70 }
71 } else if (sc.state == SCE_LOUT_STRING) {
72 if (sc.ch == '\\') {
73 if (sc.chNext == '\"' || sc.chNext == '\\') {
74 sc.Forward();
75 }
76 } else if (sc.ch == '\"') {
77 sc.ForwardSetState(SCE_LOUT_DEFAULT);
78 } else if (sc.atLineEnd) {
79 sc.ChangeState(SCE_LOUT_STRINGEOL);
80 sc.ForwardSetState(SCE_LOUT_DEFAULT);
81 visibleChars = 0;
82 }
83 } else if (sc.state == SCE_LOUT_IDENTIFIER) {
84 if (!IsAWordChar(sc.ch)) {
85 char s[100];
86 sc.GetCurrent(s, sizeof(s));
87
88 if (leadingAtSign) {
89 if (keywords.InList(s)) {
90 sc.ChangeState(SCE_LOUT_WORD);
91 } else {
92 sc.ChangeState(SCE_LOUT_WORD4);
93 }
94 } else if (firstWordInLine && keywords3.InList(s)) {
95 sc.ChangeState(SCE_LOUT_WORD3);
96 }
97 sc.SetState(SCE_LOUT_DEFAULT);
98 }
99 } else if (sc.state == SCE_LOUT_OPERATOR) {
100 if (!IsAnOther(sc.ch)) {
101 char s[100];
102 sc.GetCurrent(s, sizeof(s));
103
104 if (keywords2.InList(s)) {
105 sc.ChangeState(SCE_LOUT_WORD2);
106 }
107 sc.SetState(SCE_LOUT_DEFAULT);
108 }
109 }
110
111 // Determine if a new state should be entered.
112 if (sc.state == SCE_LOUT_DEFAULT) {
113 if (sc.ch == '#') {
114 sc.SetState(SCE_LOUT_COMMENT);
115 } else if (sc.ch == '\"') {
116 sc.SetState(SCE_LOUT_STRING);
117 } else if (IsADigit(sc.ch) ||
118 (sc.ch == '.' && IsADigit(sc.chNext))) {
119 sc.SetState(SCE_LOUT_NUMBER);
120 } else if (IsAWordChar(sc.ch)) {
121 firstWordInLine = (visibleChars == 0);
122 leadingAtSign = (sc.ch == '@');
123 sc.SetState(SCE_LOUT_IDENTIFIER);
124 } else if (IsAnOther(sc.ch)) {
125 sc.SetState(SCE_LOUT_OPERATOR);
126 }
127 }
128
129 if (sc.atLineEnd) {
130 // Reset states to begining of colourise so no surprises
131 // if different sets of lines lexed.
132 visibleChars = 0;
133 }
134 if (!IsASpace(sc.ch)) {
135 visibleChars++;
136 }
137 }
138 sc.Complete();
139 }
140
FoldLoutDoc(Sci_PositionU startPos,Sci_Position length,int,WordList * [],Accessor & styler)141 static void FoldLoutDoc(Sci_PositionU startPos, Sci_Position length, int, WordList *[],
142 Accessor &styler) {
143
144 Sci_PositionU endPos = startPos + length;
145 int visibleChars = 0;
146 Sci_Position lineCurrent = styler.GetLine(startPos);
147 int levelPrev = styler.LevelAt(lineCurrent) & SC_FOLDLEVELNUMBERMASK;
148 int levelCurrent = levelPrev;
149 char chNext = styler[startPos];
150 bool foldCompact = styler.GetPropertyInt("fold.compact", 1) != 0;
151 int styleNext = styler.StyleAt(startPos);
152 char s[10] = "";
153
154 for (Sci_PositionU i = startPos; i < endPos; i++) {
155 char ch = chNext;
156 chNext = styler.SafeGetCharAt(i + 1);
157 int style = styleNext;
158 styleNext = styler.StyleAt(i + 1);
159 bool atEOL = (ch == '\r' && chNext != '\n') || (ch == '\n');
160
161 if (style == SCE_LOUT_WORD) {
162 if (ch == '@') {
163 for (Sci_PositionU j = 0; j < 8; j++) {
164 if (!IsAWordChar(styler[i + j])) {
165 break;
166 }
167 s[j] = styler[i + j];
168 s[j + 1] = '\0';
169 }
170 if (strcmp(s, "@Begin") == 0) {
171 levelCurrent++;
172 } else if (strcmp(s, "@End") == 0) {
173 levelCurrent--;
174 }
175 }
176 } else if (style == SCE_LOUT_OPERATOR) {
177 if (ch == '{') {
178 levelCurrent++;
179 } else if (ch == '}') {
180 levelCurrent--;
181 }
182 }
183 if (atEOL) {
184 int lev = levelPrev;
185 if (visibleChars == 0 && foldCompact) {
186 lev |= SC_FOLDLEVELWHITEFLAG;
187 }
188 if ((levelCurrent > levelPrev) && (visibleChars > 0)) {
189 lev |= SC_FOLDLEVELHEADERFLAG;
190 }
191 if (lev != styler.LevelAt(lineCurrent)) {
192 styler.SetLevel(lineCurrent, lev);
193 }
194 lineCurrent++;
195 levelPrev = levelCurrent;
196 visibleChars = 0;
197 }
198 if (!isspacechar(ch))
199 visibleChars++;
200 }
201 // Fill in the real level of the next line, keeping the current flags as they will be filled in later
202 int flagsNext = styler.LevelAt(lineCurrent) & ~SC_FOLDLEVELNUMBERMASK;
203 styler.SetLevel(lineCurrent, levelPrev | flagsNext);
204 }
205
206 static const char * const loutWordLists[] = {
207 "Predefined identifiers",
208 "Predefined delimiters",
209 "Predefined keywords",
210 0,
211 };
212
213 LexerModule lmLout(SCLEX_LOUT, ColouriseLoutDoc, "lout", FoldLoutDoc, loutWordLists);
214