tmpl: fix doubling templates folder path and enhancements (#9029)

pull/9036/head
Anton Zavodchikov 2021-03-01 14:15:59 +05:00 committed by GitHub
parent 15896beace
commit 506041a15b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 113 additions and 47 deletions

View File

@ -80,14 +80,15 @@ fn (mut p Parser) comp_call() ast.ComptimeCall {
} }
p.check(.lpar) p.check(.lpar)
spos := p.tok.position() spos := p.tok.position()
s := if is_html { '' } else { p.tok.lit } literal_string_param := if is_html { '' } else { p.tok.lit }
path_of_literal_string_param := literal_string_param.replace('/', os.path_separator)
if !is_html { if !is_html {
p.check(.string) p.check(.string)
} }
p.check(.rpar) p.check(.rpar)
// $embed_file('/path/to/file') // $embed_file('/path/to/file')
if is_embed_file { if is_embed_file {
mut epath := s mut epath := path_of_literal_string_param
// Validate that the epath exists, and that it is actually a file. // Validate that the epath exists, and that it is actually a file.
if epath == '' { if epath == '' {
p.error_with_pos('supply a valid relative or absolute file path to the file to embed', p.error_with_pos('supply a valid relative or absolute file path to the file to embed',
@ -119,7 +120,7 @@ fn (mut p Parser) comp_call() ast.ComptimeCall {
scope: 0 scope: 0
is_embed: true is_embed: true
embed_file: ast.EmbeddedFile{ embed_file: ast.EmbeddedFile{
rpath: s rpath: literal_string_param
apath: epath apath: epath
} }
} }
@ -127,10 +128,12 @@ fn (mut p Parser) comp_call() ast.ComptimeCall {
// Compile vweb html template to V code, parse that V code and embed the resulting V function // Compile vweb html template to V code, parse that V code and embed the resulting V function
// that returns an html string. // that returns an html string.
fn_path := p.cur_fn_name.split('_') fn_path := p.cur_fn_name.split('_')
tmpl_path := if is_html { '${fn_path.last()}.html' } else { s } fn_path_joined := fn_path.join(os.path_separator)
compiled_vfile_path := os.real_path(p.scanner.file_path.replace('/', os.path_separator))
tmpl_path := if is_html { '${fn_path.last()}.html' } else { path_of_literal_string_param }
// Looking next to the vweb program // Looking next to the vweb program
dir := os.dir(p.scanner.file_path.replace('/', os.path_separator)) dir := os.dir(compiled_vfile_path)
mut path := os.join_path(dir, fn_path.join(os.path_separator)) mut path := os.join_path(dir, fn_path_joined)
path += '.html' path += '.html'
path = os.real_path(path) path = os.real_path(path)
if !is_html { if !is_html {
@ -139,7 +142,7 @@ fn (mut p Parser) comp_call() ast.ComptimeCall {
if !os.exists(path) { if !os.exists(path) {
// can be in `templates/` // can be in `templates/`
if is_html { if is_html {
path = os.join_path(dir, 'templates', fn_path.join('/')) path = os.join_path(dir, 'templates', fn_path_joined)
path += '.html' path += '.html'
} }
if !os.exists(path) { if !os.exists(path) {
@ -152,10 +155,10 @@ fn (mut p Parser) comp_call() ast.ComptimeCall {
} }
// println('path is now "$path"') // println('path is now "$path"')
} }
if p.pref.is_verbose {
println('>>> compiling comptime template file "$path"')
}
tmp_fn_name := p.cur_fn_name.replace('.', '__') tmp_fn_name := p.cur_fn_name.replace('.', '__')
$if trace_comptime ? {
println('>>> compiling comptime template file "$path" for $tmp_fn_name')
}
v_code := tmpl.compile_file(path, tmp_fn_name) v_code := tmpl.compile_file(path, tmp_fn_name)
$if print_vweb_template_expansions ? { $if print_vweb_template_expansions ? {
lines := v_code.split('\n') lines := v_code.split('\n')
@ -167,12 +170,12 @@ fn (mut p Parser) comp_call() ast.ComptimeCall {
start_pos: 0 start_pos: 0
parent: p.global_scope parent: p.global_scope
} }
if p.pref.is_verbose { $if trace_comptime ? {
println('\n\n') println('')
println('>>> vweb template for $path:') println('>>> vweb template for $path:')
println(v_code) println(v_code)
println('>>> end of vweb template END') println('>>> end of vweb template END')
println('\n\n') println('')
} }
mut file := parse_comptime(v_code, p.table, p.pref, scope, p.global_scope) mut file := parse_comptime(v_code, p.table, p.pref, scope, p.global_scope)
file = ast.File{ file = ast.File{
@ -207,7 +210,7 @@ fn (mut p Parser) comp_call() ast.ComptimeCall {
is_vweb: true is_vweb: true
vweb_tmpl: file vweb_tmpl: file
method_name: n method_name: n
args_var: s args_var: literal_string_param
} }
} }

View File

@ -1,9 +1,9 @@
name: @name name: @name
age: @age age: @age
numbers: @numbers numbers: @numbers
@for number in numbers @for number in numbers
@number @number
@end @end
@include 'inner.txt'

View File

@ -0,0 +1,17 @@
@for i in 0..10
${i*2} - $i
@end
@for key, val in downloads
${key}, downloaded $val times.
@end
@if !ignored
this is ignored
@else
this is not ignored
@end
@if true
so, it's basically true
@end

View File

@ -2,40 +2,84 @@ fn one() string {
name := 'Peter' name := 'Peter'
age := 25 age := 25
numbers := [1, 2, 3] numbers := [1, 2, 3]
return $tmpl('tmpl/1.txt') downloads := map{
'vlang/ui': '3201'
'vlang/vtl': '123'
}
ignored := true
return $tmpl('tmpl/base.txt')
} }
fn test_tmpl() { fn test_tmpl() {
assert one().trim_space() == 'name: Peter assert one().trim_space() == "name: Peter
age: 25 age: 25
numbers: [1, 2, 3] numbers: [1, 2, 3]
1 1
2 2
3
3'
0 - 0
2 - 1
4 - 2
6 - 3
8 - 4
10 - 5
12 - 6
14 - 7
16 - 8
18 - 9
vlang/ui, downloaded 3201 times.
vlang/vtl, downloaded 123 times.
this is not ignored
so, it's basically true"
} }
fn test_tmpl_in_anon_fn() { fn test_tmpl_in_anon_fn() {
anon := fn (name string, age int, numbers []int) string { anon := fn (name string, age int, numbers []int, downloads map[string]string, ignored bool) string {
return $tmpl('tmpl/1.txt')
return $tmpl('tmpl/base.txt')
} }
println(anon('Peter', 25, [1, 2, 3])) assert anon('Peter', 25, [1, 2, 3], map{
assert anon('Peter', 25, [1, 2, 3]).trim_space() == 'name: Peter 'vlang/ui': '3201'
'vlang/vtl': '123'
}, true).trim_space() == "name: Peter
age: 25 age: 25
numbers: [1, 2, 3] numbers: [1, 2, 3]
1 1
2 2
3
3'
0 - 0
2 - 1
4 - 2
6 - 3
8 - 4
10 - 5
12 - 6
14 - 7
16 - 8
18 - 9
vlang/ui, downloaded 3201 times.
vlang/vtl, downloaded 123 times.
this is not ignored
so, it's basically true"
} }

View File

@ -30,16 +30,16 @@ pub fn compile_template(basepath string, html_ string, fn_name string) string {
mut html := html_.trim_space() mut html := html_.trim_space()
mut header := '' mut header := ''
mut footer := '' mut footer := ''
if os.exists('templates/header.html') && html.contains('@header') { if os.exists(os.join_path(basepath, 'header.html')) && html.contains('@header') {
h := os.read_file('templates/header.html') or { h := os.read_file(os.join_path(basepath, 'header.html')) or {
panic('reading file templates/header.html failed') panic('reading file ${os.join_path(basepath, 'header.html')} failed')
} }
header = h.trim_space().replace("'", '"') header = h.trim_space().replace("'", '"')
html = header + html html = header + html
} }
if os.exists('templates/footer.html') && html.contains('@footer') { if os.exists(os.join_path(basepath, 'footer.html')) && html.contains('@footer') {
f := os.read_file('templates/footer.html') or { f := os.read_file(os.join_path(basepath, 'footer.html')) or {
panic('reading file templates/footer.html failed') panic('reading file ${os.join_path(basepath, 'footer.html')} failed')
} }
footer = f.trim_space().replace("'", '"') footer = f.trim_space().replace("'", '"')
html += footer html += footer
@ -82,22 +82,18 @@ _ = footer
file_ext = '.html' file_ext = '.html'
} }
file_name = file_name.replace(file_ext, '') file_name = file_name.replace(file_ext, '')
mut templates_folder := os.join_path(basepath, 'templates') // relative path, starting with the current folder
if file_name.contains('/') { mut templates_folder := os.real_path(basepath)
if file_name.starts_with('/') { if file_name.contains('/') && file_name.starts_with('/') {
// absolute path // an absolute path
templates_folder = '' templates_folder = ''
} else {
// relative path, starting with the current folder
templates_folder = os.real_path(basepath)
}
} }
file_path := os.real_path(os.join_path(templates_folder, '$file_name$file_ext')) file_path := os.real_path(os.join_path(templates_folder, '$file_name$file_ext'))
$if trace_tmpl ? { $if trace_tmpl ? {
eprintln('>>> basepath: "$basepath" , fn_name: "$fn_name" , @include line: "$line" , file_name: "$file_name" , file_ext: "$file_ext" , templates_folder: "$templates_folder" , file_path: "$file_path"') eprintln('>>> basepath: "$basepath" , fn_name: "$fn_name" , @include line: "$line" , file_name: "$file_name" , file_ext: "$file_ext" , templates_folder: "$templates_folder" , file_path: "$file_path"')
} }
file_content := os.read_file(file_path) or { file_content := os.read_file(file_path) or {
panic('Vweb: Reading file $file_name failed.') panic('Vweb: reading file $file_name from path: $file_path failed.')
} }
file_splitted := file_content.split_into_lines().reverse() file_splitted := file_content.split_into_lines().reverse()
for f in file_splitted { for f in file_splitted {
@ -120,10 +116,16 @@ _ = footer
s.writeln('if ' + line[pos + 4..] + '{') s.writeln('if ' + line[pos + 4..] + '{')
s.writeln(tmpl.str_start) s.writeln(tmpl.str_start)
} else if line.contains('@end') { } else if line.contains('@end') {
// Remove new line byte
s.go_back(1)
s.writeln(tmpl.str_end) s.writeln(tmpl.str_end)
s.writeln('}') s.writeln('}')
s.writeln(tmpl.str_start) s.writeln(tmpl.str_start)
} else if line.contains('@else') { } else if line.contains('@else') {
// Remove new line byte
s.go_back(1)
s.writeln(tmpl.str_end) s.writeln(tmpl.str_end)
s.writeln(' } else { ') s.writeln(' } else { ')
s.writeln(tmpl.str_start) s.writeln(tmpl.str_start)
@ -155,7 +157,7 @@ _ = footer
} else { } else {
// HTML, may include `@var` // HTML, may include `@var`
// escaped by cgen, unless it's a `vweb.RawHtml` string // escaped by cgen, unless it's a `vweb.RawHtml` string
s.writeln(line.replace('@', '$').replace("'", '"')) s.writeln(line.replace('@', '$').replace('$$', '@').replace("'", "\\'"))
} }
} }
s.writeln(tmpl.str_end) s.writeln(tmpl.str_end)