forked from flosch/pongo2
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathtags_include.go
146 lines (125 loc) · 4.13 KB
/
tags_include.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
package pongo2
type tagIncludeNode struct {
tpl *Template
filenameEvaluator IEvaluator
lazy bool
only bool
filename string
withPairs map[string]IEvaluator
ifExists bool
}
func (node *tagIncludeNode) Execute(ctx *ExecutionContext, writer TemplateWriter) *Error {
// Building the context for the template
includeCtx := make(Context)
// Fill the context with all data from the parent
if !node.only {
includeCtx.Update(ctx.Public)
includeCtx.Update(ctx.Private)
}
// Put all custom with-pairs into the context
for key, value := range node.withPairs {
val, err := value.Evaluate(ctx)
if err != nil {
return err
}
includeCtx[key] = val
}
// Execute the template
if node.lazy {
// Evaluate the filename
filename, err := node.filenameEvaluator.Evaluate(ctx)
if err != nil {
return err
}
if filename.String() == "" {
return ctx.Error("Filename for 'include'-tag evaluated to an empty string.", nil)
}
// Get include-filename
includedFilename := ctx.template.set.resolveFilename(ctx.template, filename.String())
includedTpl, err2 := ctx.template.set.FromFile(includedFilename)
if err2 != nil {
// if this is ReadFile error, and "if_exists" flag is enabled
if node.ifExists && err2.(*Error).Sender == "fromfile" {
return nil
}
return err2.(*Error)
}
err2 = includedTpl.ExecuteWriter(includeCtx, writer)
if err2 != nil {
return err2.(*Error)
}
return nil
}
// Template is already parsed with static filename
err := node.tpl.ExecuteWriter(includeCtx, writer)
if err != nil {
return err.(*Error)
}
return nil
}
type tagIncludeEmptyNode struct{}
func (node *tagIncludeEmptyNode) Execute(ctx *ExecutionContext, writer TemplateWriter) *Error {
return nil
}
func tagIncludeParser(doc *Parser, start *Token, arguments *Parser) (INodeTag, *Error) {
includeNode := &tagIncludeNode{
withPairs: make(map[string]IEvaluator),
}
if filenameToken := arguments.MatchType(TokenString); filenameToken != nil {
// prepared, static template
// "if_exists" flag
ifExists := arguments.Match(TokenIdentifier, "if_exists") != nil
// Get include-filename
includedFilename := doc.template.set.resolveFilename(doc.template, filenameToken.Val)
// Parse the parent
includeNode.filename = includedFilename
includedTpl, err := doc.template.set.FromFile(includedFilename)
if err != nil {
// if this is ReadFile error, and "if_exists" token presents we should create and empty node
if err.(*Error).Sender == "fromfile" && ifExists {
return &tagIncludeEmptyNode{}, nil
}
return nil, err.(*Error).updateFromTokenIfNeeded(doc.template, filenameToken)
}
includeNode.tpl = includedTpl
} else {
// No String, then the user wants to use lazy-evaluation (slower, but possible)
filenameEvaluator, err := arguments.ParseExpression()
if err != nil {
return nil, err.updateFromTokenIfNeeded(doc.template, filenameToken)
}
includeNode.filenameEvaluator = filenameEvaluator
includeNode.lazy = true
includeNode.ifExists = arguments.Match(TokenIdentifier, "if_exists") != nil // "if_exists" flag
}
// After having parsed the filename we're gonna parse the with+only options
if arguments.Match(TokenIdentifier, "with") != nil {
for arguments.Remaining() > 0 {
// We have at least one key=expr pair (because of starting "with")
keyToken := arguments.MatchType(TokenIdentifier)
if keyToken == nil {
return nil, arguments.Error("Expected an identifier", nil)
}
if arguments.Match(TokenSymbol, "=") == nil {
return nil, arguments.Error("Expected '='.", nil)
}
valueExpr, err := arguments.ParseExpression()
if err != nil {
return nil, err.updateFromTokenIfNeeded(doc.template, keyToken)
}
includeNode.withPairs[keyToken.Val] = valueExpr
// Only?
if arguments.Match(TokenIdentifier, "only") != nil {
includeNode.only = true
break // stop parsing arguments because it's the last option
}
}
}
if arguments.Remaining() > 0 {
return nil, arguments.Error("Malformed 'include'-tag arguments.", nil)
}
return includeNode, nil
}
func init() {
RegisterTag("include", tagIncludeParser)
}