2
2
mirror of https://github.com/Hilbis/Hilbish synced 2025-07-01 00:32:03 +00:00

feat: add yarn library

This commit is contained in:
sammyette 2025-06-12 21:46:17 -04:00
parent 1bb433dc64
commit 002282f186
Signed by: sammyette
GPG Key ID: 904FC49417B44DCD
4 changed files with 235 additions and 82 deletions

88
api.go
View File

@ -25,30 +25,31 @@ import (
"hilbish/util"
rt "github.com/arnodel/golua/runtime"
"github.com/arnodel/golua/lib/packagelib"
rt "github.com/arnodel/golua/runtime"
//"github.com/arnodel/golua/lib/iolib"
"github.com/maxlandon/readline"
//"mvdan.cc/sh/v3/interp"
)
var exports = map[string]util.LuaExport{
"alias": {hlalias, 2, false},
"appendPath": {hlappendPath, 1, false},
"complete": {hlcomplete, 2, false},
"cwd": {hlcwd, 0, false},
"exec": {hlexec, 1, false},
"goro": {hlgoro, 1, true},
"alias": {hlalias, 2, false},
"appendPath": {hlappendPath, 1, false},
"complete": {hlcomplete, 2, false},
"cwd": {hlcwd, 0, false},
"exec": {hlexec, 1, false},
"goro": {hlgoro, 1, true},
"highlighter": {hlhighlighter, 1, false},
"hinter": {hlhinter, 1, false},
"hinter": {hlhinter, 1, false},
"multiprompt": {hlmultiprompt, 1, false},
"prependPath": {hlprependPath, 1, false},
"prompt": {hlprompt, 1, true},
"inputMode": {hlinputMode, 1, false},
"interval": {hlinterval, 2, false},
"read": {hlread, 1, false},
"timeout": {hltimeout, 2, false},
"which": {hlwhich, 1, false},
"prompt": {hlprompt, 1, true},
"inputMode": {hlinputMode, 1, false},
"interval": {hlinterval, 2, false},
"read": {hlread, 1, false},
"timeout": {hltimeout, 2, false},
"which": {hlwhich, 1, false},
}
var hshMod *rt.Table
@ -61,7 +62,9 @@ func hilbishLoad(rtm *rt.Runtime) (rt.Value, func()) {
mod := rt.NewTable()
util.SetExports(rtm, mod, exports)
hshMod = mod
if hshMod == nil {
hshMod = mod
}
host, _ := os.Hostname()
username := curuser.Username
@ -131,18 +134,18 @@ 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
}
func getenv(key, fallback string) string {
value := os.Getenv(key)
if len(value) == 0 {
return fallback
}
return value
value := os.Getenv(key)
if len(value) == 0 {
return fallback
}
return value
}
func setVimMode(mode string) {
@ -194,7 +197,6 @@ func hlcwd(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
return c.PushingNext1(t.Runtime, rt.StringValue(cwd)), nil
}
// read(prompt) -> input (string)
// Read input from the user, using Hilbish's line editor/input reader.
// This is a separate instance from the one Hilbish actually uses.
@ -212,7 +214,7 @@ func hlread(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
// substitute with an empty string
prompt = ""
}
lualr := &lineReader{
rl: readline.NewInstance(),
}
@ -265,11 +267,13 @@ func hlprompt(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
}
switch typ {
case "left":
prompt = p
lr.SetPrompt(fmtPrompt(prompt))
case "right": lr.SetRightPrompt(fmtPrompt(p))
default: return nil, errors.New("expected prompt type to be right or left, got " + typ)
case "left":
prompt = p
lr.SetPrompt(fmtPrompt(prompt))
case "right":
lr.SetRightPrompt(fmtPrompt(p))
default:
return nil, errors.New("expected prompt type to be right or left, got " + typ)
}
return c.Next(), nil
@ -290,7 +294,7 @@ will look like:
user ~ echo "hey
--> ...!"
so then you get
so then you get
user ~ echo "hey
--> ...!"
hey ...!
@ -386,7 +390,7 @@ func appendPath(dir string) {
// if dir isnt already in $PATH, add it
if !strings.Contains(pathenv, dir) {
os.Setenv("PATH", pathenv + string(os.PathListSeparator) + dir)
os.Setenv("PATH", pathenv+string(os.PathListSeparator)+dir)
}
}
@ -480,7 +484,7 @@ func hltimeout(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
interval := time.Duration(ms) * time.Millisecond
timer := timers.create(timerTimeout, interval, cb)
timer.start()
return c.PushingNext1(t.Runtime, rt.UserDataValue(timer.ud)), nil
}
@ -571,7 +575,7 @@ func hlprependPath(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
// if dir isnt already in $PATH, add in
if !strings.Contains(pathenv, dir) {
os.Setenv("PATH", dir + string(os.PathListSeparator) + pathenv)
os.Setenv("PATH", dir+string(os.PathListSeparator)+pathenv)
}
return c.Next(), nil
@ -625,14 +629,14 @@ func hlinputMode(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
}
switch mode {
case "emacs":
unsetVimMode()
lr.rl.InputMode = readline.Emacs
case "vim":
setVimMode("insert")
lr.rl.InputMode = readline.Vim
default:
return nil, errors.New("inputMode: expected vim or emacs, received " + mode)
case "emacs":
unsetVimMode()
lr.rl.InputMode = readline.Emacs
case "vim":
setVimMode("insert")
lr.rl.InputMode = readline.Vim
default:
return nil, errors.New("inputMode: expected vim or emacs, received " + mode)
}
return c.Next(), nil
@ -667,7 +671,9 @@ func hlhinter(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
// #example
// --This code will highlight all double quoted strings in green.
// function hilbish.highlighter(line)
// return line:gsub('"%w+"', function(c) return lunacolors.green(c) end)
//
// return line:gsub('"%w+"', function(c) return lunacolors.green(c) end)
//
// end
// #example
// #param line string

10
exec.go
View File

@ -29,12 +29,12 @@ func handleLua(input string) (string, uint8, error) {
chunk, err := l.CompileAndLoadLuaChunk("", []byte(cmdString), rt.TableValue(l.GlobalEnv()))
if err != nil && noexecute {
fmt.Println(err)
/* if lerr, ok := err.(*lua.ApiError); ok {
if perr, ok := lerr.Cause.(*parse.Error); ok {
print(perr.Pos.Line == parse.EOF)
/* if lerr, ok := err.(*lua.ApiError); ok {
if perr, ok := lerr.Cause.(*parse.Error); ok {
print(perr.Pos.Line == parse.EOF)
}
}
}
*/
*/
return cmdString, 125, err
}
// And if there's no syntax errors and -n isnt provided, run

130
golibs/yarn/yarn.go Normal file
View File

@ -0,0 +1,130 @@
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 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: yarncreate,
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)
}
// create(fun)
// Creates a new, fresh Yarn thread.
func yarncreate(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())
}

89
lua.go
View File

@ -5,60 +5,31 @@ import (
"os"
"path/filepath"
"hilbish/util"
"hilbish/golibs/bait"
"hilbish/golibs/commander"
"hilbish/golibs/fs"
"hilbish/golibs/snail"
"hilbish/golibs/terminal"
"hilbish/golibs/yarn"
"hilbish/util"
rt "github.com/arnodel/golua/runtime"
"github.com/arnodel/golua/lib"
"github.com/arnodel/golua/lib/debuglib"
rt "github.com/arnodel/golua/runtime"
)
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'")
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)
loadLibs(l)
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)
_, err := util.DoString(l, "package.path = package.path .. "+requirePaths)
if err != nil {
fmt.Fprintln(os.Stderr, "Could not add Hilbish require paths! Libraries will be missing. This shouldn't happen.")
}
@ -74,6 +45,52 @@ 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)
}
func yarnloadLibs(r *rt.Runtime) {
r.PushContext(rt.RuntimeContextDef{
MessageHandler: debuglib.Traceback,
})
lib.LoadAll(r)
lib.LoadLibs(r, hilbishLoader)
}
func runConfig(confpath string) {
if !interactive {
return