mirror of
https://github.com/Hilbis/Hilbish
synced 2025-07-01 16:52:03 +00:00
feat: add yarn library (#355)
This commit is contained in:
parent
5ca858d112
commit
49f2bae9e1
@ -10,6 +10,8 @@ and the dot operator will cause errors in 3.0.
|
|||||||
Example: `hilbish.editor.getLine()` should be changed to `hilbish.editor:getLine()`
|
Example: `hilbish.editor.getLine()` should be changed to `hilbish.editor:getLine()`
|
||||||
before 3.0
|
before 3.0
|
||||||
- Added the `hilbish.editor:read` and `hilbish.editor:log(text)` functions.
|
- Added the `hilbish.editor:read` and `hilbish.editor:log(text)` functions.
|
||||||
|
- `yarn` threading library (See the docs)
|
||||||
|
|
||||||
### Changed
|
### Changed
|
||||||
- Documentation for Lunacolors has been improved, with more information added.
|
- Documentation for Lunacolors has been improved, with more information added.
|
||||||
- Values returned by bait hooks will be passed to the `throw` caller
|
- Values returned by bait hooks will be passed to the `throw` caller
|
||||||
|
4
api.go
4
api.go
@ -62,7 +62,9 @@ func hilbishLoad(rtm *rt.Runtime) (rt.Value, func()) {
|
|||||||
mod := rt.NewTable()
|
mod := rt.NewTable()
|
||||||
|
|
||||||
util.SetExports(rtm, mod, exports)
|
util.SetExports(rtm, mod, exports)
|
||||||
|
if hshMod == nil {
|
||||||
hshMod = mod
|
hshMod = mod
|
||||||
|
}
|
||||||
|
|
||||||
host, _ := os.Hostname()
|
host, _ := os.Hostname()
|
||||||
username := curuser.Username
|
username := curuser.Username
|
||||||
@ -129,7 +131,7 @@ func hilbishLoad(rtm *rt.Runtime) (rt.Value, func()) {
|
|||||||
pluginModule := moduleLoader(rtm)
|
pluginModule := moduleLoader(rtm)
|
||||||
mod.Set(rt.StringValue("module"), rt.TableValue(pluginModule))
|
mod.Set(rt.StringValue("module"), rt.TableValue(pluginModule))
|
||||||
|
|
||||||
sinkModule := util.SinkLoader(l)
|
sinkModule := util.SinkLoader(rtm)
|
||||||
mod.Set(rt.StringValue("sink"), rt.TableValue(sinkModule))
|
mod.Set(rt.StringValue("sink"), rt.TableValue(sinkModule))
|
||||||
|
|
||||||
return rt.TableValue(mod), nil
|
return rt.TableValue(mod), nil
|
||||||
|
@ -86,6 +86,7 @@ var prefix = map[string]string{
|
|||||||
"terminal": "term",
|
"terminal": "term",
|
||||||
"snail": "snail",
|
"snail": "snail",
|
||||||
"readline": "rl",
|
"readline": "rl",
|
||||||
|
"yarn": "yarn",
|
||||||
}
|
}
|
||||||
|
|
||||||
func getTagsAndDocs(docs string) (map[string][]tag, []string) {
|
func getTagsAndDocs(docs string) (map[string][]tag, []string) {
|
||||||
|
51
docs/api/yarn.md
Normal file
51
docs/api/yarn.md
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
---
|
||||||
|
title: Module yarn
|
||||||
|
description: multi threading library
|
||||||
|
layout: doc
|
||||||
|
menu:
|
||||||
|
docs:
|
||||||
|
parent: "API"
|
||||||
|
---
|
||||||
|
|
||||||
|
## Introduction
|
||||||
|
Yarn is a simple multithreading library. Threads are individual Lua states,
|
||||||
|
so they do NOT share the same environment as the code that runs the thread.
|
||||||
|
Bait and Commanders are shared though, so you *can* throw hooks from 1 thread to another.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
|
||||||
|
```lua
|
||||||
|
local yarn = require 'yarn'
|
||||||
|
|
||||||
|
-- calling t will run the yarn thread.
|
||||||
|
local t = yarn.thread(print)
|
||||||
|
t 'printing from another lua state!'
|
||||||
|
```
|
||||||
|
|
||||||
|
## Functions
|
||||||
|
|||
|
||||||
|
|----|----|
|
||||||
|
|<a href="#thread">thread(fun) -> @Thread</a>|Creates a new, fresh Yarn thread.|
|
||||||
|
|
||||||
|
<hr>
|
||||||
|
<div id='thread'>
|
||||||
|
<h4 class='heading'>
|
||||||
|
yarn.thread(fun) -> <a href="/Hilbish/docs/api/yarn/#thread" style="text-decoration: none;" id="lol">Thread</a>
|
||||||
|
<a href="#thread" class='heading-link'>
|
||||||
|
<i class="fas fa-paperclip"></i>
|
||||||
|
</a>
|
||||||
|
</h4>
|
||||||
|
|
||||||
|
Creates a new, fresh Yarn thread.
|
||||||
|
`fun` is the function that will run in the thread.
|
||||||
|
|
||||||
|
#### Parameters
|
||||||
|
This function has no parameters.
|
||||||
|
</div>
|
||||||
|
|
||||||
|
## Types
|
||||||
|
<hr>
|
||||||
|
|
||||||
|
## Thread
|
||||||
|
|
||||||
|
### Methods
|
9
emmyLuaDocs/yarn.lua
Normal file
9
emmyLuaDocs/yarn.lua
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
--- @meta
|
||||||
|
|
||||||
|
local yarn = {}
|
||||||
|
|
||||||
|
--- Creates a new, fresh Yarn thread.
|
||||||
|
--- `fun` is the function that will run in the thread.
|
||||||
|
function yarn.thread(fun) end
|
||||||
|
|
||||||
|
return yarn
|
147
golibs/yarn/yarn.go
Normal file
147
golibs/yarn/yarn.go
Normal file
@ -0,0 +1,147 @@
|
|||||||
|
// multi threading library
|
||||||
|
// Yarn is a simple multithreading library. Threads are individual Lua states,
|
||||||
|
// so they do NOT share the same environment as the code that runs the thread.
|
||||||
|
// Bait and Commanders are shared though, so you *can* throw hooks from 1 thread to another.
|
||||||
|
/*
|
||||||
|
Example:
|
||||||
|
|
||||||
|
```lua
|
||||||
|
local yarn = require 'yarn'
|
||||||
|
|
||||||
|
-- calling t will run the yarn thread.
|
||||||
|
local t = yarn.thread(print)
|
||||||
|
t 'printing from another lua state!'
|
||||||
|
```
|
||||||
|
*/
|
||||||
|
package yarn
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"hilbish/util"
|
||||||
|
"os"
|
||||||
|
|
||||||
|
"github.com/arnodel/golua/lib/packagelib"
|
||||||
|
rt "github.com/arnodel/golua/runtime"
|
||||||
|
)
|
||||||
|
|
||||||
|
var yarnMetaKey = rt.StringValue("hshyarn")
|
||||||
|
var globalSpool *Yarn
|
||||||
|
|
||||||
|
type Yarn struct {
|
||||||
|
initializer func(*rt.Runtime)
|
||||||
|
Loader packagelib.Loader
|
||||||
|
}
|
||||||
|
|
||||||
|
// #type
|
||||||
|
type Thread struct {
|
||||||
|
rtm *rt.Runtime
|
||||||
|
f rt.Callable
|
||||||
|
}
|
||||||
|
|
||||||
|
func New(init func(*rt.Runtime)) *Yarn {
|
||||||
|
yrn := &Yarn{
|
||||||
|
initializer: init,
|
||||||
|
}
|
||||||
|
yrn.Loader = packagelib.Loader{
|
||||||
|
Load: yrn.loaderFunc,
|
||||||
|
Name: "yarn",
|
||||||
|
}
|
||||||
|
|
||||||
|
globalSpool = yrn
|
||||||
|
|
||||||
|
return yrn
|
||||||
|
}
|
||||||
|
|
||||||
|
func (y *Yarn) loaderFunc(rtm *rt.Runtime) (rt.Value, func()) {
|
||||||
|
yarnMeta := rt.NewTable()
|
||||||
|
yarnMeta.Set(rt.StringValue("__call"), rt.FunctionValue(rt.NewGoFunction(yarnrun, "__call", 1, true)))
|
||||||
|
rtm.SetRegistry(yarnMetaKey, rt.TableValue(yarnMeta))
|
||||||
|
|
||||||
|
exports := map[string]util.LuaExport{
|
||||||
|
"thread": {
|
||||||
|
Function: yarnthread,
|
||||||
|
ArgNum: 1,
|
||||||
|
Variadic: false,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
mod := rt.NewTable()
|
||||||
|
util.SetExports(rtm, mod, exports)
|
||||||
|
|
||||||
|
return rt.TableValue(mod), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (y *Yarn) init(th *Thread) {
|
||||||
|
y.initializer(th.rtm)
|
||||||
|
}
|
||||||
|
|
||||||
|
// thread(fun) -> @Thread
|
||||||
|
// Creates a new, fresh Yarn thread.
|
||||||
|
// `fun` is the function that will run in the thread.
|
||||||
|
func yarnthread(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
|
||||||
|
if err := c.Check1Arg(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
fun, err := c.CallableArg(0)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
yrn := &Thread{
|
||||||
|
rtm: rt.New(os.Stdout),
|
||||||
|
f: fun,
|
||||||
|
}
|
||||||
|
globalSpool.init(yrn)
|
||||||
|
|
||||||
|
return c.PushingNext(t.Runtime, rt.UserDataValue(yarnUserData(t.Runtime, yrn))), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func yarnrun(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
|
||||||
|
if err := c.Check1Arg(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
yrn, err := yarnArg(c, 0)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
yrn.Run(c.Etc())
|
||||||
|
|
||||||
|
return c.Next(), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (y *Thread) Run(args []rt.Value) {
|
||||||
|
go func() {
|
||||||
|
term := rt.NewTerminationWith(y.rtm.MainThread().CurrentCont(), 0, true)
|
||||||
|
err := rt.Call(y.rtm.MainThread(), rt.FunctionValue(y.f), args, term)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
|
||||||
|
func yarnArg(c *rt.GoCont, arg int) (*Thread, error) {
|
||||||
|
j, ok := valueToYarn(c.Arg(arg))
|
||||||
|
if !ok {
|
||||||
|
return nil, fmt.Errorf("#%d must be a yarn thread", arg+1)
|
||||||
|
}
|
||||||
|
|
||||||
|
return j, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func valueToYarn(val rt.Value) (*Thread, bool) {
|
||||||
|
u, ok := val.TryUserData()
|
||||||
|
if !ok {
|
||||||
|
return nil, false
|
||||||
|
}
|
||||||
|
|
||||||
|
j, ok := u.Value().(*Thread)
|
||||||
|
return j, ok
|
||||||
|
}
|
||||||
|
|
||||||
|
func yarnUserData(rtm *rt.Runtime, t *Thread) *rt.UserData {
|
||||||
|
yarnMeta := rtm.Registry(yarnMetaKey)
|
||||||
|
return rt.NewUserData(t, yarnMeta.AsTable())
|
||||||
|
}
|
91
lua.go
91
lua.go
@ -10,6 +10,7 @@ import (
|
|||||||
"hilbish/golibs/fs"
|
"hilbish/golibs/fs"
|
||||||
"hilbish/golibs/snail"
|
"hilbish/golibs/snail"
|
||||||
"hilbish/golibs/terminal"
|
"hilbish/golibs/terminal"
|
||||||
|
"hilbish/golibs/yarn"
|
||||||
"hilbish/util"
|
"hilbish/util"
|
||||||
|
|
||||||
"github.com/arnodel/golua/lib"
|
"github.com/arnodel/golua/lib"
|
||||||
@ -21,41 +22,11 @@ var minimalconf = `hilbish.prompt '& '`
|
|||||||
|
|
||||||
func luaInit() {
|
func luaInit() {
|
||||||
l = rt.New(os.Stdout)
|
l = rt.New(os.Stdout)
|
||||||
l.PushContext(rt.RuntimeContextDef{
|
|
||||||
MessageHandler: debuglib.Traceback,
|
|
||||||
})
|
|
||||||
lib.LoadAll(l)
|
|
||||||
|
|
||||||
lib.LoadLibs(l, hilbishLoader)
|
loadLibs(l)
|
||||||
// yes this is stupid, i know
|
|
||||||
util.DoString(l, "hilbish = require 'hilbish'")
|
|
||||||
|
|
||||||
hooks = bait.New(l)
|
yarnPool := yarn.New(yarnloadLibs)
|
||||||
hooks.SetRecoverer(func(event string, handler *bait.Listener, err interface{}) {
|
lib.LoadLibs(l, yarnPool.Loader)
|
||||||
fmt.Println("Error in `error` hook handler:", err)
|
|
||||||
hooks.Off(event, handler)
|
|
||||||
})
|
|
||||||
lib.LoadLibs(l, hooks.Loader)
|
|
||||||
|
|
||||||
// Add Ctrl-C handler
|
|
||||||
hooks.On("signal.sigint", func(...interface{}) rt.Value {
|
|
||||||
if !interactive {
|
|
||||||
os.Exit(0)
|
|
||||||
}
|
|
||||||
return rt.NilValue
|
|
||||||
})
|
|
||||||
|
|
||||||
lr.rl.RawInputCallback = func(r []rune) {
|
|
||||||
hooks.Emit("hilbish.rawInput", string(r))
|
|
||||||
}
|
|
||||||
|
|
||||||
lib.LoadLibs(l, fs.Loader)
|
|
||||||
lib.LoadLibs(l, terminal.Loader)
|
|
||||||
lib.LoadLibs(l, snail.Loader)
|
|
||||||
|
|
||||||
cmds = commander.New(l)
|
|
||||||
lib.LoadLibs(l, cmds.Loader)
|
|
||||||
lib.LoadLibs(l, lr.rl.Loader)
|
|
||||||
|
|
||||||
// Add more paths that Lua can require from
|
// Add more paths that Lua can require from
|
||||||
_, err := util.DoString(l, "package.path = package.path .. "+requirePaths)
|
_, err := util.DoString(l, "package.path = package.path .. "+requirePaths)
|
||||||
@ -74,6 +45,60 @@ func luaInit() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func loadLibs(r *rt.Runtime) {
|
||||||
|
r.PushContext(rt.RuntimeContextDef{
|
||||||
|
MessageHandler: debuglib.Traceback,
|
||||||
|
})
|
||||||
|
lib.LoadAll(r)
|
||||||
|
|
||||||
|
lib.LoadLibs(r, hilbishLoader)
|
||||||
|
// yes this is stupid, i know
|
||||||
|
util.DoString(r, "hilbish = require 'hilbish'")
|
||||||
|
|
||||||
|
hooks = bait.New(r)
|
||||||
|
hooks.SetRecoverer(func(event string, handler *bait.Listener, err interface{}) {
|
||||||
|
fmt.Println("Error in `error` hook handler:", err)
|
||||||
|
hooks.Off(event, handler)
|
||||||
|
})
|
||||||
|
lib.LoadLibs(r, hooks.Loader)
|
||||||
|
|
||||||
|
// Add Ctrl-C handler
|
||||||
|
hooks.On("signal.sigint", func(...interface{}) rt.Value {
|
||||||
|
if !interactive {
|
||||||
|
os.Exit(0)
|
||||||
|
}
|
||||||
|
return rt.NilValue
|
||||||
|
})
|
||||||
|
|
||||||
|
lr.rl.RawInputCallback = func(rn []rune) {
|
||||||
|
hooks.Emit("hilbish.rawInput", string(rn))
|
||||||
|
}
|
||||||
|
|
||||||
|
lib.LoadLibs(r, fs.Loader)
|
||||||
|
lib.LoadLibs(r, terminal.Loader)
|
||||||
|
lib.LoadLibs(r, snail.Loader)
|
||||||
|
|
||||||
|
cmds = commander.New(r)
|
||||||
|
lib.LoadLibs(r, cmds.Loader)
|
||||||
|
lib.LoadLibs(l, lr.rl.Loader)
|
||||||
|
}
|
||||||
|
|
||||||
|
func yarnloadLibs(r *rt.Runtime) {
|
||||||
|
r.PushContext(rt.RuntimeContextDef{
|
||||||
|
MessageHandler: debuglib.Traceback,
|
||||||
|
})
|
||||||
|
lib.LoadAll(r)
|
||||||
|
|
||||||
|
lib.LoadLibs(r, hilbishLoader)
|
||||||
|
lib.LoadLibs(r, hooks.Loader)
|
||||||
|
lib.LoadLibs(r, fs.Loader)
|
||||||
|
lib.LoadLibs(r, terminal.Loader)
|
||||||
|
lib.LoadLibs(r, snail.Loader)
|
||||||
|
lib.LoadLibs(r, cmds.Loader)
|
||||||
|
lib.LoadLibs(l, lr.rl.Loader)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
func runConfig(confpath string) {
|
func runConfig(confpath string) {
|
||||||
if !interactive {
|
if !interactive {
|
||||||
return
|
return
|
||||||
|
Loading…
x
Reference in New Issue
Block a user