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()`
|
||||
before 3.0
|
||||
- Added the `hilbish.editor:read` and `hilbish.editor:log(text)` functions.
|
||||
- `yarn` threading library (See the docs)
|
||||
|
||||
### Changed
|
||||
- Documentation for Lunacolors has been improved, with more information added.
|
||||
- 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()
|
||||
|
||||
util.SetExports(rtm, mod, exports)
|
||||
if hshMod == nil {
|
||||
hshMod = mod
|
||||
}
|
||||
|
||||
host, _ := os.Hostname()
|
||||
username := curuser.Username
|
||||
@ -129,7 +131,7 @@ func hilbishLoad(rtm *rt.Runtime) (rt.Value, func()) {
|
||||
pluginModule := moduleLoader(rtm)
|
||||
mod.Set(rt.StringValue("module"), rt.TableValue(pluginModule))
|
||||
|
||||
sinkModule := util.SinkLoader(l)
|
||||
sinkModule := util.SinkLoader(rtm)
|
||||
mod.Set(rt.StringValue("sink"), rt.TableValue(sinkModule))
|
||||
|
||||
return rt.TableValue(mod), nil
|
||||
|
@ -86,6 +86,7 @@ var prefix = map[string]string{
|
||||
"terminal": "term",
|
||||
"snail": "snail",
|
||||
"readline": "rl",
|
||||
"yarn": "yarn",
|
||||
}
|
||||
|
||||
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/snail"
|
||||
"hilbish/golibs/terminal"
|
||||
"hilbish/golibs/yarn"
|
||||
"hilbish/util"
|
||||
|
||||
"github.com/arnodel/golua/lib"
|
||||
@ -21,41 +22,11 @@ var minimalconf = `hilbish.prompt '& '`
|
||||
|
||||
func luaInit() {
|
||||
l = rt.New(os.Stdout)
|
||||
l.PushContext(rt.RuntimeContextDef{
|
||||
MessageHandler: debuglib.Traceback,
|
||||
})
|
||||
lib.LoadAll(l)
|
||||
|
||||
lib.LoadLibs(l, hilbishLoader)
|
||||
// yes this is stupid, i know
|
||||
util.DoString(l, "hilbish = require 'hilbish'")
|
||||
loadLibs(l)
|
||||
|
||||
hooks = bait.New(l)
|
||||
hooks.SetRecoverer(func(event string, handler *bait.Listener, err interface{}) {
|
||||
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)
|
||||
yarnPool := yarn.New(yarnloadLibs)
|
||||
lib.LoadLibs(l, yarnPool.Loader)
|
||||
|
||||
// Add more paths that Lua can require from
|
||||
_, 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) {
|
||||
if !interactive {
|
||||
return
|
||||
|
Loading…
x
Reference in New Issue
Block a user