Skip to content

Commit

Permalink
Merge pull request #206 from sempare/whitespace
Browse files Browse the repository at this point in the history
Simpler whitespace support #147
  • Loading branch information
darnocian authored Sep 23, 2024
2 parents 29c830f + a5d2b25 commit 0b50a46
Show file tree
Hide file tree
Showing 17 changed files with 1,469 additions and 1,004 deletions.
49 changes: 43 additions & 6 deletions demo/SempareTemplatePlayground/Sempare.Template.PlaygroundForm.pas
Original file line number Diff line number Diff line change
Expand Up @@ -136,11 +136,13 @@ TFormTemplateEnginePlayground = class(TForm)
procedure butExtractVarsClick(Sender: TObject);
private
{ Private declarations }
FLastContent: string;
FEncoding: TEncoding;
FContext: ITemplateContext;
FTemplate: ITemplate;
FFilename: string;
Finit: boolean;
FInit: boolean;
FForce: boolean;
procedure Process;
procedure GridPropsToContext;
procedure WriteTmpHtml;
Expand Down Expand Up @@ -248,21 +250,29 @@ procedure TFormTemplateEnginePlayground.butSaveClick(Sender: TObject);
procedure TFormTemplateEnginePlayground.cbConvertTabsToSpacesClick(Sender: TObject);
begin
SetOption(cbConvertTabsToSpaces.Checked, eoConvertTabsToSpaces);
FForce := true;
Eval;
end;

procedure TFormTemplateEnginePlayground.cbEvalEarlyClick(Sender: TObject);
begin
SetOption(cbEvalEarly.Checked, eoEvalEarly);
FForce := true;
Eval;
end;

procedure TFormTemplateEnginePlayground.cbEvalVarsEarlyClick(Sender: TObject);
begin
SetOption(cbEvalVarsEarly.Checked, eoEvalVarsEarly);
FForce := true;
Eval;
end;

procedure TFormTemplateEnginePlayground.cbFlattenTemplateClick(Sender: TObject);
begin
SetOption(cbFlattenTemplate.Checked, eoFlattenTemplate);
FForce := true;
Eval;
end;

function DefaultEncoder(const AValue: string): string;
Expand All @@ -276,6 +286,7 @@ procedure TFormTemplateEnginePlayground.cbHtmlClick(Sender: TObject);
FContext.UseHtmlVariableEncoder
else
FContext.VariableEncoder := DefaultEncoder;
FForce := true;
Eval;
end;

Expand All @@ -284,26 +295,36 @@ procedure TFormTemplateEnginePlayground.cbOptimiseTemplateClick(Sender: TObject)
SetOption(cbOptimiseTemplate.Checked, eoOptimiseTemplate);
if cbOptimiseTemplate.Checked then
cbFlattenTemplate.Checked := true;
FForce := true;
Eval;
end;

procedure TFormTemplateEnginePlayground.cbRaiseErrorWhenVariableNotFoundClick(Sender: TObject);
begin
SetOption(cbRaiseErrorWhenVariableNotFound.Checked, eoRaiseErrorWhenVariableNotFound);
FForce := true;
Eval;
end;

procedure TFormTemplateEnginePlayground.cbStripRecurringNewlinesClick(Sender: TObject);
begin
SetOption(cbStripRecurringNewlines.Checked, eoStripRecurringNewlines);
FForce := true;
Eval;
end;

procedure TFormTemplateEnginePlayground.cbStripRecurringSpacesClick(Sender: TObject);
begin
SetOption(cbStripRecurringSpaces.Checked, eoStripRecurringSpaces);
FForce := true;
Eval;
end;

procedure TFormTemplateEnginePlayground.cbTrimLinesClick(Sender: TObject);
begin
SetOption(cbTrimLines.Checked, eoTrimLines);
FForce := true;
Eval;
end;

procedure TFormTemplateEnginePlayground.cbUseCustomScriptTagsClick(Sender: TObject);
Expand All @@ -320,12 +341,15 @@ procedure TFormTemplateEnginePlayground.cbUseHtmlBRClick(Sender: TObject);
FContext.NewLine := '<br>'#13#10
else
FContext.NewLine := #13#10;
FForce := true;
Eval;
end;

procedure TFormTemplateEnginePlayground.cmbCustomScriptTagsChange(Sender: TObject);
begin
cbUseCustomScriptTags.Checked := true;
SetScriptTags(cmbCustomScriptTags.ItemIndex);
FForce := true;
Eval;
end;

Expand All @@ -336,7 +360,13 @@ procedure TFormTemplateEnginePlayground.Eval;
try
if FFilename <> '' then
butSave.Enabled := true;
FTemplate := Template.Parse(FContext, memoTemplate.Lines.Text);

if FForce or (FLastContent <> memoTemplate.Lines.Text) then
begin
FTemplate := Template.Parse(FContext, memoTemplate.Lines.Text);
FLastContent := memoTemplate.Lines.Text;
end;

Process;
// this is a hack so that app does not throw an exception
// during shutdown. it seems that the webbrowser must be visible
Expand Down Expand Up @@ -366,15 +396,22 @@ procedure TFormTemplateEnginePlayground.cbSetEncodingClick(Sender: TObject);
end
else
FEncoding := TEncoding.UTF8WithoutBOM;
FForce := true;
Eval;
end;

procedure TFormTemplateEnginePlayground.cbShowWhitespaceClick(Sender: TObject);
begin
if cbShowWhitespace.Checked then
FContext.WhitespaceChar := #183
begin
if cbHtml.Checked then
FContext.WhitespaceChar := '&bull;'
else
FContext.WhitespaceChar := #183
end
else
FContext.WhitespaceChar := ' ';
FForce := true;
Eval;
end;

Expand All @@ -396,7 +433,7 @@ procedure TFormTemplateEnginePlayground.FormCreate(Sender: TObject);
WebBrowser1.Enabled := true;
tsGithubHelp.TabVisible := false;
wbHelp.Enabled := false; // Doesn't work on github at this stage
// wbHelp.Navigate('https://github.com/sempare/sempare-delphi-template-engine#Introduction');
// wbHelp.Navigate('https://github.com/sempare/sempare-delphi-template-engine#Introduction');
{$IF defined(RELEASE)}
FContext.MaxRunTimeMs := 5000;
{$ENDIF}
Expand Down Expand Up @@ -453,7 +490,7 @@ procedure TFormTemplateEnginePlayground.FormCreate(Sender: TObject);
' ' + #13#10 + //
' If you like this project, please consider supporting enhancements via a commercial license which also entitles you to priority support.<p> ' + #13#10;

Finit := true;
FInit := true;
end;

procedure TFormTemplateEnginePlayground.GridPropsToContext;
Expand Down Expand Up @@ -519,7 +556,7 @@ procedure TFormTemplateEnginePlayground.Process;
end;

begin
if not Finit then
if not FInit then
exit;
GridPropsToContext;
LPrettyOk := false;
Expand Down
46 changes: 31 additions & 15 deletions src/Sempare.Template.AST.pas
Original file line number Diff line number Diff line change
Expand Up @@ -56,8 +56,7 @@ ETemplate = class(Exception);

TStripAction = ( //
saWhitespace, //
saNL, //
saKeepOneSpace //
saNL //
);

TStripActionSet = set of TStripAction;
Expand Down Expand Up @@ -150,10 +149,8 @@ ETemplate = class(Exception);
vsBlock, //

vsNewLine, //
vsWhiteSpace, //
vsWhiteSpace //

vsSingleton, //
vsValidate //
);

TTemplateSymbolSet = set of TTemplateSymbol;
Expand Down Expand Up @@ -201,9 +198,13 @@ ETemplate = class(Exception);
['{8C539211-ED84-4963-B894-C569C2F7B2FE}']
end;

TParserOption = (poAllowEnd, poAllowElse, poAllowElIf, poHasElse, poInLoop, poStripNL, poStripWS, poStripRecurringNL);
TParserOptions = set of TParserOption;

IStmt = interface(ITemplateVisitorHost)
['{6D37028E-A0C0-41F1-8A59-EDC0C9ADD9C7}']
function Flatten: TArray<IStmt>;
procedure OptimiseTemplate(const AOptions: TParserOptions; const ANewLine: string);
function GetHasEnd: boolean;
property HasEnd: boolean read GetHasEnd;
end;
Expand All @@ -214,22 +215,19 @@ ETemplate = class(Exception);
property Stmt: IStmt read GetStmt;
end;

TParserOption = (poAllowEnd, poAllowElse, poAllowElIf, poHasElse, poInLoop, poStripNL, poStripWS);
TParserOptions = set of TParserOption;

ITemplate = interface(ITemplateVisitorHost)
['{93AAB971-5B4B-4959-93F2-6C7DAE15C91B}']
function GetItem(const AOffset: integer): IStmt;
function GetCount: integer;
function GetLastItem: IStmt;
procedure FlattenTemplate;
procedure OptimiseTemplate(const AOptions: TParserOptions);
procedure OptimiseTemplate(const AOptions: TParserOptions; const ANewLine: string);
property Items[const AOffset: integer]: IStmt read GetItem;
property Count: integer read GetCount;
property LastItem: IStmt read GetLastItem;
end;

TAddLocation = (alLast, alBeforeNL, alAfterNL);
TAddLocation = (alLast, alFront);

ITemplateAdd = interface(ITemplate)
['{64465D68-0E9D-479F-9EF3-A30E75967809}']
Expand Down Expand Up @@ -260,7 +258,7 @@ ETemplate = class(Exception);
['{FB4CC3AB-BFEC-4189-B555-153DDA490D15}']
end;

TStripDirection = (sdEnd, sdLeft, sdRight, sdBeforeNewLine, sdAfterNewLine);
TStripDirection = (sdLeft, sdRight);

IStripStmt = interface(IStmt)
['{3313745B-D635-4453-9808-660DC462E15C}']
Expand Down Expand Up @@ -369,6 +367,16 @@ ETemplate = class(Exception);
property Container: ITemplate read GetContainer;
end;

IIgnoreNLStmt = interface(IStmt)
function GetContainer: ITemplate;
property Container: ITemplate read GetContainer;
end;

IIgnoreWSStmt = interface(IStmt)
function GetContainer: ITemplate;
property Container: ITemplate read GetContainer;
end;

ILoopStmt = interface(IStmt)
['{D6C26A41-3250-4EB9-A776-8952DE3931BD}']
function GetOnBeginContainer: ITemplate;
Expand Down Expand Up @@ -580,7 +588,10 @@ ETemplate = class(Exception);
procedure Visit(const AStmt: IBlockStmt); overload;
procedure Visit(const AStmt: IExtendsStmt); overload;
procedure Visit(const AStmt: ICompositeStmt); overload;
procedure Visit(const AStmt: INoopStmt); overload;
procedure Visit(const AStmt: IStripStmt); overload;
procedure Visit(const AStmt: IIgnoreNLStmt); overload;
procedure Visit(const AStmt: IIgnoreWSStmt); overload;
end;

IEvaluationTemplateVisitor = interface(ITemplateVisitor)
Expand Down Expand Up @@ -614,6 +625,7 @@ TAbstractStmt = class abstract(TAbstractBase, IStmt)
protected
function Flatten: TArray<IStmt>; virtual;
function GetHasEnd: boolean; virtual;
procedure OptimiseTemplate(const AOptions: TParserOptions; const ANewLine: string); virtual;
public
constructor Create(const APosition: IPosition);
end;
Expand All @@ -632,12 +644,11 @@ TMapExpr = class(TAbstractExpr, IMapExpr)

const
StripDirectionStr: array [TStripDirection] of string = ( //
'sdEnd', 'sdLeft', 'sdRight', 'sdBeforeNewLine', 'sdAfterNewLine');
'sdLeft', 'sdRight' //
);

StripActionStr: array [TStripAction] of string = ( //
'saWhitespace', //
'saNL', //
'saKeepOneSpace' //
'saWhitespace', 'saNL' //
);

type
Expand Down Expand Up @@ -744,4 +755,9 @@ function TAbstractStmt.GetHasEnd: boolean;
exit(false);
end;

procedure TAbstractStmt.OptimiseTemplate(const AOptions: TParserOptions; const ANewLine: string);
begin

end;

end.
20 changes: 8 additions & 12 deletions src/Sempare.Template.Context.pas
Original file line number Diff line number Diff line change
Expand Up @@ -169,8 +169,8 @@ interface
procedure SetPrettyPrintOutput(const APrettyPrintOutput: TPrettyPrintOutput);
function GetPrettyPrintOutput: TPrettyPrintOutput;

function GetWhitespace: char;
procedure SetWhiteSpace(const AWS: char);
function GetWhitespace: string;
procedure SetWhiteSpace(const AWS: string);

function GetVariableResolver: TTemplateVariableResolver;
procedure SetVariableResolver(const AResolver: TTemplateVariableResolver);
Expand All @@ -181,7 +181,7 @@ interface
property RttiContext: TGetRttiContext read GetRttiContext write SetRttiContext;
property Functions: ITemplateFunctions read GetFunctions write SetFunctions;
property NewLine: string read GetNewLine write SetNewLine;
property WhitespaceChar: char read GetWhitespace write SetWhiteSpace;
property WhitespaceChar: string read GetWhitespace write SetWhiteSpace;
property TemplateResolver: TTemplateResolver read GetTemplateResolver write SetTemplateResolver;
property TemplateResolverWithContext: TTemplateResolverWithContext read GetTemplateResolverWithContext write SetTemplateResolverWithContext;
property MaxRunTimeMs: integer read GetMaxRunTimeMs write SetMaxRunTimeMs;
Expand Down Expand Up @@ -227,8 +227,6 @@ function CreateTemplateContext(const AOptions: TTemplateEvaluationOptions = []):
GUTF8WithoutPreambleEncoding: TUTF8WithoutPreambleEncoding;
GStreamWriterProvider: TStreamWriterProvider;
GPrettyPrintOutput: TPrettyPrintOutput;
GDefaultOpenStripWSTag: string = '<|';
GDefaultCloseWSTag: string = '|>';

implementation

Expand Down Expand Up @@ -286,7 +284,7 @@ TTemplateContext = class(TInterfacedObject, ITemplateContext, ITemplateContext
FFormatSettings: TFormatSettings;
FDebugFormat: string;
FPrettyPrintOutput: TPrettyPrintOutput;
FWhiteSpace: char;
FWhiteSpace: string;
FVariableResolver: TTemplateVariableResolver;
FRttiContext: TGetRttiContext;
public
Expand Down Expand Up @@ -376,8 +374,8 @@ TTemplateContext = class(TInterfacedObject, ITemplateContext, ITemplateContext
function GetDebugErrorFormat: string;
procedure SetDebugErrorFormat(const AFormat: string);

function GetWhitespace: char;
procedure SetWhiteSpace(const AWS: char);
function GetWhitespace: string;
procedure SetWhiteSpace(const AWS: string);

function GetVariableResolver: TTemplateVariableResolver;
procedure SetVariableResolver(const AResolver: TTemplateVariableResolver);
Expand Down Expand Up @@ -438,8 +436,6 @@ constructor TTemplateContext.Create(const AOptions: TTemplateEvaluationOptions);
SetEncoding(GDefaultEncoding);
FStartToken := GDefaultOpenTag;
FEndToken := GDefaultCloseTag;
FStartStripToken := GDefaultOpenStripWSTag;
FEndStripToken := GDefaultCloseWSTag;
FTemplates := TDictionary<string, ITemplate>.Create;
FVariables := TTemplateVariables.Create;
FFunctions := CreateTemplateFunctions(self);
Expand Down Expand Up @@ -579,7 +575,7 @@ function TTemplateContext.GetVariables: ITemplateVariables;
exit(FVariables);
end;

function TTemplateContext.GetWhitespace: char;
function TTemplateContext.GetWhitespace: string;
begin
exit(FWhiteSpace);
end;
Expand Down Expand Up @@ -738,7 +734,7 @@ procedure TTemplateContext.SetVariableResolver(const AResolver: TTemplateVariabl
FVariableResolver := AResolver;
end;

procedure TTemplateContext.SetWhiteSpace(const AWS: char);
procedure TTemplateContext.SetWhiteSpace(const AWS: string);
begin
FWhiteSpace := AWS;
end;
Expand Down
Loading

0 comments on commit 0b50a46

Please sign in to comment.