mirror of https://github.com/Hilbis/Hilbish
Merge 398702cafa
into c969f5ed15
commit
8b6494c126
3
go.mod
3
go.mod
|
@ -10,10 +10,11 @@ require (
|
||||||
github.com/blackfireio/osinfo v1.0.5
|
github.com/blackfireio/osinfo v1.0.5
|
||||||
github.com/maxlandon/readline v1.0.14
|
github.com/maxlandon/readline v1.0.14
|
||||||
github.com/pborman/getopt v1.1.0
|
github.com/pborman/getopt v1.1.0
|
||||||
|
github.com/rjeczalik/notify v0.9.3
|
||||||
github.com/sahilm/fuzzy v0.1.1
|
github.com/sahilm/fuzzy v0.1.1
|
||||||
golang.org/x/sys v0.22.0
|
golang.org/x/sys v0.22.0
|
||||||
golang.org/x/term v0.22.0
|
golang.org/x/term v0.22.0
|
||||||
mvdan.cc/sh/v3 v3.8.0
|
mvdan.cc/sh/v3 v3.0.0-00010101000000-000000000000
|
||||||
)
|
)
|
||||||
|
|
||||||
require (
|
require (
|
||||||
|
|
3
go.sum
3
go.sum
|
@ -32,12 +32,15 @@ github.com/pborman/getopt v1.1.0 h1:eJ3aFZroQqq0bWmraivjQNt6Dmm5M0h2JcDW38/Azb0=
|
||||||
github.com/pborman/getopt v1.1.0/go.mod h1:FxXoW1Re00sQG/+KIkuSqRL/LwQgSkv7uyac+STFsbk=
|
github.com/pborman/getopt v1.1.0/go.mod h1:FxXoW1Re00sQG/+KIkuSqRL/LwQgSkv7uyac+STFsbk=
|
||||||
github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ=
|
github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ=
|
||||||
github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
|
github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
|
||||||
|
github.com/rjeczalik/notify v0.9.3 h1:6rJAzHTGKXGj76sbRgDiDcYj/HniypXmSJo1SWakZeY=
|
||||||
|
github.com/rjeczalik/notify v0.9.3/go.mod h1:gF3zSOrafR9DQEWSE8TjfI9NkooDxbyT4UgRGKZA0lc=
|
||||||
github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8=
|
github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8=
|
||||||
github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4=
|
github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4=
|
||||||
github.com/sahilm/fuzzy v0.1.1 h1:ceu5RHF8DGgoi+/dR5PsECjCDH1BE3Fnmpo7aVXOdRA=
|
github.com/sahilm/fuzzy v0.1.1 h1:ceu5RHF8DGgoi+/dR5PsECjCDH1BE3Fnmpo7aVXOdRA=
|
||||||
github.com/sahilm/fuzzy v0.1.1/go.mod h1:VFvziUEIMCrT6A6tw2RFIXPXXmzXbOsSHF0DOI8ZK9Y=
|
github.com/sahilm/fuzzy v0.1.1/go.mod h1:VFvziUEIMCrT6A6tw2RFIXPXXmzXbOsSHF0DOI8ZK9Y=
|
||||||
golang.org/x/sync v0.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M=
|
golang.org/x/sync v0.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M=
|
||||||
golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||||
|
golang.org/x/sys v0.0.0-20180926160741-c2ed4eda69e7/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
golang.org/x/sys v0.22.0 h1:RI27ohtqKCnwULzJLqkv897zojh5/DwS/ENaMzUOaWI=
|
golang.org/x/sys v0.22.0 h1:RI27ohtqKCnwULzJLqkv897zojh5/DwS/ENaMzUOaWI=
|
||||||
golang.org/x/sys v0.22.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
golang.org/x/sys v0.22.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||||
golang.org/x/term v0.22.0 h1:BbsgPEJULsl2fV/AT3v15Mjva5yXKQDyKf+TbDz7QJk=
|
golang.org/x/term v0.22.0 h1:BbsgPEJULsl2fV/AT3v15Mjva5yXKQDyKf+TbDz7QJk=
|
||||||
|
|
|
@ -22,6 +22,7 @@ import (
|
||||||
"mvdan.cc/sh/v3/interp"
|
"mvdan.cc/sh/v3/interp"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var watcherMetaKey = rt.StringValue("hshwatcher")
|
||||||
type fs struct{
|
type fs struct{
|
||||||
runner *interp.Runner
|
runner *interp.Runner
|
||||||
Loader packagelib.Loader
|
Loader packagelib.Loader
|
||||||
|
@ -40,6 +41,30 @@ func New(runner *interp.Runner) *fs {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *fs) loaderFunc(rtm *rt.Runtime) (rt.Value, func()) {
|
func (f *fs) loaderFunc(rtm *rt.Runtime) (rt.Value, func()) {
|
||||||
|
watcherMethods := rt.NewTable()
|
||||||
|
watcherFuncs := map[string]util.LuaExport{
|
||||||
|
"start": {watcherStart, 1, false},
|
||||||
|
"stop": {watcherStop, 1, false},
|
||||||
|
}
|
||||||
|
util.SetExports(rtm, watcherMethods, watcherFuncs)
|
||||||
|
|
||||||
|
watcherMeta := rt.NewTable()
|
||||||
|
watcherIndex := func(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
|
||||||
|
//ti, _ := watcherArg(c, 0)
|
||||||
|
|
||||||
|
arg := c.Arg(1)
|
||||||
|
val := watcherMethods.Get(arg)
|
||||||
|
|
||||||
|
if val != rt.NilValue {
|
||||||
|
return c.PushingNext1(t.Runtime, val), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return c.PushingNext1(t.Runtime, val), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
watcherMeta.Set(rt.StringValue("__index"), rt.FunctionValue(rt.NewGoFunction(watcherIndex, "__index", 2, false)))
|
||||||
|
rtm.SetRegistry(watcherMetaKey, rt.TableValue(watcherMeta))
|
||||||
|
|
||||||
exports := map[string]util.LuaExport{
|
exports := map[string]util.LuaExport{
|
||||||
"cd": util.LuaExport{f.fcd, 1, false},
|
"cd": util.LuaExport{f.fcd, 1, false},
|
||||||
"mkdir": util.LuaExport{f.fmkdir, 2, false},
|
"mkdir": util.LuaExport{f.fmkdir, 2, false},
|
||||||
|
@ -51,6 +76,7 @@ func (f *fs) loaderFunc(rtm *rt.Runtime) (rt.Value, func()) {
|
||||||
"glob": util.LuaExport{f.fglob, 1, false},
|
"glob": util.LuaExport{f.fglob, 1, false},
|
||||||
"join": util.LuaExport{f.fjoin, 0, true},
|
"join": util.LuaExport{f.fjoin, 0, true},
|
||||||
"pipe": util.LuaExport{f.fpipe, 0, false},
|
"pipe": util.LuaExport{f.fpipe, 0, false},
|
||||||
|
"watch": util.LuaExport{fwatch, 2, false},
|
||||||
}
|
}
|
||||||
mod := rt.NewTable()
|
mod := rt.NewTable()
|
||||||
util.SetExports(rtm, mod, exports)
|
util.SetExports(rtm, mod, exports)
|
||||||
|
@ -334,3 +360,28 @@ func (f *fs) fstat(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
|
||||||
return c.PushingNext1(t.Runtime, rt.TableValue(statTbl)), nil
|
return c.PushingNext1(t.Runtime, rt.TableValue(statTbl)), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// watch(path, callback)
|
||||||
|
// Watches a path for changes made to it. For example, to monitor
|
||||||
|
// new files created in a folder.
|
||||||
|
// The callback passed 2 string arguments, the `event` and the absolute `path`
|
||||||
|
// #param path string
|
||||||
|
// #param callback function
|
||||||
|
func fwatch(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
|
||||||
|
if err := c.CheckNArgs(2); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
dir, err := c.StringArg(0)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
watcher, err := c.ClosureArg(1)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
dw := newWatcher(dir, watcher, t.Runtime)
|
||||||
|
|
||||||
|
return c.PushingNext1(t.Runtime, rt.UserDataValue(dw.ud)), nil
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,111 @@
|
||||||
|
package fs
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/rjeczalik/notify"
|
||||||
|
rt "github.com/arnodel/golua/runtime"
|
||||||
|
)
|
||||||
|
|
||||||
|
// #type
|
||||||
|
// Watcher type describes a `fs` library file watcher.
|
||||||
|
type watcher struct{
|
||||||
|
path string
|
||||||
|
callback *rt.Closure
|
||||||
|
paused bool
|
||||||
|
started bool
|
||||||
|
ud *rt.UserData
|
||||||
|
notifyChan chan notify.EventInfo
|
||||||
|
rtm *rt.Runtime
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w *watcher) start() {
|
||||||
|
if w.callback == nil || w.started {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
w.started = true
|
||||||
|
w.notifyChan = make(chan notify.EventInfo)
|
||||||
|
notify.Watch(w.path, w.notifyChan, notify.All)
|
||||||
|
|
||||||
|
go func() {
|
||||||
|
for notif := range w.notifyChan {
|
||||||
|
ev := notif.Event().String()
|
||||||
|
path := notif.Path()
|
||||||
|
|
||||||
|
_, err := rt.Call1(w.rtm.MainThread(), rt.FunctionValue(w.callback), rt.StringValue(ev), rt.StringValue(path))
|
||||||
|
if err != nil {
|
||||||
|
// TODO: throw error
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w *watcher) stop() {
|
||||||
|
w.started = false
|
||||||
|
notify.Stop(w.notifyChan)
|
||||||
|
}
|
||||||
|
|
||||||
|
// #member
|
||||||
|
// start()
|
||||||
|
// Start/resume file watching.
|
||||||
|
func watcherStart(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
|
||||||
|
pw, err := watcherArg(c, 0)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
pw.start()
|
||||||
|
|
||||||
|
return c.Next(), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// #member
|
||||||
|
// stop()
|
||||||
|
// Stops watching for changes. Effectively ignores changes.
|
||||||
|
func watcherStop(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
|
||||||
|
pw, err := watcherArg(c, 0)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
pw.stop()
|
||||||
|
|
||||||
|
return c.Next(), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func newWatcher(path string, callback *rt.Closure, rtm *rt.Runtime) *watcher {
|
||||||
|
pw := &watcher{
|
||||||
|
path: path,
|
||||||
|
rtm: rtm,
|
||||||
|
callback: callback,
|
||||||
|
}
|
||||||
|
pw.ud = watcherUserData(pw)
|
||||||
|
pw.start()
|
||||||
|
|
||||||
|
return pw
|
||||||
|
}
|
||||||
|
|
||||||
|
func watcherArg(c *rt.GoCont, arg int) (*watcher, error) {
|
||||||
|
j, ok := valueToWatcher(c.Arg(arg))
|
||||||
|
if !ok {
|
||||||
|
return nil, fmt.Errorf("#%d must be a watcher", arg + 1)
|
||||||
|
}
|
||||||
|
|
||||||
|
return j, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func valueToWatcher(val rt.Value) (*watcher, bool) {
|
||||||
|
u, ok := val.TryUserData()
|
||||||
|
if !ok {
|
||||||
|
return nil, false
|
||||||
|
}
|
||||||
|
|
||||||
|
j, ok := u.Value().(*watcher)
|
||||||
|
return j, ok
|
||||||
|
}
|
||||||
|
|
||||||
|
func watcherUserData(j *watcher) *rt.UserData {
|
||||||
|
watcherMeta := j.rtm.Registry(watcherMetaKey)
|
||||||
|
return rt.NewUserData(j, watcherMeta.AsTable())
|
||||||
|
}
|
Loading…
Reference in New Issue