diff --git a/Taskfile.yaml b/Taskfile.yaml index 5c5caae..264e7d5 100644 --- a/Taskfile.yaml +++ b/Taskfile.yaml @@ -13,12 +13,22 @@ vars: tasks: default: + cmds: + - go build {{.GOFLAGS}} + vars: + GOFLAGS: '-ldflags "-s -w -X main.dataDir={{.LIBDIR}} -X main.gitCommit=$(git rev-parse --short HEAD) -X main.gitBranch=$(git rev-parse --abbrev-ref HEAD)"' + + default-nocgo: cmds: - CGO_ENABLED=0 go build {{.GOFLAGS}} vars: GOFLAGS: '-ldflags "-s -w -X main.dataDir={{.LIBDIR}} -X main.gitCommit=$(git rev-parse --short HEAD) -X main.gitBranch=$(git rev-parse --abbrev-ref HEAD)"' build: + cmds: + - go build {{.GOFLAGS}} + + build-nocgo: cmds: - CGO_ENABLED=0 go build {{.GOFLAGS}} diff --git a/api.go b/api.go index 61aac21..142e410 100644 --- a/api.go +++ b/api.go @@ -166,6 +166,9 @@ func hilbishLoad(rtm *rt.Runtime) (rt.Value, func()) { util.SetField(rtm, versionModule, "release", rt.StringValue(releaseName)) mod.Set(rt.StringValue("version"), rt.TableValue(versionModule)) + pluginModule := moduleLoader(rtm) + mod.Set(rt.StringValue("module"), rt.TableValue(pluginModule)) + return rt.TableValue(fakeMod), nil } diff --git a/cmd/docgen/docgen.go b/cmd/docgen/docgen.go index aae6202..cbe6baa 100644 --- a/cmd/docgen/docgen.go +++ b/cmd/docgen/docgen.go @@ -417,7 +417,7 @@ func main() { f, _ := os.Create(docPath) f.WriteString(fmt.Sprintf(header, modOrIface, modname, modu.ShortDescription)) - typeTag, _ := regexp.Compile(`@\w+`) + typeTag, _ := regexp.Compile(`\B@\w+`) modDescription := typeTag.ReplaceAllStringFunc(strings.Replace(modu.Description, "<", `\<`, -1), func(typ string) string { typName := typ[1:] typLookup := typeTable[strings.ToLower(typName)] diff --git a/docs/api/hilbish/hilbish.module.md b/docs/api/hilbish/hilbish.module.md new file mode 100644 index 0000000..e88ac2c --- /dev/null +++ b/docs/api/hilbish/hilbish.module.md @@ -0,0 +1,53 @@ +--- +title: Interface hilbish.module +description: native module loading +layout: doc +menu: + docs: + parent: "API" +--- + +## Introduction + +The hilbish.module interface provides a function to load +Hilbish plugins/modules. Hilbish modules are Go-written +plugins (see https://pkg.go.dev/plugin) that are used to add functionality +to Hilbish that cannot be written in Lua for any reason. + +Note that you don't ever need to use the load function that is here as +modules can be loaded with a `require` call like Lua C modules, and the +search paths can be changed with the `paths` property here. + +To make a valid native module, the Go plugin has to export a Loader function +with a signature like so: `func(*rt.Runtime) rt.Value`. + +`rt` in this case refers to the Runtime type at +https://pkg.go.dev/github.com/arnodel/golua@master/runtime#Runtime + +Hilbish uses this package as its Lua runtime. You will need to read +it to use it for a native plugin. + +Here is some code for an example plugin: +```go +package main + +import ( + rt "github.com/arnodel/golua/runtime" +) + +func Loader(rtm *rt.Runtime) rt.Value { + return rt.StringValue("hello world!") +} +``` + +This can be compiled with `go build -buildmode=plugin plugin.go`. +If you attempt to require and print the result (`print(require 'plugin')`), it will show "hello world!" + +## Interface fields +- `paths`: A list of paths to search when loading native modules. This is in the style of Lua search paths and will be used when requiring native modules. Example: `?.so;?/?.so` + +## Functions +### load(path) +Loads a module at the designated `path`. +It will throw if any error occurs. + diff --git a/emmyLuaDocs/hilbish.lua b/emmyLuaDocs/hilbish.lua index 9646b8e..2ee93ed 100644 --- a/emmyLuaDocs/hilbish.lua +++ b/emmyLuaDocs/hilbish.lua @@ -220,6 +220,10 @@ function hilbish.jobs:start() end --- Stops the job from running. function hilbish.jobs:stop() end +--- Loads a module at the designated `path`. +--- It will throw if any error occurs. +function hilbish.module.load(path) end + --- Runs a command in Hilbish's shell script interpreter. --- This is the equivalent of using `source`. --- @param cmd string diff --git a/go.mod b/go.mod index c17d906..1549f76 100644 --- a/go.mod +++ b/go.mod @@ -5,7 +5,6 @@ go 1.17 require ( github.com/arnodel/golua v0.0.0-20220221163911-dfcf252b6f86 github.com/blackfireio/osinfo v1.0.3 - github.com/chuckpreslar/emission v0.0.0-20170206194824-a7ddd980baf9 github.com/maxlandon/readline v0.1.0-beta.0.20211027085530-2b76cabb8036 github.com/pborman/getopt v1.1.0 github.com/sahilm/fuzzy v0.1.0 @@ -18,6 +17,7 @@ require ( github.com/acarl005/stripansi v0.0.0-20180116102854-5a71ef0e047d // indirect github.com/arnodel/strftime v0.1.6 // indirect github.com/evilsocket/islazy v1.10.6 // indirect + github.com/kylelemons/godebug v1.1.0 // indirect github.com/olekukonko/ts v0.0.0-20171002115256-78ecb04241c0 // indirect github.com/rivo/uniseg v0.2.0 // indirect golang.org/x/sync v0.0.0-20220513210516-0976fa681c29 // indirect diff --git a/go.sum b/go.sum index 1917008..7c36fa0 100644 --- a/go.sum +++ b/go.sum @@ -1,13 +1,5 @@ -github.com/Rosettea/golua v0.0.0-20220419183026-6d22d6fec5ac h1:dtXrgjch8PQyf7C90anZUquB5U3dr8AcMGJofeuirrI= -github.com/Rosettea/golua v0.0.0-20220419183026-6d22d6fec5ac/go.mod h1:9jzpYPiU2is0HVGCiuIOBSXdergHUW44IEjmuN1UrIE= -github.com/Rosettea/golua v0.0.0-20220518005949-116371948fe3 h1:I/wWr40FFLFF9pbT3wLb1FAEZhKb/hUWE+nJ5uHBK2g= -github.com/Rosettea/golua v0.0.0-20220518005949-116371948fe3/go.mod h1:9jzpYPiU2is0HVGCiuIOBSXdergHUW44IEjmuN1UrIE= -github.com/Rosettea/golua v0.0.0-20220621002945-b05143999437 h1:6lWu4YVLeKuZ8jR9xwHONhkHBsrIbw5dpfG1gtOVw0A= -github.com/Rosettea/golua v0.0.0-20220621002945-b05143999437/go.mod h1:9jzpYPiU2is0HVGCiuIOBSXdergHUW44IEjmuN1UrIE= github.com/Rosettea/golua v0.0.0-20221213193027-cbf6d4e4d345 h1:QNYjYDogUSiNUkffbhFSrSCtpZhofeiVYGFN2FI4wSs= github.com/Rosettea/golua v0.0.0-20221213193027-cbf6d4e4d345/go.mod h1:9jzpYPiU2is0HVGCiuIOBSXdergHUW44IEjmuN1UrIE= -github.com/Rosettea/sh/v3 v3.4.0-0.dev.0.20220306140409-795a84b00b4e h1:P2XupP8SaylWaudD1DqbWtZ3mIa8OsE9635LmR+Q+lg= -github.com/Rosettea/sh/v3 v3.4.0-0.dev.0.20220306140409-795a84b00b4e/go.mod h1:R09vh/04ILvP2Gj8/Z9Jd0Dh0ZIvaucowMEs6abQpWs= github.com/Rosettea/sh/v3 v3.4.0-0.dev.0.20220524215627-dfd9a4fa219b h1:s5eDMhBk6H1BgipgLub/gv9qeyBaTuiHM0k3h2/9TSE= github.com/Rosettea/sh/v3 v3.4.0-0.dev.0.20220524215627-dfd9a4fa219b/go.mod h1:R09vh/04ILvP2Gj8/Z9Jd0Dh0ZIvaucowMEs6abQpWs= github.com/acarl005/stripansi v0.0.0-20180116102854-5a71ef0e047d h1:licZJFw2RwpHMqeKTCYkitsPqHNxTmd4SNR5r94FGM8= @@ -18,8 +10,6 @@ github.com/arnodel/strftime v0.1.6/go.mod h1:5NbK5XqYK8QpRZpqKNt4OlxLtIB8cotkLk4 github.com/atotto/clipboard v0.1.4/go.mod h1:ZY9tmq7sm5xIbd9bOK4onWV4S6X0u6GY7Vn0Yu86PYI= github.com/blackfireio/osinfo v1.0.3 h1:Yk2t2GTPjBcESv6nDSWZKO87bGMQgO+Hi9OoXPpxX8c= github.com/blackfireio/osinfo v1.0.3/go.mod h1:Pd987poVNmd5Wsx6PRPw4+w7kLlf9iJxoRKPtPAjOrA= -github.com/chuckpreslar/emission v0.0.0-20170206194824-a7ddd980baf9 h1:xz6Nv3zcwO2Lila35hcb0QloCQsc38Al13RNEzWRpX4= -github.com/chuckpreslar/emission v0.0.0-20170206194824-a7ddd980baf9/go.mod h1:2wSM9zJkl1UQEFZgSd68NfCgRz1VL1jzy/RjCg+ULrs= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/creack/pty v1.1.15 h1:cKRCLMj3Ddm54bKSpemfQ8AtYFBhAI2MPmdys22fBdc= github.com/creack/pty v1.1.15/go.mod h1:MOBLtS5ELjhRRrroQr9kyvTxUAFNvYEK993ew/Vr4O4= @@ -36,6 +26,8 @@ github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= +github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc= +github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw= github.com/lucasb-eyer/go-colorful v1.0.3/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0= github.com/mattn/go-runewidth v0.0.10/go.mod h1:RAqKPSqVFrSLVXbA8x7dzmKdmGzieGRCM46jaSJTDAk= github.com/olekukonko/ts v0.0.0-20171002115256-78ecb04241c0 h1:LiZB1h0GIcudcDci2bxbqI6DXV8bF8POAnArqvRrIyw= @@ -51,7 +43,6 @@ github.com/rogpeppe/go-internal v1.8.1-0.20210923151022-86f73c517451 h1:d1PiN4Rx github.com/rogpeppe/go-internal v1.8.1-0.20210923151022-86f73c517451/go.mod h1:JeRgkft04UBgHMgCIwADu4Pn6Mtm5d4nPKWu0nJ5d+o= github.com/sahilm/fuzzy v0.1.0 h1:FzWGaw2Opqyu+794ZQ9SYifWv2EIXpwP4q8dY1kDAwI= github.com/sahilm/fuzzy v0.1.0/go.mod h1:VFvziUEIMCrT6A6tw2RFIXPXXmzXbOsSHF0DOI8ZK9Y= -golang.org/x/sync v0.0.0-20210220032951-036812b2e83c h1:5KslGYwFpkhGh+Q16bwMP3cOontH8FOep7tGV86Y7SQ= golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220513210516-0976fa681c29 h1:w8s32wxx3sY+OjLlv9qltkLU5yvJzxjjgiHWLjdIcw4= golang.org/x/sync v0.0.0-20220513210516-0976fa681c29/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -60,18 +51,13 @@ golang.org/x/sys v0.0.0-20210320140829-1e4c9ba3b0c4/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210925032602-92d5a993a665/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220227234510-4e6760a101f9 h1:nhht2DYV/Sn3qOayu8lM+cU1ii9sTLUeBQwQQfUHtrs= -golang.org/x/sys v0.0.0-20220227234510-4e6760a101f9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a h1:dGzPydgVsqGcTRVwiLJ1jVbufYwmzD3LfVPLKsKg+0k= golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201210144234-2321bbc49cbf/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210916214954-140adaaadfaf/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= -golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 h1:JGgROgKl9N8DuW20oFS5gxc+lE67/N3FcwmBPMe7ArY= -golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.0.0-20220411215600-e5f449aeb171 h1:EH1Deb8WZJ0xc0WK//leUHXcX9aLE5SymusoTmMZye8= golang.org/x/term v0.0.0-20220411215600-e5f449aeb171/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/text v0.3.6 h1:aRYxNxv6iGQlyVaZmk6ZgYEDa+Jg18DxebPSrd6bg1M= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= diff --git a/module.go b/module.go new file mode 100644 index 0000000..2ab55e8 --- /dev/null +++ b/module.go @@ -0,0 +1,92 @@ +package main + +import ( + "plugin" + + "hilbish/util" + + rt "github.com/arnodel/golua/runtime" +) + +// #interface module +// native module loading +// #field paths A list of paths to search when loading native modules. This is in the style of Lua search paths and will be used when requiring native modules. Example: `?.so;?/?.so` +/* +The hilbish.module interface provides a function to load +Hilbish plugins/modules. Hilbish modules are Go-written +plugins (see https://pkg.go.dev/plugin) that are used to add functionality +to Hilbish that cannot be written in Lua for any reason. + +Note that you don't ever need to use the load function that is here as +modules can be loaded with a `require` call like Lua C modules, and the +search paths can be changed with the `paths` property here. + +To make a valid native module, the Go plugin has to export a Loader function +with a signature like so: `func(*rt.Runtime) rt.Value`. + +`rt` in this case refers to the Runtime type at +https://pkg.go.dev/github.com/arnodel/golua@master/runtime#Runtime + +Hilbish uses this package as its Lua runtime. You will need to read +it to use it for a native plugin. + +Here is some code for an example plugin: +```go +package main + +import ( + rt "github.com/arnodel/golua/runtime" +) + +func Loader(rtm *rt.Runtime) rt.Value { + return rt.StringValue("hello world!") +} +``` + +This can be compiled with `go build -buildmode=plugin plugin.go`. +If you attempt to require and print the result (`print(require 'plugin')`), it will show "hello world!" +*/ +func moduleLoader(rtm *rt.Runtime) *rt.Table { + exports := map[string]util.LuaExport{ + "load": {moduleLoad, 2, false}, + } + + mod := rt.NewTable() + util.SetExports(rtm, mod, exports) + + return mod +} + +// #interface module +// load(path) +// Loads a module at the designated `path`. +// It will throw if any error occurs. +func moduleLoad(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) { + if err := c.CheckNArgs(1); err != nil { + return nil, err + } + + path, err := c.StringArg(0) + if err != nil { + return nil, err + } + + p, err := plugin.Open(path) + if err != nil { + return nil, err + } + + value, err := p.Lookup("Loader") + if err != nil { + return nil, err + } + + loader, ok := value.(func(*rt.Runtime) rt.Value) + if !ok { + return nil, nil + } + + val := loader(t.Runtime) + + return c.PushingNext1(t.Runtime, val), nil +} diff --git a/nature/init.lua b/nature/init.lua index 9e78135..a0579d7 100644 --- a/nature/init.lua +++ b/nature/init.lua @@ -6,6 +6,18 @@ local fs = require 'fs' package.path = package.path .. ';' .. hilbish.dataDir .. '/?/init.lua' .. ';' .. hilbish.dataDir .. '/?/?.lua' .. ";" .. hilbish.dataDir .. '/?.lua' +hilbish.module.paths = '?.so;?/?.so;' +.. hilbish.userDir.data .. 'hilbish/libs/?/?.so' +.. ";" .. hilbish.userDir.data .. 'hilbish/libs/?.so' + +table.insert(package.searchers, function(module) + local path = package.searchpath(module, hilbish.module.paths) + if not path then return nil end + + -- it didnt work normally, idk + return function() return hilbish.module.load(path) end, path +end) + require 'nature.commands' require 'nature.completions' require 'nature.opts' diff --git a/testplugin/testplugin.go b/testplugin/testplugin.go new file mode 100644 index 0000000..2d8a41b --- /dev/null +++ b/testplugin/testplugin.go @@ -0,0 +1,9 @@ +package main + +import ( + rt "github.com/arnodel/golua/runtime" +) + +func Loader(rtm *rt.Runtime) rt.Value { + return rt.StringValue("hello world!") +} diff --git a/testplugin/testplugin.so b/testplugin/testplugin.so new file mode 100644 index 0000000..3c83992 Binary files /dev/null and b/testplugin/testplugin.so differ