feat: move tht to sep rep.
This commit is contained in:
parent
0c7f2d9df0
commit
7052724c13
11 changed files with 2 additions and 631 deletions
2
build.sh
2
build.sh
|
@ -1,4 +1,4 @@
|
||||||
#!/bin/sh
|
#!/bin/sh
|
||||||
#
|
#
|
||||||
go build -o ./exe/ ./cmd/tpp ./cmd/tht
|
go build -o ./exe/ ./cmd/tpp
|
||||||
|
|
||||||
|
|
|
@ -1,97 +0,0 @@
|
||||||
package htmlx
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/d5/tengo/v2"
|
|
||||||
"strings"
|
|
||||||
"html"
|
|
||||||
"fmt"
|
|
||||||
)
|
|
||||||
|
|
||||||
const RawTag = "raw"
|
|
||||||
|
|
||||||
// The type implements basic
|
|
||||||
// way to structrize HTML elements.
|
|
||||||
type Element struct {
|
|
||||||
tengo.ObjectImpl
|
|
||||||
Tag string
|
|
||||||
Attr map[string] string
|
|
||||||
Children []*Element
|
|
||||||
// The value makes sense only if
|
|
||||||
// the tag is the "raw"
|
|
||||||
Content string
|
|
||||||
}
|
|
||||||
|
|
||||||
func (el *Element) TypeName() string {
|
|
||||||
return "*HTMLElement"
|
|
||||||
}
|
|
||||||
|
|
||||||
// The method renders the element to it's
|
|
||||||
// HTML representation.
|
|
||||||
func (el *Element) String() string {
|
|
||||||
if el.Tag == RawTag {
|
|
||||||
return html.EscapeString(el.Content)
|
|
||||||
}
|
|
||||||
|
|
||||||
var b strings.Builder
|
|
||||||
|
|
||||||
fmt.Fprintf(&b, "<%s", el.Tag)
|
|
||||||
for k, v := range el.Attr {
|
|
||||||
fmt.Fprintf(&b, " %s=%q", k, v)
|
|
||||||
}
|
|
||||||
fmt.Fprint(&b, ">")
|
|
||||||
|
|
||||||
for _, child := range el.Children {
|
|
||||||
if child == nil {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
fmt.Fprint(&b, child.String())
|
|
||||||
}
|
|
||||||
|
|
||||||
fmt.Fprintf(&b, "</%s>", el.Tag)
|
|
||||||
return b.String()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (el *Element) Body(els ...*Element) *Element {
|
|
||||||
el.Children = els
|
|
||||||
return el
|
|
||||||
}
|
|
||||||
|
|
||||||
func (el *Element) IndexGet(
|
|
||||||
index tengo.Object,
|
|
||||||
) (tengo.Object, error) {
|
|
||||||
arg, ok := tengo.ToString(index)
|
|
||||||
if !ok {
|
|
||||||
return nil, tengo.ErrInvalidIndexValueType
|
|
||||||
}
|
|
||||||
|
|
||||||
switch arg {
|
|
||||||
case "body" :
|
|
||||||
return &tengo.UserFunction{
|
|
||||||
Name: "Element.Body",
|
|
||||||
Value: func(
|
|
||||||
args ...tengo.Object,
|
|
||||||
) (tengo.Object, error) {
|
|
||||||
s := []*Element{}
|
|
||||||
for _, arg := range args {
|
|
||||||
el, ok := arg.(*Element)
|
|
||||||
if !ok {
|
|
||||||
str, ok := tengo.ToString(arg)
|
|
||||||
if ok {
|
|
||||||
s = append(s, &Element{
|
|
||||||
Tag: RawTag,
|
|
||||||
Content: str,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
s = append(s, el)
|
|
||||||
}
|
|
||||||
return el.Body(s...), nil
|
|
||||||
},
|
|
||||||
}, nil
|
|
||||||
}
|
|
||||||
return nil, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,86 +0,0 @@
|
||||||
package htmlx
|
|
||||||
|
|
||||||
import "github.com/d5/tengo/v2"
|
|
||||||
|
|
||||||
type HTML struct{
|
|
||||||
tengo.ObjectImpl
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
|
|
||||||
html.div({
|
|
||||||
id: "some-el-id",
|
|
||||||
value: "shit value"
|
|
||||||
}).body(
|
|
||||||
html.raw("cock "),
|
|
||||||
html.strong("something")
|
|
||||||
)
|
|
||||||
|
|
||||||
*/
|
|
||||||
|
|
||||||
func (html *HTML) IndexGet(
|
|
||||||
index tengo.Object,
|
|
||||||
) (tengo.Object, error) {
|
|
||||||
str, ok := tengo.ToString(index)
|
|
||||||
if !ok {
|
|
||||||
return nil, tengo.ErrInvalidIndexValueType
|
|
||||||
}
|
|
||||||
|
|
||||||
fn := func(args ...tengo.Object) (tengo.Object, error) {
|
|
||||||
if len(args) > 1 {
|
|
||||||
return nil, tengo.ErrWrongNumArguments
|
|
||||||
}
|
|
||||||
var arg tengo.Object
|
|
||||||
if len(args) == 1 {
|
|
||||||
arg = args[0]
|
|
||||||
}
|
|
||||||
|
|
||||||
if arg == nil {
|
|
||||||
return &Element{
|
|
||||||
Tag: str,
|
|
||||||
}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
if can := arg.CanIterate() ; !can {
|
|
||||||
return nil, tengo.ErrInvalidArgumentType{
|
|
||||||
Name: "first",
|
|
||||||
Expected: "iterable",
|
|
||||||
Found: arg.TypeName(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
attr := map[string] string{}
|
|
||||||
iter := arg.Iterate()
|
|
||||||
for iter.Next() {
|
|
||||||
key, val := iter.Key(), iter.Value()
|
|
||||||
skey, ok := tengo.ToString(key)
|
|
||||||
if !ok {
|
|
||||||
return nil, tengo.ErrInvalidArgumentType{
|
|
||||||
Name: "attribute(key)",
|
|
||||||
Expected: "stringer",
|
|
||||||
Found: key.TypeName(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
sval, ok := tengo.ToString(val)
|
|
||||||
if !ok {
|
|
||||||
return nil, tengo.ErrInvalidArgumentType{
|
|
||||||
Name: "attribute(value)",
|
|
||||||
Expected: "stringer",
|
|
||||||
Found: val.TypeName(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
attr[skey] = sval
|
|
||||||
}
|
|
||||||
return &Element{
|
|
||||||
Tag: str,
|
|
||||||
Attr: attr,
|
|
||||||
}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
return &tengo.UserFunction{
|
|
||||||
Name: str,
|
|
||||||
Value: fn,
|
|
||||||
}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,3 +1,3 @@
|
||||||
#!/bin/sh
|
#!/bin/sh
|
||||||
|
|
||||||
go install ./cmd/tpp/ ./cmd/tht/
|
go install ./cmd/tpp/
|
||||||
|
|
83
mdx/main.go
83
mdx/main.go
|
@ -1,83 +0,0 @@
|
||||||
package mdx
|
|
||||||
import "github.com/gomarkdown/markdown"
|
|
||||||
import "github.com/gomarkdown/markdown/html"
|
|
||||||
import "github.com/gomarkdown/markdown/parser"
|
|
||||||
import "github.com/d5/tengo/v2"
|
|
||||||
import "bytes"
|
|
||||||
|
|
||||||
type Markdown struct {
|
|
||||||
tengo.ObjectImpl
|
|
||||||
MakeParser func() *parser.Parser
|
|
||||||
MakeRenderer func() *html.Renderer
|
|
||||||
}
|
|
||||||
|
|
||||||
func MakeDefaultMarkdown() *Markdown {
|
|
||||||
return &Markdown{
|
|
||||||
MakeParser: MakeDefaultParser,
|
|
||||||
MakeRenderer: MakeDefaultRenderer,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (md *Markdown) TypeName() string {
|
|
||||||
return "*Markdown"
|
|
||||||
}
|
|
||||||
|
|
||||||
func (md *Markdown) String() string {
|
|
||||||
if md == nil {
|
|
||||||
return "<nil>"
|
|
||||||
}
|
|
||||||
return "&Markdown{...}"
|
|
||||||
}
|
|
||||||
|
|
||||||
func (md *Markdown) Render(
|
|
||||||
data []byte,
|
|
||||||
) ([]byte, error) {
|
|
||||||
doc := md.MakeParser().Parse(data)
|
|
||||||
rendered := markdown.Render(doc, md.MakeRenderer())
|
|
||||||
return rendered, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (md *Markdown) CanCall() bool {
|
|
||||||
return md != nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (md *Markdown) Call(
|
|
||||||
args ...tengo.Object,
|
|
||||||
) (tengo.Object, error) {
|
|
||||||
var b bytes.Buffer
|
|
||||||
for _, arg := range args {
|
|
||||||
str, ok := tengo.ToString(arg)
|
|
||||||
if !ok {
|
|
||||||
return nil, tengo.ErrInvalidArgumentType{
|
|
||||||
Name: "v",
|
|
||||||
Expected: "stringer",
|
|
||||||
Found: arg.TypeName(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
b.Write([]byte(str))
|
|
||||||
}
|
|
||||||
|
|
||||||
rendered, err := md.Render(b.Bytes())
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return tengo.FromInterface(rendered)
|
|
||||||
}
|
|
||||||
|
|
||||||
func MakeDefaultParser() *parser.Parser {
|
|
||||||
return parser.NewWithExtensions(
|
|
||||||
parser.CommonExtensions | parser.AutoHeadingIDs |
|
|
||||||
parser.NoEmptyLineBeforeBlock | parser.Attributes |
|
|
||||||
parser.Tables,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
func MakeDefaultRenderer() *html.Renderer {
|
|
||||||
return html.NewRenderer(
|
|
||||||
html.RendererOptions{
|
|
||||||
Flags: html.CommonFlags | html.HrefTargetBlank,
|
|
||||||
},
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,26 +0,0 @@
|
||||||
fmt := import("fmt")
|
|
||||||
paths := import("paths")
|
|
||||||
htmExt := func(c){
|
|
||||||
if c.is_compo {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
c.pp.print(`</body></html>`)
|
|
||||||
}
|
|
||||||
|
|
||||||
exts := {
|
|
||||||
".htm": htmExt,
|
|
||||||
".html": htmExt
|
|
||||||
}
|
|
||||||
|
|
||||||
export func(c){
|
|
||||||
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) {
|
|
||||||
cl(c)
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,40 +0,0 @@
|
||||||
fmt := import("fmt")
|
|
||||||
paths := import("paths")
|
|
||||||
html := import("html").new_render()
|
|
||||||
|
|
||||||
htmExt := func(c){
|
|
||||||
if c.is_compo {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
c.pp.print(`<!doctype html><html>`)
|
|
||||||
|
|
||||||
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(`<body>`)
|
|
||||||
}
|
|
||||||
|
|
||||||
exts := {
|
|
||||||
".htm": htmExt,
|
|
||||||
".html": htmExt
|
|
||||||
}
|
|
||||||
|
|
||||||
export func(c){
|
|
||||||
ext := paths.ext(c.pp.filepath)
|
|
||||||
ext = paths.ext(
|
|
||||||
c.pp.filepath[:len(c.pp.filepath) - len(ext)]
|
|
||||||
)
|
|
||||||
|
|
||||||
cl := exts[ext]
|
|
||||||
if cl {
|
|
||||||
cl(c)
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,51 +0,0 @@
|
||||||
package paths
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/d5/tengo/v2"
|
|
||||||
"path"
|
|
||||||
)
|
|
||||||
|
|
||||||
var Module = &tengo.BuiltinModule {
|
|
||||||
Attrs: moduleMap,
|
|
||||||
}
|
|
||||||
|
|
||||||
var moduleMap = map[string] tengo.Object {
|
|
||||||
"base" : &tengo.UserFunction{
|
|
||||||
Name: "base",
|
|
||||||
Value: wrapOneArg(path.Base),
|
|
||||||
},
|
|
||||||
"ext" : &tengo.UserFunction{
|
|
||||||
Name: "ext",
|
|
||||||
Value: wrapOneArg(path.Ext),
|
|
||||||
},
|
|
||||||
"dir" : &tengo.UserFunction{
|
|
||||||
Name: "dir",
|
|
||||||
Value: wrapOneArg(path.Dir),
|
|
||||||
},
|
|
||||||
"clean" : &tengo.UserFunction{
|
|
||||||
Name: "clean",
|
|
||||||
Value: wrapOneArg(path.Clean),
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
func wrapOneArg(
|
|
||||||
fn func(string) string,
|
|
||||||
) func(...tengo.Object) (tengo.Object, error) {
|
|
||||||
return func(args ...tengo.Object) (tengo.Object, error) {
|
|
||||||
if len(args) != 1 {
|
|
||||||
return nil, tengo.ErrWrongNumArguments
|
|
||||||
}
|
|
||||||
str, ok := tengo.ToString(args[0])
|
|
||||||
if !ok {
|
|
||||||
return nil, tengo.ErrInvalidArgumentType{
|
|
||||||
Name: "first",
|
|
||||||
Expected: "string(compatible)",
|
|
||||||
Found: args[0].TypeName(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return &tengo.String{
|
|
||||||
Value: fn(str),
|
|
||||||
}, nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,4 +0,0 @@
|
||||||
#!/bin/sh
|
|
||||||
#
|
|
||||||
go build -o ./exe/ ./cmd/tht/ && \
|
|
||||||
./exe/tht
|
|
|
@ -1,189 +0,0 @@
|
||||||
package server
|
|
||||||
|
|
||||||
import (
|
|
||||||
//"github.com/d5/tengo/v2"
|
|
||||||
"surdeus.su/util/tpp/mdx"
|
|
||||||
//"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"
|
|
||||||
"context"
|
|
||||||
"path"
|
|
||||||
"mime"
|
|
||||||
"log"
|
|
||||||
"os"
|
|
||||||
"io"
|
|
||||||
)
|
|
||||||
|
|
||||||
var _ = http.Handler(&Handler{})
|
|
||||||
|
|
||||||
// The type describes behaviour
|
|
||||||
// of handling stuff like in PHP.
|
|
||||||
type Handler struct {
|
|
||||||
// THe field represents
|
|
||||||
// where we store site's
|
|
||||||
// source files and request handlers.
|
|
||||||
sourcePath string
|
|
||||||
// Preprocessor must be set by user
|
|
||||||
// to be able to bring custom features in.
|
|
||||||
pp *tpp.Preprocessor
|
|
||||||
// Aditional extension. ".tpp" by default.
|
|
||||||
// For example "file.html.tpp" will be
|
|
||||||
// first preprocessed TPP and sent back as simple HTML.
|
|
||||||
ext string
|
|
||||||
|
|
||||||
// The global map accessable from all the
|
|
||||||
// request so you can keep the states
|
|
||||||
// between requests.
|
|
||||||
global any
|
|
||||||
md *mdx.Markdown
|
|
||||||
indexSuffix string
|
|
||||||
}
|
|
||||||
|
|
||||||
// Returns the new Handler with
|
|
||||||
// specified preprocessor, source path,
|
|
||||||
// preprocessor extension and the global value.
|
|
||||||
func NewHandler(
|
|
||||||
pp *tpp.Preprocessor,
|
|
||||||
src, ext, index string,
|
|
||||||
global any,
|
|
||||||
) *Handler {
|
|
||||||
ret := &Handler{}
|
|
||||||
ret.sourcePath = src
|
|
||||||
ret.ext = ext
|
|
||||||
ret.pp = pp
|
|
||||||
ret.global = global
|
|
||||||
ret.indexSuffix = index
|
|
||||||
return ret
|
|
||||||
}
|
|
||||||
|
|
||||||
// Returns the default tpp.Preprocessor suitable for
|
|
||||||
// the most needs.
|
|
||||||
func DefaultPP(mod string) *tpp.Preprocessor {
|
|
||||||
t := tpp.NewTengo().SetPreCompile(func(
|
|
||||||
ctx context.Context,
|
|
||||||
s *tpp.Script,
|
|
||||||
) {
|
|
||||||
s.SetImportDir(mod)
|
|
||||||
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))
|
|
||||||
}).SetPreCode(func(ctx context.Context) []byte {
|
|
||||||
return []byte(`
|
|
||||||
markdown := func(...args) {
|
|
||||||
pp.write_raw(__markdown__(args...))
|
|
||||||
}
|
|
||||||
__http__ := immutable({
|
|
||||||
request : __http_request__
|
|
||||||
})
|
|
||||||
context.http = __http__
|
|
||||||
context.pp = pp
|
|
||||||
context.global = __global__
|
|
||||||
import("./pre")(context)
|
|
||||||
`)
|
|
||||||
}).SetPostCode(func(ctx context.Context) []byte {
|
|
||||||
return []byte(`
|
|
||||||
import("./post")(context)
|
|
||||||
`)
|
|
||||||
})
|
|
||||||
|
|
||||||
return tpp.New(t)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (h *Handler) SetMD(md *mdx.Markdown) *Handler {
|
|
||||||
h.md = md
|
|
||||||
return h
|
|
||||||
}
|
|
||||||
|
|
||||||
func (h *Handler) ServeHTTP(
|
|
||||||
w http.ResponseWriter,
|
|
||||||
r *http.Request,
|
|
||||||
) {
|
|
||||||
shouldProcess := true
|
|
||||||
urlPath := r.URL.Path
|
|
||||||
// Cleaning URL path to prevent injections.
|
|
||||||
urlPath = path.Clean(urlPath)
|
|
||||||
urlExt := path.Ext(urlPath)
|
|
||||||
|
|
||||||
filePath := filepath.Join(
|
|
||||||
filepath.FromSlash(h.sourcePath),
|
|
||||||
filepath.FromSlash(urlPath),
|
|
||||||
)
|
|
||||||
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 {
|
|
||||||
shouldProcess = false
|
|
||||||
file, err = os.Open(filePath)
|
|
||||||
if err != nil {
|
|
||||||
http.NotFound(w, r)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//process := true
|
|
||||||
fileData, err := io.ReadAll(file)
|
|
||||||
if err != nil {
|
|
||||||
http.NotFound(w, r)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
ctx := context.WithValue(
|
|
||||||
r.Context(),
|
|
||||||
KeyRequest,
|
|
||||||
&httpx.Request{
|
|
||||||
Request: r,
|
|
||||||
},
|
|
||||||
)
|
|
||||||
|
|
||||||
ctx = context.WithValue(
|
|
||||||
ctx,
|
|
||||||
KeyGlobal,
|
|
||||||
h.global,
|
|
||||||
)
|
|
||||||
|
|
||||||
ctx = context.WithValue(
|
|
||||||
ctx,
|
|
||||||
KeyMarkdown,
|
|
||||||
h.md,
|
|
||||||
)
|
|
||||||
|
|
||||||
// Setting before the code to let it change own
|
|
||||||
// content type?
|
|
||||||
contentType := mime.TypeByExtension(urlExt)
|
|
||||||
w.Header().Set("Content-Type", contentType)
|
|
||||||
processedData := fileData
|
|
||||||
if shouldProcess {
|
|
||||||
processedData, err = h.pp.Process(
|
|
||||||
ctx,
|
|
||||||
true,
|
|
||||||
filePathTpp,
|
|
||||||
fileData,
|
|
||||||
)
|
|
||||||
if err != nil {
|
|
||||||
http.NotFound(w, r)
|
|
||||||
log.Printf(
|
|
||||||
"Error: pp.Process(...): %s\n",
|
|
||||||
err,
|
|
||||||
)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
w.Write(processedData)
|
|
||||||
}
|
|
|
@ -1,53 +0,0 @@
|
||||||
package server
|
|
||||||
|
|
||||||
import (
|
|
||||||
|
|
||||||
"github.com/d5/tengo/v2"
|
|
||||||
//"github.com/d5/tengo/v2/stdlib"
|
|
||||||
"surdeus.su/util/tpp/mdx"
|
|
||||||
"surdeus.su/core/cli/mtool"
|
|
||||||
"net/http"
|
|
||||||
"log"
|
|
||||||
//"context"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Context key type for internal usage.
|
|
||||||
type CKey string
|
|
||||||
|
|
||||||
const (
|
|
||||||
KeyRequest CKey = "http-request"
|
|
||||||
KeyGlobal = "global"
|
|
||||||
KeyMarkdown = "markdown"
|
|
||||||
KeyHTML = "html"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Simple PHP-like server implementation.
|
|
||||||
var Tool = mtool.T("tht").Func(func(flags *mtool.Flags) {
|
|
||||||
var (
|
|
||||||
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()
|
|
||||||
|
|
||||||
|
|
||||||
srv := &http.Server{
|
|
||||||
Addr: addr,
|
|
||||||
Handler: NewHandler(
|
|
||||||
DefaultPP(mod),
|
|
||||||
src, ext, index,
|
|
||||||
map[string] tengo.Object{},
|
|
||||||
).SetMD(mdx.MakeDefaultMarkdown()),
|
|
||||||
}
|
|
||||||
|
|
||||||
log.Printf("Listening on %q\n", addr)
|
|
||||||
err := srv.ListenAndServe()
|
|
||||||
if err != nil {
|
|
||||||
log.Printf("Error: srv.ListenAndServe(...): %s\n", err)
|
|
||||||
}
|
|
||||||
})
|
|
Loading…
Reference in a new issue