Ctrl K
ComunidadGuías…

lua/onthefly/onthefly.go

Rama main · réplica de lectura del repositorio original.

Archivo original ↗Preguntar a KiBot
// Package onthefly provides Lua functions for building HTML, XML and TinySVG documents
package onthefly

import (
	"errors"

	"github.com/sirupsen/logrus"
	lua "github.com/xyproto/gopher-lua"
	"github.com/xyproto/onthefly"
	"github.com/xyproto/tinysvg"
)

const (
	// PageClass is an identifier for the Page class in Lua
	PageClass = "Page"

	// TagClass is an identifier for the Tag class in Lua
	TagClass = "Tag"
)

// Get the first argument, "self", and cast it from userdata to a Tag.
func checkTag(L *lua.LState) *onthefly.Tag {
	ud := L.CheckUserData(1)
	if tag, ok := ud.Value.(*onthefly.Tag); ok {
		return tag
	}
	L.ArgError(1, "Tag expected")
	return nil
}

// Get the first argument, "self", and cast it from userdata to a Page.
func checkPage(L *lua.LState) *onthefly.Page {
	ud := L.CheckUserData(1)
	if page, ok := ud.Value.(*onthefly.Page); ok {
		return page
	}
	L.ArgError(1, "Page expected")
	return nil
}

// pushSelf re-pushes the first argument (self) so that setters can be chained.
// Always returns 1, to be used as the return value of a Lua function.
func pushSelf(L *lua.LState) int {
	L.Push(L.Get(1))
	return 1
}

// pushTag wraps the given Tag in a Lua userdata with the Tag metatable.
// Pushes nil if the given Tag is nil.
func pushTag(L *lua.LState, tag *onthefly.Tag) {
	if tag == nil {
		L.Push(lua.LNil)
		return
	}
	ud := L.NewUserData()
	ud.Value = tag
	L.SetMetatable(ud, L.GetTypeMetatable(TagClass))
	L.Push(ud)
}

// Create a new onthefly.Tag node.
// Logs an error if the given tag name is empty.
// Always returns a Tag userdata.
func constructTag(L *lua.LState) (*lua.LUserData, error) {
	// Use the first argument as the name of the tag
	name := L.ToString(1)
	if name == "" {
		L.ArgError(1, "tag name expected")
		return nil, errors.New("tag name expected")
	}

	// Create a new onthefly.Tag
	tag := onthefly.NewTag(name)

	// Create a new userdata struct
	ud := L.NewUserData()
	ud.Value = tag
	L.SetMetatable(ud, L.GetTypeMetatable(TagClass))
	return ud, nil
}

// Create a new HTML5 onthefly.Page.
func constructHTML5Page(L *lua.LState) (*lua.LUserData, error) {
	// Use the first argument as the title of the page
	title := L.ToString(1)

	// Create a new HTML5 Page
	page := onthefly.NewHTML5Page(title)

	// Create a new userdata struct
	ud := L.NewUserData()
	ud.Value = page
	L.SetMetatable(ud, L.GetTypeMetatable(PageClass))

	return ud, nil
}

// Construct a TinySVG document that is wrapped in a Page-compatible userdata.
// NOTE: tinysvg.Document is a separate type from onthefly.Page, so only
// __tostring works on the returned userdata. Use this for SVG generation only.
func constructTinySVGPage(L *lua.LState) (*lua.LUserData, error) {
	// Use the first arguments as the width and height of the SVG
	w := L.ToInt(1)
	h := L.ToInt(2)
	description := L.ToString(3)

	// Create a new TinySVG Page
	document, svgTag := tinysvg.NewTinySVG(w, h)
	svgTag.Describe(description)

	// Create a new userdata struct
	ud := L.NewUserData()
	ud.Value = document
	L.SetMetatable(ud, L.GetTypeMetatable(PageClass))

	return ud, nil
}

// Create a new onthefly.Page
func constructPage(L *lua.LState) (*lua.LUserData, error) {
	// Use the first argument as the title of the page
	title := L.ToString(1)
	if title == "" {
		L.ArgError(1, "page title expected")
		return nil, errors.New("page title expected")
	}

	// Use the second argument as the name of the root tag
	rootTagName := L.ToString(2)
	if rootTagName == "" {
		L.ArgError(2, "root tag name expected")
		return nil, errors.New("root tag name expected")
	}

	// Create a new onthefly.Page
	page := onthefly.NewPage(title, rootTagName)

	// Create a new userdata struct
	ud := L.NewUserData()
	ud.Value = page
	L.SetMetatable(ud, L.GetTypeMetatable(PageClass))

	return ud, nil
}

// Load makes functions related to onthefly.Page nodes available to the given Lua state
func Load(L *lua.LState) {
	// Register the Page class and the methods that belongs with it.
	metaTablePage := L.NewTypeMetatable(PageClass)
	metaTablePage.RawSetH(lua.LString("__index"), metaTablePage)
	L.SetFuncs(metaTablePage, pageMethods)

	// Register the Tag class and the methods that belongs with it.
	metaTableTag := L.NewTypeMetatable(TagClass)
	metaTableTag.RawSetH(lua.LString("__index"), metaTableTag)
	L.SetFuncs(metaTableTag, tagMethods)

	// The constructor for Page
	L.SetGlobal("Page", L.NewFunction(func(L *lua.LState) int {
		// Construct a new Page
		userdata, err := constructPage(L)
		if err != nil {
			logrus.Error(err)
			L.Push(lua.LString(err.Error()))
			return 1 // Number of returned values
		}

		// Return the Lua Page object
		L.Push(userdata)
		return 1 // number of results
	}))

	// The constructor for HTML5 returns a Page
	L.SetGlobal("HTML5", L.NewFunction(func(L *lua.LState) int {
		// Construct a new Page
		userdata, err := constructHTML5Page(L)
		if err != nil {
			logrus.Error(err)
			L.Push(lua.LString(err.Error()))
			return 1 // Number of returned values
		}

		// Return the Lua Page object
		L.Push(userdata)
		return 1 // number of results
	}))

	// The constructor for TinySVG returns a Page
	L.SetGlobal("TinySVG", L.NewFunction(func(L *lua.LState) int {
		// Construct a new Page
		userdata, err := constructTinySVGPage(L)
		if err != nil {
			logrus.Error(err)
			L.Push(lua.LString(err.Error()))
			return 1 // Number of returned values
		}

		// Return the Lua Page object
		L.Push(userdata)
		return 1 // number of results
	}))

	// The constructor for Tag
	L.SetGlobal("Tag", L.NewFunction(func(L *lua.LState) int {
		// Construct a new Tag
		userdata, err := constructTag(L)
		if err != nil {
			logrus.Error(err)
			L.Push(lua.LString(err.Error()))
			return 1 // Number of returned values
		}

		// Return the Lua Tag object
		L.Push(userdata)
		return 1 // number of results
	}))

}