summaryrefslogtreecommitdiffstats
path: root/tpl/template.go
blob: c5a6a44c0c41332950286162fda437f74b18f1aa (plain)
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
// Copyright 2019 The Hugo Authors. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package tpl

import (
	"io"
	"reflect"
	"regexp"

	"github.com/gohugoio/hugo/output"

	texttemplate "github.com/gohugoio/hugo/tpl/internal/go_templates/texttemplate"
)

// TemplateManager manages the collection of templates.
type TemplateManager interface {
	TemplateHandler
	TemplateFuncGetter
	AddTemplate(name, tpl string) error
	MarkReady() error
}

// TemplateVariants describes the possible variants of a template.
// All of these may be empty.
type TemplateVariants struct {
	Language     string
	OutputFormat output.Format
}

// TemplateFinder finds templates.
type TemplateFinder interface {
	TemplateLookup
	TemplateLookupVariant
}

// UnusedTemplatesProvider lists unused templates if the build is configured to track those.
type UnusedTemplatesProvider interface {
	UnusedTemplates() []FileInfo
}

// TemplateHandler finds and executes templates.
type TemplateHandler interface {
	TemplateFinder
	Execute(t Template, wr io.Writer, data interface{}) error
	LookupLayout(d output.LayoutDescriptor, f output.Format) (Template, bool, error)
	HasTemplate(name string) bool
}

type TemplateLookup interface {
	Lookup(name string) (Template, bool)
}

type TemplateLookupVariant interface {
	// TODO(bep) this currently only works for shortcodes.
	// We may unify and expand this variant pattern to the
	// other templates, but we need this now for the shortcodes to
	// quickly determine if a shortcode has a template for a given
	// output format.
	// It returns the template, if it was found or not and if there are
	// alternative representations (output format, language).
	// We are currently only interested in output formats, so we should improve
	// this for speed.
	LookupVariant(name string, variants TemplateVariants) (Template, bool, bool)
	LookupVariants(name string) []Template
}

// Template is the common interface between text/template and html/template.
type Template interface {
	Name() string
	Prepare() (*texttemplate.Template, error)
}

// TemplateParser is used to parse ad-hoc templates, e.g. in the Resource chain.
type TemplateParser interface {
	Parse(name, tpl string) (Template, error)
}

// TemplateParseFinder provides both parsing and finding.
type TemplateParseFinder interface {
	TemplateParser
	TemplateFinder
}

// TemplateDebugger prints some debug info to stdout.
type TemplateDebugger interface {
	Debug()
}

// templateInfo wraps a Template with some additional information.
type templateInfo struct {
	Template
	Info
}

// templateInfo wraps a Template with some additional information.
type templateInfoManager struct {
	Template
	InfoManager
}

// TemplatesProvider as implemented by deps.Deps.
type TemplatesProvider interface {
	Tmpl() TemplateHandler
	TextTmpl() TemplateParseFinder
}

// WithInfo wraps the info in a template.
func WithInfo(templ Template, info Info) Template {
	if manager, ok := info.(InfoManager); ok {
		return &templateInfoManager{
			Template:    templ,
			InfoManager: manager,
		}
	}

	return &templateInfo{
		Template: templ,
		Info:     info,
	}
}

var baseOfRe = regexp.MustCompile("template: (.*?):")

func extractBaseOf(err string) string {
	m := baseOfRe.FindStringSubmatch(err)
	if len(m) == 2 {
		return m[1]
	}
	return ""
}

// TemplateFuncGetter allows to find a template func by name.
type TemplateFuncGetter interface {
	GetFunc(name string) (reflect.Value, bool)
}