1
0
Fork 0
mirror of https://github.com/Eggbertx/gochan.git synced 2025-08-02 02:36:24 -07:00

Add function to lua for setting custom bbcode tags

This commit is contained in:
Eggbertx 2025-02-09 15:32:57 -08:00
parent 30c1c1c037
commit 5bc47e003d
6 changed files with 137 additions and 13 deletions

View file

@ -0,0 +1,5 @@
local bbcode = require("bbcode")
bbcode.set_tag("rcv", function(node)
return {name="span", attrs={class="rcv"}}
end)

View file

@ -14,6 +14,7 @@ import (
"github.com/gochan-org/gochan/pkg/gctemplates"
"github.com/gochan-org/gochan/pkg/gcutil"
"github.com/gochan-org/gochan/pkg/manage"
"github.com/gochan-org/gochan/pkg/posting"
"github.com/gochan-org/gochan/pkg/posting/geoip"
"github.com/gochan-org/gochan/pkg/posting/uploads"
"github.com/gochan-org/gochan/pkg/server/serverutil"
@ -106,6 +107,7 @@ func preloadLua() {
lState.PreloadModule("manage", manage.PreloadModule)
lState.PreloadModule("uploads", uploads.PreloadModule)
lState.PreloadModule("serverutil", serverutil.PreloadModule)
lState.PreloadModule("bbcode", posting.PreloadBBCodeModule)
lState.SetGlobal("_GOCHAN_VERSION", lua.LString(config.GetVersion().String()))
}

View file

@ -14,14 +14,13 @@ import (
)
var (
msgfmtr *MessageFormatter
msgfmtr MessageFormatter
urlRE = regexp.MustCompile(`https?://(\S+)`)
unsetBBcodeTags = []string{"center", "color", "img", "quote", "size"}
)
// InitPosting prepares the formatter and the temp post pruner
func InitPosting() {
msgfmtr = new(MessageFormatter)
msgfmtr.Init()
go tempCleaner()
}

View file

@ -5,20 +5,17 @@ import (
"github.com/gochan-org/gochan/pkg/config"
"github.com/stretchr/testify/assert"
lua "github.com/yuin/gopher-lua"
)
const (
versionStr = "4.0.0"
bbcodeMsgPreRender = `[b]Bold[/b]
[i]Italics[/i]
[u]Underline[/u]
[url=https://gochan.org]URL[/url]
[code]Code[/code]`
bbcodeMsgExpected = `<b>Bold</b><br>` +
`<i>Italics</i><br>` +
`<u>Underline</u><br>` +
`<a href="https://gochan.org">URL</a><br>` +
`<pre>Code</pre>`
bbcodeMsgPreRender = `[b]Bold[/b] [i]Italics[/i] [u]Underline[/u] [url=https://gochan.org]URL[/url] [?]Spoiler[/?]
[code]Code[/code]
[hide]Hidden[/hide]`
bbcodeMsgExpected = `<b>Bold</b> <i>Italics</i> <u>Underline</u> <a href="https://gochan.org">URL</a> <span class="spoiler">Spoiler</span><br>` +
`<pre>Code</pre><br>` +
`<div class="hideblock hidden">Hidden</div>`
linkTestPreRender = `gochan.org: https://gochan.org
gochan.org with path: https://gochan.org/a
@ -29,6 +26,12 @@ gochan.org with bad link: https://gochan.org/a">:)</a>`
doubleTagPreRender = `[url=https://gochan.org]Gochan[/url] [url]https://gochan.org[/url]`
doubleTagExpected = `<a href="https://gochan.org">Gochan</a> <a href="https://gochan.org">https://gochan.org</a>`
luaBBCodeTest = `local bbcode = require("bbcode")
local msg = "[lua]Lua test[/lua]"
bbcode.set_tag("lua", function(node)
return {name="span", attrs={class="lua"}}
end)`
luaBBCodeTestExpected = `<span class="lua">Lua test</span>`
)
func TestBBCode(t *testing.T) {
@ -50,9 +53,22 @@ func TestLinks(t *testing.T) {
func TestNoDoubleTags(t *testing.T) {
config.SetVersion(versionStr)
msgfmtr = new(MessageFormatter)
msgfmtr.Init()
rendered, err := FormatMessage(doubleTagPreRender, "")
assert.NoError(t, err)
assert.EqualValues(t, doubleTagExpected, rendered)
}
func TestLuaBBCode(t *testing.T) {
config.SetVersion(versionStr)
msgfmtr.Init()
l := lua.NewState()
defer l.Close()
l.PreloadModule("bbcode", PreloadBBCodeModule)
assert.NoError(t, l.DoString(luaBBCodeTest))
compiled := msgfmtr.bbCompiler.Compile("[lua]Lua test[/lua]")
assert.Equal(t, luaBBCodeTestExpected, compiled)
assert.NoError(t, l.DoString(`require("bbcode").set_tag("b", nil)`))
assert.Equal(t, "[b]Lua test[/b]", msgfmtr.bbCompiler.Compile("[b]Lua test[/b]"))
assert.Error(t, l.DoString(`bbcode.set_tag("lua", 1)`))
}

97
pkg/posting/lua.go Normal file
View file

@ -0,0 +1,97 @@
package posting
import (
"fmt"
"github.com/frustra/bbcode"
"github.com/gochan-org/gochan/pkg/gcutil"
lua "github.com/yuin/gopher-lua"
luar "layeh.com/gopher-luar"
)
func luaTableToHTMLTag(l *lua.LState, table *lua.LTable) (*bbcode.HTMLTag, error) {
tag := &bbcode.HTMLTag{
Name: table.RawGetString("name").String(),
}
value := table.RawGetString("value")
if value.Type() != lua.LTNil {
tag.Value = value.String()
}
attrsLV := table.RawGetString("attrs")
switch attrsLV.Type() {
case lua.LTTable:
attrsLT := attrsLV.(*lua.LTable)
fmt.Println("attrs size:", attrsLT.Len())
attrsLT.ForEach(func(key, val lua.LValue) {
if tag.Attrs == nil {
tag.Attrs = make(map[string]string)
}
tag.Attrs[key.String()] = val.String()
})
case lua.LTNil:
default:
return nil, fmt.Errorf("expected table or nil for attrs value, got %s", attrsLV.Type().String())
}
childrenLV := table.RawGetString("children")
switch childrenLV.Type() {
case lua.LTTable:
childrenT := childrenLV.(*lua.LTable)
if childrenT.Len() > 0 {
tag.Children = make([]*bbcode.HTMLTag, childrenT.Len())
childrenT.ForEach(func(iLV, childLV lua.LValue) {
childT, err := luaTableToHTMLTag(l, childLV.(*lua.LTable))
if err != nil {
l.RaiseError("Error converting child table to HTMLTag: %v", err)
return
}
tag.Children[int(iLV.(lua.LNumber)-1)] = childT
})
}
case lua.LTNil:
default:
return nil, fmt.Errorf("expected table or nil for children value, got %s", childrenLV.Type().String())
}
return tag, nil
}
func PreloadBBCodeModule(l *lua.LState) int {
t := l.NewTable()
l.SetFuncs(t, map[string]lua.LGFunction{
"set_tag": func(l *lua.LState) int {
bbcodeTag := l.CheckString(1)
bbCodeLV := l.CheckAny(2)
if bbCodeLV.Type() == lua.LTNil {
msgfmtr.bbCompiler.SetTag(bbcodeTag, nil)
return 0
}
bbcodeFunc := l.CheckFunction(2)
msgfmtr.bbCompiler.SetTag(bbcodeTag, func(node *bbcode.BBCodeNode) (*bbcode.HTMLTag, bool) {
err := l.CallByParam(lua.P{
Fn: bbcodeFunc,
NRet: 2,
}, luar.New(l, node))
if err != nil {
gcutil.LogError(err).Caller().Msg("Error calling bbcode function")
l.RaiseError("Error calling bbcode function: %v", err)
return nil, false
}
tagRet := l.CheckAny(-2)
if tagRet.Type() != lua.LTTable {
l.RaiseError("Invalid return value from bbcode function (expected table)")
return nil, false
}
tagTable := tagRet.(*lua.LTable)
tag, err := luaTableToHTMLTag(l, tagTable)
if err != nil {
gcutil.LogError(err).Caller().Msg("Error converting table to HTMLTag")
l.RaiseError("Error converting table to HTMLTag: %v", err)
return nil, false
}
return tag, true
})
return 0
},
})
l.Push(t)
return 1
}

View file

@ -9,6 +9,11 @@ The following are modules that can be loaded via `require("modulename")`. See [.
- [filepath](https://pkg.go.dev/github.com/vadv/gopher-lua-libs@v0.5.0/filepath)
- [json](https://pkg.go.dev/layeh.com/gopher-json@v0.0.0-20201124131017-552bb3c4c3bf)
- [strings](https://pkg.go.dev/github.com/vadv/gopher-lua-libs@v0.5.0/strings)
## bbcode
- **set_tag(tag string, handler [bbcode.TagCompilerFunc](https://pkg.go.dev/github.com/frustra/bbcode@v0.0.0-20201127003707-6ef347fbe1c8#TagCompilerFunc)))**
- Registers a new BBCode function to handle the given tag. Struct-table fields are expected to use snake case (e.g., name instead of Name)
## config
- **config.system_critical_config()**
- Returns the [SystemCriticalConfig](https://pkg.go.dev/github.com/gochan-org/gochan/pkg/config#SystemCriticalConfig)