...
1 package statements
2
3 import (
4
5
6 "fmt"
7 "strings"
8
9 "github.com/noirbizarre/gonja/exec"
10 "github.com/noirbizarre/gonja/nodes"
11 "github.com/noirbizarre/gonja/parser"
12 "github.com/noirbizarre/gonja/tokens"
13 )
14
15 type IfChangedStmt struct {
16 Location *tokens.Token
17 watchedExpr []nodes.Expression
18 lastValues []*exec.Value
19 lastContent string
20 thenWrapper *nodes.Wrapper
21 elseWrapper *nodes.Wrapper
22 }
23
24 func (stmt *IfChangedStmt) Position() *tokens.Token { return stmt.Location }
25 func (stmt *IfChangedStmt) String() string {
26 t := stmt.Position()
27 return fmt.Sprintf("IfChangedStmt(Line=%d Col=%d)", t.Line, t.Col)
28 }
29
30 func (stmt *IfChangedStmt) Execute(r *exec.Renderer, tag *nodes.StatementBlock) error {
31 if len(stmt.watchedExpr) == 0 {
32
33 var out strings.Builder
34 sub := r.Inherit()
35 sub.Out = &out
36 err := sub.ExecuteWrapper(stmt.thenWrapper)
37 if err != nil {
38 return err
39 }
40
41 str := out.String()
42 if stmt.lastContent != str {
43
44 r.WriteString(str)
45 stmt.lastContent = str
46 }
47 } else {
48 nowValues := make([]*exec.Value, 0, len(stmt.watchedExpr))
49 for _, expr := range stmt.watchedExpr {
50 val := r.Eval(expr)
51 if val.IsError() {
52 return val
53 }
54 nowValues = append(nowValues, val)
55 }
56
57
58 changed := len(stmt.lastValues) == 0
59
60 for idx, oldVal := range stmt.lastValues {
61 if !oldVal.EqualValueTo(nowValues[idx]) {
62 changed = true
63 break
64 }
65 }
66
67 stmt.lastValues = nowValues
68
69 if changed {
70
71 err := r.ExecuteWrapper(stmt.thenWrapper)
72 if err != nil {
73 return err
74 }
75 } else {
76
77 err := r.ExecuteWrapper(stmt.elseWrapper)
78 if err != nil {
79 return err
80 }
81 }
82 }
83
84 return nil
85 }
86
87 func ifchangedParser(p *parser.Parser, args *parser.Parser) (nodes.Statement, error) {
88 stmt := &IfChangedStmt{
89 Location: p.Current(),
90 }
91
92 for !args.End() {
93
94 expr, err := args.ParseExpression()
95 if err != nil {
96 return nil, err
97 }
98 stmt.watchedExpr = append(stmt.watchedExpr, expr)
99 }
100
101 if !args.End() {
102 return nil, args.Error("Ifchanged-arguments are malformed.", nil)
103 }
104
105
106 wrapper, endargs, err := p.WrapUntil("else", "endifchanged")
107 if err != nil {
108 return nil, err
109 }
110 stmt.thenWrapper = wrapper
111
112 if !endargs.End() {
113 return nil, endargs.Error("Arguments not allowed here.", nil)
114 }
115
116 if wrapper.EndTag == "else" {
117
118 wrapper, endargs, err = p.WrapUntil("endifchanged")
119 if err != nil {
120 return nil, err
121 }
122 stmt.elseWrapper = wrapper
123
124 if !endargs.End() {
125 return nil, endargs.Error("Arguments not allowed here.", nil)
126 }
127 }
128
129 return stmt, nil
130 }
131
132 func init() {
133 All.Register("ifchanged", ifchangedParser)
134 }
135
View as plain text