sh_pas.pp 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331
  1. {
  2. $Id$
  3. "SHEdit" - Text editor with syntax highlighting
  4. Copyright (C) 1999-2000 by Sebastian Guenther ([email protected])
  5. See the file COPYING.FPC, included in this distribution,
  6. for details about the copyright.
  7. This program is distributed in the hope that it will be useful,
  8. but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  10. }
  11. // Syntax highlighting class for Pascal sources
  12. {$MODE objfpc}
  13. {$H+}
  14. {$IFDEF Debug}
  15. {$ASSERTIONS On}
  16. {$ENDIF}
  17. unit sh_pas;
  18. interface
  19. uses doc_text, shedit;
  20. type
  21. TSHPasEdit = class(TSHTextEdit)
  22. protected
  23. procedure DoHighlighting(var flags: Byte; source, dest: PChar); override;
  24. procedure KeyReturn; override;
  25. public
  26. // Syntax highlighter style indices
  27. shInvalid, shSymbol, shKeyword, shComment, shDirective, shNumbers,
  28. shCharacters, shStrings, shAssembler: Integer;
  29. end;
  30. implementation
  31. uses Strings;
  32. const
  33. LF_SH_Comment1 = LF_SH_Multiline1; { Normal braced Comments}
  34. LF_SH_Comment2 = LF_SH_Multiline2; { (* *) Comments}
  35. LF_SH_Asm = LF_SH_Multiline3;
  36. MaxKeywordLength = 15;
  37. MaxKeyword = 60;
  38. KeywordTable: array[0..MaxKeyword] of PChar =
  39. ('AND', 'ARRAY', 'ASM', 'ASSEMBLER',
  40. 'BEGIN', 'BREAK',
  41. 'CASE', 'CONST', 'CONSTRUCTOR', 'CLASS',
  42. 'DEFAULT', 'DESTRUCTOR', 'DIV', 'DO', 'DOWNTO',
  43. 'ELSE', 'END', 'EXCEPT', 'EXIT',
  44. 'FINALIZATION', 'FINALLY', 'FOR', 'FUNCTION',
  45. 'GOTO',
  46. 'IF', 'IMPLEMENTATION', 'IN', 'INHERITED', 'INITIALIZATION', 'INTERFACE',
  47. 'NIL', 'NOT',
  48. 'OBJECT', 'OF', 'ON', 'OR', 'OVERRIDE',
  49. 'PACKED', 'PRIVATE', 'PROCEDURE', 'PROGRAM', 'PROPERTY', 'PROTECTED',
  50. 'PUBLIC', 'PUBLISHED',
  51. 'RAISE', 'RECORD', 'REPEAT', 'RESOURCESTRING',
  52. 'SET',
  53. 'THEN', 'TRY', 'TYPE',
  54. 'UNIT', 'UNTIL', 'USES',
  55. 'VAR', 'VIRTUAL',
  56. 'WHILE', 'WITH',
  57. 'XOR');
  58. KeywordAsmIndex = 2;
  59. procedure TSHPasEdit.KeyReturn;
  60. var
  61. s: String;
  62. i, count: Integer;
  63. begin
  64. // Get # of spaces in front of previous line
  65. s := FDoc.LineText[CursorY - 1];
  66. i := 1; count := 0;
  67. while (i <= Length(s)) and (s[i] = ' ') do begin
  68. Inc(i);
  69. Inc(count);
  70. end;
  71. FDoc.LineText[CursorY] := Copy(s, 1, count) + FDoc.LineText[CursorY];
  72. Inc(FCursorX, count);
  73. AddUndoInfo(TUndoEdit.Create(count), True);
  74. ChangeInLine(CursorY);
  75. end;
  76. procedure TSHPasEdit.DoHighlighting(var flags: Byte; source, dest: PChar);
  77. var
  78. dp: Integer; // Destination position - current offset in dest
  79. LastSHPos: Integer; // Position of last highlighting character, or 0
  80. procedure AddSH(sh: Byte);
  81. begin
  82. ASSERT(sh > 0);
  83. if (LastSHPos > 0) and (dp = LastSHPos + 1) then Dec(dp, 2);
  84. dest[dp] := LF_Escape; Inc(dp);
  85. LastSHPos := dp;
  86. dest[dp] := Chr(sh); Inc(dp);
  87. end;
  88. procedure PutChar;
  89. begin
  90. dest[dp] := source[0]; Inc(dp); Inc(source);
  91. end;
  92. procedure ProcessComment1;
  93. begin
  94. while source[0] <> #0 do begin
  95. if source[0] = '}' then begin
  96. PutChar;
  97. flags := flags and not LF_SH_Comment1;
  98. AddSH(shDefault);
  99. break;
  100. end;
  101. PutChar;
  102. end;
  103. end;
  104. procedure ProcessComment2;
  105. begin
  106. while source[0] <> #0 do begin
  107. if (source[0] = '*') and (source[1] = ')') then begin
  108. PutChar; PutChar;
  109. flags := flags and not LF_SH_Comment2;
  110. AddSH(shDefault);
  111. break;
  112. end;
  113. PutChar;
  114. end;
  115. end;
  116. { Checks if we are at the beginning of a comment (or directive) and processes
  117. all types of comments and directives, or returns False }
  118. function CheckForComment: Boolean;
  119. begin
  120. Result := True;
  121. if source[0] = '{' then begin
  122. if source[1] = '$' then
  123. AddSH(shDirective)
  124. else
  125. AddSH(shComment);
  126. PutChar;
  127. flags := flags or LF_SH_Comment1;
  128. ProcessComment1;
  129. end else if (source[0] = '(') and (source[1] = '*') then begin
  130. AddSH(shComment);
  131. PutChar; PutChar;
  132. flags := flags or LF_SH_Comment2;
  133. ProcessComment2;
  134. end else if (source[0] = '/') and (source[1] = '/') then begin
  135. AddSH(shComment);
  136. repeat PutChar until source[0] = #0;
  137. AddSH(shDefault);
  138. end else
  139. Result := False;
  140. end;
  141. procedure ProcessAsm;
  142. var
  143. LastChar: Char;
  144. begin
  145. LastChar := ' ';
  146. while source[0] <> #0 do begin
  147. if (LastChar in [' ', #9, #10, #13]) and
  148. (UpCase(source[0]) = 'E') and (UpCase(source[1]) = 'N') and
  149. (UpCase(source[2]) = 'D') then begin
  150. AddSH(shKeyword);
  151. PutChar; PutChar; PutChar;
  152. flags := flags and not LF_SH_Asm;
  153. AddSH(shDefault);
  154. break;
  155. end else
  156. if CheckForComment then LastChar := ' '
  157. else begin
  158. LastChar := source[0];
  159. PutChar;
  160. end;
  161. end;
  162. end;
  163. procedure ProcessSymbol;
  164. begin
  165. AddSH(shSymbol);
  166. if (source[0] = ':') and (source[1] = '=') then
  167. PutChar;
  168. PutChar;
  169. AddSH(shDefault);
  170. end;
  171. function CheckForKeyword: Boolean;
  172. var
  173. keyword, ukeyword: array[0..MaxKeywordLength] of Char;
  174. i, j: Integer;
  175. begin
  176. i := 0;
  177. while (source[i] <> #0) and (i < MaxKeywordLength) and
  178. (source[i] in ['0'..'9', 'A'..'Z', 'a'..'z']) do begin
  179. keyword[i] := source[i];
  180. ukeyword[i] := UpCase(source[i]);
  181. Inc(i);
  182. end;
  183. keyword[i] := #0; ukeyword[i] := #0;
  184. Result := False;
  185. if i < MaxKeywordLength then
  186. for j := 0 to MaxKeyword do
  187. if StrIComp(KeywordTable[j], ukeyword) = 0 then begin
  188. Result := True; break;
  189. end;
  190. if not Result then exit;
  191. Inc(source, i);
  192. AddSH(shKeyword);
  193. StrCopy(dest + dp, keyword);
  194. Inc(dp, i);
  195. if j <> KeywordAsmIndex then
  196. AddSH(shDefault)
  197. else begin
  198. AddSH(shAssembler);
  199. flags := flags or LF_SH_Asm;
  200. ProcessAsm;
  201. end;
  202. end;
  203. var
  204. StringLength: Integer;
  205. begin
  206. dp := 0;
  207. LastSHPos := 0;
  208. if (flags and LF_SH_Comment1) <> 0 then begin
  209. AddSH(shComment);
  210. ProcessComment1;
  211. end;
  212. if (flags and LF_SH_Comment2) <> 0 then begin
  213. AddSH(shComment);
  214. ProcessComment2;
  215. end;
  216. if (flags and LF_SH_Asm) <> 0 then begin
  217. AddSH(shAssembler);
  218. ProcessAsm;
  219. end;
  220. while source[0] <> #0 do begin
  221. if CheckForComment then continue;
  222. case source[0] of
  223. ',', ';', ':', '.', '(', ')', '[', ']', '<', '>', '=',
  224. '*', '/', '+', '-', '^', '&', '@': ProcessSymbol;
  225. '#': begin
  226. AddSH(shCharacters);
  227. PutChar;
  228. if source[0] = '$' then PutChar;
  229. while (source[0] >= '0') and (source[0] <= '9') do PutChar;
  230. AddSH(shDefault);
  231. end;
  232. '$': begin
  233. AddSH(shNumbers);
  234. PutChar;
  235. while source[0] in ['0'..'9', 'A'..'F', 'a'..'f'] do PutChar;
  236. AddSH(shDefault);
  237. end;
  238. '0'..'9': begin
  239. AddSH(shNumbers);
  240. PutChar;
  241. while (source[0] >= '0') and (source[0] <= '9') do PutChar;
  242. AddSH(shDefault);
  243. end;
  244. '''': begin
  245. AddSH(shStrings);
  246. PutChar;
  247. StringLength := 0;
  248. while source[0] <> #0 do begin
  249. if source[0] = '''' then
  250. if source[1] = '''' then PutChar
  251. else begin
  252. PutChar; break;
  253. end;
  254. Inc(StringLength);
  255. PutChar;
  256. end;
  257. if StringLength = 1 then
  258. dest[LastSHPos] := Chr(shCharacters);
  259. if (source[0] = #0) and (dest[dp - 1] <> '''') then
  260. dest[LastSHPos] := Chr(shInvalid);
  261. AddSH(shDefault);
  262. end;
  263. '_', 'A'..'Z', 'a'..'z': begin
  264. if not CheckForKeyword then
  265. repeat
  266. PutChar
  267. until not (source[0] in ['0'..'9', '_', 'A'..'Z', 'a'..'z']);
  268. end;
  269. ' ': PutChar;
  270. else begin
  271. AddSH(shInvalid);
  272. PutChar; // = found an invalid char!
  273. AddSH(shDefault);
  274. end;
  275. end;
  276. end;
  277. dest[dp] := #0;
  278. end;
  279. end.
  280. {
  281. $Log$
  282. Revision 1.2 2000-07-13 11:33:02 michael
  283. + removed logs
  284. }