mirror of https://github.com/Hilbis/Hilbish
Compare commits
4 Commits
86aa40af64
...
3d525aa7da
Author | SHA1 | Date |
---|---|---|
TorchedSammy | 3d525aa7da | |
TorchedSammy | 37e1b12b81 | |
TorchedSammy | abfd4e5196 | |
TorchedSammy | bd35e3b871 |
118
api.go
118
api.go
|
@ -52,7 +52,30 @@ var hilbishLoader = packagelib.Loader{
|
||||||
}
|
}
|
||||||
|
|
||||||
func hilbishLoad(rtm *rt.Runtime) (rt.Value, func()) {
|
func hilbishLoad(rtm *rt.Runtime) (rt.Value, func()) {
|
||||||
|
fakeMod := rt.NewTable()
|
||||||
|
modmt := rt.NewTable()
|
||||||
mod := rt.NewTable()
|
mod := rt.NewTable()
|
||||||
|
|
||||||
|
modIndex := func(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
|
||||||
|
arg := c.Arg(1)
|
||||||
|
val := mod.Get(arg)
|
||||||
|
|
||||||
|
return c.PushingNext1(t.Runtime, val), nil
|
||||||
|
}
|
||||||
|
modNewIndex := func(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
|
||||||
|
k := c.Arg(1)
|
||||||
|
v := c.Arg(2)
|
||||||
|
if modVal := mod.Get(k); modVal != rt.NilValue {
|
||||||
|
return nil, errors.New("not allowed to override in hilbish table")
|
||||||
|
}
|
||||||
|
mod.Set(k, v)
|
||||||
|
|
||||||
|
return c.Next(), nil
|
||||||
|
}
|
||||||
|
modmt.Set(rt.StringValue("__newindex"), rt.FunctionValue(rt.NewGoFunction(modNewIndex, "__newindex", 3, false)))
|
||||||
|
modmt.Set(rt.StringValue("__index"), rt.FunctionValue(rt.NewGoFunction(modIndex, "__index", 2, false)))
|
||||||
|
fakeMod.SetMetatable(modmt)
|
||||||
|
|
||||||
util.SetExports(rtm, mod, exports)
|
util.SetExports(rtm, mod, exports)
|
||||||
hshMod = mod
|
hshMod = mod
|
||||||
|
|
||||||
|
@ -76,7 +99,7 @@ Check out the {blue}{bold}guide{reset} command to get started.
|
||||||
util.SetField(rtm, mod, "login", rt.BoolValue(login), "Whether this is a login shell")
|
util.SetField(rtm, mod, "login", rt.BoolValue(login), "Whether this is a login shell")
|
||||||
util.SetField(rtm, mod, "greeting", rt.StringValue(greeting), "Hilbish's welcome message for interactive shells. It has Lunacolors formatting.")
|
util.SetField(rtm, mod, "greeting", rt.StringValue(greeting), "Hilbish's welcome message for interactive shells. It has Lunacolors formatting.")
|
||||||
util.SetField(rtm, mod, "vimMode", rt.NilValue, "Current Vim mode of Hilbish (nil if not in Vim mode)")
|
util.SetField(rtm, mod, "vimMode", rt.NilValue, "Current Vim mode of Hilbish (nil if not in Vim mode)")
|
||||||
util.SetField(rtm, hshMod, "exitCode", rt.IntValue(0), "Exit code of last exected command")
|
util.SetField(rtm, mod, "exitCode", rt.IntValue(0), "Exit code of last exected command")
|
||||||
util.Document(mod, "Hilbish's core API, containing submodules and functions which relate to the shell itself.")
|
util.Document(mod, "Hilbish's core API, containing submodules and functions which relate to the shell itself.")
|
||||||
|
|
||||||
// hilbish.userDir table
|
// hilbish.userDir table
|
||||||
|
@ -118,6 +141,10 @@ Check out the {blue}{bold}guide{reset} command to get started.
|
||||||
rt.FunctionValue(rt.NewGoFunction(luaBinaryComplete, "bins", 3, false)),
|
rt.FunctionValue(rt.NewGoFunction(luaBinaryComplete, "bins", 3, false)),
|
||||||
"Completer for executables/binaries")
|
"Completer for executables/binaries")
|
||||||
|
|
||||||
|
util.SetField(rtm, hshcomp, "call",
|
||||||
|
rt.FunctionValue(rt.NewGoFunction(callLuaCompleter, "call", 4, false)),
|
||||||
|
"Calls a completer and get its entries for completions")
|
||||||
|
|
||||||
util.Document(hshcomp, "Completions interface for Hilbish.")
|
util.Document(hshcomp, "Completions interface for Hilbish.")
|
||||||
mod.Set(rt.StringValue("completion"), rt.TableValue(hshcomp))
|
mod.Set(rt.StringValue("completion"), rt.TableValue(hshcomp))
|
||||||
|
|
||||||
|
@ -137,7 +164,7 @@ Check out the {blue}{bold}guide{reset} command to get started.
|
||||||
util.Document(timerModule, "Timer interface, for control of all intervals and timeouts.")
|
util.Document(timerModule, "Timer interface, for control of all intervals and timeouts.")
|
||||||
mod.Set(rt.StringValue("timers"), rt.TableValue(timerModule))
|
mod.Set(rt.StringValue("timers"), rt.TableValue(timerModule))
|
||||||
|
|
||||||
return rt.TableValue(mod), nil
|
return rt.TableValue(fakeMod), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func getenv(key, fallback string) string {
|
func getenv(key, fallback string) string {
|
||||||
|
@ -148,75 +175,6 @@ func getenv(key, fallback string) string {
|
||||||
return value
|
return value
|
||||||
}
|
}
|
||||||
|
|
||||||
func luaFileComplete(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
|
|
||||||
query, ctx, fds, err := getCompleteParams(t, c)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
completions, _ := fileComplete(query, ctx, fds)
|
|
||||||
luaComps := rt.NewTable()
|
|
||||||
|
|
||||||
for i, comp := range completions {
|
|
||||||
luaComps.Set(rt.IntValue(int64(i + 1)), rt.StringValue(comp))
|
|
||||||
}
|
|
||||||
|
|
||||||
return c.PushingNext1(t.Runtime, rt.TableValue(luaComps)), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func luaBinaryComplete(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
|
|
||||||
query, ctx, fds, err := getCompleteParams(t, c)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
completions, _ := binaryComplete(query, ctx, fds)
|
|
||||||
luaComps := rt.NewTable()
|
|
||||||
|
|
||||||
for i, comp := range completions {
|
|
||||||
luaComps.Set(rt.IntValue(int64(i + 1)), rt.StringValue(comp))
|
|
||||||
}
|
|
||||||
|
|
||||||
return c.PushingNext1(t.Runtime, rt.TableValue(luaComps)), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func getCompleteParams(t *rt.Thread, c *rt.GoCont) (string, string, []string, error) {
|
|
||||||
if err := c.CheckNArgs(3); err != nil {
|
|
||||||
return "", "", []string{}, err
|
|
||||||
}
|
|
||||||
query, err := c.StringArg(0)
|
|
||||||
if err != nil {
|
|
||||||
return "", "", []string{}, err
|
|
||||||
}
|
|
||||||
ctx, err := c.StringArg(1)
|
|
||||||
if err != nil {
|
|
||||||
return "", "", []string{}, err
|
|
||||||
}
|
|
||||||
fields, err := c.TableArg(2)
|
|
||||||
if err != nil {
|
|
||||||
return "", "", []string{}, err
|
|
||||||
}
|
|
||||||
|
|
||||||
var fds []string
|
|
||||||
nextVal := rt.NilValue
|
|
||||||
for {
|
|
||||||
next, val, ok := fields.Next(nextVal)
|
|
||||||
if next == rt.NilValue {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
nextVal = next
|
|
||||||
|
|
||||||
valStr, ok := val.TryString()
|
|
||||||
if !ok {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
fds = append(fds, valStr)
|
|
||||||
}
|
|
||||||
|
|
||||||
return query, ctx, fds, err
|
|
||||||
}
|
|
||||||
|
|
||||||
func setVimMode(mode string) {
|
func setVimMode(mode string) {
|
||||||
util.SetField(l, hshMod, "vimMode", rt.StringValue(mode), "Current Vim mode of Hilbish (nil if not in Vim mode)")
|
util.SetField(l, hshMod, "vimMode", rt.StringValue(mode), "Current Vim mode of Hilbish (nil if not in Vim mode)")
|
||||||
hooks.Em.Emit("hilbish.vimMode", mode)
|
hooks.Em.Emit("hilbish.vimMode", mode)
|
||||||
|
@ -395,21 +353,11 @@ func hlappendPath(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
|
||||||
|
|
||||||
// check if dir is a table or a string
|
// check if dir is a table or a string
|
||||||
if arg.Type() == rt.TableType {
|
if arg.Type() == rt.TableType {
|
||||||
nextVal := rt.NilValue
|
util.ForEach(arg.AsTable(), func(k rt.Value, v rt.Value) {
|
||||||
for {
|
if v.Type() == rt.StringType {
|
||||||
next, val, ok := arg.AsTable().Next(nextVal)
|
appendPath(v.AsString())
|
||||||
if next == rt.NilValue {
|
|
||||||
break
|
|
||||||
}
|
}
|
||||||
nextVal = next
|
})
|
||||||
|
|
||||||
valStr, ok := val.TryString()
|
|
||||||
if !ok {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
appendPath(valStr)
|
|
||||||
}
|
|
||||||
} else if arg.Type() == rt.StringType {
|
} else if arg.Type() == rt.StringType {
|
||||||
appendPath(arg.AsString())
|
appendPath(arg.AsString())
|
||||||
} else {
|
} else {
|
||||||
|
|
103
complete.go
103
complete.go
|
@ -1,9 +1,14 @@
|
||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"errors"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"strings"
|
"strings"
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
|
"hilbish/util"
|
||||||
|
|
||||||
|
rt "github.com/arnodel/golua/runtime"
|
||||||
)
|
)
|
||||||
|
|
||||||
func fileComplete(query, ctx string, fields []string) ([]string, string) {
|
func fileComplete(query, ctx string, fields []string) ([]string, string) {
|
||||||
|
@ -111,3 +116,101 @@ func escapeFilename(fname string) string {
|
||||||
r := strings.NewReplacer(args...)
|
r := strings.NewReplacer(args...)
|
||||||
return r.Replace(fname)
|
return r.Replace(fname)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func callLuaCompleter(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
|
||||||
|
if err := c.CheckNArgs(4); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
completer, err := c.StringArg(0)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
query, err := c.StringArg(1)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
ctx, err := c.StringArg(2)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
fields, err := c.TableArg(3)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var completecb *rt.Closure
|
||||||
|
var ok bool
|
||||||
|
if completecb, ok = luaCompletions[completer]; !ok {
|
||||||
|
return nil, errors.New("completer " + completer + " does not exist")
|
||||||
|
}
|
||||||
|
|
||||||
|
// we must keep the holy 80 cols
|
||||||
|
completerReturn, err := rt.Call1(l.MainThread(),
|
||||||
|
rt.FunctionValue(completecb), rt.StringValue(query),
|
||||||
|
rt.StringValue(ctx), rt.TableValue(fields))
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return c.PushingNext1(t.Runtime, completerReturn), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func luaFileComplete(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
|
||||||
|
query, ctx, fds, err := getCompleteParams(t, c)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
completions, _ := fileComplete(query, ctx, fds)
|
||||||
|
luaComps := rt.NewTable()
|
||||||
|
|
||||||
|
for i, comp := range completions {
|
||||||
|
luaComps.Set(rt.IntValue(int64(i + 1)), rt.StringValue(comp))
|
||||||
|
}
|
||||||
|
|
||||||
|
return c.PushingNext1(t.Runtime, rt.TableValue(luaComps)), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func luaBinaryComplete(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
|
||||||
|
query, ctx, fds, err := getCompleteParams(t, c)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
completions, _ := binaryComplete(query, ctx, fds)
|
||||||
|
luaComps := rt.NewTable()
|
||||||
|
|
||||||
|
for i, comp := range completions {
|
||||||
|
luaComps.Set(rt.IntValue(int64(i + 1)), rt.StringValue(comp))
|
||||||
|
}
|
||||||
|
|
||||||
|
return c.PushingNext1(t.Runtime, rt.TableValue(luaComps)), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func getCompleteParams(t *rt.Thread, c *rt.GoCont) (string, string, []string, error) {
|
||||||
|
if err := c.CheckNArgs(3); err != nil {
|
||||||
|
return "", "", []string{}, err
|
||||||
|
}
|
||||||
|
query, err := c.StringArg(0)
|
||||||
|
if err != nil {
|
||||||
|
return "", "", []string{}, err
|
||||||
|
}
|
||||||
|
ctx, err := c.StringArg(1)
|
||||||
|
if err != nil {
|
||||||
|
return "", "", []string{}, err
|
||||||
|
}
|
||||||
|
fields, err := c.TableArg(2)
|
||||||
|
if err != nil {
|
||||||
|
return "", "", []string{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var fds []string
|
||||||
|
util.ForEach(fields, func(k rt.Value, v rt.Value) {
|
||||||
|
if v.Type() == rt.StringType {
|
||||||
|
fds = append(fds, v.AsString())
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
return query, ctx, fds, err
|
||||||
|
}
|
||||||
|
|
70
rl.go
70
rl.go
|
@ -34,8 +34,7 @@ func newLineReader(prompt string, noHist bool) *lineReader {
|
||||||
case readline.VimKeys: modeStr = "normal"
|
case readline.VimKeys: modeStr = "normal"
|
||||||
case readline.VimInsert: modeStr = "insert"
|
case readline.VimInsert: modeStr = "insert"
|
||||||
case readline.VimDelete: modeStr = "delete"
|
case readline.VimDelete: modeStr = "delete"
|
||||||
case readline.VimReplaceOnce:
|
case readline.VimReplaceOnce, readline.VimReplaceMany: modeStr = "replace"
|
||||||
case readline.VimReplaceMany: modeStr = "replace"
|
|
||||||
}
|
}
|
||||||
setVimMode(modeStr)
|
setVimMode(modeStr)
|
||||||
}
|
}
|
||||||
|
@ -153,71 +152,54 @@ func newLineReader(prompt string, noHist bool) *lineReader {
|
||||||
to work on subcommands and subcompletions
|
to work on subcommands and subcompletions
|
||||||
*/
|
*/
|
||||||
if cmpTbl, ok := luacompleteTable.TryTable(); ok {
|
if cmpTbl, ok := luacompleteTable.TryTable(); ok {
|
||||||
nextVal := rt.NilValue
|
util.ForEach(cmpTbl, func(key rt.Value, val rt.Value) {
|
||||||
for {
|
if key.Type() != rt.IntType && val.Type() != rt.TableType {
|
||||||
next, val, ok := cmpTbl.Next(nextVal)
|
return
|
||||||
if next == rt.NilValue {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
nextVal = next
|
|
||||||
|
|
||||||
_, ok = next.TryInt()
|
|
||||||
valTbl, okk := val.TryTable()
|
|
||||||
if !ok || !okk {
|
|
||||||
// TODO: error?
|
|
||||||
break
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
valTbl := val.AsTable()
|
||||||
luaCompType := valTbl.Get(rt.StringValue("type"))
|
luaCompType := valTbl.Get(rt.StringValue("type"))
|
||||||
luaCompItems := valTbl.Get(rt.StringValue("items"))
|
luaCompItems := valTbl.Get(rt.StringValue("items"))
|
||||||
|
|
||||||
compType, ok := luaCompType.TryString()
|
if luaCompType.Type() != rt.StringType && luaCompItems.Type() != rt.TableType {
|
||||||
compItems, okk := luaCompItems.TryTable()
|
return
|
||||||
if !ok || !okk {
|
|
||||||
// TODO: error
|
|
||||||
break
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var items []string
|
items := []string{}
|
||||||
itemDescriptions := make(map[string]string)
|
itemDescriptions := make(map[string]string)
|
||||||
nxVal := rt.NilValue
|
|
||||||
for {
|
|
||||||
nx, vl, _ := compItems.Next(nxVal)
|
|
||||||
if nx == rt.NilValue {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
nxVal = nx
|
|
||||||
|
|
||||||
if tstr := nx.Type(); tstr == rt.StringType {
|
util.ForEach(luaCompItems.AsTable(), func(lkey rt.Value, lval rt.Value) {
|
||||||
|
if keytyp := lkey.Type(); keytyp == rt.StringType {
|
||||||
// ['--flag'] = {'description', '--flag-alias'}
|
// ['--flag'] = {'description', '--flag-alias'}
|
||||||
nxStr, ok := nx.TryString()
|
itemName, ok := lkey.TryString()
|
||||||
vlTbl, okk := vl.TryTable()
|
vlTbl, okk := lval.TryTable()
|
||||||
if !ok || !okk {
|
if !ok && !okk {
|
||||||
// TODO: error
|
// TODO: error
|
||||||
continue
|
return
|
||||||
}
|
}
|
||||||
items = append(items, nxStr)
|
|
||||||
|
items = append(items, itemName)
|
||||||
itemDescription, ok := vlTbl.Get(rt.IntValue(1)).TryString()
|
itemDescription, ok := vlTbl.Get(rt.IntValue(1)).TryString()
|
||||||
if !ok {
|
if !ok {
|
||||||
// TODO: error
|
// TODO: error
|
||||||
continue
|
return
|
||||||
}
|
}
|
||||||
itemDescriptions[nxStr] = itemDescription
|
itemDescriptions[itemName] = itemDescription
|
||||||
} else if tstr == rt.IntType {
|
} else if keytyp == rt.IntType {
|
||||||
vlStr, okk := vl.TryString()
|
vlStr, ok := lval.TryString()
|
||||||
if !okk {
|
if !ok {
|
||||||
// TODO: error
|
// TODO: error
|
||||||
continue
|
return
|
||||||
}
|
}
|
||||||
items = append(items, vlStr)
|
items = append(items, vlStr)
|
||||||
} else {
|
} else {
|
||||||
// TODO: error
|
// TODO: error
|
||||||
continue
|
return
|
||||||
}
|
}
|
||||||
}
|
})
|
||||||
|
|
||||||
var dispType readline.TabDisplayType
|
var dispType readline.TabDisplayType
|
||||||
switch compType {
|
switch luaCompType.AsString() {
|
||||||
case "grid": dispType = readline.TabDisplayGrid
|
case "grid": dispType = readline.TabDisplayGrid
|
||||||
case "list": dispType = readline.TabDisplayList
|
case "list": dispType = readline.TabDisplayList
|
||||||
// need special cases, will implement later
|
// need special cases, will implement later
|
||||||
|
@ -231,7 +213,7 @@ func newLineReader(prompt string, noHist bool) *lineReader {
|
||||||
TrimSlash: false,
|
TrimSlash: false,
|
||||||
NoSpace: true,
|
NoSpace: true,
|
||||||
})
|
})
|
||||||
}
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
22
util/util.go
22
util/util.go
|
@ -29,12 +29,16 @@ func SetField(rtm *rt.Runtime, module *rt.Table, field string, value rt.Value, d
|
||||||
|
|
||||||
if mt == nil {
|
if mt == nil {
|
||||||
mt = rt.NewTable()
|
mt = rt.NewTable()
|
||||||
docProp := rt.NewTable()
|
|
||||||
mt.Set(rt.StringValue("__docProp"), rt.TableValue(docProp))
|
|
||||||
|
|
||||||
module.SetMetatable(mt)
|
module.SetMetatable(mt)
|
||||||
}
|
}
|
||||||
|
|
||||||
docProp := mt.Get(rt.StringValue("__docProp"))
|
docProp := mt.Get(rt.StringValue("__docProp"))
|
||||||
|
if docProp == rt.NilValue {
|
||||||
|
docPropTbl := rt.NewTable()
|
||||||
|
mt.Set(rt.StringValue("__docProp"), rt.TableValue(docPropTbl))
|
||||||
|
docProp = mt.Get(rt.StringValue("__docProp"))
|
||||||
|
}
|
||||||
|
|
||||||
docProp.AsTable().Set(rt.StringValue(field), rt.StringValue(doc))
|
docProp.AsTable().Set(rt.StringValue(field), rt.StringValue(doc))
|
||||||
module.Set(rt.StringValue(field), value)
|
module.Set(rt.StringValue(field), value)
|
||||||
|
@ -118,3 +122,17 @@ func HandleStrCallback(t *rt.Thread, c *rt.GoCont) (string, *rt.Closure, error)
|
||||||
|
|
||||||
return name, cb, err
|
return name, cb, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ForEach loops through a Lua table.
|
||||||
|
func ForEach(tbl *rt.Table, cb func(key rt.Value, val rt.Value)) {
|
||||||
|
nextVal := rt.NilValue
|
||||||
|
for {
|
||||||
|
key, val, _ := tbl.Next(nextVal)
|
||||||
|
if key == rt.NilValue {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
nextVal = key
|
||||||
|
|
||||||
|
cb(key, val)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue