LexInno.cpp 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291
  1. // Scintilla source code edit control
  2. /** @file LexInno.cxx
  3. ** Lexer for Inno Setup scripts.
  4. **/
  5. // Written by Friedrich Vedder <fvedd@t-online.de>, using code from LexOthers.cxx.
  6. // The License.txt file describes the conditions under which this software may be distributed.
  7. #include <stdlib.h>
  8. #include <string.h>
  9. #include <stdio.h>
  10. #include <stdarg.h>
  11. #include <assert.h>
  12. #include <ctype.h>
  13. #include "ILexer.h"
  14. #include "Scintilla.h"
  15. #include "SciLexer.h"
  16. #include "WordList.h"
  17. #include "LexAccessor.h"
  18. #include "Accessor.h"
  19. #include "StyleContext.h"
  20. #include "CharacterSet.h"
  21. #include "LexerModule.h"
  22. #ifdef SCI_NAMESPACE
  23. using namespace Scintilla;
  24. #endif
  25. static void ColouriseInnoDoc(Sci_PositionU startPos, Sci_Position length, int, WordList *keywordLists[], Accessor &styler) {
  26. int state = SCE_INNO_DEFAULT;
  27. char chPrev;
  28. char ch = 0;
  29. char chNext = styler[startPos];
  30. Sci_Position lengthDoc = startPos + length;
  31. char *buffer = new char[length+1];
  32. Sci_Position bufferCount = 0;
  33. bool isBOL, isEOL, isWS, isBOLWS = 0;
  34. bool isCStyleComment = false;
  35. WordList &sectionKeywords = *keywordLists[0];
  36. WordList &standardKeywords = *keywordLists[1];
  37. WordList &parameterKeywords = *keywordLists[2];
  38. WordList &preprocessorKeywords = *keywordLists[3];
  39. WordList &pascalKeywords = *keywordLists[4];
  40. WordList &userKeywords = *keywordLists[5];
  41. Sci_Position curLine = styler.GetLine(startPos);
  42. int curLineState = curLine > 0 ? styler.GetLineState(curLine - 1) : 0;
  43. bool isCode = (curLineState == 1);
  44. // Go through all provided text segment
  45. // using the hand-written state machine shown below
  46. styler.StartAt(startPos);
  47. styler.StartSegment(startPos);
  48. for (Sci_Position i = startPos; i < lengthDoc; i++) {
  49. chPrev = ch;
  50. ch = chNext;
  51. chNext = styler.SafeGetCharAt(i + 1);
  52. if (styler.IsLeadByte(ch)) {
  53. chNext = styler.SafeGetCharAt(i + 2);
  54. i++;
  55. continue;
  56. }
  57. isBOL = (chPrev == 0) || (chPrev == '\n') || (chPrev == '\r' && ch != '\n');
  58. isBOLWS = (isBOL) ? 1 : (isBOLWS && (chPrev == ' ' || chPrev == '\t'));
  59. isEOL = (ch == '\n' || ch == '\r');
  60. isWS = (ch == ' ' || ch == '\t');
  61. if ((ch == '\r' && chNext != '\n') || (ch == '\n')) {
  62. // Remember the line state for future incremental lexing
  63. curLine = styler.GetLine(i);
  64. styler.SetLineState(curLine, (isCode ? 1 : 0));
  65. }
  66. switch(state) {
  67. case SCE_INNO_DEFAULT:
  68. if (!isCode && ch == ';' && isBOLWS) {
  69. // Start of a comment
  70. state = SCE_INNO_COMMENT;
  71. } else if (ch == '[' && isBOLWS) {
  72. // Start of a section name
  73. bufferCount = 0;
  74. state = SCE_INNO_SECTION;
  75. } else if (ch == '#' && isBOLWS) {
  76. // Start of a preprocessor directive
  77. state = SCE_INNO_PREPROC;
  78. } else if (!isCode && ch == '{' && chNext != '{' && chPrev != '{') {
  79. // Start of an inline expansion
  80. state = SCE_INNO_INLINE_EXPANSION;
  81. } else if (isCode && (ch == '{' || (ch == '(' && chNext == '*'))) {
  82. // Start of a Pascal comment
  83. state = SCE_INNO_COMMENT_PASCAL;
  84. isCStyleComment = false;
  85. } else if (isCode && ch == '/' && chNext == '/') {
  86. // Apparently, C-style comments are legal, too
  87. state = SCE_INNO_COMMENT_PASCAL;
  88. isCStyleComment = true;
  89. } else if (ch == '"') {
  90. // Start of a double-quote string
  91. state = SCE_INNO_STRING_DOUBLE;
  92. } else if (ch == '\'') {
  93. // Start of a single-quote string
  94. state = SCE_INNO_STRING_SINGLE;
  95. } else if (IsASCII(ch) && (isalpha(ch) || (ch == '_'))) {
  96. // Start of an identifier
  97. bufferCount = 0;
  98. buffer[bufferCount++] = static_cast<char>(tolower(ch));
  99. state = SCE_INNO_IDENTIFIER;
  100. } else {
  101. // Style it the default style
  102. styler.ColourTo(i,SCE_INNO_DEFAULT);
  103. }
  104. break;
  105. case SCE_INNO_COMMENT:
  106. if (isEOL) {
  107. state = SCE_INNO_DEFAULT;
  108. styler.ColourTo(i,SCE_INNO_COMMENT);
  109. }
  110. break;
  111. case SCE_INNO_IDENTIFIER:
  112. if (IsASCII(ch) && (isalnum(ch) || (ch == '_'))) {
  113. buffer[bufferCount++] = static_cast<char>(tolower(ch));
  114. } else {
  115. state = SCE_INNO_DEFAULT;
  116. buffer[bufferCount] = '\0';
  117. // Check if the buffer contains a keyword
  118. if (!isCode && standardKeywords.InList(buffer)) {
  119. styler.ColourTo(i-1,SCE_INNO_KEYWORD);
  120. } else if (!isCode && parameterKeywords.InList(buffer)) {
  121. styler.ColourTo(i-1,SCE_INNO_PARAMETER);
  122. } else if (isCode && pascalKeywords.InList(buffer)) {
  123. styler.ColourTo(i-1,SCE_INNO_KEYWORD_PASCAL);
  124. } else if (!isCode && userKeywords.InList(buffer)) {
  125. styler.ColourTo(i-1,SCE_INNO_KEYWORD_USER);
  126. } else {
  127. styler.ColourTo(i-1,SCE_INNO_DEFAULT);
  128. }
  129. // Push back the faulty character
  130. chNext = styler[i--];
  131. ch = chPrev;
  132. }
  133. break;
  134. case SCE_INNO_SECTION:
  135. if (ch == ']') {
  136. state = SCE_INNO_DEFAULT;
  137. buffer[bufferCount] = '\0';
  138. // Check if the buffer contains a section name
  139. if (sectionKeywords.InList(buffer)) {
  140. styler.ColourTo(i,SCE_INNO_SECTION);
  141. isCode = !CompareCaseInsensitive(buffer, "code");
  142. } else {
  143. styler.ColourTo(i,SCE_INNO_DEFAULT);
  144. }
  145. } else if (IsASCII(ch) && (isalnum(ch) || (ch == '_'))) {
  146. buffer[bufferCount++] = static_cast<char>(tolower(ch));
  147. } else {
  148. state = SCE_INNO_DEFAULT;
  149. styler.ColourTo(i,SCE_INNO_DEFAULT);
  150. }
  151. break;
  152. case SCE_INNO_PREPROC:
  153. if (isWS || isEOL) {
  154. if (IsASCII(chPrev) && isalpha(chPrev)) {
  155. state = SCE_INNO_DEFAULT;
  156. buffer[bufferCount] = '\0';
  157. // Check if the buffer contains a preprocessor directive
  158. if (preprocessorKeywords.InList(buffer)) {
  159. styler.ColourTo(i-1,SCE_INNO_PREPROC);
  160. } else {
  161. styler.ColourTo(i-1,SCE_INNO_DEFAULT);
  162. }
  163. // Push back the faulty character
  164. chNext = styler[i--];
  165. ch = chPrev;
  166. }
  167. } else if (IsASCII(ch) && isalpha(ch)) {
  168. if (chPrev == '#' || chPrev == ' ' || chPrev == '\t')
  169. bufferCount = 0;
  170. buffer[bufferCount++] = static_cast<char>(tolower(ch));
  171. }
  172. break;
  173. case SCE_INNO_STRING_DOUBLE:
  174. if (ch == '"' || isEOL) {
  175. state = SCE_INNO_DEFAULT;
  176. styler.ColourTo(i,SCE_INNO_STRING_DOUBLE);
  177. }
  178. break;
  179. case SCE_INNO_STRING_SINGLE:
  180. if (ch == '\'' || isEOL) {
  181. state = SCE_INNO_DEFAULT;
  182. styler.ColourTo(i,SCE_INNO_STRING_SINGLE);
  183. }
  184. break;
  185. case SCE_INNO_INLINE_EXPANSION:
  186. if (ch == '}') {
  187. state = SCE_INNO_DEFAULT;
  188. styler.ColourTo(i,SCE_INNO_INLINE_EXPANSION);
  189. } else if (isEOL) {
  190. state = SCE_INNO_DEFAULT;
  191. styler.ColourTo(i,SCE_INNO_DEFAULT);
  192. }
  193. break;
  194. case SCE_INNO_COMMENT_PASCAL:
  195. if (isCStyleComment) {
  196. if (isEOL) {
  197. state = SCE_INNO_DEFAULT;
  198. styler.ColourTo(i,SCE_INNO_COMMENT_PASCAL);
  199. }
  200. } else {
  201. if (ch == '}' || (ch == ')' && chPrev == '*')) {
  202. state = SCE_INNO_DEFAULT;
  203. styler.ColourTo(i,SCE_INNO_COMMENT_PASCAL);
  204. } else if (isEOL) {
  205. state = SCE_INNO_DEFAULT;
  206. styler.ColourTo(i,SCE_INNO_DEFAULT);
  207. }
  208. }
  209. break;
  210. }
  211. }
  212. delete []buffer;
  213. }
  214. static const char * const innoWordListDesc[] = {
  215. "Sections",
  216. "Keywords",
  217. "Parameters",
  218. "Preprocessor directives",
  219. "Pascal keywords",
  220. "User defined keywords",
  221. 0
  222. };
  223. static void FoldInnoDoc(Sci_PositionU startPos, Sci_Position length, int, WordList *[], Accessor &styler) {
  224. Sci_PositionU endPos = startPos + length;
  225. char chNext = styler[startPos];
  226. Sci_Position lineCurrent = styler.GetLine(startPos);
  227. bool sectionFlag = false;
  228. int levelPrev = lineCurrent > 0 ? styler.LevelAt(lineCurrent - 1) : SC_FOLDLEVELBASE;
  229. int level;
  230. for (Sci_PositionU i = startPos; i < endPos; i++) {
  231. char ch = chNext;
  232. chNext = styler[i+1];
  233. bool atEOL = (ch == '\r' && chNext != '\n') || (ch == '\n');
  234. int style = styler.StyleAt(i);
  235. if (style == SCE_INNO_SECTION)
  236. sectionFlag = true;
  237. if (atEOL || i == endPos - 1) {
  238. if (sectionFlag) {
  239. level = SC_FOLDLEVELBASE | SC_FOLDLEVELHEADERFLAG;
  240. if (level == levelPrev)
  241. styler.SetLevel(lineCurrent - 1, levelPrev & ~SC_FOLDLEVELHEADERFLAG);
  242. } else {
  243. level = levelPrev & SC_FOLDLEVELNUMBERMASK;
  244. if (levelPrev & SC_FOLDLEVELHEADERFLAG)
  245. level++;
  246. }
  247. styler.SetLevel(lineCurrent, level);
  248. levelPrev = level;
  249. lineCurrent++;
  250. sectionFlag = false;
  251. }
  252. }
  253. }
  254. LexerModule lmInno(SCLEX_INNOSETUP, ColouriseInnoDoc, "inno", FoldInnoDoc, innoWordListDesc);