diff --git a/cmd/tht/main.go b/cmd/tht/main.go index 3170fd7..80844f0 100644 --- a/cmd/tht/main.go +++ b/cmd/tht/main.go @@ -1,10 +1,10 @@ package main import ( - "surdeus.su/util/tpp/httpx" + "surdeus.su/util/tpp/server" "os" ) func main() { - httpx.Tool.Run(os.Args[1:]) + server.Tool.Run(os.Args[1:]) } diff --git a/go.mod b/go.mod index 2221189..67794c2 100644 --- a/go.mod +++ b/go.mod @@ -1,9 +1,11 @@ module surdeus.su/util/tpp -go 1.21.7 +go 1.22.3 require ( github.com/d5/tengo/v2 v2.17.0 github.com/gomarkdown/markdown v0.0.0-20240419095408-642f0ee99ae2 - surdeus.su/core/cli v0.0.2 + surdeus.su/core/cli v0.1.2 ) + +require surdeus.su/core/xgo v0.5.0 // indirect diff --git a/go.sum b/go.sum index cac8de3..fb791d2 100644 --- a/go.sum +++ b/go.sum @@ -4,3 +4,7 @@ github.com/gomarkdown/markdown v0.0.0-20240419095408-642f0ee99ae2 h1:yEt5djSYb4i github.com/gomarkdown/markdown v0.0.0-20240419095408-642f0ee99ae2/go.mod h1:JDGcbDT52eL4fju3sZ4TeHGsQwhG9nbDV21aMyhwPoA= surdeus.su/core/cli v0.0.2 h1:RdHHk3/Fhwxz9PjaE+vTlCuF9KmhrmNUb5y4oqulrYI= surdeus.su/core/cli v0.0.2/go.mod h1:UKwCmcSX+x7XX9aF3gOaaAaJcJA3gtUmL4vdnM43+fM= +surdeus.su/core/cli v0.1.2 h1:qPzjawqPyZsO4Z5SaA1u141recVE65yioA83Qs7Jecs= +surdeus.su/core/cli v0.1.2/go.mod h1:r9JtQz3aEJzpYzMaNUNQHJoYkoWKNPi047qhd5uGlmA= +surdeus.su/core/xgo v0.5.0 h1:/Rk3scfFkoSb0qjHRlkUNOp9sr/fd7wAvCiT4fBRo+U= +surdeus.su/core/xgo v0.5.0/go.mod h1:6C/AHbjfvAMvt3TOzLB4eIZ40eU3ahJXtdY+kr4yXoc= diff --git a/httpx/http.go b/httpx/http.go deleted file mode 100644 index 0e441e6..0000000 --- a/httpx/http.go +++ /dev/null @@ -1,2 +0,0 @@ -package httpx - diff --git a/httpx/module.go b/httpx/module.go deleted file mode 100644 index f7a0765..0000000 --- a/httpx/module.go +++ /dev/null @@ -1,24 +0,0 @@ -package httpx - -import "github.com/d5/tengo/v2" -import "github.com/d5/tengo/v2/stdlib" -import "surdeus.su/util/tpp/paths" - -var Modules = map[string]tengo.Importable{ - "paths": paths.Module, -} - -var Stdlib = stdlib.GetModuleMap(stdlib.AllModuleNames()...) - -type ModuleGetter struct{} - -func (m *ModuleGetter) Get( - name string, -) tengo.Importable { - module, exist := Modules[name] - if exist { - return module - } - - return Stdlib.Get(name) -} diff --git a/httpx/request.go b/httpx/request.go deleted file mode 100644 index 8f72830..0000000 --- a/httpx/request.go +++ /dev/null @@ -1,49 +0,0 @@ -package httpx - -import ( - "github.com/d5/tengo/v2" - "net/http" - "io" - //"log" -) - -type Request struct { - tengo.ObjectImpl - *http.Request -} - -func (r *Request) TypeName() string { - return "*http.Request" -} - -func (r *Request) String() string { - return "*http.Request{...}" -} - -func (r *Request) IndexGet( - index tengo.Object, -) (tengo.Object, error) { - key, ok := tengo.ToString(index) - if !ok { - return nil, tengo.ErrInvalidIndexValueType - } - - switch key { - case "url" : - return &URL{ - URL: r.URL, - }, nil - case "body" : - bts, err := io.ReadAll(r.Body) - if err != nil { - return nil, err - } - return &tengo.Bytes{ - Value: bts, - }, nil - } - - // Nothing found. - return nil, nil -} - diff --git a/httpx/url.go b/httpx/url.go deleted file mode 100644 index 1e0727e..0000000 --- a/httpx/url.go +++ /dev/null @@ -1,76 +0,0 @@ -package httpx - -import ( - "github.com/d5/tengo/v2" - "net/url" - "fmt" -) - -var _ = tengo.Object(&Values{}) -type Values struct { - tengo.ObjectImpl - url.Values -} - -func (vs *Values) TypeName() string { - return "*url.Values" -} - -func (vs *Values) String() string { - return fmt.Sprintf("%v", vs.Values) -} - -func (vs *Values) IndexGet( - index tengo.Object, -) (tengo.Object, error) { - key, ok := tengo.ToString(index) - if !ok { - return nil, tengo.ErrInvalidIndexValueType - } - - val, ok := vs.Values[key] - if !ok { - return nil, nil - } - - arr := make([]tengo.Object, len(val)) - for i, v := range val { - arr[i], _ = tengo.FromInterface(v) - } - - return &tengo.Array{Value: arr}, nil -} - -type URL struct { - tengo.ObjectImpl - *url.URL -} - -func (u *URL) TypeName() string { - return "" -} - -func (u *URL) String() string { - return u.URL.String() -} - -func (u *URL) IndexGet( - index tengo.Object, -) (tengo.Object, error) { - key, ok := tengo.ToString(index) - if !ok { - return nil, tengo.ErrInvalidIndexValueType - } - - switch key { - case "path" : - return tengo.FromInterface(u.Path) - case "query" : - return &Values{ - Values: u.Query(), - }, nil - } - - // Nothing found. - return nil, nil -} diff --git a/install.sh b/install.sh new file mode 100755 index 0000000..dc0cd6e --- /dev/null +++ b/install.sh @@ -0,0 +1,3 @@ +#!/bin/sh + +go install ./cmd/tpp/ ./cmd/tht/ diff --git a/main.go b/main.go index 188474c..6237f05 100644 --- a/main.go +++ b/main.go @@ -1,7 +1,6 @@ package tpp import ( - //"fmt" "bytes" "context" ) @@ -31,7 +30,7 @@ func (pp *Preprocessor) Process( filePath string, data []byte, ) ([]byte, error) { - var b bytes.Buffer + //var b bytes.Buffer preCode := []byte(nil) texts := [][]byte{} codes := [][]byte{} @@ -72,15 +71,13 @@ func (pp *Preprocessor) Process( codes = append(codes, code) data = data[idxEnd + len(pp.tags[1]):] - /*if len(data) > 0 && data[0] == '\n' { - data = data[1:] - }*/ } - codeRets, err := pp.tengo.Eval( + ret, err := pp.tengo.Eval( ctx, recompile, filePath, + texts, preCode, codes, ) @@ -88,14 +85,6 @@ func (pp *Preprocessor) Process( return nil, err } - for i := range codeRets { - b.Write(texts[i]) - b.Write(codeRets[i]) - } - if len(texts) > len(codeRets) { - b.Write(texts[len(codeRets)]) - } - - return b.Bytes(), nil + return ret, nil } diff --git a/mod/post.tengo b/mod/post.tengo index f73eb45..c4a439e 100644 --- a/mod/post.tengo +++ b/mod/post.tengo @@ -4,9 +4,8 @@ htmExt := func(c){ if c.is_compo { return } - c.pp.print(` - - `) + + c.pp.print(``) } exts := { @@ -15,8 +14,10 @@ exts := { } export func(c){ - url_path := c.http.request.url.path - ext := paths.ext(url_path) + ext := paths.ext(c.pp.filepath) + ext = paths.ext( + c.pp.filepath[:len(c.pp.filepath) - len(ext)] + ) cl := exts[ext] if !is_undefined(cl) { diff --git a/mod/pre.tengo b/mod/pre.tengo index b62c370..b550388 100644 --- a/mod/pre.tengo +++ b/mod/pre.tengo @@ -1,22 +1,25 @@ fmt := import("fmt") paths := import("paths") +html := import("html").new_render() htmExt := func(c){ if c.is_compo { return } - fmt.println("shit") - c.pp.print(` - - - - `) - if c.title { - c.pp.printf(`%s`, c.title) - } - c.pp.print(` - - `) + c.pp.print(``) + + c.pp.print(html.head().body( + func(){ + if c.title { + return html.title().body(c.title) + } + }(), + html.script({ + src: `https://unpkg.com/htmx.org@1.9.2` + }) + )) + + c.pp.print(``) } exts := { @@ -25,8 +28,10 @@ exts := { } export func(c){ - url_path := c.http.request.url.path - ext := paths.ext(url_path) + ext := paths.ext(c.pp.filepath) + ext = paths.ext( + c.pp.filepath[:len(c.pp.filepath) - len(ext)] + ) cl := exts[ext] if cl { diff --git a/httpx/handler.go b/server/handler.go similarity index 87% rename from httpx/handler.go rename to server/handler.go index 9358f3e..daa2408 100644 --- a/httpx/handler.go +++ b/server/handler.go @@ -1,9 +1,11 @@ -package httpx +package server import ( //"github.com/d5/tengo/v2" "surdeus.su/util/tpp/mdx" - "surdeus.su/util/tpp/htmlx" + //"surdeus.su/core/xgo/xmodules/htmlx" + "surdeus.su/core/xgo/xmodules/httpx" + "surdeus.su/core/xgo/xmodules" "surdeus.su/util/tpp" "path/filepath" "net/http" @@ -37,7 +39,7 @@ type Handler struct { // between requests. global any md *mdx.Markdown - html *htmlx.HTML + indexSuffix string } // Returns the new Handler with @@ -45,7 +47,7 @@ type Handler struct { // preprocessor extension and the global value. func NewHandler( pp *tpp.Preprocessor, - src, ext string, + src, ext, index string, global any, ) *Handler { ret := &Handler{} @@ -53,6 +55,7 @@ func NewHandler( ret.ext = ext ret.pp = pp ret.global = global + ret.indexSuffix = index return ret } @@ -64,26 +67,23 @@ func DefaultPP(mod string) *tpp.Preprocessor { s *tpp.Script, ) { s.SetImportDir(mod) - s.SetImports(&ModuleGetter{}) + s.SetImports(xmodules.Modules) s.EnableFileImport(true) s.Add("__http_request__", ctx.Value(KeyRequest)) s.Add("__global__", ctx.Value(KeyGlobal)) s.Add("__markdown__", ctx.Value(KeyMarkdown)) - s.Add("__html__", ctx.Value(KeyHTML)) }).SetPreCode(func(ctx context.Context) []byte { return []byte(` markdown := func(...args) { pp.write_raw(__markdown__(args...)) } - http := immutable({ + __http__ := immutable({ request : __http_request__ }) - html := __html__ - context.http = http + context.http = __http__ context.pp = pp context.global = __global__ - context.html = html import("./pre")(context) `) }).SetPostCode(func(ctx context.Context) []byte { @@ -99,10 +99,6 @@ func (h *Handler) SetMD(md *mdx.Markdown) *Handler { h.md = md return h } -func (h *Handler) SetHTML(html *htmlx.HTML) *Handler { - h.html = html - return h -} func (h *Handler) ServeHTTP( w http.ResponseWriter, @@ -118,8 +114,17 @@ func (h *Handler) ServeHTTP( filepath.FromSlash(h.sourcePath), filepath.FromSlash(urlPath), ) - filePathTpp := filePath + h.ext + fileStat, err := os.Stat(filePath) + if err == nil { + if fileStat.IsDir() { + filePath = filepath.Join( + filePath, + h.indexSuffix, + ) + } + } + filePathTpp := filePath + h.ext //log.Println("pth:", urlPath, filePathTpp) file, err := os.Open(filePathTpp) if err != nil { @@ -141,7 +146,7 @@ func (h *Handler) ServeHTTP( ctx := context.WithValue( r.Context(), KeyRequest, - &Request{ + &httpx.Request{ Request: r, }, ) @@ -158,17 +163,10 @@ func (h *Handler) ServeHTTP( h.md, ) - ctx = context.WithValue( - ctx, - KeyHTML, - h.html, - ) - // Setting before the code to let it change own - // content type. + // content type? contentType := mime.TypeByExtension(urlExt) w.Header().Set("Content-Type", contentType) - processedData := fileData if shouldProcess { processedData, err = h.pp.Process( diff --git a/httpx/tool.go b/server/tool.go similarity index 88% rename from httpx/tool.go rename to server/tool.go index 08a60f9..24cebfc 100644 --- a/httpx/tool.go +++ b/server/tool.go @@ -1,4 +1,4 @@ -package httpx +package server import ( @@ -24,13 +24,14 @@ const ( // Simple PHP-like server implementation. var Tool = mtool.T("tht").Func(func(flags *mtool.Flags) { var ( - addr, ext, src, mod string + addr, ext, src, mod, index string ) flags.StringVar(&addr, "addr", ":3000", "address to serve at") flags.StringVar(&mod, "mod", "./mod", "path to store Tengo modules") flags.StringVar(&src, "src", "./src", "directory with source files") flags.StringVar(&ext, "ext", ".tpp", "extension for TPP files") + flags.StringVar(&index, "index", "index.htm", "index file name") flags.Parse() @@ -39,7 +40,7 @@ var Tool = mtool.T("tht").Func(func(flags *mtool.Flags) { Addr: addr, Handler: NewHandler( DefaultPP(mod), - src, ext, + src, ext, index, map[string] tengo.Object{}, ).SetMD(mdx.MakeDefaultMarkdown()), } diff --git a/src/check.htm.tpp b/src/check.htm.tpp new file mode 100644 index 0000000..6674cd9 --- /dev/null +++ b/src/check.htm.tpp @@ -0,0 +1,5 @@ +
shit
+{{ + pp.print("cock") +}} +
later
diff --git a/src/check/index.htm.tpp b/src/check/index.htm.tpp new file mode 100644 index 0000000..ee4255e --- /dev/null +++ b/src/check/index.htm.tpp @@ -0,0 +1,12 @@ +{{# + html := import("html").new_render() +}} +{{ +h := html.main().body( + html.p().body( + "some paragraph shit" + ) +) + +pp.print(h) +}} diff --git a/src/incorrect.htm.tpp b/src/incorrect.htm.tpp new file mode 100644 index 0000000..0f67522 --- /dev/null +++ b/src/incorrect.htm.tpp @@ -0,0 +1,11 @@ +html := import("html").new_render() + +pp.print(html.html().body( + html.head().body( + html.title().body( + "some title" + ) + ), + html.body().body( + ) +)) diff --git a/src/index.htm.tpp b/src/index.htm.tpp new file mode 100644 index 0000000..2e4c875 --- /dev/null +++ b/src/index.htm.tpp @@ -0,0 +1,78 @@ +{{# + context.title = "The example.site main page" + + fmt := import("fmt") + html := import("html").new_render() +}} + +

This is the example page for the THT

+{{ + /*if !context.global.int { + context.global.int = 0 + } else { + context.global.int++ + }*/ + + if !context.global.val { + context.global.val = 1 + } else { + context.global.val += 1 + } + fmt.println("global: ", context.global) + req := context.http.request + q := req.url.query + // List checking. + list := [] + rng := int(q.range[0]) + fmt.println("range:", q.range) + if rng { + pp.print(`") + } + if q.name { + pp.print("
", q.name[0], "
") + } +}} +
+ {{ pp.print(context.global.val) }} +
+
+ Hello, Cock! +
+
+ {{ + pp.print(req.url.path) + }} +
+ + +{{ + vals := ["die", "with", "them", "as", "you", 1, "could", "do"] + pp.print(html.div({ + id: "the-uniq-shit" + }).body( + html.ul( + ).body( + func(){ + ret := [] + for i:=0 ; i + +
diff --git a/src/main.htm.tpp b/src/main.htm.tpp index 437e465..b0febe7 100644 --- a/src/main.htm.tpp +++ b/src/main.htm.tpp @@ -1,27 +1,31 @@ {{# context.title = "The example.site main page" + + fmt := import("fmt") + html := import("html").new_render() }}

This is the example page for the THT

{{ - /*if !context.global.int { - context.global.int = 0 - } else { - context.global.int++ - }*/ + pp.print( + html.h1().body("This is the example page for THT") + ) - fmt := import("fmt") if !context.global.val { context.global.val = 1 } else { context.global.val += 1 } - fmt.println("global: ", context.global) - req := http.request + + req + ("global: ", context.global) +}} + +{{ + req := context.http.request q := req.url.query // List checking. - list := [] rng := int(q.range[0]) fmt.println("range:", q.range) if rng { @@ -35,43 +39,3 @@ pp.print("
", q.name[0], "
") } }} -
- {{ pp.print(context.global.val) }} -
-
- Hello, Cock! -
-
- {{ - pp.print(req.url.path) - }} -
- - -{{ - vals := ["die", "with", "them", "as", "you", 1, "could", "do"] - pp.print(html.div({ - id: "the-uniq-shit" - }).body( - html.ul( - ).body( - func(){ - ret := [] - for i:=0 ; i - -
diff --git a/src/page.htm.tpp b/src/page.htm.tpp index 9bedc46..f9fb15f 100644 --- a/src/page.htm.tpp +++ b/src/page.htm.tpp @@ -16,7 +16,7 @@ This is the markdown example shit. And even more text -> Cheap is talk, show the code. +> Cheap is talk, show me the code. (c) Linus Torvalds diff --git a/tengo.go b/tengo.go index a1c8c59..b2a6acc 100644 --- a/tengo.go +++ b/tengo.go @@ -48,39 +48,30 @@ func (pp *Tengo) Eval( ctx context.Context, recompile bool, filePath string, + texts [][]byte, preCode []byte, codes [][]byte, -) ([][]byte, error) { - var fullCodeBuf bytes.Buffer +) ([]byte, error) { + var fullCodeBuf, retBuf bytes.Buffer const retHead = ` context := {} - __ret_one__ := bytes("") pp := immutable({ - filepath: __filepath__, - printf : func(format, ...vals) { - __ret_one__ += __sprintf__(format, vals...) - }, - - print : func(...vals) { - __ret_one__ += __sprint__(vals...) - }, - println : func(...vals) { - __ret_one__ += __sprintln__(vals...) - }, - write_raw : func(bts) { - __ret_one__ += bytes(bts) - } + filepath: __pp_filepath__, + printf : __pp_printf__, + print : __pp_print__, + println : __pp_println__, + write_raw : __pp_write_raw__ }) ` const retSeparator = ` - __separate__(__ret_one__) - __ret_one__ = "" + __separate__() ` - rets := [][]byte{} + //rets := [][]byte{} fmt.Fprint(&fullCodeBuf, retHead) + if preCode != nil { fmt.Fprintln( &fullCodeBuf, @@ -93,12 +84,22 @@ func (pp *Tengo) Eval( fullCodeBuf.Write([]byte(retSeparator)) } - for _, code := range codes { + for i, code := range codes { + fmt.Fprintf( + &fullCodeBuf, + "\n__pp_write_raw__(%q)\n", + texts[i], + ) fmt.Fprintln( &fullCodeBuf, "\n" + string(code) + retSeparator, ) } + fmt.Fprintf( + &fullCodeBuf, + "\n__pp_write_raw__(%q)\n", + texts[len(texts)-1], + ) if pp.postCode != nil { fullCodeBuf.Write(pp.postCode(ctx)) @@ -110,8 +111,8 @@ func (pp *Tengo) Eval( pp.preCompile(ctx, script) } - script.Add("__filepath__", filePath) - script.Add("__sprintf__", &tengo.UserFunction{ + script.Add("__pp_filepath__", filePath) + script.Add("__pp_printf__", &tengo.UserFunction{ Value: func(args ...tengo.Object) (tengo.Object, error){ if len(args) < 1 { return nil, tengo.ErrWrongNumArguments @@ -127,41 +128,64 @@ func (pp *Tengo) Eval( gargs[i] = tengo.ToInterface(args[i+1]) //fmt.Printf("shit: %q\n", gargs[i]) } - str := fmt.Sprintf(format, gargs...) - return tengo.FromInterface([]byte(str)) + fmt.Fprintf(&retBuf, format, gargs...) + return nil, nil + //return tengo.FromInterface([]byte(str)) }, }) - script.Add("__sprint__", &tengo.UserFunction{ + script.Add("__pp_print__", &tengo.UserFunction{ Value: func(args ...tengo.Object) (tengo.Object, error){ gargs := make([]any, len(args)) for i := range gargs { gargs[i] = tengo.ToInterface(args[i]) } - str := fmt.Sprint(gargs...) - return tengo.FromInterface([]byte(str)) + fmt.Fprint(&retBuf, gargs...) + return nil, nil + //return tengo.FromInterface([]byte(str)) }, }) - script.Add("__sprintln__", &tengo.UserFunction{ + script.Add("__pp_println__", &tengo.UserFunction{ Value: func(args ...tengo.Object) (tengo.Object, error){ gargs := make([]any, len(args)) for i := range gargs { gargs[i] = tengo.ToInterface(args[i]) } - str := fmt.Sprintln(gargs...) - return tengo.FromInterface([]byte(str)) + fmt.Fprintln(&retBuf, gargs...) + return nil, nil + //return tengo.FromInterface([]byte(str)) + }, + }) + script.Add("__pp_write_raw__", &tengo.UserFunction{ + Value: func(args ...tengo.Object) (tengo.Object, error){ + bt := make([][]byte, len(args)) + for i, o := range args { + bts, ok := tengo.ToByteSlice(o) + if !ok { + return nil, tengo.ErrInvalidArgumentType{ + Expected: "string/bytes", + } + } + bt[i] = bts + } + for _, b := range bt { + retBuf.Write(b) + } + return nil, nil }, }) script.Add("__separate__", &tengo.UserFunction{ Value: func(args ...tengo.Object) (tengo.Object, error){ - if len(args) < 1 { + return nil, nil + /*if len(args) < 1 { return nil, tengo.ErrWrongNumArguments } bts, ok := tengo.ToByteSlice(args[0]) if !ok { return nil, tengo.ErrInvalidArgumentType{ } - } - rets = append(rets, bts) + }*/ + //rets = append(rets, retBuf.Bytes()) + //retBuf.Reset() return nil, nil }, }) @@ -171,5 +195,5 @@ func (pp *Tengo) Eval( return nil, err } - return rets, nil + return retBuf.Bytes(), nil }