1785 lines
68 KiB
ObjectPascal
1785 lines
68 KiB
ObjectPascal
unit IDE.ScintStylerInnoSetup;
|
|
|
|
{
|
|
Inno Setup
|
|
Copyright (C) 1997-2025 Jordan Russell
|
|
Portions by Martijn Laan
|
|
For conditions of distribution and use, see LICENSE.TXT.
|
|
|
|
TInnoSetupStyler: styler for Inno Setup scripts
|
|
}
|
|
|
|
interface
|
|
|
|
uses
|
|
SysUtils, Classes, Graphics, Generics.Collections, TypInfo,
|
|
ScintEdit, ModernColors, Shared.ScriptFunc;
|
|
|
|
const
|
|
InnoSetupStylerWordListSeparator = #9;
|
|
InnoSetupStylerWordListTypeSeparator = '!'; { Must sort before numbers - so the default '?' is not ok }
|
|
|
|
{ AutoComplete word types }
|
|
awtSection = 0;
|
|
awtParameter = 1;
|
|
awtDirective = 2;
|
|
awtFlag = 3;
|
|
awtPreprocessorDirective = 4;
|
|
awtConstant = 5;
|
|
awtScriptFunction = 10;
|
|
awtScriptType = 11;
|
|
awtScriptVariable = 12;
|
|
awtScriptConstant = 13;
|
|
awtScriptInterface = 14;
|
|
awtScriptProperty = 15;
|
|
awtScriptEvent = 16;
|
|
awtScriptKeyword = 17;
|
|
awtScriptEnumValue = 18;
|
|
|
|
type
|
|
TInnoSetupStylerSection = (
|
|
scNone, { Not inside a section (start of file, or previous section was closed )
|
|
Section tags themselves are not associated with any section! }
|
|
scUnknown, { Inside an unrecognized section }
|
|
scThirdParty, { Inside a '_' section (reserved for third-party tools) }
|
|
scCode,
|
|
scComponents,
|
|
scCustomMessages,
|
|
scDirs,
|
|
scISSigKeys,
|
|
scFiles,
|
|
scIcons,
|
|
scINI,
|
|
scInstallDelete,
|
|
scLangOptions,
|
|
scLanguages,
|
|
scMessages,
|
|
scRegistry,
|
|
scRun,
|
|
scSetup,
|
|
scTasks,
|
|
scTypes,
|
|
scUninstallDelete,
|
|
scUninstallRun);
|
|
|
|
{ Internally-used types }
|
|
TInnoSetupStylerSpanState = (spNone, spBraceComment, spStarComment);
|
|
|
|
{ Starts at 1 instead of 0 to make sure ApplyStyle doesn't overwrite already applied stDefault
|
|
styles which is needed for PreStyleInlineISPPDirectives to work properly when the inline
|
|
directive is inside a comment or string. This is done by added a dummy 'st0' style. If done by
|
|
using 'stDefault = 1' then this enum looses its TypeInfo. }
|
|
TInnoSetupStylerStyle = (st0, stDefault, stCompilerDirective,
|
|
stComment, stSection, stSymbol, stKeyword, stParameterValue,
|
|
stEventFunction, stConstant, stMessageArg,
|
|
stPascalReservedWord, stPascalString, stPascalNumber,
|
|
stISPPReservedWord, stISPPString, stISPPNumber);
|
|
|
|
TWordsBySection = TObjectDictionary<TInnoSetupStylerSection, TStringList>;
|
|
TFunctionDefinition = record
|
|
ScriptFuncWithoutHeader: AnsiString;
|
|
WasFunction, HasParams: Boolean;
|
|
constructor Create(const ScriptFunc: AnsiString);
|
|
end;
|
|
TFunctionDefinitions = array of TFunctionDefinition;
|
|
TFunctionDefinitionsByName = TDictionary<String, TFunctionDefinitions>;
|
|
|
|
TInnoSetupStyler = class(TScintCustomStyler)
|
|
private
|
|
FEventFunctionsWordList: array[Boolean] of AnsiString;
|
|
FKeywordsWordList, FFlagsWordList: array[TInnoSetupStylerSection] of AnsiString;
|
|
FNoHighlightAtCursorWords: TWordsBySection;
|
|
FFlagsWords: TWordsBySection;
|
|
FISPPDirectivesWordList, FConstantsWordList: AnsiString;
|
|
FSectionsWordList: AnsiString;
|
|
FScriptFunctionsByName: array[Boolean] of TFunctionDefinitionsByName; { Only has functions with at least 1 parameter }
|
|
FScriptWordList: array[Boolean] of AnsiString;
|
|
FISPPInstalled: Boolean;
|
|
FTheme: TTheme;
|
|
procedure AddWordToList(const SL: TStringList; const Word: AnsiString;
|
|
const Typ: Integer);
|
|
procedure ApplyPendingSquigglyFromToIndex(const StartIndex, EndIndex: Integer);
|
|
procedure ApplyPendingSquigglyFromIndex(const StartIndex: Integer);
|
|
procedure ApplySquigglyFromIndex(const StartIndex: Integer);
|
|
procedure BuildConstantsWordList;
|
|
procedure BuildEventFunctionsWordList;
|
|
procedure BuildFlagsWordList(const Section: TInnoSetupStylerSection;
|
|
const Flags: array of TScintRawString);
|
|
procedure BuildISPPDirectivesWordList;
|
|
procedure BuildKeywordsWordList(const Section: TInnoSetupStylerSection;
|
|
const Parameters: array of TScintRawString);
|
|
procedure BuildKeywordsWordListFromTypeInfo(const Section: TInnoSetupStylerSection;
|
|
const EnumTypeInfo: Pointer; const PrefixLength: Integer);
|
|
procedure BuildScriptFunctionsLists(const ScriptFuncTable: TScriptTable;
|
|
const ClassMembers: Boolean; const SL: TStringList);
|
|
function BuildWordList(const WordStringList: TStringList): AnsiString;
|
|
procedure BuildSectionsWordList;
|
|
procedure CommitStyleSq(const Style: TInnoSetupStylerStyle;
|
|
const Squigglify: Boolean);
|
|
procedure CommitStyleSqPending(const Style: TInnoSetupStylerStyle);
|
|
function GetEventFunctionsWordList(Procedures: Boolean): AnsiString;
|
|
function GetFlagsWordList(Section: TInnoSetupStylerSection): AnsiString;
|
|
function GetKeywordsWordList(Section: TInnoSetupStylerSection): AnsiString;
|
|
procedure HandleCodeSection(var SpanState: TInnoSetupStylerSpanState);
|
|
procedure HandleKeyValueSection(const Section: TInnoSetupStylerSection);
|
|
procedure HandleParameterSection(const ValidParameters: array of TScintRawString);
|
|
procedure HandleCompilerDirective(const InlineDirective: Boolean;
|
|
const InlineDirectiveEndIndex: Integer; var OpenCount: ShortInt);
|
|
procedure PreStyleInlineISPPDirectives;
|
|
procedure SkipWhitespace;
|
|
procedure SquigglifyUntilChars(const Chars: TScintRawCharSet;
|
|
const Style: TInnoSetupStylerStyle);
|
|
procedure StyleConstsUntilChars(const Chars: TScintRawCharSet;
|
|
const NonConstStyle: TInnoSetupStylerStyle; var BraceLevel: Integer);
|
|
procedure SetISPPInstalled(const Value: Boolean);
|
|
function GetScriptWordList(ClassOrRecordMembers: Boolean): AnsiString;
|
|
protected
|
|
procedure CommitStyle(const Style: TInnoSetupStylerStyle);
|
|
procedure GetFoldLevel(const LineState, PreviousLineState: TScintLineState;
|
|
var Level: Integer; var Header, EnableHeaderOnPrevious: Boolean); override;
|
|
procedure GetStyleAttributes(const Style: Integer;
|
|
var Attributes: TScintStyleAttributes); override;
|
|
function LineTextSpans(const S: TScintRawString): Boolean; override;
|
|
procedure StyleNeeded; override;
|
|
public
|
|
constructor Create(AOwner: TComponent); override;
|
|
destructor Destroy; override;
|
|
class function GetSectionFromLineState(const LineState: TScintLineState): TInnoSetupStylerSection;
|
|
class function IsCommentOrPascalStringStyle(const Style: TScintStyleNumber): Boolean;
|
|
class function IsParamSection(const Section: TInnoSetupStylerSection): Boolean;
|
|
class function IsSymbolStyle(const Style: TScintStyleNumber): Boolean;
|
|
function GetScriptFunctionDefinition(const ClassMember: Boolean;
|
|
const Name: String; const Index: Integer; out Count: Integer): TFunctionDefinition; overload;
|
|
function GetScriptFunctionDefinition(const ClassMember: Boolean;
|
|
const Name: String; const Index: Integer): TFunctionDefinition; overload;
|
|
function SectionHasFlag(const Section: TInnoSetupStylerSection; const Flag: String): Boolean;
|
|
function HighlightAtCursorAllowed(const Section: TInnoSetupStylerSection; const Word: String): Boolean;
|
|
property ConstantsWordList: AnsiString read FConstantsWordList;
|
|
property EventFunctionsWordList[Procedures: Boolean]: AnsiString read GetEventFunctionsWordList;
|
|
property FlagsWordList[Section: TInnoSetupStylerSection]: AnsiString read GetFlagsWordList;
|
|
property ISPPDirectivesWordList: AnsiString read FISPPDirectivesWordList;
|
|
property ISPPInstalled: Boolean read FISPPInstalled write SetISPPInstalled;
|
|
property KeywordsWordList[Section: TInnoSetupStylerSection]: AnsiString read GetKeywordsWordList;
|
|
property ScriptWordList[ClassOrRecordMembers: Boolean]: AnsiString read GetScriptWordList;
|
|
property SectionsWordList: AnsiString read FSectionsWordList;
|
|
property Theme: TTheme read FTheme write FTheme;
|
|
end;
|
|
|
|
implementation
|
|
|
|
uses
|
|
Generics.Defaults,
|
|
Shared.SetupMessageIDs, ScintInt, Shared.SetupSectionDirectives, Shared.LangOptionsSectionDirectives,
|
|
Shared.CommonFunc.Vcl, Shared.SetupSteps, Shared.Struct, Shared.DotNetVersion, isxclasses_wordlists_generated;
|
|
|
|
type
|
|
{ Size must be <= SizeOf(TScintLineState) }
|
|
TInnoSetupStylerLineState = record
|
|
Section, NextLineSection: TInnoSetupStylerSection;
|
|
SpanState: TInnoSetupStylerSpanState;
|
|
OpenCompilerDirectivesCount: ShortInt;
|
|
end;
|
|
|
|
type
|
|
TSectionMapItem = record
|
|
Name: TScintRawString;
|
|
Section: TInnoSetupStylerSection;
|
|
end;
|
|
|
|
const
|
|
SectionMap: array[0..18] of TSectionMapItem = (
|
|
(Name: 'Code'; Section: scCode),
|
|
(Name: 'Components'; Section: scComponents),
|
|
(Name: 'CustomMessages'; Section: scCustomMessages),
|
|
(Name: 'Dirs'; Section: scDirs),
|
|
(Name: 'ISSigKeys'; Section: scISSigKeys),
|
|
(Name: 'Files'; Section: scFiles),
|
|
(Name: 'Icons'; Section: scIcons),
|
|
(Name: 'INI'; Section: scINI),
|
|
(Name: 'InstallDelete'; Section: scInstallDelete),
|
|
(Name: 'LangOptions'; Section: scLangOptions),
|
|
(Name: 'Languages'; Section: scLanguages),
|
|
(Name: 'Messages'; Section: scMessages),
|
|
(Name: 'Registry'; Section: scRegistry),
|
|
(Name: 'Run'; Section: scRun),
|
|
(Name: 'Setup'; Section: scSetup),
|
|
(Name: 'Tasks'; Section: scTasks),
|
|
(Name: 'Types'; Section: scTypes),
|
|
(Name: 'UninstallDelete'; Section: scUninstallDelete),
|
|
(Name: 'UninstallRun'; Section: scUninstallRun));
|
|
|
|
ComponentsSectionParameters: array of TScintRawString = [
|
|
'Check', 'Description', 'ExtraDiskSpaceRequired', 'Flags', 'Languages',
|
|
'MinVersion', 'Name', 'OnlyBelowVersion', 'Types'
|
|
];
|
|
|
|
ComponentsSectionFlags: array of TScintRawString = [
|
|
'checkablealone', 'disablenouninstallwarning', 'dontinheritcheck', 'exclusive',
|
|
'fixed', 'restart'
|
|
];
|
|
|
|
DeleteSectionParameters: array of TScintRawString = [
|
|
'AfterInstall', 'BeforeInstall', 'Check', 'Components', 'Languages',
|
|
'MinVersion', 'Name', 'OnlyBelowVersion', 'Tasks', 'Type'
|
|
];
|
|
|
|
DeleteSectionTypes: array of TScintRawString = [
|
|
'files', 'filesandordirs', 'dirifempty'
|
|
];
|
|
|
|
DirsSectionParameters: array of TScintRawString = [
|
|
'AfterInstall', 'Attribs', 'BeforeInstall', 'Check', 'Components', 'Flags',
|
|
'Languages', 'MinVersion', 'Name', 'OnlyBelowVersion', 'Permissions', 'Tasks'
|
|
];
|
|
|
|
DirsSectionFlags: array of TScintRawString = [
|
|
'deleteafterinstall', 'setntfscompression', 'uninsalwaysuninstall',
|
|
'uninsneveruninstall', 'unsetntfscompression'
|
|
];
|
|
|
|
ISSigKeysSectionParameters: array of TScintRawString = [
|
|
'Name', 'Group', 'KeyFile', 'KeyID', 'PublicX', 'PublicY', 'RuntimeID'
|
|
];
|
|
|
|
FilesSectionParameters: array of TScintRawString = [
|
|
'AfterInstall', 'Attribs', 'BeforeInstall', 'Check', 'Components', 'CopyMode',
|
|
'DestDir', 'DestName', 'DownloadISSigSource', 'DownloadPassword',
|
|
'DownloadUserName', 'Excludes', 'ExternalSize', 'ExtractArchivePassword',
|
|
'Flags', 'FontInstall', 'Hash', 'ISSigAllowedKeys', 'Languages', 'MinVersion',
|
|
'OnlyBelowVersion', 'Permissions', 'Source', 'StrongAssemblyName', 'Tasks'
|
|
];
|
|
|
|
FilesSectionFlags: array of TScintRawString = [
|
|
'32bit', '64bit', 'allowunsafefiles', 'comparetimestamp', 'confirmoverwrite',
|
|
'createallsubdirs', 'deleteafterinstall', 'dontcopy', 'dontverifychecksum', 'download',
|
|
'external', 'extractarchive', 'fontisnttruetype', 'gacinstall', 'ignoreversion',
|
|
'isreadme', 'issigverify', 'nocompression', 'noencryption', 'noregerror',
|
|
'onlyifdestfileexists', 'onlyifdoesntexist', 'overwritereadonly', 'promptifolder',
|
|
'recursesubdirs', 'regserver', 'regtypelib', 'replacesameversion', 'restartreplace',
|
|
'setntfscompression', 'sharedfile', 'sign', 'signcheck', 'signonce',
|
|
'skipifsourcedoesntexist', 'solidbreak', 'sortfilesbyextension',
|
|
'sortfilesbyname', 'touch', 'uninsnosharedfileprompt', 'uninsremovereadonly',
|
|
'uninsrestartdelete', 'uninsneveruninstall', 'unsetntfscompression'
|
|
];
|
|
|
|
IconsSectionParameters: array of TScintRawString = [
|
|
'AfterInstall', 'AppUserModelID', 'AppUserModelToastActivatorCLSID',
|
|
'BeforeInstall', 'Check', 'Comment', 'Components', 'Filename', 'Flags',
|
|
'HotKey', 'IconFilename', 'IconIndex', 'Languages', 'MinVersion', 'Name',
|
|
'OnlyBelowVersion', 'Parameters', 'Tasks', 'WorkingDir'
|
|
];
|
|
|
|
IconsSectionFlags: array of TScintRawString = [
|
|
'closeonexit', 'createonlyiffileexists', 'dontcloseonexit',
|
|
'excludefromshowinnewinstall', 'foldershortcut', 'preventpinning',
|
|
'runmaximized', 'runminimized', 'uninsneveruninstall', 'useapppaths'
|
|
];
|
|
|
|
INISectionParameters: array of TScintRawString = [
|
|
'AfterInstall', 'BeforeInstall', 'Check', 'Components', 'Filename',
|
|
'Flags', 'Key', 'Languages', 'MinVersion', 'OnlyBelowVersion', 'Section',
|
|
'String', 'Tasks'
|
|
];
|
|
|
|
INISectionFlags: array of TScintRawString = [
|
|
'createkeyifdoesntexist', 'uninsdeleteentry', 'uninsdeletesection',
|
|
'uninsdeletesectionifempty'
|
|
];
|
|
|
|
LanguagesSectionParameters: array of TScintRawString = [
|
|
'InfoAfterFile', 'InfoBeforeFile', 'LicenseFile', 'MessagesFile', 'Name'
|
|
];
|
|
|
|
RegistrySectionParameters: array of TScintRawString = [
|
|
'AfterInstall', 'BeforeInstall', 'Check', 'Components', 'Flags', 'Languages',
|
|
'MinVersion', 'OnlyBelowVersion', 'Permissions', 'Root', 'Subkey', 'Tasks',
|
|
'ValueData', 'ValueName', 'ValueType'
|
|
];
|
|
|
|
RegistrySectionFlags: array of TScintRawString = [
|
|
'createvalueifdoesntexist', 'deletekey', 'deletevalue', 'dontcreatekey',
|
|
'noerror', 'preservestringtype', 'uninsclearvalue', 'uninsdeletekey',
|
|
'uninsdeletekeyifempty', 'uninsdeletevalue'
|
|
];
|
|
|
|
RunSectionParameters: array of TScintRawString = [
|
|
'AfterInstall', 'BeforeInstall', 'Check', 'Components', 'Description',
|
|
'Filename', 'Flags', 'Languages', 'MinVersion', 'OnlyBelowVersion',
|
|
'Parameters', 'StatusMsg', 'Tasks', 'Verb', 'WorkingDir'
|
|
];
|
|
|
|
RunSectionFlags: array of TScintRawString = [
|
|
'32bit', '64bit', 'dontlogparameters', 'hidewizard', 'logoutput', 'nowait',
|
|
'postinstall', 'runascurrentuser', 'runasoriginaluser', 'runhidden',
|
|
'runmaximized', 'runminimized', 'shellexec', 'skipifdoesntexist', 'skipifnotsilent',
|
|
'skipifsilent', 'unchecked', 'waituntilidle', 'waituntilterminated'
|
|
];
|
|
|
|
UninstallRunSectionParameters: array of TScintRawString = [
|
|
'AfterInstall', 'BeforeInstall', 'Check', 'Components', 'Filename', 'Flags',
|
|
'Languages', 'MinVersion', 'OnlyBelowVersion', 'Parameters', 'RunOnceId',
|
|
'Tasks', 'Verb', 'WorkingDir'
|
|
];
|
|
|
|
UninstallRunSectionFlags: array of TScintRawString = [
|
|
'32bit', '64bit', 'dontlogparameters', 'hidewizard', 'logoutput', 'nowait',
|
|
'runascurrentuser', 'runhidden', 'runmaximized', 'runminimized', 'shellexec',
|
|
'skipifdoesntexist', 'waituntilidle', 'waituntilterminated'
|
|
];
|
|
|
|
TasksSectionParameters: array of TScintRawString = [
|
|
'Check', 'Components', 'Description', 'Flags', 'GroupDescription', 'Languages',
|
|
'MinVersion', 'Name', 'OnlyBelowVersion'
|
|
];
|
|
|
|
TasksSectionFlags: array of TScintRawString = [
|
|
'checkablealone', 'checkedonce', 'dontinheritcheck', 'exclusive', 'restart',
|
|
'unchecked'
|
|
];
|
|
|
|
TypesSectionParameters: array of TScintRawString = [
|
|
'Check', 'Description', 'Flags', 'Languages', 'MinVersion', 'Name',
|
|
'OnlyBelowVersion'
|
|
];
|
|
|
|
TypesSectionFlags: array of TScintRawString = [
|
|
'iscustom'
|
|
];
|
|
|
|
type
|
|
TISPPDirective = record
|
|
Name: TScintRawString;
|
|
RequiresParameter: Boolean;
|
|
OpenCountChange: ShortInt;
|
|
end;
|
|
|
|
const
|
|
ISPPDirectives: array[0..23] of TISPPDirective = (
|
|
(Name: 'preproc'; RequiresParameter: True; OpenCountChange: 0),
|
|
(Name: 'define'; RequiresParameter: True; OpenCountChange: 0),
|
|
(Name: 'dim'; RequiresParameter: True; OpenCountChange: 0),
|
|
(Name: 'redim'; RequiresParameter: True; OpenCountChange: 0),
|
|
(Name: 'undef'; RequiresParameter: True; OpenCountChange: 0),
|
|
(Name: 'include'; RequiresParameter: True; OpenCountChange: 0),
|
|
(Name: 'file'; RequiresParameter: True; OpenCountChange: 0),
|
|
(Name: 'emit'; RequiresParameter: True; OpenCountChange: 0),
|
|
(Name: 'expr'; RequiresParameter: True; OpenCountChange: 0),
|
|
(Name: 'insert'; RequiresParameter: True; OpenCountChange: 0),
|
|
(Name: 'append'; RequiresParameter: False; OpenCountChange: 0),
|
|
(Name: 'if'; RequiresParameter: True; OpenCountChange: 1),
|
|
(Name: 'elif'; RequiresParameter: False { bug in ISPP? }; OpenCountChange: 0),
|
|
(Name: 'else'; RequiresParameter: False; OpenCountChange: 0),
|
|
(Name: 'endif'; RequiresParameter: False; OpenCountChange: -1),
|
|
(Name: 'ifdef'; RequiresParameter: True; OpenCountChange: 1),
|
|
(Name: 'ifndef'; RequiresParameter: True; OpenCountChange: 1),
|
|
(Name: 'ifexist'; RequiresParameter: True; OpenCountChange: 1),
|
|
(Name: 'ifnexist'; RequiresParameter: True; OpenCountChange: 1),
|
|
(Name: 'for'; RequiresParameter: True; OpenCountChange: 0),
|
|
(Name: 'sub'; RequiresParameter: True; OpenCountChange: 1),
|
|
(Name: 'endsub'; RequiresParameter: False; OpenCountChange: -1),
|
|
(Name: 'pragma'; RequiresParameter: False; OpenCountChange: 0),
|
|
(Name: 'error'; RequiresParameter: False; OpenCountChange: 0));
|
|
|
|
{ The following and some others below are not used by StyleNeeded and therefore
|
|
simply of type AnsiString instead of TScintRawString }
|
|
ConstantsWithParam: array of AnsiString = [
|
|
'cm', 'code', 'drive', 'ini', 'param', 'reg'
|
|
];
|
|
|
|
Constants: array of AnsiString = [
|
|
{ #emit and #file handled separately by BuildConstantsWordList.
|
|
Also doesnt include constants with non words chars. }
|
|
'{', 'app', 'win', 'sys', 'sysnative', 'syswow64', 'src', 'sd', 'commonpf',
|
|
'commoncf', 'tmp', 'commonfonts', 'dao', 'dotnet11', 'dotnet20', 'dotnet40',
|
|
'group', 'localappdata', 'userappdata', 'commonappdata', 'usercf',
|
|
'userdesktop', 'commondesktop', 'userdocs', 'commondocs', 'userfavorites',
|
|
'userfonts', 'userpf', 'userprograms', 'commonprograms', 'usersavedgames',
|
|
'userstartmenu', 'commonstartmenu', 'userstartup', 'commonstartup',
|
|
'usertemplates', 'commontemplates', 'autoappdata', 'autocf', 'autodesktop',
|
|
'autodocs', 'autofonts', 'autopf', 'autoprograms', 'autostartmenu', 'cmd',
|
|
'computername', 'groupname', 'hwnd', 'wizardhwnd', 'language', 'srcexe',
|
|
'uninstallexe', 'sysuserinfoname', 'sysuserinfoorg', 'userinfoname',
|
|
'userinfoorg', 'userinfoserial', 'username', 'log'
|
|
];
|
|
|
|
PascalConstants: array of AnsiString = [
|
|
{ ROPS }
|
|
'varEmpty', 'varNull', 'varSmallInt', 'varInteger', 'varSingle', 'varDouble',
|
|
'varCurrency', 'varDate', 'varOleStr', 'varDispatch', 'varError', 'varBoolean',
|
|
'varVariant', 'varUnknown', 'varShortInt', 'varByte', 'varWord', 'varLongWord',
|
|
'varInt64', 'varStrArg', 'varAny', 'varString', 'varTypeMask', 'varArray',
|
|
'varByRef', 'varUString', 'False', 'True',
|
|
{ ScriptFunc }
|
|
'MaxInt', 'wpWelcome', 'wpLicense', 'wpPassword', 'wpInfoBefore',
|
|
'wpUserInfo', 'wpSelectDir', 'wpSelectComponents', 'wpSelectProgramGroup',
|
|
'wpSelectTasks', 'wpReady', 'wpPreparing', 'wpInstalling', 'wpInfoAfter',
|
|
'wpFinished', 'MB_OK', 'MB_OKCANCEL', 'MB_ABORTRETRYIGNORE', 'MB_YESNOCANCEL',
|
|
'MB_YESNO', 'MB_RETRYCANCEL', 'MB_DEFBUTTON1', 'MB_DEFBUTTON2', 'MB_DEFBUTTON3',
|
|
'MB_SETFOREGROUND', 'IDOK', 'IDCANCEL', 'IDABORT', 'IDRETRY', 'IDIGNORE',
|
|
'IDYES', 'IDNO', 'HWND_BROADCAST', 'HKEY_AUTO', 'HKEY_AUTO_32', 'HKEY_AUTO_64',
|
|
'HKEY_CLASSES_ROOT', 'HKEY_CLASSES_ROOT_32', 'HKEY_CLASSES_ROOT_64',
|
|
'HKEY_CURRENT_USER', 'HKEY_CURRENT_USER_32', 'HKEY_CURRENT_USER_64',
|
|
'HKEY_LOCAL_MACHINE', 'HKEY_LOCAL_MACHINE_32', 'HKEY_LOCAL_MACHINE_64',
|
|
'HKEY_USERS', 'HKEY_USERS_32', 'HKEY_USERS_64', 'HKEY_PERFORMANCE_DATA',
|
|
'HKEY_CURRENT_CONFIG', 'HKEY_CURRENT_CONFIG_32', 'HKEY_CURRENT_CONFIG_64',
|
|
'HKEY_DYN_DATA', 'HKA', 'HKA32', 'HKA64', 'HKCR', 'HKCR32', 'HKCR64', 'HKCU',
|
|
'HKCU32', 'HKCU64', 'HKLM', 'HKLM32', 'HKLM64', 'HKU', 'HKU32', 'HKU64',
|
|
'HKCC', 'HKCC32', 'HKCC64', 'SW_HIDE', 'SW_SHOWNORMAL', 'SW_SHOWMINIMIZED',
|
|
'SW_SHOWMAXIMIZED', 'SW_SHOWMINNOACTIVE', 'SW_SHOW', 'FILE_ATTRIBUTE_READONLY',
|
|
'FILE_ATTRIBUTE_HIDDEN', 'FILE_ATTRIBUTE_SYSTEM', 'FILE_ATTRIBUTE_DIRECTORY',
|
|
'FILE_ATTRIBUTE_ARCHIVE', 'FILE_ATTRIBUTE_DEVICE', 'FILE_ATTRIBUTE_NORMAL',
|
|
'FILE_ATTRIBUTE_TEMPORARY', 'FILE_ATTRIBUTE_SPARSE_FILE','FILE_ATTRIBUTE_REPARSE_POINT',
|
|
'FILE_ATTRIBUTE_COMPRESSED', 'FILE_ATTRIBUTE_OFFLINE', 'FILE_ATTRIBUTE_NOT_CONTENT_INDEXED',
|
|
'FILE_ATTRIBUTE_ENCRYPTED', 'VER_NT_WORKSTATION', 'VER_NT_DOMAIN_CONTROLLER',
|
|
'VER_NT_SERVER', 'VER_SUITE_SMALLBUSINESS', 'VER_SUITE_ENTERPRISE', 'VER_SUITE_BACKOFFICE',
|
|
'VER_SUITE_COMMUNICATIONS', 'VER_SUITE_TERMINAL', 'VER_SUITE_SMALLBUSINESS_RESTRICTED',
|
|
'VER_SUITE_EMBEDDEDNT', 'VER_SUITE_DATACENTER', 'VER_SUITE_SINGLEUSERTS',
|
|
'VER_SUITE_PERSONAL', 'VER_SUITE_BLADE', 'VER_SUITE_EMBEDDED_RESTRICTED',
|
|
'VER_SUITE_SECURITY_APPLIANCE'
|
|
//undocumented: irInstall
|
|
{ ScriptClasses: see PascalConstants_Isxclasses in isxclasses_wordlists_generated }
|
|
];
|
|
|
|
PascalInterfaces: array of AnsiString = [
|
|
{ ROPS }
|
|
'IUnknown', 'IInterface', 'IDispatch'
|
|
];
|
|
|
|
PascalReservedWords: array of TScintRawString = [
|
|
'and', 'array', 'as', 'begin', 'case', 'const', 'div', 'do', 'downto',
|
|
'else', 'end', 'except', 'external', 'finally', 'for', 'forward', 'function',
|
|
'goto', 'if', 'in', 'is', 'label', 'mod', 'nil', 'not', 'of', 'or',
|
|
'procedure', 'program', 'record', 'repeat', 'set', 'shl', 'shr', 'then',
|
|
'to', 'try', 'type', 'until', 'var', 'while', 'with', 'xor', 'delayload',
|
|
'loadwithalteredsearchpath', 'stdcall', 'cdecl', 'register', 'pascal',
|
|
'setuponly', 'uninstallonly', 'event'
|
|
];
|
|
|
|
PascalTypes: array of AnsiString = [
|
|
{ ROPS }
|
|
'Byte', 'Boolean', 'LongBool', 'WordBool', 'ByteBool', 'AnsiChar', 'Char',
|
|
'WideChar', 'WideString', 'UnicodeString', 'AnsiString', 'String', 'ShortInt',
|
|
'Word', 'SmallInt', 'LongInt', 'LongWord', 'Integer', 'Cardinal', 'Int64',
|
|
'Single', 'Double', 'Extended', 'Currency', 'PAnsiChar', 'Variant',
|
|
'TVariantArray',
|
|
//undocumented: NativeString, AnyString, AnyMethod, ___Pointer, tbtString, NativeString, !NotificationVariant
|
|
'TVarType',
|
|
//undocumented: TIFException
|
|
{ ScriptFunc's real enums, values done via PascalRealEnumValues instead of PascalEnumValues}
|
|
'TMsgBoxType', 'TSetupMessageID', 'TSetupStep', 'TUninstallStep',
|
|
'TSetupProcessorArchitecture', 'TDotNetVersion',
|
|
{ ScriptFunc's non real enums and other types - also see PascalEnumValues below }
|
|
'TArrayOfString', 'TArrayOfChar', 'TArrayOfBoolean', 'TArrayOfInteger', 'DWORD',
|
|
'UINT', 'BOOL', 'DWORD_PTR', 'UINT_PTR', 'INT_PTR', 'TFileTime',
|
|
'TSplitType', 'TExecWait', 'TExecOutput', 'TFindRec', 'TWindowsVersion',
|
|
'TOnDownloadProgress', 'TOnExtractionProgress', 'TOnLog'
|
|
{ ScriptClasses: see PascalTypes_Isxclasses in isxclasses_wordlists_generated }
|
|
];
|
|
|
|
PascalEnumValues: array of AnsiString = [
|
|
{ ScriptFunc's values of non real enums - also see PascalTypes above }
|
|
'stAll', 'stExcludeEmpty', 'stExcludeLastEmpty',
|
|
'ewNoWait', 'ewWaitUntilTerminated', 'ewWaitUntilIdle'
|
|
{ ScriptClasses: see PascalEnumValues_Isxclasses in isxclasses_wordlists_generated }
|
|
];
|
|
|
|
var
|
|
PascalRealEnumValues: array of PTypeInfo; { Initialized below }
|
|
|
|
const
|
|
PascalVariables: array of AnsiString = [
|
|
{ ROPS }
|
|
'Result',
|
|
{ ScriptClasses }
|
|
'WizardForm', 'MainForm', 'UninstallProgressForm'
|
|
];
|
|
|
|
BasicEventFunctions: array of TScintRawString = [
|
|
'InitializeSetup', 'InitializeWizard', 'DeinitializeSetup', 'CurStepChanged',
|
|
'CurInstallProgressChanged', 'NextButtonClick', 'BackButtonClick',
|
|
'CancelButtonClick', 'ShouldSkipPage', 'CurPageChanged', 'CheckPassword',
|
|
'NeedRestart', 'UpdateReadyMemo', 'RegisterPreviousData', 'CheckSerial',
|
|
'GetCustomSetupExitCode', 'PrepareToInstall',
|
|
'RegisterExtraCloseApplicationsResources', 'InitializeUninstall',
|
|
'InitializeUninstallProgressForm', 'DeinitializeUninstall',
|
|
'CurUninstallStepChanged', 'UninstallNeedRestart'
|
|
];
|
|
|
|
FullEventFunctions: array of AnsiString = [
|
|
'function InitializeSetup: Boolean;',
|
|
'procedure InitializeWizard;',
|
|
'procedure DeinitializeSetup;',
|
|
'procedure CurStepChanged(CurStep: TSetupStep);',
|
|
'procedure CurInstallProgressChanged(CurProgress, MaxProgress: Integer);',
|
|
'function NextButtonClick(CurPageID: Integer): Boolean;',
|
|
'function BackButtonClick(CurPageID: Integer): Boolean;',
|
|
'procedure CancelButtonClick(CurPageID: Integer; var Cancel, Confirm: Boolean);',
|
|
'function ShouldSkipPage(PageID: Integer): Boolean;',
|
|
'procedure CurPageChanged(CurPageID: Integer);',
|
|
'function CheckPassword(Password: String): Boolean;',
|
|
'function NeedRestart: Boolean;',
|
|
'function UpdateReadyMemo(Space, NewLine, MemoUserInfoInfo, MemoDirInfo, MemoTypeInfo, MemoComponentsInfo, MemoGroupInfo, MemoTasksInfo: String): String;',
|
|
'procedure RegisterPreviousData(PreviousDataKey: Integer);',
|
|
'function CheckSerial(Serial: String): Boolean;',
|
|
'function GetCustomSetupExitCode: Integer;',
|
|
'function PrepareToInstall(var NeedsRestart: Boolean): String;',
|
|
'procedure RegisterExtraCloseApplicationsResources;',
|
|
'function InitializeUninstall: Boolean;',
|
|
'procedure InitializeUninstallProgressForm;',
|
|
'procedure DeinitializeUninstall;',
|
|
'procedure CurUninstallStepChanged(CurUninstallStep: TUninstallStep);',
|
|
'function UninstallNeedRestart: Boolean;'
|
|
];
|
|
|
|
EventFunctionsParameters: array of AnsiString = [
|
|
'CurStep', 'CurProgress', 'MaxProgress', 'CurPageID', 'Cancel', 'Confirm',
|
|
'PageID', 'Password', 'Space', 'NewLine', 'MemoUserInfoInfo',
|
|
'MemoDirInfo', 'MemoTypeInfo', 'MemoComponentsInfo', 'MemoGroupInfo',
|
|
'MemoTasksInfo', 'PreviousDataKey', 'Serial', 'NeedsRestart',
|
|
'CurUninstallStep'
|
|
];
|
|
|
|
inSquiggly = 0;
|
|
inPendingSquiggly = 1;
|
|
|
|
AllChars = [#0..#255];
|
|
WhitespaceChars = [#0..' '];
|
|
AlphaChars = ['A'..'Z', 'a'..'z'];
|
|
DigitChars = ['0'..'9'];
|
|
HexDigitChars = DigitChars + ['A'..'F', 'a'..'f'];
|
|
AlphaUnderscoreChars = AlphaChars + ['_'];
|
|
AlphaDigitChars = AlphaChars + DigitChars;
|
|
AlphaDigitUnderscoreChars = AlphaChars + DigitChars + ['_'];
|
|
|
|
PascalIdentFirstChars = AlphaUnderscoreChars;
|
|
PascalIdentChars = AlphaDigitUnderscoreChars;
|
|
|
|
ISPPIdentFirstChars = AlphaUnderscoreChars;
|
|
ISPPIdentChars = AlphaDigitUnderscoreChars;
|
|
|
|
function SameRawText(const S1, S2: TScintRawString): Boolean;
|
|
var
|
|
Len, I: Integer;
|
|
C1, C2: AnsiChar;
|
|
begin
|
|
Len := Length(S1);
|
|
if Length(S2) <> Len then begin
|
|
Result := False;
|
|
Exit;
|
|
end;
|
|
for I := 1 to Len do begin
|
|
C1 := S1[I];
|
|
C2 := S2[I];
|
|
if C1 in ['A'..'Z'] then
|
|
Inc(C1, 32);
|
|
if C2 in ['A'..'Z'] then
|
|
Inc(C2, 32);
|
|
if C1 <> C2 then begin
|
|
Result := False;
|
|
Exit;
|
|
end;
|
|
end;
|
|
Result := True;
|
|
end;
|
|
|
|
{ TFunctionDefinition }
|
|
|
|
constructor TFunctionDefinition.Create(const ScriptFunc: AnsiString);
|
|
begin
|
|
ScriptFuncWithoutHeader := RemoveScriptFuncHeader(ScriptFunc, WasFunction);
|
|
HasParams := ScriptFuncHasParameters(ScriptFunc);
|
|
end;
|
|
|
|
{ TInnoSetupStyler }
|
|
|
|
constructor TInnoSetupStyler.Create(AOwner: TComponent);
|
|
|
|
procedure BuildFlagsWordLists;
|
|
begin
|
|
{ Builds FFlagsWordList (for autocomplete) and FFlagsWords }
|
|
BuildFlagsWordList(scFiles, FilesSectionFlags);
|
|
BuildFlagsWordList(scComponents, ComponentsSectionFlags);
|
|
BuildFlagsWordList(scDirs, DirsSectionFlags);
|
|
BuildFlagsWordList(scIcons, IconsSectionFlags);
|
|
BuildFlagsWordList(scINI, INISectionFlags);
|
|
BuildFlagsWordList(scRegistry, RegistrySectionFlags);
|
|
BuildFlagsWordList(scRun, RunSectionFlags);
|
|
BuildFlagsWordList(scTasks, TasksSectionFlags);
|
|
BuildFlagsWordList(scTypes, TypesSectionFlags);
|
|
BuildFlagsWordList(scUninstallRun, UninstallRunSectionFlags);
|
|
{ Bit of a trick }
|
|
BuildFlagsWordList(scInstallDelete, DeleteSectionTypes);
|
|
BuildFlagsWordList(scUninstallDelete, DeleteSectionTypes);
|
|
end;
|
|
|
|
procedure BuildKeywordsWordLists;
|
|
begin
|
|
{ Builds FKeywordsWordList (for autocomplete) and FNoHighlightAtCursorWords }
|
|
BuildKeywordsWordList(scISSigKeys, ISSigKeysSectionParameters);
|
|
BuildKeywordsWordList(scFiles, FilesSectionParameters);
|
|
BuildKeywordsWordList(scComponents, ComponentsSectionParameters);
|
|
BuildKeywordsWordList(scDirs, DirsSectionParameters);
|
|
BuildKeywordsWordList(scIcons, IconsSectionParameters);
|
|
BuildKeywordsWordList(scINI, INISectionParameters);
|
|
BuildKeywordsWordList(scInstallDelete, DeleteSectionParameters);
|
|
BuildKeywordsWordListFromTypeInfo(scLangOptions, TypeInfo(TLangOptionsSectionDirective), LangOptionsSectionDirectivePrefixLength);
|
|
BuildKeywordsWordList(scLanguages, LanguagesSectionParameters);
|
|
BuildKeywordsWordList(scRegistry, RegistrySectionParameters);
|
|
BuildKeywordsWordList(scRun, RunSectionParameters);
|
|
BuildKeywordsWordListFromTypeInfo(scSetup, TypeInfo(TSetupSectionDirective), SetupSectionDirectivePrefixLength);
|
|
BuildKeywordsWordList(scTasks, TasksSectionParameters);
|
|
BuildKeywordsWordList(scTypes, TypesSectionParameters);
|
|
BuildKeywordsWordList(scUninstallDelete, DeleteSectionParameters);
|
|
BuildKeywordsWordList(scUninstallRun, UninstallRunSectionParameters);
|
|
BuildKeywordsWordListFromTypeInfo(scMessages, TypeInfo(TSetupMessageID), SetupMessageIDPrefixLength);
|
|
end;
|
|
|
|
procedure BuildScriptLists;
|
|
begin
|
|
{ Builds FScriptFunctionsByName (for calltips) and FScriptWordList (for autocomplete)
|
|
and FNoHighlightAtCursorWords }
|
|
const SL1 = FNoHighlightAtCursorWords[scCode];
|
|
const SL2 = TStringList.Create;
|
|
try
|
|
{ Add stuff from ScriptFunc }
|
|
var ClassMembers := False;
|
|
for var ScriptFuncTable in ScriptFuncTables do
|
|
BuildScriptFunctionsLists(ScriptFuncTable, ClassMembers, SL2);
|
|
BuildScriptFunctionsLists(DelphiScriptFuncTable, ClassMembers, SL2);
|
|
BuildScriptFunctionsLists(ROPSScriptFuncTable, ClassMembers, SL2);
|
|
{ Add stuff from this unit }
|
|
for var S in PascalConstants do
|
|
AddWordToList(SL2, S, awtScriptConstant);
|
|
for var S in PascalConstants_Isxclasses do
|
|
AddWordToList(SL2, S, awtScriptConstant);
|
|
for var S in PascalInterfaces do
|
|
AddWordToList(SL2, S, awtScriptInterface);
|
|
for var S in PascalReservedWords do begin
|
|
SL1.Add(String(S));
|
|
AddWordToList(SL2, S, awtScriptKeyword);
|
|
end;
|
|
for var S in PascalTypes do
|
|
AddWordToList(SL2, S, awtScriptType);
|
|
for var S in PascalTypes_Isxclasses do
|
|
AddWordToList(SL2, S, awtScriptType);
|
|
for var S in PascalEnumValues do
|
|
AddWordToList(SL2, S, awtScriptEnumValue);
|
|
for var S in PascalEnumValues_Isxclasses do
|
|
AddWordToList(SL2, S, awtScriptEnumValue);
|
|
for var TypeInfo in PascalRealEnumValues do begin
|
|
var TypeData := GetTypeData(TypeInfo);
|
|
for var I := TypeData.MinValue to TypeData.MaxValue do
|
|
AddWordToList(SL2, AnsiString(GetEnumName(TypeInfo, I)), awtScriptEnumValue);
|
|
end;
|
|
for var S in PascalVariables do
|
|
AddWordToList(SL2, S, awtScriptVariable);
|
|
for var S in EventFunctionsParameters do
|
|
AddWordToList(SL2, S, awtScriptVariable);
|
|
FScriptWordList[False] := BuildWordList(SL2);
|
|
|
|
{ Add stuff from Isxclasses }
|
|
SL2.Clear;
|
|
ClassMembers := True;
|
|
BuildScriptFunctionsLists(PascalMembers_Isxclasses, ClassMembers, SL2);
|
|
for var S in PascalProperties_Isxclasses do
|
|
AddWordToList(SL2, S, awtScriptProperty);
|
|
FScriptWordList[True] := BuildWordList(SL2);
|
|
finally
|
|
SL2.Free;
|
|
end;
|
|
end;
|
|
|
|
function CreateWordsBySectionList: TStringList;
|
|
begin
|
|
Result := TStringList.Create;
|
|
Result.CaseSensitive := False;
|
|
Result.Sorted := True;
|
|
end;
|
|
|
|
begin
|
|
inherited;
|
|
FNoHighlightAtCursorWords := TWordsBySection.Create([doOwnsValues]);
|
|
FFlagsWords := TWordsBySection.Create([doOwnsValues]);
|
|
for var Section := Low(TInnoSetupStylerSection) to High(TInnoSetupStylerSection) do begin
|
|
FNoHighlightAtCursorWords.Add(Section, CreateWordsBySectionList);
|
|
FFlagsWords.Add(Section, CreateWordsBySectionList);
|
|
end;
|
|
BuildConstantsWordList;
|
|
BuildEventFunctionsWordList;
|
|
BuildFlagsWordLists;
|
|
BuildISPPDirectivesWordList;
|
|
BuildKeywordsWordLists;
|
|
BuildSectionsWordList;
|
|
FScriptFunctionsByName[False] := TFunctionDefinitionsByName.Create(TIStringComparer.Ordinal);
|
|
FScriptFunctionsByName[True] := TFunctionDefinitionsByName.Create(TIStringComparer.Ordinal);
|
|
BuildScriptLists;
|
|
end;
|
|
|
|
destructor TInnoSetupStyler.Destroy;
|
|
begin
|
|
FScriptFunctionsByName[False].Free;
|
|
FScriptFunctionsByName[True].Free;
|
|
FFlagsWords.Free;
|
|
FNoHighlightAtCursorWords.Free;
|
|
inherited;
|
|
end;
|
|
|
|
procedure TInnoSetupStyler.AddWordToList(const SL: TStringList;
|
|
const Word: AnsiString; const Typ: Integer);
|
|
begin
|
|
if Typ >= 0 then
|
|
SL.Add(Format('%s%s%d', [Word, InnoSetupStylerWordListTypeSeparator, Typ]))
|
|
else
|
|
SL.Add(String(Word));
|
|
end;
|
|
|
|
procedure TInnoSetupStyler.ApplyPendingSquigglyFromToIndex(const StartIndex, EndIndex: Integer);
|
|
begin
|
|
if (CaretIndex >= StartIndex) and (CaretIndex <= EndIndex + 1) then
|
|
ApplyStyleByteIndicators([inPendingSquiggly], StartIndex, EndIndex)
|
|
else
|
|
ApplyStyleByteIndicators([inSquiggly], StartIndex, EndIndex);
|
|
end;
|
|
|
|
procedure TInnoSetupStyler.ApplyPendingSquigglyFromIndex(const StartIndex: Integer);
|
|
begin
|
|
ApplyPendingSquigglyFromToIndex(StartIndex, CurIndex - 1);
|
|
end;
|
|
|
|
procedure TInnoSetupStyler.ApplySquigglyFromIndex(const StartIndex: Integer);
|
|
begin
|
|
ApplyStyleByteIndicators([inSquiggly], StartIndex, CurIndex - 1);
|
|
end;
|
|
|
|
function TInnoSetupStyler.BuildWordList(const WordStringList: TStringList): AnsiString;
|
|
begin
|
|
{ Scintilla uses an ASCII binary search so the list must be in ASCII sort
|
|
order (case-insensitive). }
|
|
WordStringList.CaseSensitive := False;
|
|
WordStringList.UseLocale := False; { Make sure it uses CompareText and not AnsiCompareText }
|
|
WordStringList.Sort;
|
|
|
|
Result := '';
|
|
for var S in WordStringList do begin
|
|
var A := AnsiString(S);
|
|
if Result = '' then
|
|
Result := A
|
|
else
|
|
Result := Result + InnoSetupStylerWordListSeparator + A;
|
|
end;
|
|
end;
|
|
|
|
procedure TInnoSetupStyler.BuildSectionsWordList;
|
|
begin
|
|
var SL := TStringList.Create;
|
|
try
|
|
for var Section in SectionMap do
|
|
AddWordToList(SL, '[' + Section.Name + ']', awtSection);
|
|
FSectionsWordList := BuildWordList(SL);
|
|
finally
|
|
SL.Free;
|
|
end;
|
|
end;
|
|
|
|
procedure TInnoSetupStyler.BuildKeywordsWordList(
|
|
const Section: TInnoSetupStylerSection;
|
|
const Parameters: array of TScintRawString);
|
|
begin
|
|
const SL1 = FNoHighlightAtCursorWords[Section];
|
|
const SL2 = TStringList.Create;
|
|
try
|
|
for var Parameter in Parameters do begin
|
|
SL1.Add(String(Parameter));
|
|
AddWordToList(SL2, Parameter, awtParameter);
|
|
end;
|
|
FKeywordsWordList[Section] := BuildWordList(SL2);
|
|
finally
|
|
SL2.Free;
|
|
end;
|
|
end;
|
|
|
|
procedure TInnoSetupStyler.BuildKeywordsWordListFromTypeInfo(
|
|
const Section: TInnoSetupStylerSection; const EnumTypeInfo: Pointer;
|
|
const PrefixLength: Integer);
|
|
begin
|
|
const SL1 = FNoHighlightAtCursorWords[Section];
|
|
const SL2 = TStringList.Create;
|
|
try
|
|
for var I := 0 to GetTypeData(EnumTypeInfo).MaxValue do begin
|
|
const Parameter = Copy(GetEnumName(EnumTypeInfo, I), PrefixLength+1, MaxInt);
|
|
SL1.Add(Parameter);
|
|
AddWordToList(SL2, AnsiString(Parameter), awtDirective);
|
|
end;
|
|
FKeywordsWordList[Section] := BuildWordList(SL2);
|
|
finally
|
|
SL2.Free;
|
|
end;
|
|
end;
|
|
|
|
procedure TInnoSetupStyler.BuildFlagsWordList(const Section: TInnoSetupStylerSection;
|
|
const Flags: array of TScintRawString);
|
|
begin
|
|
const SL1 = FFlagsWords[Section];
|
|
const SL2 = TStringList.Create;
|
|
try
|
|
for var Flag in Flags do begin
|
|
SL1.Add(String(Flag));
|
|
AddWordToList(SL2, Flag, awtFlag);
|
|
end;
|
|
FFlagsWordList[Section] := BuildWordList(SL2);
|
|
finally
|
|
SL2.Free;
|
|
end;
|
|
end;
|
|
|
|
procedure TInnoSetupStyler.BuildScriptFunctionsLists(
|
|
const ScriptFuncTable: TScriptTable; const ClassMembers: Boolean;
|
|
const SL: TStringList);
|
|
begin
|
|
for var ScriptFunc in ScriptFuncTable do begin
|
|
var FunctionDefinition := TFunctionDefinition.Create(ScriptFunc);
|
|
var ScriptFuncName := ExtractScriptFuncWithoutHeaderName(FunctionDefinition.ScriptFuncWithoutHeader);
|
|
var DoAddWordToList := True;
|
|
var Key := String(ScriptFuncName);
|
|
if not FScriptFunctionsByName[ClassMembers].TryAdd(Key, [FunctionDefinition]) then begin
|
|
{ Function has multiple prototypes }
|
|
var ScriptFunctions := FScriptFunctionsByName[ClassMembers][Key];
|
|
var N := Length(ScriptFunctions);
|
|
SetLength(ScriptFunctions, N+1);
|
|
ScriptFunctions[N] := FunctionDefinition;
|
|
FScriptFunctionsByName[ClassMembers][Key] := ScriptFunctions;
|
|
DoAddWordToList := False; { Already added it when the first prototype was found }
|
|
end;
|
|
if DoAddWordToList then
|
|
AddWordToList(SL, ScriptFuncName, awtScriptFunction);
|
|
end;
|
|
end;
|
|
|
|
procedure TInnoSetupStyler.BuildISPPDirectivesWordList;
|
|
begin
|
|
var SL := TStringList.Create;
|
|
try
|
|
for var ISPPDirective in ISPPDirectives do
|
|
AddWordToList(SL, '#' + ISPPDirective.Name, awtPreprocessorDirective);
|
|
FISPPDirectivesWordList := BuildWordList(SL);
|
|
finally
|
|
SL.Free;
|
|
end;
|
|
end;
|
|
|
|
procedure TInnoSetupStyler.BuildConstantsWordList;
|
|
begin
|
|
var SL := TStringList.Create;
|
|
try
|
|
for var Constant in Constants do
|
|
AddWordToList(SL, '{' + Constant + '}', awtConstant);
|
|
if ISPPInstalled then begin
|
|
AddWordToList(SL, '{#', awtConstant);
|
|
AddWordToList(SL, '{#file ', awtConstant);
|
|
end;
|
|
for var ConstantWithParam in ConstantsWithParam do
|
|
AddWordToList(SL, '{' + ConstantWithParam, awtConstant);
|
|
FConstantsWordList := BuildWordList(SL);
|
|
finally
|
|
SL.Free;
|
|
end;
|
|
end;
|
|
|
|
procedure TInnoSetupStyler.BuildEventFunctionsWordList;
|
|
begin
|
|
var SLFunctions: TStringList := nil;
|
|
var SLProcedures: TStringList := nil;
|
|
try
|
|
SLFunctions := TStringList.Create;
|
|
SLProcedures := TStringList.Create;
|
|
for var FullEventFunction in FullEventFunctions do begin
|
|
var WasFunction: Boolean;
|
|
var S := RemoveScriptFuncHeader(FullEventFunction, WasFunction);
|
|
if WasFunction then
|
|
AddWordToList(SLFunctions, S, awtScriptEvent)
|
|
else
|
|
AddWordToList(SLProcedures, S, awtScriptEvent);
|
|
end;
|
|
FEventFunctionsWordList[False] := BuildWordList(SLFunctions);
|
|
FEventFunctionsWordList[True] := BuildWordList(SLProcedures);
|
|
finally
|
|
SLProcedures.Free;
|
|
SLFunctions.Free;
|
|
end;
|
|
end;
|
|
|
|
procedure TInnoSetupStyler.CommitStyle(const Style: TInnoSetupStylerStyle);
|
|
begin
|
|
inherited CommitStyle(Ord(Style));
|
|
end;
|
|
|
|
procedure TInnoSetupStyler.CommitStyleSq(const Style: TInnoSetupStylerStyle;
|
|
const Squigglify: Boolean);
|
|
begin
|
|
if Squigglify then
|
|
ApplySquigglyFromIndex(StyleStartIndex);
|
|
CommitStyle(Style);
|
|
end;
|
|
|
|
procedure TInnoSetupStyler.CommitStyleSqPending(const Style: TInnoSetupStylerStyle);
|
|
begin
|
|
ApplyPendingSquigglyFromIndex(StyleStartIndex);
|
|
CommitStyle(Style);
|
|
end;
|
|
|
|
function TInnoSetupStyler.GetEventFunctionsWordList(Procedures: Boolean): AnsiString;
|
|
begin
|
|
Result := FEventFunctionsWordList[Procedures];
|
|
end;
|
|
|
|
function TInnoSetupStyler.GetFlagsWordList(Section: TInnoSetupStylerSection): AnsiString;
|
|
begin
|
|
Result := FFlagsWordList[Section];
|
|
end;
|
|
|
|
procedure TInnoSetupStyler.GetFoldLevel(const LineState, PreviousLineState: TScintLineState;
|
|
var Level: Integer; var Header, EnableHeaderOnPrevious: Boolean);
|
|
begin
|
|
{ Set folding per section. Lines outside of a section (=lines at the start of
|
|
the document and section tags and section end tags and lines after section
|
|
end tags) get level 0 with header flags for section tags. Other lines
|
|
(=lines inside a section) get level 1. }
|
|
|
|
var Section := TInnoSetupStyler.GetSectionFromLineState(LineState);
|
|
if Section = scNone then begin
|
|
Level := 0;
|
|
Header := False; { Might be set to True via EnableHeaderOnPrevious below when we know about next line }
|
|
EnableHeaderOnPrevious := False;
|
|
end else begin
|
|
Level := 1;
|
|
Header := False;
|
|
var PreviousSection := TInnoSetupStyler.GetSectionFromLineState(PreviousLineState);
|
|
EnableHeaderOnPrevious := PreviousSection = scNone;
|
|
end;
|
|
end;
|
|
|
|
function TInnoSetupStyler.GetKeywordsWordList(Section: TInnoSetupStylerSection): AnsiString;
|
|
begin
|
|
Result := FKeywordsWordList[Section];
|
|
end;
|
|
|
|
function TInnoSetupStyler.GetScriptFunctionDefinition(const ClassMember: Boolean;
|
|
const Name: String; const Index: Integer; out Count: Integer): TFunctionDefinition;
|
|
begin
|
|
var ScriptFunctions: TFunctionDefinitions;
|
|
if FScriptFunctionsByName[ClassMember].TryGetValue(Name, ScriptFunctions) then begin
|
|
Count := Length(ScriptFunctions);
|
|
var ResultIndex := Index;
|
|
if ResultIndex >= Count then
|
|
ResultIndex := Count-1;
|
|
Result := ScriptFunctions[ResultIndex]
|
|
end else
|
|
Count := 0;
|
|
end;
|
|
|
|
function TInnoSetupStyler.GetScriptFunctionDefinition(
|
|
const ClassMember: Boolean; const Name: String;
|
|
const Index: Integer): TFunctionDefinition;
|
|
begin
|
|
var Count: Integer;
|
|
Result := GetScriptFunctionDefinition(ClassMember, Name, Index, Count);
|
|
end;
|
|
|
|
function TInnoSetupStyler.GetScriptWordList(
|
|
ClassOrRecordMembers: Boolean): AnsiString;
|
|
begin
|
|
Result := FScriptWordList[ClassOrRecordMembers];
|
|
end;
|
|
|
|
class function TInnoSetupStyler.GetSectionFromLineState(
|
|
const LineState: TScintLineState): TInnoSetupStylerSection;
|
|
begin
|
|
Result := TInnoSetupStylerLineState(LineState).Section;
|
|
end;
|
|
|
|
procedure TInnoSetupStyler.GetStyleAttributes(const Style: Integer;
|
|
var Attributes: TScintStyleAttributes);
|
|
begin
|
|
if FTheme <> nil then begin
|
|
if (Style >= 0) and (Style <= Ord(High(TInnoSetupStylerStyle))) then begin
|
|
if not FTheme.Modern then begin
|
|
{ Check for some exceptions }
|
|
case TInnoSetupStylerStyle(Style) of
|
|
stCompilerDirective, stISPPReservedWord: begin Attributes.ForeColor := $4040C0; Exit; end;
|
|
stMessageArg: begin Attributes.ForeColor := $FF8000; Exit; end;
|
|
stPascalString, stPascalNumber, stISPPString, stISPPNumber: begin Attributes.ForeColor := clMaroon; Exit; end;
|
|
end;
|
|
end;
|
|
case TInnoSetupStylerStyle(Style) of
|
|
stCompilerDirective, stISPPReservedWord: Attributes.ForeColor := FTheme.Colors[tcRed];
|
|
stComment: Attributes.ForeColor := FTheme.Colors[tcGreen];
|
|
stSection: Attributes.FontStyle := [fsBold];
|
|
stSymbol: Attributes.ForeColor := FTheme.Colors[tcGray];
|
|
stKeyword, stPascalReservedWord: Attributes.ForeColor := FTheme.Colors[tcBlue];
|
|
//stParameterValue: Attributes.ForeColor := FTheme.Colors[tcTeal];
|
|
stEventFunction: Attributes.FontStyle := [fsBold];
|
|
stConstant: Attributes.ForeColor := FTheme.Colors[tcPurple];
|
|
stMessageArg: Attributes.ForeColor := FTheme.Colors[tcRed];
|
|
stPascalString, stPascalNumber, stISPPString, stISPPNumber: Attributes.ForeColor := FTheme.Colors[tcOrange];
|
|
end;
|
|
end else begin
|
|
case Style of
|
|
STYLE_LINENUMBER: { Also sets the background colour for the margin with the markers like mmIconBreakpoint }
|
|
begin
|
|
Attributes.ForeColor := FTheme.Colors[tcMarginFore];
|
|
Attributes.BackColor := FTheme.Colors[tcMarginBack];
|
|
end;
|
|
STYLE_BRACEBAD: Attributes.ForeColor := FTheme.Colors[tcRed];
|
|
STYLE_BRACELIGHT: Attributes.BackColor := FTheme.Colors[tcBraceBack];
|
|
STYLE_INDENTGUIDE: Attributes.ForeColor := FTheme.Colors[tcIndentGuideFore];
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure TInnoSetupStyler.HandleCodeSection(var SpanState: TInnoSetupStylerSpanState);
|
|
|
|
function FinishConsumingBraceComment: Boolean;
|
|
begin
|
|
ConsumeCharsNot(['}']);
|
|
Result := ConsumeChar('}');
|
|
CommitStyle(stComment);
|
|
end;
|
|
|
|
function FinishConsumingStarComment: Boolean;
|
|
begin
|
|
Result := False;
|
|
while True do begin
|
|
ConsumeCharsNot(['*']);
|
|
if not ConsumeChar('*') then
|
|
Break;
|
|
if ConsumeChar(')') then begin
|
|
Result := True;
|
|
Break;
|
|
end;
|
|
end;
|
|
CommitStyle(stComment);
|
|
end;
|
|
|
|
begin
|
|
case SpanState of
|
|
spBraceComment:
|
|
if not FinishConsumingBraceComment then
|
|
Exit;
|
|
spStarComment:
|
|
if not FinishConsumingStarComment then
|
|
Exit;
|
|
end;
|
|
|
|
SpanState := spNone;
|
|
SkipWhitespace;
|
|
while not EndOfLine do begin
|
|
if CurChar in PascalIdentFirstChars then begin
|
|
var S := ConsumeString(PascalIdentChars);
|
|
for var Word in PascalReservedWords do
|
|
if SameRawText(S, Word) then begin
|
|
CommitStyle(stPascalReservedWord);
|
|
Break;
|
|
end;
|
|
for var EventFunction in BasicEventFunctions do
|
|
if SameRawText(S, EventFunction) then begin
|
|
CommitStyle(stEventFunction);
|
|
Break;
|
|
end;
|
|
CommitStyle(stDefault);
|
|
end else if ConsumeChars(DigitChars) then begin
|
|
if not CurCharIs('.') or not NextCharIs('.') then begin
|
|
if ConsumeChar('.') then
|
|
ConsumeChars(DigitChars);
|
|
var C := CurChar;
|
|
if C in ['E', 'e'] then begin
|
|
ConsumeChar(C);
|
|
if not ConsumeChar('-') then
|
|
ConsumeChar('+');
|
|
if not ConsumeChars(DigitChars) then
|
|
CommitStyleSqPending(stPascalNumber);
|
|
end;
|
|
end;
|
|
CommitStyle(stPascalNumber);
|
|
end else begin
|
|
var C := CurChar;
|
|
ConsumeChar(C);
|
|
case C of
|
|
';', ':', '=', '+', '-', '*', '/', '<', '>', ',', '(', ')',
|
|
'.', '[', ']', '@', '^':
|
|
begin
|
|
if (C = '/') and ConsumeChar('/') then begin
|
|
ConsumeAllRemaining;
|
|
CommitStyle(stComment);
|
|
end else if (C = '(') and ConsumeChar('*') then begin
|
|
if not FinishConsumingStarComment then begin
|
|
SpanState := spStarComment;
|
|
Exit;
|
|
end;
|
|
end else
|
|
CommitStyle(stSymbol);
|
|
end;
|
|
'''':
|
|
begin
|
|
while True do begin
|
|
ConsumeCharsNot([C]);
|
|
if not ConsumeChar(C) then begin
|
|
CommitStyleSqPending(stPascalString);
|
|
Break;
|
|
end;
|
|
if not ConsumeChar(C) then begin
|
|
CommitStyle(stPascalString);
|
|
Break;
|
|
end;
|
|
end;
|
|
end;
|
|
'{':
|
|
begin
|
|
if not FinishConsumingBraceComment then begin
|
|
SpanState := spBraceComment;
|
|
Exit;
|
|
end;
|
|
end;
|
|
'$':
|
|
begin
|
|
if not ConsumeChars(HexDigitChars) then
|
|
CommitStyleSqPending(stPascalNumber);
|
|
CommitStyle(stPascalNumber);
|
|
end;
|
|
'#':
|
|
begin
|
|
if ConsumeChar('$') then begin
|
|
if not ConsumeChars(HexDigitChars) then
|
|
CommitStyleSqPending(stPascalString);
|
|
end else if not ConsumeChars(DigitChars) then
|
|
CommitStyleSqPending(stPascalString);
|
|
CommitStyle(stPascalString);
|
|
end;
|
|
else
|
|
{ Illegal character }
|
|
CommitStyleSq(stSymbol, True);
|
|
end;
|
|
end;
|
|
SkipWhitespace;
|
|
end;
|
|
end;
|
|
|
|
procedure TInnoSetupStyler.HandleCompilerDirective(const InlineDirective: Boolean; const InlineDirectiveEndIndex: Integer; var OpenCount: ShortInt);
|
|
|
|
function EndOfDirective: Boolean;
|
|
begin
|
|
Result := EndOfLine or (InlineDirective and (CurIndex > InlineDirectiveEndIndex));
|
|
end;
|
|
|
|
procedure FinishDirectiveNameOrShorthand(const RequiresParameter: Boolean);
|
|
begin
|
|
if RequiresParameter then begin
|
|
ConsumeChars(WhitespaceChars); { This will give the whitespace the stCompilerDirective style instead of stDefault but that's ok }
|
|
if EndOfDirective then
|
|
CommitStyleSqPending(stCompilerDirective)
|
|
else
|
|
CommitStyle(stCompilerDirective);
|
|
end else
|
|
CommitStyle(stCompilerDirective);
|
|
end;
|
|
|
|
function FinishConsumingStarComment: Boolean;
|
|
begin
|
|
Result := False;
|
|
while True do begin
|
|
ConsumeCharsNot(['*']);
|
|
if not ConsumeChar('*') then
|
|
Break;
|
|
if ConsumeChar('/') then begin
|
|
Result := True;
|
|
Break;
|
|
end;
|
|
end;
|
|
if Result then
|
|
CommitStyle(stComment)
|
|
else
|
|
CommitStyleSqPending(stComment);
|
|
end;
|
|
|
|
procedure ConsumeISPPString(const Terminator: AnsiChar; const AllowEscapedTerminator: Boolean);
|
|
begin
|
|
while True do begin
|
|
ConsumeCharsNot([Terminator]);
|
|
if not ConsumeChar(Terminator) then begin
|
|
{ Non terminated string found }
|
|
CommitStyleSqPending(stISPPString);
|
|
Break;
|
|
end;
|
|
{ Terminated string found and consumed. Now check if the terminator is actually escaped by doubling, if allowed }
|
|
if not AllowEscapedTerminator or not ConsumeChar(Terminator) then begin
|
|
{ Doubling not allowed or no double terminator found, so we're done }
|
|
CommitStyle(stISPPString);
|
|
Break;
|
|
end;
|
|
{ The terminator was doubled so we should continue to find the real terminator }
|
|
end;
|
|
|
|
end;
|
|
|
|
const
|
|
ISPPReservedWords: array[0..16] of TScintRawString = (
|
|
'private', 'protected', 'public', 'any', 'int',
|
|
'str', 'func', 'option', 'parseroption', 'inlinestart',
|
|
'inlineend', 'message', 'warning', 'error',
|
|
'verboselevel', 'include', 'spansymbol');
|
|
ISPPDirectiveShorthands: TScintRawCharSet =
|
|
[':' {define},
|
|
'x' {undef},
|
|
'+' {include},
|
|
'=' {emit},
|
|
'!' {expr}];
|
|
begin
|
|
var StartIndex := CurIndex;
|
|
var NeedIspp: Boolean;
|
|
if InlineDirective then begin
|
|
ConsumeChar('{');
|
|
NeedIspp := True;
|
|
end else
|
|
NeedIspp := False; { Might be updated later to True later }
|
|
var ForDirectiveExpressionsNext := False;
|
|
var DoIncludeFileNotationCheck := False;
|
|
var ErrorDirective := False;
|
|
ConsumeChar('#');
|
|
CommitStyle(stCompilerDirective);
|
|
|
|
{ Directive name or shorthand }
|
|
SkipWhiteSpace;
|
|
var C := CurChar;
|
|
if ConsumeCharIn(ISPPDirectiveShorthands) then begin
|
|
DoIncludeFileNotationCheck := C = '+'; { We need to check the include file notation }
|
|
NeedIspp := True;
|
|
FinishDirectiveNameOrShorthand(True); { All shorthands require a parameter }
|
|
end else begin
|
|
var S := ConsumeString(ISPPIdentChars);
|
|
for var ISPPDirective in ISPPDirectives do
|
|
if SameRawText(S, ISPPDirective.Name) then begin
|
|
if SameRawText(S, 'error') then
|
|
ErrorDirective := True
|
|
else if SameRawText(S, 'include') then
|
|
DoIncludeFileNotationCheck := True { See above }
|
|
else
|
|
NeedIspp := True; { Built-in preprocessor only supports '#include' }
|
|
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 }
|
|
Inc(OpenCount, ISPPDirective.OpenCountChange);
|
|
if OpenCount < 0 then begin
|
|
CommitStyleSq(stCompilerDirective, True);
|
|
OpenCount := 0; { Reset so that next doesn't automatically gets error as well }
|
|
end;
|
|
FinishDirectiveNameOrShorthand(ISPPDirective.RequiresParameter);
|
|
Break;
|
|
end;
|
|
if InlineDirective then
|
|
CommitStyle(stDefault) { #emit shorthand was used (='#' directly followed by an expression): not an error }
|
|
else
|
|
CommitStyleSqPending(stCompilerDirective);
|
|
end;
|
|
|
|
{ Rest of the directive }
|
|
if ErrorDirective then begin
|
|
SkipWhitespace;
|
|
while not EndOfDirective do begin
|
|
C := CurChar;
|
|
ConsumeChar(C);
|
|
if InlineDirective and (C = '}') then
|
|
CommitStyle(stCompilerDirective)
|
|
else
|
|
CommitStyle(stISPPString);
|
|
end;
|
|
end else begin
|
|
SkipWhitespace;
|
|
while not EndOfDirective do begin
|
|
if DoIncludeFileNotationCheck then begin
|
|
if CurChar <> '"' then begin
|
|
NeedIspp := True; { Built-in preprocessor requires a '"' quoted string after the '#include' and doesn't support anything else }
|
|
if CurChar = '<' then { Check for ISPP's special bracket notation for include files }
|
|
ConsumeISPPString('>', False); { Consume now instead of using regular consumption }
|
|
end;
|
|
DoIncludeFileNotationCheck := False;
|
|
end;
|
|
if CurChar in ISPPIdentFirstChars then begin
|
|
var S := ConsumeString(ISPPIdentChars);
|
|
for var ISPPReservedWord in ISPPReservedWords do
|
|
if SameRawText(S, ISPPReservedWord) then begin
|
|
CommitStyle(stISPPReservedWord);
|
|
Break;
|
|
end;
|
|
CommitStyle(stDefault)
|
|
end else if ConsumeChars(DigitChars) then begin
|
|
if not CurCharIs('.') or not NextCharIs('.') then begin
|
|
if ConsumeChar('.') then
|
|
ConsumeChars(DigitChars);
|
|
C := CurChar;
|
|
if C in ['X', 'x'] then begin
|
|
ConsumeChar(C);
|
|
if not ConsumeChars(HexDigitChars) then
|
|
CommitStyleSqPending(stISPPNumber);
|
|
end;
|
|
ConsumeChars(['L', 'U', 'l', 'u']);
|
|
end;
|
|
CommitStyle(stISPPNumber);
|
|
end else begin
|
|
C := CurChar;
|
|
ConsumeChar(C);
|
|
case C of
|
|
'!', '&', '=', '|', '^', '>', '<', '+', '-', '/', '%', '*',
|
|
'?', ':', ',', '.', '~', '(', '[', '{', ')', ']', '}', '@',
|
|
'#':
|
|
begin
|
|
if (C = '}') and ForDirectiveExpressionsNext then
|
|
ForDirectiveExpressionsNext := False;
|
|
if (C = '/') and ConsumeChar('*') then
|
|
FinishConsumingStarComment
|
|
else if InlineDirective and (C = '}') then
|
|
CommitStyle(stCompilerDirective) (* Closing '}' of the ISPP inline directive *)
|
|
else
|
|
CommitStyle(stSymbol);
|
|
end;
|
|
';':
|
|
begin
|
|
if ForDirectiveExpressionsNext then
|
|
CommitStyle(stSymbol)
|
|
else begin
|
|
if not InlineDirective then
|
|
ConsumeAllRemaining
|
|
else
|
|
ConsumeCharsNot(['}']);
|
|
CommitStyle(stComment);
|
|
end;
|
|
end;
|
|
'''', '"':
|
|
ConsumeISPPString(C, True);
|
|
else
|
|
{ Illegal character }
|
|
CommitStyleSq(stSymbol, True);
|
|
end;
|
|
end;
|
|
SkipWhitespace;
|
|
end;
|
|
end;
|
|
|
|
if NeedIspp and not ISPPInstalled then begin
|
|
if InlineDirective then
|
|
ApplyPendingSquigglyFromToIndex(StartIndex + 1, InlineDirectiveEndIndex - 1)
|
|
else
|
|
ApplyPendingSquigglyFromIndex(StartIndex + 1);
|
|
end;
|
|
end;
|
|
|
|
procedure TInnoSetupStyler.HandleParameterSection(
|
|
const ValidParameters: array of TScintRawString);
|
|
var
|
|
ParamsSpecified: set of 0..31;
|
|
S: TScintRawString;
|
|
I, ParamValueIndex, BraceLevel: Integer;
|
|
NamePresent, ValidName, DuplicateName, ColonPresent: Boolean;
|
|
begin
|
|
ParamsSpecified := [];
|
|
while not EndOfLine do begin
|
|
{ Squigglify any bogus characters before the parameter name }
|
|
SquigglifyUntilChars(AlphaChars + [':'], stDefault);
|
|
|
|
{ Parameter name }
|
|
S := ConsumeString(AlphaDigitChars);
|
|
NamePresent := (S <> '');
|
|
ValidName := False;
|
|
DuplicateName := False;
|
|
for I := Low(ValidParameters) to High(ValidParameters) do
|
|
if SameRawText(S, ValidParameters[I]) then begin
|
|
ValidName := True;
|
|
DuplicateName := (I in ParamsSpecified);
|
|
Include(ParamsSpecified, I);
|
|
Break;
|
|
end;
|
|
if DuplicateName then
|
|
CommitStyleSqPending(stKeyword)
|
|
else if ValidName then
|
|
CommitStyle(stKeyword)
|
|
else
|
|
CommitStyleSqPending(stDefault);
|
|
SkipWhitespace;
|
|
|
|
{ If there's a semicolon with no colon, squigglify the semicolon }
|
|
if ConsumeChar(';') then begin
|
|
CommitStyleSq(stSymbol, True);
|
|
SkipWhitespace;
|
|
Continue;
|
|
end;
|
|
|
|
{ Colon }
|
|
ColonPresent := ConsumeChar(':');
|
|
CommitStyleSq(stSymbol, not NamePresent);
|
|
SkipWhitespace;
|
|
|
|
{ Parameter value. This consumes until a ';' is found or EOL is reached. }
|
|
ParamValueIndex := CurIndex;
|
|
BraceLevel := 0;
|
|
if ConsumeChar('"') then begin
|
|
while True do begin
|
|
StyleConstsUntilChars(['"'], stParameterValue, BraceLevel);
|
|
{ If no closing quote exists, squigglify the whole value and break }
|
|
if not ConsumeChar('"') then begin
|
|
ApplyPendingSquigglyFromIndex(ParamValueIndex);
|
|
Break;
|
|
end;
|
|
{ Quote found, now break, unless there are two quotes in a row }
|
|
if not ConsumeChar('"') then
|
|
Break;
|
|
end;
|
|
end else begin
|
|
while True do begin
|
|
StyleConstsUntilChars([';', '"'], stParameterValue, BraceLevel);
|
|
{ Squigglify any quote characters inside an unquoted string }
|
|
if ConsumeChar('"') then
|
|
ApplySquigglyFromIndex(CurIndex - 1)
|
|
else
|
|
Break;
|
|
end;
|
|
end;
|
|
CommitStyle(stParameterValue);
|
|
if not ColonPresent then
|
|
ApplySquigglyFromIndex(ParamValueIndex);
|
|
{ Squigglify any characters between a quoted string and the next ';' }
|
|
SquigglifyUntilChars([';'], stDefault);
|
|
|
|
{ Semicolon }
|
|
ConsumeChar(';');
|
|
CommitStyle(stSymbol);
|
|
SkipWhitespace;
|
|
end;
|
|
end;
|
|
|
|
procedure TInnoSetupStyler.HandleKeyValueSection(const Section: TInnoSetupStylerSection);
|
|
|
|
procedure StyleMessageArgs;
|
|
begin
|
|
while True do begin
|
|
ConsumeCharsNot(['%']);
|
|
CommitStyle(stDefault);
|
|
if not ConsumeChar('%') then
|
|
Break;
|
|
if CurCharIn(['1'..'9', '%', 'n']) then begin
|
|
ConsumeChar(CurChar);
|
|
CommitStyle(stMessageArg);
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
var
|
|
S: String;
|
|
I, BraceLevel: Integer;
|
|
begin
|
|
{ Squigglify any bogus characters at the start of the line }
|
|
SquigglifyUntilChars(AlphaUnderscoreChars, stDefault);
|
|
if EndOfLine then
|
|
Exit;
|
|
|
|
S := String(ConsumeString(AlphaDigitUnderscoreChars));
|
|
{ Was that a language name? }
|
|
if (Section in [scCustomMessages, scLangOptions, scMessages]) and
|
|
CurCharIs('.') then begin
|
|
CommitStyle(stDefault);
|
|
ConsumeChar('.');
|
|
CommitStyle(stSymbol);
|
|
{ Squigglify any spaces or bogus characters between the '.' and key name }
|
|
if ConsumeCharsNot(AlphaUnderscoreChars) then
|
|
CommitStyleSq(stDefault, True);
|
|
S := String(ConsumeString(AlphaDigitUnderscoreChars));
|
|
end;
|
|
|
|
case Section of
|
|
scCustomMessages:
|
|
I := 0;
|
|
scLangOptions:
|
|
I := GetEnumValue(TypeInfo(TLangOptionsSectionDirective), 'ls' + S);
|
|
scMessages:
|
|
I := GetEnumValue(TypeInfo(TSetupMessageID), 'msg' + S);
|
|
scSetup:
|
|
I := GetEnumValue(TypeInfo(TSetupSectionDirective), 'ss' + S);
|
|
else
|
|
I := -1;
|
|
end;
|
|
if I <> -1 then
|
|
CommitStyle(stKeyword)
|
|
else begin
|
|
if Section in [scLangOptions, scMessages, scSetup] then
|
|
CommitStyleSqPending(stDefault)
|
|
else
|
|
CommitStyle(stDefault);
|
|
end;
|
|
SquigglifyUntilChars(['='], stDefault);
|
|
|
|
ConsumeChar('=');
|
|
CommitStyle(stSymbol);
|
|
SkipWhitespace;
|
|
|
|
if Section in [scCustomMessages, scMessages] then
|
|
StyleMessageArgs
|
|
else begin
|
|
BraceLevel := 0;
|
|
StyleConstsUntilChars([], stDefault, BraceLevel);
|
|
CommitStyle(stDefault);
|
|
end;
|
|
end;
|
|
|
|
class function TInnoSetupStyler.IsCommentOrPascalStringStyle(const Style: TScintStyleNumber): Boolean;
|
|
begin
|
|
Result := Style in [Ord(stComment), Ord(stPascalString)];
|
|
end;
|
|
|
|
class function TInnoSetupStyler.IsParamSection(
|
|
const Section: TInnoSetupStylerSection): Boolean;
|
|
begin
|
|
Result := not (Section in [scCustomMessages, scLangOptions, scMessages, scSetup, scCode]);
|
|
end;
|
|
|
|
class function TInnoSetupStyler.IsSymbolStyle(const Style: TScintStyleNumber): Boolean;
|
|
begin
|
|
Result := Style = Ord(stSymbol);
|
|
end;
|
|
|
|
function TInnoSetupStyler.LineTextSpans(const S: TScintRawString): Boolean;
|
|
var
|
|
I: Integer;
|
|
begin
|
|
{ Note: To match ISPP behavior, require length of at least 3 }
|
|
I := Length(S);
|
|
Result := (I > 2) and (S[I] = '\') and (S[I-1] in WhitespaceChars);
|
|
end;
|
|
|
|
procedure TInnoSetupStyler.PreStyleInlineISPPDirectives;
|
|
|
|
function IsLineCommented: Boolean;
|
|
var
|
|
I: Integer;
|
|
begin
|
|
Result := False;
|
|
for I := 1 to TextLength do begin
|
|
{ In ISPP, only ';' and '//' inhibit processing of inline directives }
|
|
if (Text[I] = ';') or
|
|
((I < TextLength) and (Text[I] = '/') and (Text[I+1] = '/')) then begin
|
|
Result := True;
|
|
Break;
|
|
end;
|
|
if not(Text[I] in WhitespaceChars) then
|
|
Break;
|
|
end;
|
|
end;
|
|
|
|
const
|
|
LineEndChars = [#10, #13];
|
|
var
|
|
I, StartIndex: Integer;
|
|
Valid: Boolean;
|
|
Dummy: ShortInt;
|
|
begin
|
|
{ Style span symbols, then replace them with spaces to prevent any further
|
|
processing }
|
|
for I := 3 to TextLength do begin
|
|
if ((I = TextLength) or (Text[I+1] in LineEndChars)) and
|
|
(Text[I] = '\') and (Text[I-1] in WhitespaceChars) and
|
|
not(Text[I-2] in LineEndChars) then begin
|
|
ReplaceText(I, I, ' ');
|
|
ApplyStyle(Ord(stSymbol), I, I);
|
|
if not ISPPInstalled then
|
|
ApplyStyleByteIndicators([inSquiggly], I, I);
|
|
end;
|
|
end;
|
|
|
|
{ Style all '{#' ISPP inline directives before anything else }
|
|
if not IsLineCommented then begin
|
|
I := 1;
|
|
while I < TextLength do begin
|
|
if (Text[I] = '{') and (Text[I+1] = '#') then begin
|
|
StartIndex := I;
|
|
Valid := False;
|
|
while I <= TextLength do begin
|
|
Inc(I);
|
|
if Text[I-1] = '}' then begin
|
|
Valid := True;
|
|
Break;
|
|
end;
|
|
end;
|
|
ResetCurIndexTo(StartIndex);
|
|
try
|
|
HandleCompilerDirective(True, I - 1, Dummy);
|
|
finally
|
|
ResetCurIndexTo(0);
|
|
end;
|
|
if not Valid then
|
|
ApplyPendingSquigglyFromToIndex(StartIndex, I - 1);
|
|
{ Replace the directive with spaces to prevent any further processing }
|
|
ReplaceText(StartIndex, I - 1, ' ');
|
|
end else
|
|
Inc(I);
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
function TInnoSetupStyler.SectionHasFlag(const Section: TInnoSetupStylerSection;
|
|
const Flag: String): Boolean;
|
|
begin
|
|
Result := FFlagsWords[Section].IndexOf(Flag) <> -1;
|
|
end;
|
|
|
|
function TInnoSetupStyler.HighlightAtCursorAllowed(const Section: TInnoSetupStylerSection;
|
|
const Word: string): Boolean;
|
|
begin
|
|
Result := FNoHighlightAtCursorWords[Section].IndexOf(Word) = -1;
|
|
end;
|
|
|
|
procedure TInnoSetupStyler.SetISPPInstalled(const Value: Boolean);
|
|
begin
|
|
if Value <> FISPPInstalled then begin
|
|
FISPPInstalled := Value;
|
|
BuildConstantsWordList;
|
|
end;
|
|
end;
|
|
|
|
procedure TInnoSetupStyler.SkipWhitespace;
|
|
begin
|
|
ConsumeChars(WhitespaceChars);
|
|
CommitStyle(stDefault);
|
|
end;
|
|
|
|
procedure TInnoSetupStyler.SquigglifyUntilChars(const Chars: TScintRawCharSet;
|
|
const Style: TInnoSetupStylerStyle);
|
|
var
|
|
IsWhitespace: Boolean;
|
|
begin
|
|
{ Consume and squigglify all non-whitespace characters until one of Chars
|
|
is encountered }
|
|
while not EndOfLine and not CurCharIn(Chars) do begin
|
|
IsWhitespace := CurCharIn(WhitespaceChars);
|
|
ConsumeChar(CurChar);
|
|
if IsWhitespace then
|
|
CommitStyle(stDefault)
|
|
else
|
|
CommitStyleSq(Style, True);
|
|
end;
|
|
CommitStyle(stDefault);
|
|
end;
|
|
|
|
procedure TInnoSetupStyler.StyleConstsUntilChars(const Chars: TScintRawCharSet;
|
|
const NonConstStyle: TInnoSetupStylerStyle; var BraceLevel: Integer);
|
|
var
|
|
C: AnsiChar;
|
|
begin
|
|
while not EndOfLine and not CurCharIn(Chars) do begin
|
|
if BraceLevel = 0 then
|
|
CommitStyle(NonConstStyle);
|
|
C := CurChar;
|
|
ConsumeChar(C);
|
|
if C = '{' then begin
|
|
if not ConsumeChar('{') then
|
|
Inc(BraceLevel);
|
|
end;
|
|
if (C = '}') and (BraceLevel > 0) then begin
|
|
Dec(BraceLevel);
|
|
if BraceLevel = 0 then
|
|
CommitStyle(stConstant);
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure TInnoSetupStyler.StyleNeeded;
|
|
|
|
function MapSectionNameString(const S: TScintRawString): TInnoSetupStylerSection;
|
|
begin
|
|
if (S <> '') and (S[1] = '_') then
|
|
Result := scThirdParty
|
|
else begin
|
|
Result := scUnknown;
|
|
for var Section in SectionMap do
|
|
if SameRawText(S, Section.Name) then begin
|
|
Result := Section.Section;
|
|
Break;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
var
|
|
NewLineState: TInnoSetupStylerLineState;
|
|
Section, NewSection: TInnoSetupStylerSection;
|
|
SectionEnd: Boolean;
|
|
S: TScintRawString;
|
|
begin
|
|
NewLineState := TInnoSetupStylerLineState(LineState);
|
|
if NewLineState.NextLineSection <> scNone then begin
|
|
{ Previous line started a section }
|
|
NewLineState.Section := NewLineState.NextLineSection;
|
|
NewLineState.NextLineSection := scNone;
|
|
end;
|
|
Section := NewLineState.Section;
|
|
|
|
PreStyleInlineISPPDirectives;
|
|
|
|
SkipWhitespace;
|
|
if (Section <> scCode) and ConsumeChar(';') then begin
|
|
ConsumeAllRemaining;
|
|
CommitStyle(stComment);
|
|
end else if CurCharIs('/') and NextCharIs('/') then begin
|
|
ConsumeAllRemaining;
|
|
CommitStyleSq(stComment, not ISPPInstalled and (Section <> scCode))
|
|
end else if ConsumeChar('[') then begin
|
|
SectionEnd := ConsumeChar('/');
|
|
S := ConsumeString(AlphaUnderscoreChars);
|
|
if ConsumeChar(']') then begin
|
|
NewSection := MapSectionNameString(S);
|
|
{ Unknown section names and erroneously-placed end tags get squigglified }
|
|
CommitStyleSq(stSection, (NewSection = scUnknown) or
|
|
(SectionEnd and (NewSection <> Section)));
|
|
if not SectionEnd then
|
|
NewLineState.NextLineSection := NewSection;
|
|
end else
|
|
CommitStyleSqPending(stDefault);
|
|
{ Section tags themselves are not associated with any section }
|
|
Section := scNone;
|
|
SquigglifyUntilChars([], stDefault);
|
|
end else if CurCharIs('#') then
|
|
HandleCompilerDirective(False, -1, NewLineState.OpenCompilerDirectivesCount)
|
|
else begin
|
|
case Section of
|
|
scUnknown: ;
|
|
scThirdParty: ;
|
|
scCode: HandleCodeSection(NewLineState.SpanState);
|
|
scComponents: HandleParameterSection(ComponentsSectionParameters);
|
|
scCustomMessages: HandleKeyValueSection(Section);
|
|
scDirs: HandleParameterSection(DirsSectionParameters);
|
|
scISSigKeys: HandleParameterSection(ISSigKeysSectionParameters);
|
|
scFiles: HandleParameterSection(FilesSectionParameters);
|
|
scIcons: HandleParameterSection(IconsSectionParameters);
|
|
scINI: HandleParameterSection(INISectionParameters);
|
|
scInstallDelete: HandleParameterSection(DeleteSectionParameters);
|
|
scLangOptions: HandleKeyValueSection(Section);
|
|
scLanguages: HandleParameterSection(LanguagesSectionParameters);
|
|
scMessages: HandleKeyValueSection(Section);
|
|
scRegistry: HandleParameterSection(RegistrySectionParameters);
|
|
scRun: HandleParameterSection(RunSectionParameters);
|
|
scSetup: HandleKeyValueSection(Section);
|
|
scTasks: HandleParameterSection(TasksSectionParameters);
|
|
scTypes: HandleParameterSection(TypesSectionParameters);
|
|
scUninstallDelete: HandleParameterSection(DeleteSectionParameters);
|
|
scUninstallRun: HandleParameterSection(UninstallRunSectionParameters);
|
|
end;
|
|
end;
|
|
|
|
NewLineState.Section := Section;
|
|
LineState := TScintLineState(NewLineState);
|
|
end;
|
|
|
|
initialization
|
|
SetLength(PascalRealEnumValues, 6);
|
|
PascalRealEnumValues[0] := TypeInfo(TMsgBoxType);
|
|
PascalRealEnumValues[1] := TypeInfo(TSetupMessageID);
|
|
PascalRealEnumValues[2] := TypeInfo(TSetupStep);
|
|
PascalRealEnumValues[3] := TypeInfo(TUninstallStep);
|
|
PascalRealEnumValues[4] := TypeInfo(TSetupProcessorArchitecture);
|
|
PascalRealEnumValues[5] := TypeInfo(TDotNetVersion);
|
|
|
|
end.
|