Skip to content

Commit a58ab64

Browse files
authored
Merge pull request #109 from xushiwei/q
internal/htmltempl
2 parents fa12101 + db43ff2 commit a58ab64

File tree

7 files changed

+129
-187
lines changed

7 files changed

+129
-187
lines changed

demo/classfile_nestetemplate/gop_autogen.go

Lines changed: 4 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

internal/htmltempl/template.go

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
/*
2+
* Copyright (c) 2023 The GoPlus Authors (goplus.org). All rights reserved.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package htmltempl
18+
19+
import (
20+
"bytes"
21+
"fmt"
22+
"html/template"
23+
"io/fs"
24+
"log"
25+
"path"
26+
"strings"
27+
_ "unsafe"
28+
29+
"github.com/goplus/yap/internal/templ"
30+
)
31+
32+
// Template is the representation of a parsed template. The *parse.Tree
33+
// field is exported only for use by html/template and should be treated
34+
// as unexported by all other clients.
35+
type Template struct {
36+
*template.Template
37+
}
38+
39+
func (p *Template) InitTemplates(fsys fs.FS, delimLeft, delimRight, suffix string) {
40+
tpl, err := parseFS(fsys, delimLeft, delimRight, suffix)
41+
if err != nil {
42+
log.Panicln(err)
43+
}
44+
p.Template = tpl
45+
}
46+
47+
//go:linkname parseFiles html/template.parseFiles
48+
func parseFiles(t *template.Template, readFile func(string) (string, []byte, error), filenames ...string) (*template.Template, error)
49+
50+
func parseFS(fsys fs.FS, delimLeft, delimRight, suffix string) (*template.Template, error) {
51+
pattern := "*" + suffix
52+
filenames, err := fs.Glob(fsys, pattern)
53+
if err != nil {
54+
return nil, err
55+
}
56+
if len(filenames) == 0 {
57+
return nil, fmt.Errorf("template: pattern matches no files: %#q", pattern)
58+
}
59+
t := template.New("").Delims(delimLeft, delimRight)
60+
return parseFiles(t, readFileFS(fsys, delimLeft, delimRight, suffix), filenames...)
61+
}
62+
63+
func readFileFS(fsys fs.FS, delimLeft, delimRight, suffix string) func(string) (string, []byte, error) {
64+
return func(file string) (name string, b []byte, err error) {
65+
name = strings.TrimSuffix(path.Base(file), suffix)
66+
if b, err = fs.ReadFile(fsys, file); err != nil {
67+
return
68+
}
69+
var buf bytes.Buffer
70+
if templ.TranslateEx(&buf, string(b), delimLeft, delimRight) {
71+
b = buf.Bytes()
72+
}
73+
return
74+
}
75+
}

internal/templ/template.go

Lines changed: 26 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -21,15 +21,35 @@ import (
2121
)
2222

2323
func Translate(text string) string {
24+
var b strings.Builder
25+
if TranslateEx(&b, text, "{{", "}}") {
26+
return b.String()
27+
}
28+
return text
29+
}
30+
31+
type iBuilder interface {
32+
Grow(n int)
33+
WriteString(s string) (int, error)
34+
String() string
35+
}
36+
37+
func TranslateEx[Builder iBuilder](b Builder, text, delimLeft, delimRight string) bool {
2438
offs := make([]int, 0, 16)
2539
base := 0
40+
if delimLeft == "" {
41+
delimLeft = "{{"
42+
}
43+
if delimRight == "" {
44+
delimRight = "}}"
45+
}
2646
for {
27-
pos := strings.Index(text[base:], "{{")
47+
pos := strings.Index(text[base:], delimLeft)
2848
if pos < 0 {
2949
break
3050
}
3151
begin := base + pos + 2 // script begin
32-
n := strings.Index(text[begin:], "}}")
52+
n := strings.Index(text[begin:], delimRight)
3353
if n < 0 {
3454
n = len(text) - begin // script length
3555
}
@@ -51,19 +71,19 @@ func Translate(text string) string {
5171
}
5272
n := len(offs)
5373
if n == 0 {
54-
return text
74+
return false
5575
}
56-
var b strings.Builder
5776
b.Grow(len(text) + n*4)
5877
base = 0
78+
delimRightLeft := delimRight + delimLeft
5979
for i := 0; i < n; i++ {
6080
off := offs[i]
6181
b.WriteString(text[base:off])
62-
b.WriteString("}}{{")
82+
b.WriteString(delimRightLeft)
6383
base = off
6484
}
6585
b.WriteString(text[base:])
66-
return b.String()
86+
return true
6787
}
6888

6989
func isSpace(c byte) bool {

internal/templ/template_test.go

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,10 @@
1616

1717
package templ
1818

19-
import "testing"
19+
import (
20+
"bytes"
21+
"testing"
22+
)
2023

2124
const yapScriptIn = `
2225
<html>
@@ -95,4 +98,9 @@ efg
9598
if ret := Translate(noScriptEnd); ret != noScriptEndOut {
9699
t.Fatal("translate(noScriptEnd):", ret)
97100
}
101+
var b bytes.Buffer
102+
TranslateEx(&b, yapScriptIn, "", "")
103+
if b.String() != yapScriptOut {
104+
t.Fatal("TranslateEx:", b.String())
105+
}
98106
}

template.go

Lines changed: 0 additions & 164 deletions
This file was deleted.

yap.go

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ import (
2424
"os"
2525
"strings"
2626

27+
"github.com/goplus/yap/internal/htmltempl"
2728
"github.com/goplus/yap/noredirect"
2829
)
2930

@@ -33,7 +34,9 @@ type Engine struct {
3334
router
3435
Mux *http.ServeMux
3536

36-
tpl *Template
37+
delimLeft, delimRight string
38+
39+
tpl htmltempl.Template
3740
fs fs.FS
3841
las func(addr string, handler http.Handler) error
3942
}
@@ -68,15 +71,6 @@ func (p *Engine) initYapFS(fsys fs.FS) {
6871
p.fs = fsys
6972
}
7073

71-
// Load template
72-
func (p *Engine) loadTemplate() {
73-
t, err := parseFS(NewTemplate(""), p.yapFS(), []string{"*_yap.html"})
74-
if err != nil {
75-
log.Panicln(err)
76-
}
77-
p.tpl = t
78-
}
79-
8074
func (p *Engine) yapFS() fs.FS {
8175
if p.fs == nil {
8276
p.initYapFS(os.DirFS("."))
@@ -163,9 +157,15 @@ func (p *Engine) SetLAS(listenAndServe func(addr string, handler http.Handler) e
163157
p.las = listenAndServe
164158
}
165159

160+
// SetDelims sets the action delimiters to the specified strings. Nested template definitions
161+
// will inherit the settings. An empty delimiter stands for the corresponding default: {{ or }}.
162+
func (p *Engine) SetDelims(left, right string) {
163+
p.delimLeft, p.delimRight = left, right
164+
}
165+
166166
func (p *Engine) templ(path string) *template.Template {
167-
if p.tpl == nil {
168-
p.loadTemplate()
167+
if p.tpl.Template == nil {
168+
p.tpl.InitTemplates(p.yapFS(), p.delimLeft, p.delimRight, "_yap.html")
169169
}
170170
return p.tpl.Lookup(path)
171171
}

0 commit comments

Comments
 (0)