IDE.ScintStylerInnoSetup.pas 68 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791
  1. unit IDE.ScintStylerInnoSetup;
  2. {
  3. Inno Setup
  4. Copyright (C) 1997-2025 Jordan Russell
  5. Portions by Martijn Laan
  6. For conditions of distribution and use, see LICENSE.TXT.
  7. TInnoSetupStyler: styler for Inno Setup scripts
  8. }
  9. interface
  10. uses
  11. SysUtils, Classes, Graphics, Generics.Collections, TypInfo,
  12. ScintEdit, ModernColors, Shared.ScriptFunc;
  13. const
  14. InnoSetupStylerWordListSeparator = #9;
  15. InnoSetupStylerWordListTypeSeparator = '!'; { Must sort before numbers - so the default '?' is not ok }
  16. { AutoComplete word types }
  17. awtSection = 0;
  18. awtParameter = 1;
  19. awtDirective = 2;
  20. awtFlag = 3;
  21. awtPreprocessorDirective = 4;
  22. awtConstant = 5;
  23. awtScriptFunction = 10;
  24. awtScriptType = 11;
  25. awtScriptVariable = 12;
  26. awtScriptConstant = 13;
  27. awtScriptInterface = 14;
  28. awtScriptProperty = 15;
  29. awtScriptEvent = 16;
  30. awtScriptKeyword = 17;
  31. awtScriptEnumValue = 18;
  32. type
  33. TInnoSetupStylerSection = (
  34. scNone, { Not inside a section (start of file, or previous section was closed )
  35. Section tags themselves are not associated with any section! }
  36. scUnknown, { Inside an unrecognized section }
  37. scThirdParty, { Inside a '_' section (reserved for third-party tools) }
  38. scCode,
  39. scComponents,
  40. scCustomMessages,
  41. scDirs,
  42. scISSigKeys,
  43. scFiles,
  44. scIcons,
  45. scINI,
  46. scInstallDelete,
  47. scLangOptions,
  48. scLanguages,
  49. scMessages,
  50. scRegistry,
  51. scRun,
  52. scSetup,
  53. scTasks,
  54. scTypes,
  55. scUninstallDelete,
  56. scUninstallRun);
  57. { Internally-used types }
  58. TInnoSetupStylerSpanState = (spNone, spBraceComment, spStarComment);
  59. { Starts at 1 instead of 0 to make sure ApplyStyle doesn't overwrite already applied stDefault
  60. styles which is needed for PreStyleInlineISPPDirectives to work properly when the inline
  61. directive is inside a comment or string. This is done by added a dummy 'st0' style. If done by
  62. using 'stDefault = 1' then this enum looses its TypeInfo. }
  63. TInnoSetupStylerStyle = (st0, stDefault, stCompilerDirective,
  64. stComment, stSection, stSymbol, stKeyword, stParameterValue,
  65. stEventFunction, stConstant, stMessageArg,
  66. stPascalReservedWord, stPascalString, stPascalNumber,
  67. stISPPReservedWord, stISPPString, stISPPNumber);
  68. TWordsBySection = TObjectDictionary<TInnoSetupStylerSection, TStringList>;
  69. TFunctionDefinition = record
  70. ScriptFuncWithoutHeader: AnsiString;
  71. WasFunction, HasParams: Boolean;
  72. constructor Create(const ScriptFunc: AnsiString);
  73. end;
  74. TFunctionDefinitions = array of TFunctionDefinition;
  75. TFunctionDefinitionsByName = TDictionary<String, TFunctionDefinitions>;
  76. TInnoSetupStyler = class(TScintCustomStyler)
  77. private
  78. FEventFunctionsWordList: array[Boolean] of AnsiString;
  79. FKeywordsWordList, FFlagsWordList: array[TInnoSetupStylerSection] of AnsiString;
  80. FNoHighlightAtCursorWords: TWordsBySection;
  81. FFlagsWords: TWordsBySection;
  82. FISPPDirectivesWordList, FConstantsWordList: AnsiString;
  83. FSectionsWordList: AnsiString;
  84. FScriptFunctionsByName: array[Boolean] of TFunctionDefinitionsByName; { Only has functions with at least 1 parameter }
  85. FScriptWordList: array[Boolean] of AnsiString;
  86. FISPPInstalled: Boolean;
  87. FTheme: TTheme;
  88. procedure AddWordToList(const SL: TStringList; const Word: AnsiString;
  89. const Typ: Integer);
  90. procedure ApplyPendingSquigglyFromToIndex(const StartIndex, EndIndex: Integer);
  91. procedure ApplyPendingSquigglyFromIndex(const StartIndex: Integer);
  92. procedure ApplySquigglyFromIndex(const StartIndex: Integer);
  93. procedure BuildConstantsWordList;
  94. procedure BuildEventFunctionsWordList;
  95. procedure BuildFlagsWordList(const Section: TInnoSetupStylerSection;
  96. const Flags: array of TScintRawString);
  97. procedure BuildISPPDirectivesWordList;
  98. procedure BuildKeywordsWordList(const Section: TInnoSetupStylerSection;
  99. const Parameters: array of TScintRawString);
  100. procedure BuildKeywordsWordListFromTypeInfo(const Section: TInnoSetupStylerSection;
  101. const EnumTypeInfo: Pointer; const PrefixLength: Integer);
  102. procedure BuildScriptFunctionsLists(const ScriptFuncTable: TScriptTable;
  103. const ClassMembers: Boolean; const SL: TStringList);
  104. function BuildWordList(const WordStringList: TStringList): AnsiString;
  105. procedure BuildSectionsWordList;
  106. procedure CommitStyleSq(const Style: TInnoSetupStylerStyle;
  107. const Squigglify: Boolean);
  108. procedure CommitStyleSqPending(const Style: TInnoSetupStylerStyle);
  109. function GetEventFunctionsWordList(Procedures: Boolean): AnsiString;
  110. function GetFlagsWordList(Section: TInnoSetupStylerSection): AnsiString;
  111. function GetKeywordsWordList(Section: TInnoSetupStylerSection): AnsiString;
  112. procedure HandleCodeSection(var SpanState: TInnoSetupStylerSpanState);
  113. procedure HandleKeyValueSection(const Section: TInnoSetupStylerSection);
  114. procedure HandleParameterSection(const ValidParameters: array of TScintRawString);
  115. procedure HandleCompilerDirective(const InlineDirective: Boolean;
  116. const InlineDirectiveEndIndex: Integer; var OpenCount: ShortInt);
  117. procedure PreStyleInlineISPPDirectives;
  118. procedure SkipWhitespace;
  119. procedure SquigglifyUntilChars(const Chars: TScintRawCharSet;
  120. const Style: TInnoSetupStylerStyle);
  121. procedure StyleConstsUntilChars(const Chars: TScintRawCharSet;
  122. const NonConstStyle: TInnoSetupStylerStyle; var BraceLevel: Integer);
  123. procedure SetISPPInstalled(const Value: Boolean);
  124. function GetScriptWordList(ClassOrRecordMembers: Boolean): AnsiString;
  125. protected
  126. procedure CommitStyle(const Style: TInnoSetupStylerStyle);
  127. procedure GetFoldLevel(const LineState, PreviousLineState: TScintLineState;
  128. var Level: Integer; var Header, EnableHeaderOnPrevious: Boolean); override;
  129. procedure GetStyleAttributes(const Style: Integer;
  130. var Attributes: TScintStyleAttributes); override;
  131. function LineTextSpans(const S: TScintRawString): Boolean; override;
  132. procedure StyleNeeded; override;
  133. public
  134. constructor Create(AOwner: TComponent); override;
  135. destructor Destroy; override;
  136. class function GetSectionFromLineState(const LineState: TScintLineState): TInnoSetupStylerSection;
  137. class function IsCommentOrPascalStringStyle(const Style: TScintStyleNumber): Boolean;
  138. class function IsParamSection(const Section: TInnoSetupStylerSection): Boolean;
  139. class function IsSymbolStyle(const Style: TScintStyleNumber): Boolean;
  140. function GetScriptFunctionDefinition(const ClassMember: Boolean;
  141. const Name: String; const Index: Integer; out Count: Integer): TFunctionDefinition; overload;
  142. function GetScriptFunctionDefinition(const ClassMember: Boolean;
  143. const Name: String; const Index: Integer): TFunctionDefinition; overload;
  144. function SectionHasFlag(const Section: TInnoSetupStylerSection; const Flag: String): Boolean;
  145. function HighlightAtCursorAllowed(const Section: TInnoSetupStylerSection; const Word: String): Boolean;
  146. property ConstantsWordList: AnsiString read FConstantsWordList;
  147. property EventFunctionsWordList[Procedures: Boolean]: AnsiString read GetEventFunctionsWordList;
  148. property FlagsWordList[Section: TInnoSetupStylerSection]: AnsiString read GetFlagsWordList;
  149. property ISPPDirectivesWordList: AnsiString read FISPPDirectivesWordList;
  150. property ISPPInstalled: Boolean read FISPPInstalled write SetISPPInstalled;
  151. property KeywordsWordList[Section: TInnoSetupStylerSection]: AnsiString read GetKeywordsWordList;
  152. property ScriptWordList[ClassOrRecordMembers: Boolean]: AnsiString read GetScriptWordList;
  153. property SectionsWordList: AnsiString read FSectionsWordList;
  154. property Theme: TTheme read FTheme write FTheme;
  155. end;
  156. implementation
  157. uses
  158. Generics.Defaults,
  159. Shared.SetupMessageIDs, ScintInt, Shared.SetupSectionDirectives, Shared.LangOptionsSectionDirectives,
  160. Shared.CommonFunc.Vcl, Shared.SetupSteps, Shared.Struct, Shared.DotNetVersion, isxclasses_wordlists_generated;
  161. type
  162. { Size must be <= SizeOf(TScintLineState) }
  163. TInnoSetupStylerLineState = record
  164. Section, NextLineSection: TInnoSetupStylerSection;
  165. SpanState: TInnoSetupStylerSpanState;
  166. OpenCompilerDirectivesCount: ShortInt;
  167. end;
  168. type
  169. TSectionMapItem = record
  170. Name: TScintRawString;
  171. Section: TInnoSetupStylerSection;
  172. end;
  173. const
  174. SectionMap: array[0..18] of TSectionMapItem = (
  175. (Name: 'Code'; Section: scCode),
  176. (Name: 'Components'; Section: scComponents),
  177. (Name: 'CustomMessages'; Section: scCustomMessages),
  178. (Name: 'Dirs'; Section: scDirs),
  179. (Name: 'ISSigKeys'; Section: scISSigKeys),
  180. (Name: 'Files'; Section: scFiles),
  181. (Name: 'Icons'; Section: scIcons),
  182. (Name: 'INI'; Section: scINI),
  183. (Name: 'InstallDelete'; Section: scInstallDelete),
  184. (Name: 'LangOptions'; Section: scLangOptions),
  185. (Name: 'Languages'; Section: scLanguages),
  186. (Name: 'Messages'; Section: scMessages),
  187. (Name: 'Registry'; Section: scRegistry),
  188. (Name: 'Run'; Section: scRun),
  189. (Name: 'Setup'; Section: scSetup),
  190. (Name: 'Tasks'; Section: scTasks),
  191. (Name: 'Types'; Section: scTypes),
  192. (Name: 'UninstallDelete'; Section: scUninstallDelete),
  193. (Name: 'UninstallRun'; Section: scUninstallRun));
  194. ComponentsSectionParameters: array of TScintRawString = [
  195. 'Check', 'Description', 'ExtraDiskSpaceRequired', 'Flags', 'Languages',
  196. 'MinVersion', 'Name', 'OnlyBelowVersion', 'Types'
  197. ];
  198. ComponentsSectionFlags: array of TScintRawString = [
  199. 'checkablealone', 'disablenouninstallwarning', 'dontinheritcheck', 'exclusive',
  200. 'fixed', 'restart'
  201. ];
  202. DeleteSectionParameters: array of TScintRawString = [
  203. 'AfterInstall', 'BeforeInstall', 'Check', 'Components', 'Languages',
  204. 'MinVersion', 'Name', 'OnlyBelowVersion', 'Tasks', 'Type'
  205. ];
  206. DeleteSectionTypes: array of TScintRawString = [
  207. 'files', 'filesandordirs', 'dirifempty'
  208. ];
  209. DirsSectionParameters: array of TScintRawString = [
  210. 'AfterInstall', 'Attribs', 'BeforeInstall', 'Check', 'Components', 'Flags',
  211. 'Languages', 'MinVersion', 'Name', 'OnlyBelowVersion', 'Permissions', 'Tasks'
  212. ];
  213. DirsSectionFlags: array of TScintRawString = [
  214. 'deleteafterinstall', 'setntfscompression', 'uninsalwaysuninstall',
  215. 'uninsneveruninstall', 'unsetntfscompression'
  216. ];
  217. ISSigKeysSectionParameters: array of TScintRawString = [
  218. 'Name', 'Group', 'KeyFile', 'KeyID', 'PublicX', 'PublicY', 'RuntimeID'
  219. ];
  220. FilesSectionParameters: array of TScintRawString = [
  221. 'AfterInstall', 'Attribs', 'BeforeInstall', 'Check', 'Components', 'CopyMode',
  222. 'DestDir', 'DestName', 'DownloadISSigSource', 'DownloadPassword',
  223. 'DownloadUserName', 'Excludes', 'ExternalSize', 'ExtractArchivePassword',
  224. 'Flags', 'FontInstall', 'Hash', 'ISSigAllowedKeys', 'Languages', 'MinVersion',
  225. 'OnlyBelowVersion', 'Permissions', 'Source', 'StrongAssemblyName', 'Tasks'
  226. ];
  227. FilesSectionFlags: array of TScintRawString = [
  228. '32bit', '64bit', 'allowunsafefiles', 'comparetimestamp', 'confirmoverwrite',
  229. 'createallsubdirs', 'deleteafterinstall', 'dontcopy', 'dontverifychecksum', 'download',
  230. 'external', 'extractarchive', 'fontisnttruetype', 'gacinstall', 'ignoreversion',
  231. 'isreadme', 'issigverify', 'nocompression', 'noencryption', 'noregerror',
  232. 'onlyifdestfileexists', 'onlyifdoesntexist', 'overwritereadonly', 'promptifolder',
  233. 'recursesubdirs', 'regserver', 'regtypelib', 'replacesameversion', 'restartreplace',
  234. 'setntfscompression', 'sharedfile', 'sign', 'signcheck', 'signonce',
  235. 'skipifsourcedoesntexist', 'solidbreak', 'sortfilesbyextension',
  236. 'sortfilesbyname', 'touch', 'uninsnosharedfileprompt', 'uninsremovereadonly',
  237. 'uninsrestartdelete', 'uninsneveruninstall', 'unsetntfscompression'
  238. ];
  239. IconsSectionParameters: array of TScintRawString = [
  240. 'AfterInstall', 'AppUserModelID', 'AppUserModelToastActivatorCLSID',
  241. 'BeforeInstall', 'Check', 'Comment', 'Components', 'Filename', 'Flags',
  242. 'HotKey', 'IconFilename', 'IconIndex', 'Languages', 'MinVersion', 'Name',
  243. 'OnlyBelowVersion', 'Parameters', 'Tasks', 'WorkingDir'
  244. ];
  245. IconsSectionFlags: array of TScintRawString = [
  246. 'closeonexit', 'createonlyiffileexists', 'dontcloseonexit',
  247. 'excludefromshowinnewinstall', 'preventpinning', 'runmaximized',
  248. 'runminimized', 'uninsneveruninstall', 'useapppaths'
  249. ];
  250. INISectionParameters: array of TScintRawString = [
  251. 'AfterInstall', 'BeforeInstall', 'Check', 'Components', 'Filename',
  252. 'Flags', 'Key', 'Languages', 'MinVersion', 'OnlyBelowVersion', 'Section',
  253. 'String', 'Tasks'
  254. ];
  255. INISectionFlags: array of TScintRawString = [
  256. 'createkeyifdoesntexist', 'uninsdeleteentry', 'uninsdeletesection',
  257. 'uninsdeletesectionifempty'
  258. ];
  259. LanguagesSectionParameters: array of TScintRawString = [
  260. 'InfoAfterFile', 'InfoBeforeFile', 'LicenseFile', 'MessagesFile', 'Name'
  261. ];
  262. RegistrySectionParameters: array of TScintRawString = [
  263. 'AfterInstall', 'BeforeInstall', 'Check', 'Components', 'Flags', 'Languages',
  264. 'MinVersion', 'OnlyBelowVersion', 'Permissions', 'Root', 'Subkey', 'Tasks',
  265. 'ValueData', 'ValueName', 'ValueType'
  266. ];
  267. RegistrySectionFlags: array of TScintRawString = [
  268. 'createvalueifdoesntexist', 'deletekey', 'deletevalue', 'dontcreatekey',
  269. 'noerror', 'preservestringtype', 'uninsclearvalue', 'uninsdeletekey',
  270. 'uninsdeletekeyifempty', 'uninsdeletevalue'
  271. ];
  272. RunSectionParameters: array of TScintRawString = [
  273. 'AfterInstall', 'BeforeInstall', 'Check', 'Components', 'Description',
  274. 'Filename', 'Flags', 'Languages', 'MinVersion', 'OnlyBelowVersion',
  275. 'Parameters', 'StatusMsg', 'Tasks', 'Verb', 'WorkingDir'
  276. ];
  277. RunSectionFlags: array of TScintRawString = [
  278. '32bit', '64bit', 'dontlogparameters', 'hidewizard', 'logoutput', 'nowait',
  279. 'postinstall', 'runascurrentuser', 'runasoriginaluser', 'runhidden',
  280. 'runmaximized', 'runminimized', 'shellexec', 'skipifdoesntexist', 'skipifnotsilent',
  281. 'skipifsilent', 'unchecked', 'waituntilidle', 'waituntilterminated'
  282. ];
  283. UninstallRunSectionParameters: array of TScintRawString = [
  284. 'AfterInstall', 'BeforeInstall', 'Check', 'Components', 'Filename', 'Flags',
  285. 'Languages', 'MinVersion', 'OnlyBelowVersion', 'Parameters', 'RunOnceId',
  286. 'Tasks', 'Verb', 'WorkingDir'
  287. ];
  288. UninstallRunSectionFlags: array of TScintRawString = [
  289. '32bit', '64bit', 'dontlogparameters', 'hidewizard', 'logoutput', 'nowait',
  290. 'runascurrentuser', 'runhidden', 'runmaximized', 'runminimized', 'shellexec',
  291. 'skipifdoesntexist', 'waituntilidle', 'waituntilterminated'
  292. ];
  293. TasksSectionParameters: array of TScintRawString = [
  294. 'Check', 'Components', 'Description', 'Flags', 'GroupDescription', 'Languages',
  295. 'MinVersion', 'Name', 'OnlyBelowVersion'
  296. ];
  297. TasksSectionFlags: array of TScintRawString = [
  298. 'checkablealone', 'checkedonce', 'dontinheritcheck', 'exclusive', 'restart',
  299. 'unchecked'
  300. ];
  301. TypesSectionParameters: array of TScintRawString = [
  302. 'Check', 'Description', 'Flags', 'Languages', 'MinVersion', 'Name',
  303. 'OnlyBelowVersion'
  304. ];
  305. TypesSectionFlags: array of TScintRawString = [
  306. 'iscustom'
  307. ];
  308. type
  309. TISPPDirective = record
  310. Name: TScintRawString;
  311. RequiresParameter: Boolean;
  312. OpenCountChange: ShortInt;
  313. end;
  314. const
  315. ISPPDirectives: array[0..23] of TISPPDirective = (
  316. (Name: 'preproc'; RequiresParameter: True; OpenCountChange: 0),
  317. (Name: 'define'; RequiresParameter: True; OpenCountChange: 0),
  318. (Name: 'dim'; RequiresParameter: True; OpenCountChange: 0),
  319. (Name: 'redim'; RequiresParameter: True; OpenCountChange: 0),
  320. (Name: 'undef'; RequiresParameter: True; OpenCountChange: 0),
  321. (Name: 'include'; RequiresParameter: True; OpenCountChange: 0),
  322. (Name: 'file'; RequiresParameter: True; OpenCountChange: 0),
  323. (Name: 'emit'; RequiresParameter: True; OpenCountChange: 0),
  324. (Name: 'expr'; RequiresParameter: True; OpenCountChange: 0),
  325. (Name: 'insert'; RequiresParameter: True; OpenCountChange: 0),
  326. (Name: 'append'; RequiresParameter: False; OpenCountChange: 0),
  327. (Name: 'if'; RequiresParameter: True; OpenCountChange: 1),
  328. (Name: 'elif'; RequiresParameter: False { bug in ISPP? }; OpenCountChange: 0),
  329. (Name: 'else'; RequiresParameter: False; OpenCountChange: 0),
  330. (Name: 'endif'; RequiresParameter: False; OpenCountChange: -1),
  331. (Name: 'ifdef'; RequiresParameter: True; OpenCountChange: 1),
  332. (Name: 'ifndef'; RequiresParameter: True; OpenCountChange: 1),
  333. (Name: 'ifexist'; RequiresParameter: True; OpenCountChange: 1),
  334. (Name: 'ifnexist'; RequiresParameter: True; OpenCountChange: 1),
  335. (Name: 'for'; RequiresParameter: True; OpenCountChange: 0),
  336. (Name: 'sub'; RequiresParameter: True; OpenCountChange: 1),
  337. (Name: 'endsub'; RequiresParameter: False; OpenCountChange: -1),
  338. (Name: 'pragma'; RequiresParameter: False; OpenCountChange: 0),
  339. (Name: 'error'; RequiresParameter: False; OpenCountChange: 0));
  340. { The following and some others below are not used by StyleNeeded and therefore
  341. simply of type AnsiString instead of TScintRawString }
  342. ConstantsWithParam: array of AnsiString = [
  343. 'cm', 'code', 'drive', 'ini', 'param', 'reg'
  344. ];
  345. Constants: array of AnsiString = [
  346. { Doesnt include constants with non words chars }
  347. '{', 'app', 'win', 'sys', 'sysnative', 'syswow64', 'src', 'sd', 'commonpf',
  348. 'commoncf', 'tmp', 'commonfonts', 'dao', 'dotnet11', 'dotnet20', 'dotnet40',
  349. 'group', 'localappdata', 'userappdata', 'commonappdata', 'usercf',
  350. 'userdesktop', 'commondesktop', 'userdocs', 'commondocs', 'userfavorites',
  351. 'userfonts', 'userpf', 'userprograms', 'commonprograms', 'usersavedgames',
  352. 'userstartmenu', 'commonstartmenu', 'userstartup', 'commonstartup',
  353. 'usertemplates', 'commontemplates', 'autoappdata', 'autocf', 'autodesktop',
  354. 'autodocs', 'autofonts', 'autopf', 'autoprograms', 'autostartmenu', 'cmd',
  355. 'computername', 'groupname', 'hwnd', 'wizardhwnd', 'language', 'srcexe',
  356. 'uninstallexe', 'sysuserinfoname', 'sysuserinfoorg', 'userinfoname',
  357. 'userinfoorg', 'userinfoserial', 'username', 'log'
  358. ];
  359. ISPPPredefinedVariables: array of AnsiString = [
  360. { #emit and #file handled separately by BuildConstantsWordList.
  361. Only includes predefined variables that are useful on their own. }
  362. 'CompilerPath', 'SourcePath'
  363. ];
  364. PascalConstants: array of AnsiString = [
  365. { ROPS }
  366. 'varEmpty', 'varNull', 'varSmallInt', 'varInteger', 'varSingle', 'varDouble',
  367. 'varCurrency', 'varDate', 'varOleStr', 'varDispatch', 'varError', 'varBoolean',
  368. 'varVariant', 'varUnknown', 'varShortInt', 'varByte', 'varWord', 'varLongWord',
  369. 'varInt64', 'varStrArg', 'varAny', 'varString', 'varTypeMask', 'varArray',
  370. 'varByRef', 'varUString', 'False', 'True',
  371. { ScriptFunc }
  372. 'MaxInt', 'wpWelcome', 'wpLicense', 'wpPassword', 'wpInfoBefore',
  373. 'wpUserInfo', 'wpSelectDir', 'wpSelectComponents', 'wpSelectProgramGroup',
  374. 'wpSelectTasks', 'wpReady', 'wpPreparing', 'wpInstalling', 'wpInfoAfter',
  375. 'wpFinished', 'MB_OK', 'MB_OKCANCEL', 'MB_ABORTRETRYIGNORE', 'MB_YESNOCANCEL',
  376. 'MB_YESNO', 'MB_RETRYCANCEL', 'MB_DEFBUTTON1', 'MB_DEFBUTTON2', 'MB_DEFBUTTON3',
  377. 'MB_SETFOREGROUND', 'IDOK', 'IDCANCEL', 'IDABORT', 'IDRETRY', 'IDIGNORE',
  378. 'IDYES', 'IDNO', 'HWND_BROADCAST', 'HKEY_AUTO', 'HKEY_AUTO_32', 'HKEY_AUTO_64',
  379. 'HKEY_CLASSES_ROOT', 'HKEY_CLASSES_ROOT_32', 'HKEY_CLASSES_ROOT_64',
  380. 'HKEY_CURRENT_USER', 'HKEY_CURRENT_USER_32', 'HKEY_CURRENT_USER_64',
  381. 'HKEY_LOCAL_MACHINE', 'HKEY_LOCAL_MACHINE_32', 'HKEY_LOCAL_MACHINE_64',
  382. 'HKEY_USERS', 'HKEY_USERS_32', 'HKEY_USERS_64', 'HKEY_PERFORMANCE_DATA',
  383. 'HKEY_CURRENT_CONFIG', 'HKEY_CURRENT_CONFIG_32', 'HKEY_CURRENT_CONFIG_64',
  384. 'HKEY_DYN_DATA', 'HKA', 'HKA32', 'HKA64', 'HKCR', 'HKCR32', 'HKCR64', 'HKCU',
  385. 'HKCU32', 'HKCU64', 'HKLM', 'HKLM32', 'HKLM64', 'HKU', 'HKU32', 'HKU64',
  386. 'HKCC', 'HKCC32', 'HKCC64', 'SW_HIDE', 'SW_SHOWNORMAL', 'SW_SHOWMINIMIZED',
  387. 'SW_SHOWMAXIMIZED', 'SW_SHOWMINNOACTIVE', 'SW_SHOW', 'FILE_ATTRIBUTE_READONLY',
  388. 'FILE_ATTRIBUTE_HIDDEN', 'FILE_ATTRIBUTE_SYSTEM', 'FILE_ATTRIBUTE_DIRECTORY',
  389. 'FILE_ATTRIBUTE_ARCHIVE', 'FILE_ATTRIBUTE_DEVICE', 'FILE_ATTRIBUTE_NORMAL',
  390. 'FILE_ATTRIBUTE_TEMPORARY', 'FILE_ATTRIBUTE_SPARSE_FILE','FILE_ATTRIBUTE_REPARSE_POINT',
  391. 'FILE_ATTRIBUTE_COMPRESSED', 'FILE_ATTRIBUTE_OFFLINE', 'FILE_ATTRIBUTE_NOT_CONTENT_INDEXED',
  392. 'FILE_ATTRIBUTE_ENCRYPTED', 'VER_NT_WORKSTATION', 'VER_NT_DOMAIN_CONTROLLER',
  393. 'VER_NT_SERVER', 'VER_SUITE_SMALLBUSINESS', 'VER_SUITE_ENTERPRISE', 'VER_SUITE_BACKOFFICE',
  394. 'VER_SUITE_COMMUNICATIONS', 'VER_SUITE_TERMINAL', 'VER_SUITE_SMALLBUSINESS_RESTRICTED',
  395. 'VER_SUITE_EMBEDDEDNT', 'VER_SUITE_DATACENTER', 'VER_SUITE_SINGLEUSERTS',
  396. 'VER_SUITE_PERSONAL', 'VER_SUITE_BLADE', 'VER_SUITE_EMBEDDED_RESTRICTED',
  397. 'VER_SUITE_SECURITY_APPLIANCE'
  398. //undocumented: irInstall
  399. { ScriptClasses: see PascalConstants_Isxclasses in isxclasses_wordlists_generated }
  400. ];
  401. PascalInterfaces: array of AnsiString = [
  402. { ROPS }
  403. 'IUnknown', 'IInterface', 'IDispatch'
  404. ];
  405. PascalReservedWords: array of TScintRawString = [
  406. 'and', 'array', 'as', 'begin', 'case', 'const', 'div', 'do', 'downto',
  407. 'else', 'end', 'except', 'external', 'finally', 'for', 'forward', 'function',
  408. 'goto', 'if', 'in', 'is', 'label', 'mod', 'nil', 'not', 'of', 'or',
  409. 'procedure', 'program', 'record', 'repeat', 'set', 'shl', 'shr', 'then',
  410. 'to', 'try', 'type', 'until', 'var', 'while', 'with', 'xor', 'delayload',
  411. 'loadwithalteredsearchpath', 'stdcall', 'cdecl', 'register', 'pascal',
  412. 'setuponly', 'uninstallonly', 'event'
  413. ];
  414. PascalTypes: array of AnsiString = [
  415. { ROPS }
  416. 'Byte', 'Boolean', 'LongBool', 'WordBool', 'ByteBool', 'AnsiChar', 'Char',
  417. 'WideChar', 'WideString', 'UnicodeString', 'AnsiString', 'String', 'ShortInt',
  418. 'Word', 'SmallInt', 'LongInt', 'LongWord', 'Integer', 'Cardinal', 'Int64',
  419. 'Single', 'Double', 'Extended', 'Currency', 'PAnsiChar', 'Variant',
  420. 'TVariantArray',
  421. //undocumented: NativeString, AnyString, AnyMethod, ___Pointer, tbtString, NativeString, !NotificationVariant
  422. 'TVarType',
  423. //undocumented: TIFException
  424. { ScriptFunc's real enums, values done via PascalRealEnumValues instead of PascalEnumValues}
  425. 'TMsgBoxType', 'TSetupMessageID', 'TSetupStep', 'TUninstallStep',
  426. 'TSetupProcessorArchitecture', 'TDotNetVersion',
  427. { ScriptFunc's non real enums and other types - also see PascalEnumValues below }
  428. 'TArrayOfString', 'TArrayOfChar', 'TArrayOfBoolean', 'TArrayOfInteger', 'DWORD',
  429. 'UINT', 'BOOL', 'DWORD_PTR', 'UINT_PTR', 'INT_PTR', 'TFileTime',
  430. 'TSplitType', 'TExecWait', 'TExecOutput', 'TFindRec', 'TWindowsVersion',
  431. 'TOnDownloadProgress', 'TOnExtractionProgress', 'TOnLog'
  432. { ScriptClasses: see PascalTypes_Isxclasses in isxclasses_wordlists_generated }
  433. ];
  434. PascalEnumValues: array of AnsiString = [
  435. { ScriptFunc's values of non real enums - also see PascalTypes above }
  436. 'stAll', 'stExcludeEmpty', 'stExcludeLastEmpty',
  437. 'ewNoWait', 'ewWaitUntilTerminated', 'ewWaitUntilIdle'
  438. { ScriptClasses: see PascalEnumValues_Isxclasses in isxclasses_wordlists_generated }
  439. ];
  440. var
  441. PascalRealEnumValues: array of PTypeInfo; { Initialized below }
  442. const
  443. PascalVariables: array of AnsiString = [
  444. { ROPS }
  445. 'Result',
  446. { ScriptClasses }
  447. 'WizardForm', 'MainForm', 'UninstallProgressForm'
  448. ];
  449. BasicEventFunctions: array of TScintRawString = [
  450. 'InitializeSetup', 'InitializeWizard', 'DeinitializeSetup', 'CurStepChanged',
  451. 'CurInstallProgressChanged', 'NextButtonClick', 'BackButtonClick',
  452. 'CancelButtonClick', 'ShouldSkipPage', 'CurPageChanged', 'CheckPassword',
  453. 'NeedRestart', 'UpdateReadyMemo', 'RegisterPreviousData', 'CheckSerial',
  454. 'GetCustomSetupExitCode', 'PrepareToInstall',
  455. 'RegisterExtraCloseApplicationsResources', 'InitializeUninstall',
  456. 'InitializeUninstallProgressForm', 'DeinitializeUninstall',
  457. 'CurUninstallStepChanged', 'UninstallNeedRestart'
  458. ];
  459. FullEventFunctions: array of AnsiString = [
  460. 'function InitializeSetup: Boolean;',
  461. 'procedure InitializeWizard;',
  462. 'procedure DeinitializeSetup;',
  463. 'procedure CurStepChanged(CurStep: TSetupStep);',
  464. 'procedure CurInstallProgressChanged(CurProgress, MaxProgress: Integer);',
  465. 'function NextButtonClick(CurPageID: Integer): Boolean;',
  466. 'function BackButtonClick(CurPageID: Integer): Boolean;',
  467. 'procedure CancelButtonClick(CurPageID: Integer; var Cancel, Confirm: Boolean);',
  468. 'function ShouldSkipPage(PageID: Integer): Boolean;',
  469. 'procedure CurPageChanged(CurPageID: Integer);',
  470. 'function CheckPassword(Password: String): Boolean;',
  471. 'function NeedRestart: Boolean;',
  472. 'function UpdateReadyMemo(Space, NewLine, MemoUserInfoInfo, MemoDirInfo, MemoTypeInfo, MemoComponentsInfo, MemoGroupInfo, MemoTasksInfo: String): String;',
  473. 'procedure RegisterPreviousData(PreviousDataKey: Integer);',
  474. 'function CheckSerial(Serial: String): Boolean;',
  475. 'function GetCustomSetupExitCode: Integer;',
  476. 'function PrepareToInstall(var NeedsRestart: Boolean): String;',
  477. 'procedure RegisterExtraCloseApplicationsResources;',
  478. 'function InitializeUninstall: Boolean;',
  479. 'procedure InitializeUninstallProgressForm;',
  480. 'procedure DeinitializeUninstall;',
  481. 'procedure CurUninstallStepChanged(CurUninstallStep: TUninstallStep);',
  482. 'function UninstallNeedRestart: Boolean;'
  483. ];
  484. EventFunctionsParameters: array of AnsiString = [
  485. 'CurStep', 'CurProgress', 'MaxProgress', 'CurPageID', 'Cancel', 'Confirm',
  486. 'PageID', 'Password', 'Space', 'NewLine', 'MemoUserInfoInfo',
  487. 'MemoDirInfo', 'MemoTypeInfo', 'MemoComponentsInfo', 'MemoGroupInfo',
  488. 'MemoTasksInfo', 'PreviousDataKey', 'Serial', 'NeedsRestart',
  489. 'CurUninstallStep'
  490. ];
  491. inSquiggly = 0;
  492. inPendingSquiggly = 1;
  493. AllChars = [#0..#255];
  494. WhitespaceChars = [#0..' '];
  495. AlphaChars = ['A'..'Z', 'a'..'z'];
  496. DigitChars = ['0'..'9'];
  497. HexDigitChars = DigitChars + ['A'..'F', 'a'..'f'];
  498. AlphaUnderscoreChars = AlphaChars + ['_'];
  499. AlphaDigitChars = AlphaChars + DigitChars;
  500. AlphaDigitUnderscoreChars = AlphaChars + DigitChars + ['_'];
  501. PascalIdentFirstChars = AlphaUnderscoreChars;
  502. PascalIdentChars = AlphaDigitUnderscoreChars;
  503. ISPPIdentFirstChars = AlphaUnderscoreChars;
  504. ISPPIdentChars = AlphaDigitUnderscoreChars;
  505. function SameRawText(const S1, S2: TScintRawString): Boolean;
  506. var
  507. Len, I: Integer;
  508. C1, C2: AnsiChar;
  509. begin
  510. Len := Length(S1);
  511. if Length(S2) <> Len then begin
  512. Result := False;
  513. Exit;
  514. end;
  515. for I := 1 to Len do begin
  516. C1 := S1[I];
  517. C2 := S2[I];
  518. if C1 in ['A'..'Z'] then
  519. Inc(C1, 32);
  520. if C2 in ['A'..'Z'] then
  521. Inc(C2, 32);
  522. if C1 <> C2 then begin
  523. Result := False;
  524. Exit;
  525. end;
  526. end;
  527. Result := True;
  528. end;
  529. { TFunctionDefinition }
  530. constructor TFunctionDefinition.Create(const ScriptFunc: AnsiString);
  531. begin
  532. ScriptFuncWithoutHeader := RemoveScriptFuncHeader(ScriptFunc, WasFunction);
  533. HasParams := ScriptFuncHasParameters(ScriptFunc);
  534. end;
  535. { TInnoSetupStyler }
  536. constructor TInnoSetupStyler.Create(AOwner: TComponent);
  537. procedure BuildFlagsWordLists;
  538. begin
  539. { Builds FFlagsWordList (for autocomplete) and FFlagsWords }
  540. BuildFlagsWordList(scFiles, FilesSectionFlags);
  541. BuildFlagsWordList(scComponents, ComponentsSectionFlags);
  542. BuildFlagsWordList(scDirs, DirsSectionFlags);
  543. BuildFlagsWordList(scIcons, IconsSectionFlags);
  544. BuildFlagsWordList(scINI, INISectionFlags);
  545. BuildFlagsWordList(scRegistry, RegistrySectionFlags);
  546. BuildFlagsWordList(scRun, RunSectionFlags);
  547. BuildFlagsWordList(scTasks, TasksSectionFlags);
  548. BuildFlagsWordList(scTypes, TypesSectionFlags);
  549. BuildFlagsWordList(scUninstallRun, UninstallRunSectionFlags);
  550. { Bit of a trick }
  551. BuildFlagsWordList(scInstallDelete, DeleteSectionTypes);
  552. BuildFlagsWordList(scUninstallDelete, DeleteSectionTypes);
  553. end;
  554. procedure BuildKeywordsWordLists;
  555. begin
  556. { Builds FKeywordsWordList (for autocomplete) and FNoHighlightAtCursorWords }
  557. BuildKeywordsWordList(scISSigKeys, ISSigKeysSectionParameters);
  558. BuildKeywordsWordList(scFiles, FilesSectionParameters);
  559. BuildKeywordsWordList(scComponents, ComponentsSectionParameters);
  560. BuildKeywordsWordList(scDirs, DirsSectionParameters);
  561. BuildKeywordsWordList(scIcons, IconsSectionParameters);
  562. BuildKeywordsWordList(scINI, INISectionParameters);
  563. BuildKeywordsWordList(scInstallDelete, DeleteSectionParameters);
  564. BuildKeywordsWordListFromTypeInfo(scLangOptions, TypeInfo(TLangOptionsSectionDirective), LangOptionsSectionDirectivePrefixLength);
  565. BuildKeywordsWordList(scLanguages, LanguagesSectionParameters);
  566. BuildKeywordsWordList(scRegistry, RegistrySectionParameters);
  567. BuildKeywordsWordList(scRun, RunSectionParameters);
  568. BuildKeywordsWordListFromTypeInfo(scSetup, TypeInfo(TSetupSectionDirective), SetupSectionDirectivePrefixLength);
  569. BuildKeywordsWordList(scTasks, TasksSectionParameters);
  570. BuildKeywordsWordList(scTypes, TypesSectionParameters);
  571. BuildKeywordsWordList(scUninstallDelete, DeleteSectionParameters);
  572. BuildKeywordsWordList(scUninstallRun, UninstallRunSectionParameters);
  573. BuildKeywordsWordListFromTypeInfo(scMessages, TypeInfo(TSetupMessageID), SetupMessageIDPrefixLength);
  574. end;
  575. procedure BuildScriptLists;
  576. begin
  577. { Builds FScriptFunctionsByName (for calltips) and FScriptWordList (for autocomplete)
  578. and FNoHighlightAtCursorWords }
  579. const SL1 = FNoHighlightAtCursorWords[scCode];
  580. const SL2 = TStringList.Create;
  581. try
  582. { Add stuff from ScriptFunc }
  583. var ClassMembers := False;
  584. for var ScriptFuncTable in ScriptFuncTables do
  585. BuildScriptFunctionsLists(ScriptFuncTable, ClassMembers, SL2);
  586. BuildScriptFunctionsLists(DelphiScriptFuncTable, ClassMembers, SL2);
  587. BuildScriptFunctionsLists(ROPSScriptFuncTable, ClassMembers, SL2);
  588. { Add stuff from this unit }
  589. for var S in PascalConstants do
  590. AddWordToList(SL2, S, awtScriptConstant);
  591. for var S in PascalConstants_Isxclasses do
  592. AddWordToList(SL2, S, awtScriptConstant);
  593. for var S in PascalInterfaces do
  594. AddWordToList(SL2, S, awtScriptInterface);
  595. for var S in PascalReservedWords do begin
  596. SL1.Add(String(S));
  597. AddWordToList(SL2, S, awtScriptKeyword);
  598. end;
  599. for var S in PascalTypes do
  600. AddWordToList(SL2, S, awtScriptType);
  601. for var S in PascalTypes_Isxclasses do
  602. AddWordToList(SL2, S, awtScriptType);
  603. for var S in PascalEnumValues do
  604. AddWordToList(SL2, S, awtScriptEnumValue);
  605. for var S in PascalEnumValues_Isxclasses do
  606. AddWordToList(SL2, S, awtScriptEnumValue);
  607. for var TypeInfo in PascalRealEnumValues do begin
  608. var TypeData := GetTypeData(TypeInfo);
  609. for var I := TypeData.MinValue to TypeData.MaxValue do
  610. AddWordToList(SL2, AnsiString(GetEnumName(TypeInfo, I)), awtScriptEnumValue);
  611. end;
  612. for var S in PascalVariables do
  613. AddWordToList(SL2, S, awtScriptVariable);
  614. for var S in EventFunctionsParameters do
  615. AddWordToList(SL2, S, awtScriptVariable);
  616. FScriptWordList[False] := BuildWordList(SL2);
  617. { Add stuff from Isxclasses }
  618. SL2.Clear;
  619. ClassMembers := True;
  620. BuildScriptFunctionsLists(PascalMembers_Isxclasses, ClassMembers, SL2);
  621. for var S in PascalProperties_Isxclasses do
  622. AddWordToList(SL2, S, awtScriptProperty);
  623. FScriptWordList[True] := BuildWordList(SL2);
  624. finally
  625. SL2.Free;
  626. end;
  627. end;
  628. function CreateWordsBySectionList: TStringList;
  629. begin
  630. Result := TStringList.Create;
  631. Result.CaseSensitive := False;
  632. Result.Sorted := True;
  633. end;
  634. begin
  635. inherited;
  636. FNoHighlightAtCursorWords := TWordsBySection.Create([doOwnsValues]);
  637. FFlagsWords := TWordsBySection.Create([doOwnsValues]);
  638. for var Section := Low(TInnoSetupStylerSection) to High(TInnoSetupStylerSection) do begin
  639. FNoHighlightAtCursorWords.Add(Section, CreateWordsBySectionList);
  640. FFlagsWords.Add(Section, CreateWordsBySectionList);
  641. end;
  642. BuildConstantsWordList;
  643. BuildEventFunctionsWordList;
  644. BuildFlagsWordLists;
  645. BuildISPPDirectivesWordList;
  646. BuildKeywordsWordLists;
  647. BuildSectionsWordList;
  648. FScriptFunctionsByName[False] := TFunctionDefinitionsByName.Create(TIStringComparer.Ordinal);
  649. FScriptFunctionsByName[True] := TFunctionDefinitionsByName.Create(TIStringComparer.Ordinal);
  650. BuildScriptLists;
  651. end;
  652. destructor TInnoSetupStyler.Destroy;
  653. begin
  654. FScriptFunctionsByName[False].Free;
  655. FScriptFunctionsByName[True].Free;
  656. FFlagsWords.Free;
  657. FNoHighlightAtCursorWords.Free;
  658. inherited;
  659. end;
  660. procedure TInnoSetupStyler.AddWordToList(const SL: TStringList;
  661. const Word: AnsiString; const Typ: Integer);
  662. begin
  663. if Typ >= 0 then
  664. SL.Add(Format('%s%s%d', [Word, InnoSetupStylerWordListTypeSeparator, Typ]))
  665. else
  666. SL.Add(String(Word));
  667. end;
  668. procedure TInnoSetupStyler.ApplyPendingSquigglyFromToIndex(const StartIndex, EndIndex: Integer);
  669. begin
  670. if (CaretIndex >= StartIndex) and (CaretIndex <= EndIndex + 1) then
  671. ApplyStyleByteIndicators([inPendingSquiggly], StartIndex, EndIndex)
  672. else
  673. ApplyStyleByteIndicators([inSquiggly], StartIndex, EndIndex);
  674. end;
  675. procedure TInnoSetupStyler.ApplyPendingSquigglyFromIndex(const StartIndex: Integer);
  676. begin
  677. ApplyPendingSquigglyFromToIndex(StartIndex, CurIndex - 1);
  678. end;
  679. procedure TInnoSetupStyler.ApplySquigglyFromIndex(const StartIndex: Integer);
  680. begin
  681. ApplyStyleByteIndicators([inSquiggly], StartIndex, CurIndex - 1);
  682. end;
  683. function TInnoSetupStyler.BuildWordList(const WordStringList: TStringList): AnsiString;
  684. begin
  685. { Scintilla uses an ASCII binary search so the list must be in ASCII sort
  686. order (case-insensitive). }
  687. WordStringList.CaseSensitive := False;
  688. WordStringList.UseLocale := False; { Make sure it uses CompareText and not AnsiCompareText }
  689. WordStringList.Sort;
  690. Result := '';
  691. for var S in WordStringList do begin
  692. var A := AnsiString(S);
  693. if Result = '' then
  694. Result := A
  695. else
  696. Result := Result + InnoSetupStylerWordListSeparator + A;
  697. end;
  698. end;
  699. procedure TInnoSetupStyler.BuildSectionsWordList;
  700. begin
  701. var SL := TStringList.Create;
  702. try
  703. for var Section in SectionMap do
  704. AddWordToList(SL, '[' + Section.Name + ']', awtSection);
  705. FSectionsWordList := BuildWordList(SL);
  706. finally
  707. SL.Free;
  708. end;
  709. end;
  710. procedure TInnoSetupStyler.BuildKeywordsWordList(
  711. const Section: TInnoSetupStylerSection;
  712. const Parameters: array of TScintRawString);
  713. begin
  714. const SL1 = FNoHighlightAtCursorWords[Section];
  715. const SL2 = TStringList.Create;
  716. try
  717. for var Parameter in Parameters do begin
  718. SL1.Add(String(Parameter));
  719. AddWordToList(SL2, Parameter, awtParameter);
  720. end;
  721. FKeywordsWordList[Section] := BuildWordList(SL2);
  722. finally
  723. SL2.Free;
  724. end;
  725. end;
  726. procedure TInnoSetupStyler.BuildKeywordsWordListFromTypeInfo(
  727. const Section: TInnoSetupStylerSection; const EnumTypeInfo: Pointer;
  728. const PrefixLength: Integer);
  729. begin
  730. const SL1 = FNoHighlightAtCursorWords[Section];
  731. const SL2 = TStringList.Create;
  732. try
  733. for var I := 0 to GetTypeData(EnumTypeInfo).MaxValue do begin
  734. const Parameter = Copy(GetEnumName(EnumTypeInfo, I), PrefixLength+1, MaxInt);
  735. SL1.Add(Parameter);
  736. AddWordToList(SL2, AnsiString(Parameter), awtDirective);
  737. end;
  738. FKeywordsWordList[Section] := BuildWordList(SL2);
  739. finally
  740. SL2.Free;
  741. end;
  742. end;
  743. procedure TInnoSetupStyler.BuildFlagsWordList(const Section: TInnoSetupStylerSection;
  744. const Flags: array of TScintRawString);
  745. begin
  746. const SL1 = FFlagsWords[Section];
  747. const SL2 = TStringList.Create;
  748. try
  749. for var Flag in Flags do begin
  750. SL1.Add(String(Flag));
  751. AddWordToList(SL2, Flag, awtFlag);
  752. end;
  753. FFlagsWordList[Section] := BuildWordList(SL2);
  754. finally
  755. SL2.Free;
  756. end;
  757. end;
  758. procedure TInnoSetupStyler.BuildScriptFunctionsLists(
  759. const ScriptFuncTable: TScriptTable; const ClassMembers: Boolean;
  760. const SL: TStringList);
  761. begin
  762. for var ScriptFunc in ScriptFuncTable do begin
  763. var FunctionDefinition := TFunctionDefinition.Create(ScriptFunc);
  764. var ScriptFuncName := ExtractScriptFuncWithoutHeaderName(FunctionDefinition.ScriptFuncWithoutHeader);
  765. var DoAddWordToList := True;
  766. var Key := String(ScriptFuncName);
  767. if not FScriptFunctionsByName[ClassMembers].TryAdd(Key, [FunctionDefinition]) then begin
  768. { Function has multiple prototypes }
  769. var ScriptFunctions := FScriptFunctionsByName[ClassMembers][Key];
  770. var N := Length(ScriptFunctions);
  771. SetLength(ScriptFunctions, N+1);
  772. ScriptFunctions[N] := FunctionDefinition;
  773. FScriptFunctionsByName[ClassMembers][Key] := ScriptFunctions;
  774. DoAddWordToList := False; { Already added it when the first prototype was found }
  775. end;
  776. if DoAddWordToList then
  777. AddWordToList(SL, ScriptFuncName, awtScriptFunction);
  778. end;
  779. end;
  780. procedure TInnoSetupStyler.BuildISPPDirectivesWordList;
  781. begin
  782. var SL := TStringList.Create;
  783. try
  784. for var ISPPDirective in ISPPDirectives do
  785. AddWordToList(SL, '#' + ISPPDirective.Name, awtPreprocessorDirective);
  786. FISPPDirectivesWordList := BuildWordList(SL);
  787. finally
  788. SL.Free;
  789. end;
  790. end;
  791. procedure TInnoSetupStyler.BuildConstantsWordList;
  792. begin
  793. var SL := TStringList.Create;
  794. try
  795. for var Constant in Constants do
  796. AddWordToList(SL, '{' + Constant + '}', awtConstant);
  797. if ISPPInstalled then begin
  798. AddWordToList(SL, '{#', awtConstant);
  799. AddWordToList(SL, '{#file ', awtConstant);
  800. for var ISPPPredefinedVariable in ISPPPredefinedVariables do
  801. AddWordToList(SL, '{#' + ISPPPredefinedVariable + '}', awtConstant);
  802. end;
  803. for var ConstantWithParam in ConstantsWithParam do
  804. AddWordToList(SL, '{' + ConstantWithParam, awtConstant);
  805. FConstantsWordList := BuildWordList(SL);
  806. finally
  807. SL.Free;
  808. end;
  809. end;
  810. procedure TInnoSetupStyler.BuildEventFunctionsWordList;
  811. begin
  812. var SLFunctions: TStringList := nil;
  813. var SLProcedures: TStringList := nil;
  814. try
  815. SLFunctions := TStringList.Create;
  816. SLProcedures := TStringList.Create;
  817. for var FullEventFunction in FullEventFunctions do begin
  818. var WasFunction: Boolean;
  819. var S := RemoveScriptFuncHeader(FullEventFunction, WasFunction);
  820. if WasFunction then
  821. AddWordToList(SLFunctions, S, awtScriptEvent)
  822. else
  823. AddWordToList(SLProcedures, S, awtScriptEvent);
  824. end;
  825. FEventFunctionsWordList[False] := BuildWordList(SLFunctions);
  826. FEventFunctionsWordList[True] := BuildWordList(SLProcedures);
  827. finally
  828. SLProcedures.Free;
  829. SLFunctions.Free;
  830. end;
  831. end;
  832. procedure TInnoSetupStyler.CommitStyle(const Style: TInnoSetupStylerStyle);
  833. begin
  834. inherited CommitStyle(Ord(Style));
  835. end;
  836. procedure TInnoSetupStyler.CommitStyleSq(const Style: TInnoSetupStylerStyle;
  837. const Squigglify: Boolean);
  838. begin
  839. if Squigglify then
  840. ApplySquigglyFromIndex(StyleStartIndex);
  841. CommitStyle(Style);
  842. end;
  843. procedure TInnoSetupStyler.CommitStyleSqPending(const Style: TInnoSetupStylerStyle);
  844. begin
  845. ApplyPendingSquigglyFromIndex(StyleStartIndex);
  846. CommitStyle(Style);
  847. end;
  848. function TInnoSetupStyler.GetEventFunctionsWordList(Procedures: Boolean): AnsiString;
  849. begin
  850. Result := FEventFunctionsWordList[Procedures];
  851. end;
  852. function TInnoSetupStyler.GetFlagsWordList(Section: TInnoSetupStylerSection): AnsiString;
  853. begin
  854. Result := FFlagsWordList[Section];
  855. end;
  856. procedure TInnoSetupStyler.GetFoldLevel(const LineState, PreviousLineState: TScintLineState;
  857. var Level: Integer; var Header, EnableHeaderOnPrevious: Boolean);
  858. begin
  859. { Set folding per section. Lines outside of a section (=lines at the start of
  860. the document and section tags and section end tags and lines after section
  861. end tags) get level 0 with header flags for section tags. Other lines
  862. (=lines inside a section) get level 1. }
  863. var Section := TInnoSetupStyler.GetSectionFromLineState(LineState);
  864. if Section = scNone then begin
  865. Level := 0;
  866. Header := False; { Might be set to True via EnableHeaderOnPrevious below when we know about next line }
  867. EnableHeaderOnPrevious := False;
  868. end else begin
  869. Level := 1;
  870. Header := False;
  871. var PreviousSection := TInnoSetupStyler.GetSectionFromLineState(PreviousLineState);
  872. EnableHeaderOnPrevious := PreviousSection = scNone;
  873. end;
  874. end;
  875. function TInnoSetupStyler.GetKeywordsWordList(Section: TInnoSetupStylerSection): AnsiString;
  876. begin
  877. Result := FKeywordsWordList[Section];
  878. end;
  879. function TInnoSetupStyler.GetScriptFunctionDefinition(const ClassMember: Boolean;
  880. const Name: String; const Index: Integer; out Count: Integer): TFunctionDefinition;
  881. begin
  882. var ScriptFunctions: TFunctionDefinitions;
  883. if FScriptFunctionsByName[ClassMember].TryGetValue(Name, ScriptFunctions) then begin
  884. Count := Length(ScriptFunctions);
  885. var ResultIndex := Index;
  886. if ResultIndex >= Count then
  887. ResultIndex := Count-1;
  888. Result := ScriptFunctions[ResultIndex]
  889. end else
  890. Count := 0;
  891. end;
  892. function TInnoSetupStyler.GetScriptFunctionDefinition(
  893. const ClassMember: Boolean; const Name: String;
  894. const Index: Integer): TFunctionDefinition;
  895. begin
  896. var Count: Integer;
  897. Result := GetScriptFunctionDefinition(ClassMember, Name, Index, Count);
  898. end;
  899. function TInnoSetupStyler.GetScriptWordList(
  900. ClassOrRecordMembers: Boolean): AnsiString;
  901. begin
  902. Result := FScriptWordList[ClassOrRecordMembers];
  903. end;
  904. class function TInnoSetupStyler.GetSectionFromLineState(
  905. const LineState: TScintLineState): TInnoSetupStylerSection;
  906. begin
  907. Result := TInnoSetupStylerLineState(LineState).Section;
  908. end;
  909. procedure TInnoSetupStyler.GetStyleAttributes(const Style: Integer;
  910. var Attributes: TScintStyleAttributes);
  911. begin
  912. if FTheme <> nil then begin
  913. if (Style >= 0) and (Style <= Ord(High(TInnoSetupStylerStyle))) then begin
  914. if not FTheme.Modern then begin
  915. { Check for some exceptions }
  916. case TInnoSetupStylerStyle(Style) of
  917. stCompilerDirective, stISPPReservedWord: begin Attributes.ForeColor := $4040C0; Exit; end;
  918. stMessageArg: begin Attributes.ForeColor := $FF8000; Exit; end;
  919. stPascalString, stPascalNumber, stISPPString, stISPPNumber: begin Attributes.ForeColor := clMaroon; Exit; end;
  920. end;
  921. end;
  922. case TInnoSetupStylerStyle(Style) of
  923. stCompilerDirective, stISPPReservedWord: Attributes.ForeColor := FTheme.Colors[tcRed];
  924. stComment: Attributes.ForeColor := FTheme.Colors[tcGreen];
  925. stSection: Attributes.FontStyle := [fsBold];
  926. stSymbol: Attributes.ForeColor := FTheme.Colors[tcGray];
  927. stKeyword, stPascalReservedWord: Attributes.ForeColor := FTheme.Colors[tcBlue];
  928. //stParameterValue: Attributes.ForeColor := FTheme.Colors[tcTeal];
  929. stEventFunction: Attributes.FontStyle := [fsBold];
  930. stConstant: Attributes.ForeColor := FTheme.Colors[tcPurple];
  931. stMessageArg: Attributes.ForeColor := FTheme.Colors[tcRed];
  932. stPascalString, stPascalNumber, stISPPString, stISPPNumber: Attributes.ForeColor := FTheme.Colors[tcOrange];
  933. end;
  934. end else begin
  935. case Style of
  936. STYLE_LINENUMBER: { Also sets the background colour for the margin with the markers like mmIconBreakpoint }
  937. begin
  938. Attributes.ForeColor := FTheme.Colors[tcMarginFore];
  939. Attributes.BackColor := FTheme.Colors[tcMarginBack];
  940. end;
  941. STYLE_BRACEBAD: Attributes.ForeColor := FTheme.Colors[tcRed];
  942. STYLE_BRACELIGHT: Attributes.BackColor := FTheme.Colors[tcBraceBack];
  943. STYLE_INDENTGUIDE: Attributes.ForeColor := FTheme.Colors[tcIndentGuideFore];
  944. end;
  945. end;
  946. end;
  947. end;
  948. procedure TInnoSetupStyler.HandleCodeSection(var SpanState: TInnoSetupStylerSpanState);
  949. function FinishConsumingBraceComment: Boolean;
  950. begin
  951. ConsumeCharsNot(['}']);
  952. Result := ConsumeChar('}');
  953. CommitStyle(stComment);
  954. end;
  955. function FinishConsumingStarComment: Boolean;
  956. begin
  957. Result := False;
  958. while True do begin
  959. ConsumeCharsNot(['*']);
  960. if not ConsumeChar('*') then
  961. Break;
  962. if ConsumeChar(')') then begin
  963. Result := True;
  964. Break;
  965. end;
  966. end;
  967. CommitStyle(stComment);
  968. end;
  969. begin
  970. case SpanState of
  971. spBraceComment:
  972. if not FinishConsumingBraceComment then
  973. Exit;
  974. spStarComment:
  975. if not FinishConsumingStarComment then
  976. Exit;
  977. end;
  978. SpanState := spNone;
  979. SkipWhitespace;
  980. while not EndOfLine do begin
  981. if CurChar in PascalIdentFirstChars then begin
  982. var S := ConsumeString(PascalIdentChars);
  983. for var Word in PascalReservedWords do
  984. if SameRawText(S, Word) then begin
  985. CommitStyle(stPascalReservedWord);
  986. Break;
  987. end;
  988. for var EventFunction in BasicEventFunctions do
  989. if SameRawText(S, EventFunction) then begin
  990. CommitStyle(stEventFunction);
  991. Break;
  992. end;
  993. CommitStyle(stDefault);
  994. end else if ConsumeChars(DigitChars) then begin
  995. if not CurCharIs('.') or not NextCharIs('.') then begin
  996. if ConsumeChar('.') then
  997. ConsumeChars(DigitChars);
  998. var C := CurChar;
  999. if C in ['E', 'e'] then begin
  1000. ConsumeChar(C);
  1001. if not ConsumeChar('-') then
  1002. ConsumeChar('+');
  1003. if not ConsumeChars(DigitChars) then
  1004. CommitStyleSqPending(stPascalNumber);
  1005. end;
  1006. end;
  1007. CommitStyle(stPascalNumber);
  1008. end else begin
  1009. var C := CurChar;
  1010. ConsumeChar(C);
  1011. case C of
  1012. ';', ':', '=', '+', '-', '*', '/', '<', '>', ',', '(', ')',
  1013. '.', '[', ']', '@', '^':
  1014. begin
  1015. if (C = '/') and ConsumeChar('/') then begin
  1016. ConsumeAllRemaining;
  1017. CommitStyle(stComment);
  1018. end else if (C = '(') and ConsumeChar('*') then begin
  1019. if not FinishConsumingStarComment then begin
  1020. SpanState := spStarComment;
  1021. Exit;
  1022. end;
  1023. end else
  1024. CommitStyle(stSymbol);
  1025. end;
  1026. '''':
  1027. begin
  1028. while True do begin
  1029. ConsumeCharsNot([C]);
  1030. if not ConsumeChar(C) then begin
  1031. CommitStyleSqPending(stPascalString);
  1032. Break;
  1033. end;
  1034. if not ConsumeChar(C) then begin
  1035. CommitStyle(stPascalString);
  1036. Break;
  1037. end;
  1038. end;
  1039. end;
  1040. '{':
  1041. begin
  1042. if not FinishConsumingBraceComment then begin
  1043. SpanState := spBraceComment;
  1044. Exit;
  1045. end;
  1046. end;
  1047. '$':
  1048. begin
  1049. if not ConsumeChars(HexDigitChars) then
  1050. CommitStyleSqPending(stPascalNumber);
  1051. CommitStyle(stPascalNumber);
  1052. end;
  1053. '#':
  1054. begin
  1055. if ConsumeChar('$') then begin
  1056. if not ConsumeChars(HexDigitChars) then
  1057. CommitStyleSqPending(stPascalString);
  1058. end else if not ConsumeChars(DigitChars) then
  1059. CommitStyleSqPending(stPascalString);
  1060. CommitStyle(stPascalString);
  1061. end;
  1062. else
  1063. { Illegal character }
  1064. CommitStyleSq(stSymbol, True);
  1065. end;
  1066. end;
  1067. SkipWhitespace;
  1068. end;
  1069. end;
  1070. procedure TInnoSetupStyler.HandleCompilerDirective(const InlineDirective: Boolean; const InlineDirectiveEndIndex: Integer; var OpenCount: ShortInt);
  1071. function EndOfDirective: Boolean;
  1072. begin
  1073. Result := EndOfLine or (InlineDirective and (CurIndex > InlineDirectiveEndIndex));
  1074. end;
  1075. procedure FinishDirectiveNameOrShorthand(const RequiresParameter: Boolean);
  1076. begin
  1077. if RequiresParameter then begin
  1078. ConsumeChars(WhitespaceChars); { This will give the whitespace the stCompilerDirective style instead of stDefault but that's ok }
  1079. if EndOfDirective then
  1080. CommitStyleSqPending(stCompilerDirective)
  1081. else
  1082. CommitStyle(stCompilerDirective);
  1083. end else
  1084. CommitStyle(stCompilerDirective);
  1085. end;
  1086. function FinishConsumingStarComment: Boolean;
  1087. begin
  1088. Result := False;
  1089. while True do begin
  1090. ConsumeCharsNot(['*']);
  1091. if not ConsumeChar('*') then
  1092. Break;
  1093. if ConsumeChar('/') then begin
  1094. Result := True;
  1095. Break;
  1096. end;
  1097. end;
  1098. if Result then
  1099. CommitStyle(stComment)
  1100. else
  1101. CommitStyleSqPending(stComment);
  1102. end;
  1103. procedure ConsumeISPPString(const Terminator: AnsiChar; const AllowEscapedTerminator: Boolean);
  1104. begin
  1105. while True do begin
  1106. ConsumeCharsNot([Terminator]);
  1107. if not ConsumeChar(Terminator) then begin
  1108. { Non terminated string found }
  1109. CommitStyleSqPending(stISPPString);
  1110. Break;
  1111. end;
  1112. { Terminated string found and consumed. Now check if the terminator is actually escaped by doubling, if allowed }
  1113. if not AllowEscapedTerminator or not ConsumeChar(Terminator) then begin
  1114. { Doubling not allowed or no double terminator found, so we're done }
  1115. CommitStyle(stISPPString);
  1116. Break;
  1117. end;
  1118. { The terminator was doubled so we should continue to find the real terminator }
  1119. end;
  1120. end;
  1121. const
  1122. ISPPReservedWords: array[0..16] of TScintRawString = (
  1123. 'private', 'protected', 'public', 'any', 'int',
  1124. 'str', 'func', 'option', 'parseroption', 'inlinestart',
  1125. 'inlineend', 'message', 'warning', 'error',
  1126. 'verboselevel', 'include', 'spansymbol');
  1127. ISPPDirectiveShorthands: TScintRawCharSet =
  1128. [':' {define},
  1129. 'x' {undef},
  1130. '+' {include},
  1131. '=' {emit},
  1132. '!' {expr}];
  1133. begin
  1134. var StartIndex := CurIndex;
  1135. var NeedIspp: Boolean;
  1136. if InlineDirective then begin
  1137. ConsumeChar('{');
  1138. NeedIspp := True;
  1139. end else
  1140. NeedIspp := False; { Might be updated later to True later }
  1141. var ForDirectiveExpressionsNext := False;
  1142. var DoIncludeFileNotationCheck := False;
  1143. var ErrorDirective := False;
  1144. ConsumeChar('#');
  1145. CommitStyle(stCompilerDirective);
  1146. { Directive name or shorthand }
  1147. SkipWhiteSpace;
  1148. var C := CurChar;
  1149. if ConsumeCharIn(ISPPDirectiveShorthands) then begin
  1150. DoIncludeFileNotationCheck := C = '+'; { We need to check the include file notation }
  1151. NeedIspp := True;
  1152. FinishDirectiveNameOrShorthand(True); { All shorthands require a parameter }
  1153. end else begin
  1154. var S := ConsumeString(ISPPIdentChars);
  1155. for var ISPPDirective in ISPPDirectives do
  1156. if SameRawText(S, ISPPDirective.Name) then begin
  1157. if SameRawText(S, 'error') then
  1158. ErrorDirective := True
  1159. else if SameRawText(S, 'include') then
  1160. DoIncludeFileNotationCheck := True { See above }
  1161. else
  1162. NeedIspp := True; { Built-in preprocessor only supports '#include' }
  1163. ForDirectiveExpressionsNext := SameRawText(S, 'for'); { #for uses ';' as an expressions list separator so we need to remember that ';' doesn't start a comment until the list is done }
  1164. Inc(OpenCount, ISPPDirective.OpenCountChange);
  1165. if OpenCount < 0 then begin
  1166. CommitStyleSq(stCompilerDirective, True);
  1167. OpenCount := 0; { Reset so that next doesn't automatically gets error as well }
  1168. end;
  1169. FinishDirectiveNameOrShorthand(ISPPDirective.RequiresParameter);
  1170. Break;
  1171. end;
  1172. if InlineDirective then
  1173. CommitStyle(stDefault) { #emit shorthand was used (='#' directly followed by an expression): not an error }
  1174. else
  1175. CommitStyleSqPending(stCompilerDirective);
  1176. end;
  1177. { Rest of the directive }
  1178. if ErrorDirective then begin
  1179. SkipWhitespace;
  1180. while not EndOfDirective do begin
  1181. C := CurChar;
  1182. ConsumeChar(C);
  1183. if InlineDirective and (C = '}') then
  1184. CommitStyle(stCompilerDirective)
  1185. else
  1186. CommitStyle(stISPPString);
  1187. end;
  1188. end else begin
  1189. SkipWhitespace;
  1190. while not EndOfDirective do begin
  1191. if DoIncludeFileNotationCheck then begin
  1192. if CurChar <> '"' then begin
  1193. NeedIspp := True; { Built-in preprocessor requires a '"' quoted string after the '#include' and doesn't support anything else }
  1194. if CurChar = '<' then { Check for ISPP's special bracket notation for include files }
  1195. ConsumeISPPString('>', False); { Consume now instead of using regular consumption }
  1196. end;
  1197. DoIncludeFileNotationCheck := False;
  1198. end;
  1199. if CurChar in ISPPIdentFirstChars then begin
  1200. var S := ConsumeString(ISPPIdentChars);
  1201. for var ISPPReservedWord in ISPPReservedWords do
  1202. if SameRawText(S, ISPPReservedWord) then begin
  1203. CommitStyle(stISPPReservedWord);
  1204. Break;
  1205. end;
  1206. CommitStyle(stDefault)
  1207. end else if ConsumeChars(DigitChars) then begin
  1208. if not CurCharIs('.') or not NextCharIs('.') then begin
  1209. if ConsumeChar('.') then
  1210. ConsumeChars(DigitChars);
  1211. C := CurChar;
  1212. if C in ['X', 'x'] then begin
  1213. ConsumeChar(C);
  1214. if not ConsumeChars(HexDigitChars) then
  1215. CommitStyleSqPending(stISPPNumber);
  1216. end;
  1217. ConsumeChars(['L', 'U', 'l', 'u']);
  1218. end;
  1219. CommitStyle(stISPPNumber);
  1220. end else begin
  1221. C := CurChar;
  1222. ConsumeChar(C);
  1223. case C of
  1224. '!', '&', '=', '|', '^', '>', '<', '+', '-', '/', '%', '*',
  1225. '?', ':', ',', '.', '~', '(', '[', '{', ')', ']', '}', '@',
  1226. '#':
  1227. begin
  1228. if (C = '}') and ForDirectiveExpressionsNext then
  1229. ForDirectiveExpressionsNext := False;
  1230. if (C = '/') and ConsumeChar('*') then
  1231. FinishConsumingStarComment
  1232. else if InlineDirective and (C = '}') then
  1233. CommitStyle(stCompilerDirective) (* Closing '}' of the ISPP inline directive *)
  1234. else
  1235. CommitStyle(stSymbol);
  1236. end;
  1237. ';':
  1238. begin
  1239. if ForDirectiveExpressionsNext then
  1240. CommitStyle(stSymbol)
  1241. else begin
  1242. if not InlineDirective then
  1243. ConsumeAllRemaining
  1244. else
  1245. ConsumeCharsNot(['}']);
  1246. CommitStyle(stComment);
  1247. end;
  1248. end;
  1249. '''', '"':
  1250. ConsumeISPPString(C, True);
  1251. else
  1252. { Illegal character }
  1253. CommitStyleSq(stSymbol, True);
  1254. end;
  1255. end;
  1256. SkipWhitespace;
  1257. end;
  1258. end;
  1259. if NeedIspp and not ISPPInstalled then begin
  1260. if InlineDirective then
  1261. ApplyPendingSquigglyFromToIndex(StartIndex + 1, InlineDirectiveEndIndex - 1)
  1262. else
  1263. ApplyPendingSquigglyFromIndex(StartIndex + 1);
  1264. end;
  1265. end;
  1266. procedure TInnoSetupStyler.HandleParameterSection(
  1267. const ValidParameters: array of TScintRawString);
  1268. var
  1269. ParamsSpecified: set of 0..31;
  1270. S: TScintRawString;
  1271. I, ParamValueIndex, BraceLevel: Integer;
  1272. NamePresent, ValidName, DuplicateName, ColonPresent: Boolean;
  1273. begin
  1274. ParamsSpecified := [];
  1275. while not EndOfLine do begin
  1276. { Squigglify any bogus characters before the parameter name }
  1277. SquigglifyUntilChars(AlphaChars + [':'], stDefault);
  1278. { Parameter name }
  1279. S := ConsumeString(AlphaDigitChars);
  1280. NamePresent := (S <> '');
  1281. ValidName := False;
  1282. DuplicateName := False;
  1283. for I := Low(ValidParameters) to High(ValidParameters) do
  1284. if SameRawText(S, ValidParameters[I]) then begin
  1285. ValidName := True;
  1286. DuplicateName := (I in ParamsSpecified);
  1287. Include(ParamsSpecified, I);
  1288. Break;
  1289. end;
  1290. if DuplicateName then
  1291. CommitStyleSqPending(stKeyword)
  1292. else if ValidName then
  1293. CommitStyle(stKeyword)
  1294. else
  1295. CommitStyleSqPending(stDefault);
  1296. SkipWhitespace;
  1297. { If there's a semicolon with no colon, squigglify the semicolon }
  1298. if ConsumeChar(';') then begin
  1299. CommitStyleSq(stSymbol, True);
  1300. SkipWhitespace;
  1301. Continue;
  1302. end;
  1303. { Colon }
  1304. ColonPresent := ConsumeChar(':');
  1305. CommitStyleSq(stSymbol, not NamePresent);
  1306. SkipWhitespace;
  1307. { Parameter value. This consumes until a ';' is found or EOL is reached. }
  1308. ParamValueIndex := CurIndex;
  1309. BraceLevel := 0;
  1310. if ConsumeChar('"') then begin
  1311. while True do begin
  1312. StyleConstsUntilChars(['"'], stParameterValue, BraceLevel);
  1313. { If no closing quote exists, squigglify the whole value and break }
  1314. if not ConsumeChar('"') then begin
  1315. ApplyPendingSquigglyFromIndex(ParamValueIndex);
  1316. Break;
  1317. end;
  1318. { Quote found, now break, unless there are two quotes in a row }
  1319. if not ConsumeChar('"') then
  1320. Break;
  1321. end;
  1322. end else begin
  1323. while True do begin
  1324. StyleConstsUntilChars([';', '"'], stParameterValue, BraceLevel);
  1325. { Squigglify any quote characters inside an unquoted string }
  1326. if ConsumeChar('"') then
  1327. ApplySquigglyFromIndex(CurIndex - 1)
  1328. else
  1329. Break;
  1330. end;
  1331. end;
  1332. CommitStyle(stParameterValue);
  1333. if not ColonPresent then
  1334. ApplySquigglyFromIndex(ParamValueIndex);
  1335. { Squigglify any characters between a quoted string and the next ';' }
  1336. SquigglifyUntilChars([';'], stDefault);
  1337. { Semicolon }
  1338. ConsumeChar(';');
  1339. CommitStyle(stSymbol);
  1340. SkipWhitespace;
  1341. end;
  1342. end;
  1343. procedure TInnoSetupStyler.HandleKeyValueSection(const Section: TInnoSetupStylerSection);
  1344. procedure StyleMessageArgs;
  1345. begin
  1346. while True do begin
  1347. ConsumeCharsNot(['%']);
  1348. CommitStyle(stDefault);
  1349. if not ConsumeChar('%') then
  1350. Break;
  1351. if CurCharIn(['1'..'9', '%', 'n']) then begin
  1352. ConsumeChar(CurChar);
  1353. CommitStyle(stMessageArg);
  1354. end;
  1355. end;
  1356. end;
  1357. var
  1358. S: String;
  1359. I, BraceLevel: Integer;
  1360. begin
  1361. { Squigglify any bogus characters at the start of the line }
  1362. SquigglifyUntilChars(AlphaUnderscoreChars, stDefault);
  1363. if EndOfLine then
  1364. Exit;
  1365. S := String(ConsumeString(AlphaDigitUnderscoreChars));
  1366. { Was that a language name? }
  1367. if (Section in [scCustomMessages, scLangOptions, scMessages]) and
  1368. CurCharIs('.') then begin
  1369. CommitStyle(stDefault);
  1370. ConsumeChar('.');
  1371. CommitStyle(stSymbol);
  1372. { Squigglify any spaces or bogus characters between the '.' and key name }
  1373. if ConsumeCharsNot(AlphaUnderscoreChars) then
  1374. CommitStyleSq(stDefault, True);
  1375. S := String(ConsumeString(AlphaDigitUnderscoreChars));
  1376. end;
  1377. case Section of
  1378. scCustomMessages:
  1379. I := 0;
  1380. scLangOptions:
  1381. I := GetEnumValue(TypeInfo(TLangOptionsSectionDirective), 'ls' + S);
  1382. scMessages:
  1383. I := GetEnumValue(TypeInfo(TSetupMessageID), 'msg' + S);
  1384. scSetup:
  1385. I := GetEnumValue(TypeInfo(TSetupSectionDirective), 'ss' + S);
  1386. else
  1387. I := -1;
  1388. end;
  1389. if I <> -1 then
  1390. CommitStyle(stKeyword)
  1391. else begin
  1392. if Section in [scLangOptions, scMessages, scSetup] then
  1393. CommitStyleSqPending(stDefault)
  1394. else
  1395. CommitStyle(stDefault);
  1396. end;
  1397. SquigglifyUntilChars(['='], stDefault);
  1398. ConsumeChar('=');
  1399. CommitStyle(stSymbol);
  1400. SkipWhitespace;
  1401. if Section in [scCustomMessages, scMessages] then
  1402. StyleMessageArgs
  1403. else begin
  1404. BraceLevel := 0;
  1405. StyleConstsUntilChars([], stDefault, BraceLevel);
  1406. CommitStyle(stDefault);
  1407. end;
  1408. end;
  1409. class function TInnoSetupStyler.IsCommentOrPascalStringStyle(const Style: TScintStyleNumber): Boolean;
  1410. begin
  1411. Result := Style in [Ord(stComment), Ord(stPascalString)];
  1412. end;
  1413. class function TInnoSetupStyler.IsParamSection(
  1414. const Section: TInnoSetupStylerSection): Boolean;
  1415. begin
  1416. Result := not (Section in [scCustomMessages, scLangOptions, scMessages, scSetup, scCode]);
  1417. end;
  1418. class function TInnoSetupStyler.IsSymbolStyle(const Style: TScintStyleNumber): Boolean;
  1419. begin
  1420. Result := Style = Ord(stSymbol);
  1421. end;
  1422. function TInnoSetupStyler.LineTextSpans(const S: TScintRawString): Boolean;
  1423. var
  1424. I: Integer;
  1425. begin
  1426. { Note: To match ISPP behavior, require length of at least 3 }
  1427. I := Length(S);
  1428. Result := (I > 2) and (S[I] = '\') and (S[I-1] in WhitespaceChars);
  1429. end;
  1430. procedure TInnoSetupStyler.PreStyleInlineISPPDirectives;
  1431. function IsLineCommented: Boolean;
  1432. var
  1433. I: Integer;
  1434. begin
  1435. Result := False;
  1436. for I := 1 to TextLength do begin
  1437. { In ISPP, only ';' and '//' inhibit processing of inline directives }
  1438. if (Text[I] = ';') or
  1439. ((I < TextLength) and (Text[I] = '/') and (Text[I+1] = '/')) then begin
  1440. Result := True;
  1441. Break;
  1442. end;
  1443. if not(Text[I] in WhitespaceChars) then
  1444. Break;
  1445. end;
  1446. end;
  1447. const
  1448. LineEndChars = [#10, #13];
  1449. var
  1450. I, StartIndex: Integer;
  1451. Valid: Boolean;
  1452. Dummy: ShortInt;
  1453. begin
  1454. { Style span symbols, then replace them with spaces to prevent any further
  1455. processing }
  1456. for I := 3 to TextLength do begin
  1457. if ((I = TextLength) or (Text[I+1] in LineEndChars)) and
  1458. (Text[I] = '\') and (Text[I-1] in WhitespaceChars) and
  1459. not(Text[I-2] in LineEndChars) then begin
  1460. ReplaceText(I, I, ' ');
  1461. ApplyStyle(Ord(stSymbol), I, I);
  1462. if not ISPPInstalled then
  1463. ApplyStyleByteIndicators([inSquiggly], I, I);
  1464. end;
  1465. end;
  1466. { Style all '{#' ISPP inline directives before anything else }
  1467. if not IsLineCommented then begin
  1468. I := 1;
  1469. while I < TextLength do begin
  1470. if (Text[I] = '{') and (Text[I+1] = '#') then begin
  1471. StartIndex := I;
  1472. Valid := False;
  1473. while I <= TextLength do begin
  1474. Inc(I);
  1475. if Text[I-1] = '}' then begin
  1476. Valid := True;
  1477. Break;
  1478. end;
  1479. end;
  1480. ResetCurIndexTo(StartIndex);
  1481. try
  1482. HandleCompilerDirective(True, I - 1, Dummy);
  1483. finally
  1484. ResetCurIndexTo(0);
  1485. end;
  1486. if not Valid then
  1487. ApplyPendingSquigglyFromToIndex(StartIndex, I - 1);
  1488. { Replace the directive with spaces to prevent any further processing }
  1489. ReplaceText(StartIndex, I - 1, ' ');
  1490. end else
  1491. Inc(I);
  1492. end;
  1493. end;
  1494. end;
  1495. function TInnoSetupStyler.SectionHasFlag(const Section: TInnoSetupStylerSection;
  1496. const Flag: String): Boolean;
  1497. begin
  1498. Result := FFlagsWords[Section].IndexOf(Flag) <> -1;
  1499. end;
  1500. function TInnoSetupStyler.HighlightAtCursorAllowed(const Section: TInnoSetupStylerSection;
  1501. const Word: string): Boolean;
  1502. begin
  1503. Result := FNoHighlightAtCursorWords[Section].IndexOf(Word) = -1;
  1504. end;
  1505. procedure TInnoSetupStyler.SetISPPInstalled(const Value: Boolean);
  1506. begin
  1507. if Value <> FISPPInstalled then begin
  1508. FISPPInstalled := Value;
  1509. BuildConstantsWordList;
  1510. end;
  1511. end;
  1512. procedure TInnoSetupStyler.SkipWhitespace;
  1513. begin
  1514. ConsumeChars(WhitespaceChars);
  1515. CommitStyle(stDefault);
  1516. end;
  1517. procedure TInnoSetupStyler.SquigglifyUntilChars(const Chars: TScintRawCharSet;
  1518. const Style: TInnoSetupStylerStyle);
  1519. var
  1520. IsWhitespace: Boolean;
  1521. begin
  1522. { Consume and squigglify all non-whitespace characters until one of Chars
  1523. is encountered }
  1524. while not EndOfLine and not CurCharIn(Chars) do begin
  1525. IsWhitespace := CurCharIn(WhitespaceChars);
  1526. ConsumeChar(CurChar);
  1527. if IsWhitespace then
  1528. CommitStyle(stDefault)
  1529. else
  1530. CommitStyleSq(Style, True);
  1531. end;
  1532. CommitStyle(stDefault);
  1533. end;
  1534. procedure TInnoSetupStyler.StyleConstsUntilChars(const Chars: TScintRawCharSet;
  1535. const NonConstStyle: TInnoSetupStylerStyle; var BraceLevel: Integer);
  1536. var
  1537. C: AnsiChar;
  1538. begin
  1539. while not EndOfLine and not CurCharIn(Chars) do begin
  1540. if BraceLevel = 0 then
  1541. CommitStyle(NonConstStyle);
  1542. C := CurChar;
  1543. ConsumeChar(C);
  1544. if C = '{' then begin
  1545. if not ConsumeChar('{') then
  1546. Inc(BraceLevel);
  1547. end;
  1548. if (C = '}') and (BraceLevel > 0) then begin
  1549. Dec(BraceLevel);
  1550. if BraceLevel = 0 then
  1551. CommitStyle(stConstant);
  1552. end;
  1553. end;
  1554. end;
  1555. procedure TInnoSetupStyler.StyleNeeded;
  1556. function MapSectionNameString(const S: TScintRawString): TInnoSetupStylerSection;
  1557. begin
  1558. if (S <> '') and (S[1] = '_') then
  1559. Result := scThirdParty
  1560. else begin
  1561. Result := scUnknown;
  1562. for var Section in SectionMap do
  1563. if SameRawText(S, Section.Name) then begin
  1564. Result := Section.Section;
  1565. Break;
  1566. end;
  1567. end;
  1568. end;
  1569. var
  1570. NewLineState: TInnoSetupStylerLineState;
  1571. Section, NewSection: TInnoSetupStylerSection;
  1572. SectionEnd: Boolean;
  1573. S: TScintRawString;
  1574. begin
  1575. NewLineState := TInnoSetupStylerLineState(LineState);
  1576. if NewLineState.NextLineSection <> scNone then begin
  1577. { Previous line started a section }
  1578. NewLineState.Section := NewLineState.NextLineSection;
  1579. NewLineState.NextLineSection := scNone;
  1580. end;
  1581. Section := NewLineState.Section;
  1582. PreStyleInlineISPPDirectives;
  1583. SkipWhitespace;
  1584. if (Section <> scCode) and ConsumeChar(';') then begin
  1585. ConsumeAllRemaining;
  1586. CommitStyle(stComment);
  1587. end else if CurCharIs('/') and NextCharIs('/') then begin
  1588. ConsumeAllRemaining;
  1589. CommitStyleSq(stComment, not ISPPInstalled and (Section <> scCode))
  1590. end else if ConsumeChar('[') then begin
  1591. SectionEnd := ConsumeChar('/');
  1592. S := ConsumeString(AlphaUnderscoreChars);
  1593. if ConsumeChar(']') then begin
  1594. NewSection := MapSectionNameString(S);
  1595. { Unknown section names and erroneously-placed end tags get squigglified }
  1596. CommitStyleSq(stSection, (NewSection = scUnknown) or
  1597. (SectionEnd and (NewSection <> Section)));
  1598. if not SectionEnd then
  1599. NewLineState.NextLineSection := NewSection;
  1600. end else
  1601. CommitStyleSqPending(stDefault);
  1602. { Section tags themselves are not associated with any section }
  1603. Section := scNone;
  1604. SquigglifyUntilChars([], stDefault);
  1605. end else if CurCharIs('#') then
  1606. HandleCompilerDirective(False, -1, NewLineState.OpenCompilerDirectivesCount)
  1607. else begin
  1608. case Section of
  1609. scUnknown: ;
  1610. scThirdParty: ;
  1611. scCode: HandleCodeSection(NewLineState.SpanState);
  1612. scComponents: HandleParameterSection(ComponentsSectionParameters);
  1613. scCustomMessages: HandleKeyValueSection(Section);
  1614. scDirs: HandleParameterSection(DirsSectionParameters);
  1615. scISSigKeys: HandleParameterSection(ISSigKeysSectionParameters);
  1616. scFiles: HandleParameterSection(FilesSectionParameters);
  1617. scIcons: HandleParameterSection(IconsSectionParameters);
  1618. scINI: HandleParameterSection(INISectionParameters);
  1619. scInstallDelete: HandleParameterSection(DeleteSectionParameters);
  1620. scLangOptions: HandleKeyValueSection(Section);
  1621. scLanguages: HandleParameterSection(LanguagesSectionParameters);
  1622. scMessages: HandleKeyValueSection(Section);
  1623. scRegistry: HandleParameterSection(RegistrySectionParameters);
  1624. scRun: HandleParameterSection(RunSectionParameters);
  1625. scSetup: HandleKeyValueSection(Section);
  1626. scTasks: HandleParameterSection(TasksSectionParameters);
  1627. scTypes: HandleParameterSection(TypesSectionParameters);
  1628. scUninstallDelete: HandleParameterSection(DeleteSectionParameters);
  1629. scUninstallRun: HandleParameterSection(UninstallRunSectionParameters);
  1630. end;
  1631. end;
  1632. NewLineState.Section := Section;
  1633. LineState := TScintLineState(NewLineState);
  1634. end;
  1635. initialization
  1636. SetLength(PascalRealEnumValues, 6);
  1637. PascalRealEnumValues[0] := TypeInfo(TMsgBoxType);
  1638. PascalRealEnumValues[1] := TypeInfo(TSetupMessageID);
  1639. PascalRealEnumValues[2] := TypeInfo(TSetupStep);
  1640. PascalRealEnumValues[3] := TypeInfo(TUninstallStep);
  1641. PascalRealEnumValues[4] := TypeInfo(TSetupProcessorArchitecture);
  1642. PascalRealEnumValues[5] := TypeInfo(TDotNetVersion);
  1643. end.