1 // Scintilla source code edit control
\r
2 /** @file LexFlagShip.cxx
\r
3 ** Lexer for FlagShip
\r
4 ** (Syntactically compatible to other XBase dialects, like dBase, Clipper, Fox etc.)
\r
6 // Copyright 2005 by Randy Butler
\r
7 // Copyright 1998-2003 by Neil Hodgson <neilh@scintilla.org>
\r
8 // The License.txt file describes the conditions under which this software may be distributed.
\r
16 #include "Platform.h"
\r
18 #include "PropSet.h"
\r
19 #include "Accessor.h"
\r
20 #include "StyleContext.h"
\r
21 #include "KeyWords.h"
\r
22 #include "Scintilla.h"
\r
23 #include "SciLexer.h"
\r
25 #ifdef SCI_NAMESPACE
\r
26 using namespace Scintilla;
\r
29 static bool IsFlagShipComment(Accessor &styler, int pos, int len) {
\r
30 return len>0 && styler[pos]=='\'';
\r
33 static inline bool IsTypeCharacter(int ch) {
\r
34 return ch == '%' || ch == '&' || ch == '@' || ch == '!' || ch == '#' || ch == '$';
\r
37 // Extended to accept accented characters
\r
38 static inline bool IsAWordChar(int ch) {
\r
39 return ch >= 0x80 ||
\r
40 (isalnum(ch) || ch == '.' || ch == '_');
\r
43 static inline bool IsAWordStart(int ch) {
\r
44 return ch >= 0x80 ||
\r
45 (isalnum(ch) || ch == '_');
\r
48 static inline bool IsADateCharacter(const int ch) {
\r
49 return (ch < 0x80) &&
\r
50 (isalnum(ch) || ch == '|' || ch == '-' || ch == '/' || ch == ':' || ch == ' ' || ch == '\t');
\r
54 static void ColouriseFlagShipDoc(unsigned int startPos, int length, int initStyle,
\r
55 WordList *keywordlists[], Accessor &styler) {
\r
57 //bool FSScriptSyntax = true;
\r
58 WordList &keywords = *keywordlists[0];
\r
59 WordList &keywords2 = *keywordlists[1];
\r
60 WordList &keywords3 = *keywordlists[2];
\r
61 WordList &keywords4 = *keywordlists[3];
\r
63 styler.StartAt(startPos);
\r
65 int visibleChars = 0;
\r
67 StyleContext sc(startPos, length, initStyle, styler);
\r
69 for (; sc.More(); sc.Forward()) {
\r
71 if (sc.state == SCE_FS_OPERATOR) {
\r
72 sc.SetState(SCE_FS_DEFAULT);
\r
73 } else if (sc.state == SCE_FS_IDENTIFIER) {
\r
74 if (!IsAWordChar(sc.ch)) {
\r
76 sc.GetCurrentLowered(s, sizeof(s));
\r
77 if (keywords.InList(s)) {
\r
78 sc.ChangeState(SCE_FS_KEYWORD);
\r
79 } else if (keywords2.InList(s)) {
\r
80 sc.ChangeState(SCE_FS_KEYWORD2);
\r
81 } else if (keywords3.InList(s)) {
\r
82 sc.ChangeState(SCE_FS_KEYWORD3);
\r
83 } else if (keywords4.InList(s)) {
\r
84 sc.ChangeState(SCE_FS_KEYWORD4);
\r
85 }// Else, it is really an identifier...
\r
86 sc.SetState(SCE_FS_DEFAULT);
\r
88 } else if (sc.state == SCE_FS_NUMBER) {
\r
89 if (!IsAWordChar(sc.ch)) {
\r
90 sc.SetState(SCE_FS_DEFAULT);
\r
92 } else if (sc.state == SCE_FS_STRING) {
\r
93 // VB doubles quotes to preserve them, so just end this string
\r
94 // state now as a following quote will start again
\r
95 if (sc.ch == '\"') {
\r
96 if (tolower(sc.chNext) == 'c') {
\r
99 sc.ForwardSetState(SCE_FS_DEFAULT);
\r
100 } else if (sc.atLineEnd) {
\r
101 sc.ChangeState(SCE_FS_STRINGEOL);
\r
102 sc.ForwardSetState(SCE_FS_DEFAULT);
\r
104 } else if (sc.state == SCE_FS_COMMENT) {
\r
105 if (sc.Match('*', '/')) { // new code
\r
107 sc.ForwardSetState(SCE_FS_DEFAULT);
\r
108 //if (sc.atLineEnd) { // old code
\r
109 // sc.SetState(SCE_FS_DEFAULT);
\r
111 } else if (sc.state == SCE_FS_COMMENTLINE) { //new code
\r
112 if (sc.ch == '\r' || sc.ch == '\n') {
\r
113 sc.SetState(SCE_FS_DEFAULT);
\r
116 } else if (sc.state == SCE_FS_PREPROCESSOR) {
\r
117 if (sc.atLineEnd) {
\r
118 sc.SetState(SCE_FS_DEFAULT);
\r
120 } else if (sc.state == SCE_FS_DATE) {
\r
121 if (sc.ch == '#' || !IsADateCharacter(sc.chNext)) {
\r
122 sc.ForwardSetState(SCE_FS_DEFAULT);
\r
126 // Determine if a new state should be entered.
\r
127 if (sc.state == SCE_FS_DEFAULT) {
\r
128 if (sc.Match('/', '*')) { // New code
\r
129 sc.SetState(SCE_FS_COMMENT);
\r
130 sc.Forward(); // Eat the * so it isn't used for the end of the comment
\r
131 //if (sc.ch == '\'') { // Old code
\r
132 // sc.SetState(SCE_FS_COMMENT); // old code
\r
133 } else if (sc.Match('/', '/')) { // New code
\r
134 sc.SetState(SCE_FS_COMMENTLINE);
\r
135 } else if (sc.ch == '\"') {
\r
136 sc.SetState(SCE_FS_STRING);
\r
137 } else if (sc.ch == '#' && visibleChars == 0) {
\r
138 // Preprocessor commands are alone on their line
\r
139 sc.SetState(SCE_FS_PREPROCESSOR);
\r
140 } else if (sc.ch == '#') {
\r
143 while ((n < 100) && (chSeek == ' ' || chSeek == '\t')) {
\r
144 chSeek = sc.GetRelative(n);
\r
147 if (IsADigit(chSeek)) {
\r
148 sc.SetState(SCE_FS_DATE);
\r
150 sc.SetState(SCE_FS_OPERATOR);
\r
152 } else if (sc.ch == '&' && tolower(sc.chNext) == 'h') {
\r
153 sc.SetState(SCE_FS_NUMBER);
\r
154 } else if (sc.ch == '&' && tolower(sc.chNext) == 'o') {
\r
155 sc.SetState(SCE_FS_NUMBER);
\r
156 } else if (IsADigit(sc.ch) || (sc.ch == '.' && IsADigit(sc.chNext))) {
\r
157 sc.SetState(SCE_FS_NUMBER);
\r
158 } else if (IsAWordStart(sc.ch) || (sc.ch == '[')) {
\r
159 sc.SetState(SCE_FS_IDENTIFIER);
\r
160 } else if (isoperator(static_cast<char>(sc.ch)) || (sc.ch == '\\')) {
\r
161 sc.SetState(SCE_FS_OPERATOR);
\r
165 if (sc.atLineEnd) {
\r
168 if (!IsASpace(sc.ch)) {
\r
175 static void FoldFlagShipDoc(unsigned int startPos, int length, int,
\r
176 WordList *[], Accessor &styler) {
\r
178 int endPos = startPos + length;
\r
180 // Backtrack to previous line in case need to fix its fold status
\r
181 int lineCurrent = styler.GetLine(startPos);
\r
182 if (startPos > 0) {
\r
183 if (lineCurrent > 0) {
\r
185 startPos = styler.LineStart(lineCurrent);
\r
188 int spaceFlags = 0;
\r
189 int indentCurrent = styler.IndentAmount(lineCurrent, &spaceFlags, IsFlagShipComment);
\r
190 char chNext = styler[startPos];
\r
191 for (int i = startPos; i < endPos; i++) {
\r
193 chNext = styler.SafeGetCharAt(i + 1);
\r
195 if ((ch == '\r' && chNext != '\n') || (ch == '\n') || (i == endPos)) {
\r
196 int lev = indentCurrent;
\r
197 int indentNext = styler.IndentAmount(lineCurrent + 1, &spaceFlags, IsFlagShipComment);
\r
198 if (!(indentCurrent & SC_FOLDLEVELWHITEFLAG)) {
\r
199 // Only non whitespace lines can be headers
\r
200 if ((indentCurrent & SC_FOLDLEVELNUMBERMASK) < (indentNext & SC_FOLDLEVELNUMBERMASK)) {
\r
201 lev |= SC_FOLDLEVELHEADERFLAG;
\r
202 } else if (indentNext & SC_FOLDLEVELWHITEFLAG) {
\r
203 // Line after is blank so check the next - maybe should continue further?
\r
204 int spaceFlags2 = 0;
\r
205 int indentNext2 = styler.IndentAmount(lineCurrent + 2, &spaceFlags2, IsFlagShipComment);
\r
206 if ((indentCurrent & SC_FOLDLEVELNUMBERMASK) < (indentNext2 & SC_FOLDLEVELNUMBERMASK)) {
\r
207 lev |= SC_FOLDLEVELHEADERFLAG;
\r
211 indentCurrent = indentNext;
\r
212 styler.SetLevel(lineCurrent, lev);
\r
219 static const char * const FSWordListDesc[] = {
\r
227 LexerModule lmFlagShip(SCLEX_FLAGSHIP, ColouriseFlagShipDoc, "flagship", FoldFlagShipDoc, FSWordListDesc);
\r