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