10 const GO_TEMPLATE = "go"
12 // Called on startup, initialized when the REVEL_BEFORE_MODULES_LOADED is called
14 AddInitEventHandler(func(typeOf Event, value interface{}) (responseOf EventResponse) {
15 if typeOf == REVEL_BEFORE_MODULES_LOADED {
16 RegisterTemplateLoader(GO_TEMPLATE, func(loader *TemplateLoader) (TemplateEngine, error) {
17 // Set the template delimiters for the project if present, then split into left
18 // and right delimiters around a space character
20 TemplateDelims := Config.StringDefault("template.go.delimiters", "")
21 var splitDelims []string
22 if TemplateDelims != "" {
23 splitDelims = strings.Split(TemplateDelims, " ")
24 if len(splitDelims) != 2 {
25 log.Fatalln("app.conf: Incorrect format for template.delimiters")
31 templateSet: template.New("__root__").Funcs(TemplateFuncs),
32 templatesByName: map[string]*GoTemplate{},
33 splitDelims: splitDelims,
41 // Adapter for Go Templates.
42 type GoTemplate struct {
48 // return a 'revel.Template' from Go's template.
49 func (gotmpl GoTemplate) Render(wr io.Writer, arg interface{}) error {
50 return gotmpl.Execute(wr, arg)
53 // The main template engine for Go
54 type GoEngine struct {
55 // The template loader
56 loader *TemplateLoader
57 // THe current template set
58 templateSet *template.Template
59 // A map of templates by name
60 templatesByName map[string]*GoTemplate
61 // The delimiter that is used to indicate template code, defaults to {{
63 // True if map is case insensitive
67 // Convert the path to lower case if needed
68 func (i *GoEngine) ConvertPath(path string) string {
69 if i.CaseInsensitive {
70 return strings.ToLower(path)
75 // Returns true if this engine can handle the response
76 func (i *GoEngine) Handles(templateView *TemplateView) bool {
77 return EngineHandles(i, templateView)
80 // Parses the template vide and adds it to the template set
81 func (engine *GoEngine) ParseAndAdd(baseTemplate *TemplateView) error {
82 // If alternate delimiters set for the project, change them for this set
83 if engine.splitDelims != nil && strings.Index(baseTemplate.Location(), ViewsPath) > -1 {
84 engine.templateSet.Delims(engine.splitDelims[0], engine.splitDelims[1])
86 // Reset to default otherwise
87 engine.templateSet.Delims("", "")
89 templateSource := string(baseTemplate.FileBytes)
90 templateName := engine.ConvertPath(baseTemplate.TemplateName)
91 tpl, err := engine.templateSet.New(baseTemplate.TemplateName).Parse(templateSource)
93 _, line, description := ParseTemplateError(err)
95 Title: "Template Compilation Error",
96 Path: baseTemplate.TemplateName,
97 Description: description,
99 SourceLines: strings.Split(templateSource, "\n"),
102 engine.templatesByName[templateName] = &GoTemplate{Template: tpl, engine: engine, TemplateView: baseTemplate}
106 // Lookups the template name, to see if it is contained in this engine
107 func (engine *GoEngine) Lookup(templateName string) Template {
108 // Case-insensitive matching of template file name
109 if tpl, found := engine.templatesByName[engine.ConvertPath(templateName)]; found {
115 // Return the engine name
116 func (engine *GoEngine) Name() string {
120 // An event listener to listen for Revel INIT events
121 func (engine *GoEngine) Event(action Event, i interface{}) {
122 if action == TEMPLATE_REFRESH_REQUESTED {
123 // At this point all the templates have been passed into the
124 engine.templatesByName = map[string]*GoTemplate{}
125 engine.templateSet = template.New("__root__").Funcs(TemplateFuncs)
126 // Check to see what should be used for case sensitivity
127 engine.CaseInsensitive = Config.BoolDefault("go.template.caseinsensitive", true)