mirror of https://github.com/Hilbis/Hilbish
Compare commits
13 Commits
4080ba90e9
...
3db6334445
Author | SHA1 | Date |
---|---|---|
TorchedSammy | 3db6334445 | |
TorchedSammy | 9e596dc271 | |
TorchedSammy | f003249632 | |
TorchedSammy | 1714aeac36 | |
TorchedSammy | bca89197ad | |
TorchedSammy | 27ac60b856 | |
TorchedSammy | dbb27f7739 | |
TorchedSammy | 03a57fce5b | |
TorchedSammy | abfbeb5f84 | |
TorchedSammy | 3194add3dc | |
TorchedSammy | 1ba88fea88 | |
TorchedSammy | 1274811739 | |
TorchedSammy | 0af36db6ff |
2
Makefile
2
Makefile
|
@ -15,7 +15,7 @@ build:
|
|||
install:
|
||||
install -v -d "$(DESTDIR)$(BINDIR)/" && install -m 0755 -v hilbish "$(DESTDIR)$(BINDIR)/hilbish"
|
||||
mkdir -p "$(DESTDIR)$(LIBDIR)"
|
||||
cp -r libs docs emmyLuaDocs prelude .hilbishrc.lua "$(DESTDIR)$(LIBDIR)"
|
||||
cp -r libs docs emmyLuaDocs nature .hilbishrc.lua "$(DESTDIR)$(LIBDIR)"
|
||||
grep -qxF "$(DESTDIR)$(BINDIR)/hilbish" /etc/shells || echo "$(DESTDIR)$(BINDIR)/hilbish" >> /etc/shells
|
||||
|
||||
uninstall:
|
||||
|
|
40
api.go
40
api.go
|
@ -107,17 +107,17 @@ func hilbishLoad(rtm *rt.Runtime) (rt.Value, func()) {
|
|||
The nice lil shell for {blue}Lua{reset} fanatics!
|
||||
Check out the {blue}{bold}guide{reset} command to get started.
|
||||
`
|
||||
util.SetField(rtm, mod, "ver", rt.StringValue(version), "Hilbish version")
|
||||
util.SetField(rtm, mod, "user", rt.StringValue(username), "Username of user")
|
||||
util.SetField(rtm, mod, "host", rt.StringValue(host), "Host name of the machine")
|
||||
util.SetField(rtm, mod, "home", rt.StringValue(curuser.HomeDir), "Home directory of the user")
|
||||
util.SetField(rtm, mod, "dataDir", rt.StringValue(dataDir), "Directory for Hilbish's data files")
|
||||
util.SetField(rtm, mod, "interactive", rt.BoolValue(interactive), "If this is an interactive 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, "vimMode", rt.NilValue, "Current Vim mode of Hilbish (nil if not in Vim mode)")
|
||||
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.SetFieldProtected(fakeMod, mod, "ver", rt.StringValue(version), "Hilbish version")
|
||||
util.SetFieldProtected(fakeMod, mod, "user", rt.StringValue(username), "Username of user")
|
||||
util.SetFieldProtected(fakeMod, mod, "host", rt.StringValue(host), "Host name of the machine")
|
||||
util.SetFieldProtected(fakeMod, mod, "home", rt.StringValue(curuser.HomeDir), "Home directory of the user")
|
||||
util.SetFieldProtected(fakeMod, mod, "dataDir", rt.StringValue(dataDir), "Directory for Hilbish's data files")
|
||||
util.SetFieldProtected(fakeMod, mod, "interactive", rt.BoolValue(interactive), "If this is an interactive shell")
|
||||
util.SetFieldProtected(fakeMod, mod, "login", rt.BoolValue(login), "Whether this is a login shell")
|
||||
util.SetFieldProtected(fakeMod, mod, "greeting", rt.StringValue(greeting), "Hilbish's welcome message for interactive shells. It has Lunacolors formatting.")
|
||||
util.SetFieldProtected(fakeMod, mod, "vimMode", rt.NilValue, "Current Vim mode of Hilbish (nil if not in Vim mode)")
|
||||
util.SetFieldProtected(fakeMod, mod, "exitCode", rt.IntValue(0), "Exit code of last exected command")
|
||||
util.Document(fakeMod, "Hilbish's core API, containing submodules and functions which relate to the shell itself.")
|
||||
|
||||
// hilbish.userDir table
|
||||
hshuser := rt.NewTable()
|
||||
|
@ -149,19 +149,7 @@ Check out the {blue}{bold}guide{reset} command to get started.
|
|||
util.Document(historyModule, "History interface for Hilbish.")
|
||||
|
||||
// hilbish.completion table
|
||||
hshcomp := rt.NewTable()
|
||||
util.SetField(rtm, hshcomp, "files",
|
||||
rt.FunctionValue(rt.NewGoFunction(luaFileComplete, "files", 3, false)),
|
||||
"Completer for files")
|
||||
|
||||
util.SetField(rtm, hshcomp, "bins",
|
||||
rt.FunctionValue(rt.NewGoFunction(luaBinaryComplete, "bins", 3, false)),
|
||||
"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")
|
||||
|
||||
hshcomp := completionLoader(rtm)
|
||||
util.Document(hshcomp, "Completions interface for Hilbish.")
|
||||
mod.Set(rt.StringValue("completion"), rt.TableValue(hshcomp))
|
||||
|
||||
|
@ -509,9 +497,7 @@ func hlinterval(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
|
|||
// A `scope` is currently only expected to be `command.<cmd>`,
|
||||
// replacing <cmd> with the name of the command (for example `command.git`).
|
||||
// `cb` must be a function that returns a table of "completion groups."
|
||||
// A completion group is a table with the keys `items` and `type`.
|
||||
// `items` being a table of items and `type` being the display type, which is
|
||||
// `grid` (the normal file completion display) or `list` (with a description)
|
||||
// Check `doc completions` for more information.
|
||||
// --- @param scope string
|
||||
// --- @param cb function
|
||||
func hlcomplete(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
|
||||
|
|
102
complete.go
102
complete.go
|
@ -117,6 +117,100 @@ func escapeFilename(fname string) string {
|
|||
return r.Replace(fname)
|
||||
}
|
||||
|
||||
func completionLoader(rtm *rt.Runtime) *rt.Table {
|
||||
exports := map[string]util.LuaExport{
|
||||
"files": {luaFileComplete, 3, false},
|
||||
"bins": {luaBinaryComplete, 3, false},
|
||||
"call": {callLuaCompleter, 4, false},
|
||||
"handler": {completionHandler, 2, false},
|
||||
}
|
||||
|
||||
mod := rt.NewTable()
|
||||
util.SetExports(rtm, mod, exports)
|
||||
|
||||
return mod
|
||||
}
|
||||
|
||||
func completionHandler(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
|
||||
if err := c.CheckNArgs(2); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
line, err := c.StringArg(0)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// just for validation
|
||||
_, err = c.IntArg(1)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
ctx := strings.TrimLeft(line, " ")
|
||||
if len(ctx) == 0 {
|
||||
return c.PushingNext(t.Runtime, rt.TableValue(rt.NewTable()), rt.StringValue("")), nil
|
||||
}
|
||||
|
||||
ctx = aliases.Resolve(ctx)
|
||||
fields := strings.Split(ctx, " ")
|
||||
query := fields[len(fields) - 1]
|
||||
|
||||
luaFields := rt.NewTable()
|
||||
|
||||
for i, f := range fields {
|
||||
luaFields.Set(rt.IntValue(int64(i + 1)), rt.StringValue(f))
|
||||
}
|
||||
|
||||
compMod := hshMod.Get(rt.StringValue("completion")).AsTable()
|
||||
var term *rt.Termination
|
||||
if len(fields) == 1 {
|
||||
term = rt.NewTerminationWith(t.CurrentCont(), 2, false)
|
||||
err := rt.Call(t, compMod.Get(rt.StringValue("bins")), []rt.Value{
|
||||
rt.StringValue(query),
|
||||
rt.StringValue(ctx),
|
||||
rt.TableValue(luaFields),
|
||||
}, term)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
} else {
|
||||
gterm := rt.NewTerminationWith(t.CurrentCont(), 2, false)
|
||||
err := rt.Call(t, compMod.Get(rt.StringValue("call")), []rt.Value{
|
||||
rt.StringValue("commands." + fields[0]),
|
||||
rt.StringValue(query),
|
||||
rt.StringValue(ctx),
|
||||
rt.TableValue(luaFields),
|
||||
}, gterm)
|
||||
|
||||
if err == nil {
|
||||
groups := gterm.Get(0)
|
||||
pfx := gterm.Get(1)
|
||||
|
||||
return c.PushingNext(t.Runtime, groups, pfx), nil
|
||||
}
|
||||
|
||||
// error means there isnt a command handler - default to files in that case
|
||||
term = rt.NewTerminationWith(t.CurrentCont(), 2, false)
|
||||
err = rt.Call(t, compMod.Get(rt.StringValue("files")), []rt.Value{
|
||||
rt.StringValue(query),
|
||||
rt.StringValue(ctx),
|
||||
rt.TableValue(luaFields),
|
||||
}, term)
|
||||
}
|
||||
|
||||
comps := term.Get(0)
|
||||
pfx := term.Get(1)
|
||||
|
||||
groups := rt.NewTable()
|
||||
|
||||
compGroup := rt.NewTable()
|
||||
compGroup.Set(rt.StringValue("items"), comps)
|
||||
compGroup.Set(rt.StringValue("type"), rt.StringValue("grid"))
|
||||
|
||||
groups.Set(rt.IntValue(1), rt.TableValue(compGroup))
|
||||
return c.PushingNext(t.Runtime, rt.TableValue(groups), pfx), nil
|
||||
}
|
||||
|
||||
func callLuaCompleter(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
|
||||
if err := c.CheckNArgs(4); err != nil {
|
||||
return nil, err
|
||||
|
@ -162,14 +256,14 @@ func luaFileComplete(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
|
|||
return nil, err
|
||||
}
|
||||
|
||||
completions, _ := fileComplete(query, ctx, fds)
|
||||
completions, pfx := 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
|
||||
return c.PushingNext(t.Runtime, rt.TableValue(luaComps), rt.StringValue(pfx)), nil
|
||||
}
|
||||
|
||||
func luaBinaryComplete(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
|
||||
|
@ -178,14 +272,14 @@ func luaBinaryComplete(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
|
|||
return nil, err
|
||||
}
|
||||
|
||||
completions, _ := binaryComplete(query, ctx, fds)
|
||||
completions, pfx := 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
|
||||
return c.PushingNext(t.Runtime, rt.TableValue(luaComps), rt.StringValue(pfx)), nil
|
||||
}
|
||||
|
||||
func getCompleteParams(t *rt.Thread, c *rt.GoCont) (string, string, []string, error) {
|
||||
|
|
|
@ -0,0 +1,44 @@
|
|||
Hilbish has a pretty good completion system. It has a nice looking menu,
|
||||
with 2 types of menus: grid (like file completions) or list.
|
||||
|
||||
Like most parts of Hilbish, it's made to be extensible and customizable.
|
||||
The default handler for completions in general can be overwritten to provide
|
||||
more advanced completions if needed.
|
||||
|
||||
# Completion Handler
|
||||
By default, it provides 3 things: for the first argument, binaries (with a
|
||||
plain name requested to complete, those in $PATH), files, or command
|
||||
completions. With the default completion handler, it will try to run a
|
||||
handler for the command or fallback to file completions.
|
||||
|
||||
To overwrite it, just assign a function to `hilbish.completion.handler`
|
||||
like so:
|
||||
function hilbish.completion.handler(line, pos)
|
||||
-- do things
|
||||
end
|
||||
It is passed 2 arguments, the entire line, and the current cursor position.
|
||||
The functions in the completion interface take 3 arguments: query, ctx,
|
||||
and fields. The `query`, which what the user is currently trying to complete,
|
||||
`ctx`, being just the entire line, and `fields` being a table of arguments.
|
||||
It's just `ctx` split up, delimited by spaces.
|
||||
It's expected to return 2 things: a table of completion groups, and a prefix.
|
||||
A completion group is defined as a table with 2 keys: `items` and `type`.
|
||||
The `items` field is just a table of items to use for completions.
|
||||
The `type` is for the completion menu type, being either `grid` or `list`.
|
||||
The prefix is what all the completions start with. It should be empty
|
||||
if the user doesn't have a query. If the beginning of the completion
|
||||
item does not match the prefix, it will be replaced and fixed properly
|
||||
in the line. It is case sensitive.
|
||||
|
||||
If you want to overwrite the functionality of the general completion handler,
|
||||
or make your command completion have files as well (and filter them),
|
||||
then there is the `files` function, which is mentioned below.
|
||||
|
||||
# Completion Interface
|
||||
## Functions
|
||||
- `files(query, ctx, fields)` -> table, prefix: get file completions, based
|
||||
on the user's query.
|
||||
- `bins(query, ctx, fields)` -> table, prefix: get binary/executable
|
||||
completions, based on user query.
|
||||
- `call(scope, query, ctx, fields)` -> table, prefix: call a completion handler
|
||||
with `scope`, usually being in the form of `command.<name>`
|
|
@ -1,3 +1,5 @@
|
|||
abs(path) > Gives an absolute version of `path`.
|
||||
|
||||
cd(dir) > Changes directory to `dir`
|
||||
|
||||
mkdir(name, recursive) > Makes a directory called `name`. If `recursive` is true, it will create its parent directories.
|
||||
|
|
|
@ -6,9 +6,7 @@ complete(scope, cb) > Registers a completion handler for `scope`.
|
|||
A `scope` is currently only expected to be `command.<cmd>`,
|
||||
replacing <cmd> with the name of the command (for example `command.git`).
|
||||
`cb` must be a function that returns a table of "completion groups."
|
||||
A completion group is a table with the keys `items` and `type`.
|
||||
`items` being a table of items and `type` being the display type, which is
|
||||
`grid` (the normal file completion display) or `list` (with a description)
|
||||
Check `doc completions` for more information.
|
||||
|
||||
cwd() > Returns the current directory of the shell
|
||||
|
||||
|
|
|
@ -4,4 +4,4 @@
|
|||
`modeName` is the name of the mode changed to (can be `insert`, `normal`, `delete` or `replace`).
|
||||
|
||||
+ `hilbish.vimAction` -> actionName, args > Sent when the user does a "vim action," being something
|
||||
like yanking or pasting text. See `doc vimMode actions` for more info.
|
||||
like yanking or pasting text. See `doc vim-mode actions` for more info.
|
||||
|
|
|
@ -2,6 +2,10 @@
|
|||
|
||||
local fs = {}
|
||||
|
||||
--- Gives an absolute version of `path`.
|
||||
--- @param path string
|
||||
function fs.abs(path) end
|
||||
|
||||
--- Changes directory to `dir`
|
||||
--- @param dir string
|
||||
function fs.cd(dir) end
|
||||
|
|
|
@ -15,9 +15,7 @@ function hilbish.appendPath(dir) end
|
|||
--- A `scope` is currently only expected to be `command.<cmd>`,
|
||||
--- replacing <cmd> with the name of the command (for example `command.git`).
|
||||
--- `cb` must be a function that returns a table of "completion groups."
|
||||
--- A completion group is a table with the keys `items` and `type`.
|
||||
--- `items` being a table of items and `type` being the display type, which is
|
||||
--- `grid` (the normal file completion display) or `list` (with a description)
|
||||
--- Check `doc completions` for more information.
|
||||
--- @param scope string
|
||||
--- @param cb function
|
||||
function hilbish.complete(scope, cb) end
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package fs
|
||||
|
||||
import (
|
||||
"path/filepath"
|
||||
"strconv"
|
||||
"os"
|
||||
"strings"
|
||||
|
@ -22,6 +23,7 @@ func loaderFunc(rtm *rt.Runtime) (rt.Value, func()) {
|
|||
"mkdir": util.LuaExport{fmkdir, 2, false},
|
||||
"stat": util.LuaExport{fstat, 1, false},
|
||||
"readdir": util.LuaExport{freaddir, 1, false},
|
||||
"abs": util.LuaExport{fabs, 1, false},
|
||||
}
|
||||
mod := rt.NewTable()
|
||||
util.SetExports(rtm, mod, exports)
|
||||
|
@ -132,3 +134,20 @@ func freaddir(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
|
|||
|
||||
return c.PushingNext1(t.Runtime, rt.TableValue(names)), nil
|
||||
}
|
||||
|
||||
// abs(path)
|
||||
// Gives an absolute version of `path`.
|
||||
// --- @param path string
|
||||
func fabs(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
|
||||
path, err := c.StringArg(0)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
abspath, err := filepath.Abs(path)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return c.PushingNext1(t.Runtime, rt.StringValue(abspath)), nil
|
||||
}
|
||||
|
|
2
lua.go
2
lua.go
|
@ -54,7 +54,7 @@ func luaInit() {
|
|||
fmt.Fprintln(os.Stderr, "Could not add preload paths! Libraries will be missing. This shouldn't happen.")
|
||||
}
|
||||
|
||||
err = util.DoFile(l, "prelude/init.lua")
|
||||
err = util.DoFile(l, "nature/init.lua")
|
||||
if err != nil {
|
||||
err = util.DoFile(l, preloadPath)
|
||||
if err != nil {
|
||||
|
|
|
@ -0,0 +1,35 @@
|
|||
local bait = require 'bait'
|
||||
local commander = require 'commander'
|
||||
local fs = require 'fs'
|
||||
local dirs = require 'nature.dirs'
|
||||
|
||||
dirs.old = hilbish.cwd()
|
||||
commander.register('cd', function (args)
|
||||
if #args > 1 then
|
||||
print("cd: too many arguments")
|
||||
return 1
|
||||
elseif #args > 0 then
|
||||
local path = args[1]:gsub('$%$','\0'):gsub('${([%w_]+)}', os.getenv)
|
||||
:gsub('$([%w_]+)', os.getenv):gsub('%z','$'):gsub('^%s*(.-)%s*$', '%1')
|
||||
|
||||
if path == '-' then
|
||||
path = dirs.old
|
||||
print(path)
|
||||
end
|
||||
dirs.setOld(hilbish.cwd())
|
||||
dirs.push(path)
|
||||
|
||||
local ok, err = pcall(function() fs.cd(path) end)
|
||||
if not ok then
|
||||
print(err)
|
||||
return 1
|
||||
end
|
||||
bait.throw('cd', path)
|
||||
|
||||
return
|
||||
end
|
||||
fs.cd(hilbish.home)
|
||||
bait.throw('cd', hilbish.home)
|
||||
|
||||
dirs.addRecent(hilbish.home)
|
||||
end)
|
|
@ -0,0 +1,39 @@
|
|||
local commander = require 'commander'
|
||||
local fs = require 'fs'
|
||||
local lunacolors = require 'lunacolors'
|
||||
local dirs = require 'nature.dirs'
|
||||
|
||||
commander.register('cdr', function(args)
|
||||
if not args[1] then
|
||||
print(lunacolors.format [[
|
||||
cdr: change directory to one which has been recently visied
|
||||
|
||||
usage: cdr <index>
|
||||
|
||||
to get a list of recent directories, use {green}{underline}cdr list{reset}]])
|
||||
return
|
||||
end
|
||||
|
||||
if args[1] == 'list' then
|
||||
local recentDirs = dirs.recentDirs
|
||||
if #recentDirs == 0 then
|
||||
print 'No directories have been visited.'
|
||||
return 1
|
||||
end
|
||||
print(table.concat(recentDirs, '\n'))
|
||||
return
|
||||
end
|
||||
|
||||
local index = tonumber(args[1])
|
||||
if not index then
|
||||
print(string.format('Received %s as index, which isn\'t a number.', index))
|
||||
return 1
|
||||
end
|
||||
|
||||
if not dirs.recent(index) then
|
||||
print(string.format('No recent directory found at index %s.', index))
|
||||
return 1
|
||||
end
|
||||
|
||||
fs.cd(dirs.recent(index))
|
||||
end)
|
|
@ -0,0 +1,93 @@
|
|||
local commander = require 'commander'
|
||||
local fs = require 'fs'
|
||||
local lunacolors = require 'lunacolors'
|
||||
|
||||
commander.register('doc', function(args)
|
||||
local moddocPath = hilbish.dataDir .. '/docs/'
|
||||
local modDocFormat = [[
|
||||
%s
|
||||
%s
|
||||
# Functions
|
||||
]]
|
||||
|
||||
if #args > 0 then
|
||||
local mod = args[1]
|
||||
|
||||
local f = io.open(moddocPath .. mod .. '.txt', 'rb')
|
||||
local funcdocs = nil
|
||||
if not f then
|
||||
-- assume subdir
|
||||
-- dataDir/docs/<mod>/<mod>.txt
|
||||
moddocPath = moddocPath .. mod .. '/'
|
||||
local subdocName = args[2]
|
||||
if not subdocName then
|
||||
subdocName = 'index'
|
||||
end
|
||||
f = io.open(moddocPath .. subdocName .. '.txt', 'rb')
|
||||
if not f then
|
||||
print('No documentation found for ' .. mod .. '.')
|
||||
return
|
||||
end
|
||||
funcdocs = f:read '*a'
|
||||
local moddocs = table.filter(fs.readdir(moddocPath), function(f) return f ~= 'index.txt' end)
|
||||
local subdocs = table.map(moddocs, function(fname)
|
||||
return lunacolors.underline(lunacolors.blue(string.gsub(fname, '.txt', '')))
|
||||
end)
|
||||
if subdocName == 'index' then
|
||||
funcdocs = funcdocs .. '\nSubdocs: ' .. table.concat(subdocs, ', ')
|
||||
end
|
||||
end
|
||||
|
||||
if not funcdocs then
|
||||
funcdocs = f:read '*a'
|
||||
end
|
||||
local desc = ''
|
||||
local ok = pcall(require, mod)
|
||||
local backtickOccurence = 0
|
||||
local formattedFuncs = lunacolors.format(funcdocs:sub(1, #funcdocs - 1):gsub('`', function()
|
||||
backtickOccurence = backtickOccurence + 1
|
||||
if backtickOccurence % 2 == 0 then
|
||||
return '{reset}'
|
||||
else
|
||||
return '{underline}{green}'
|
||||
end
|
||||
end))
|
||||
|
||||
if ok then
|
||||
local props = {}
|
||||
local propstr = ''
|
||||
local modDesc = ''
|
||||
local modmt = getmetatable(require(mod))
|
||||
modDesc = modmt.__doc
|
||||
if modmt.__docProp then
|
||||
-- not all modules have docs for properties
|
||||
props = table.map(modmt.__docProp, function(v, k)
|
||||
return lunacolors.underline(lunacolors.blue(k)) .. ' > ' .. v
|
||||
end)
|
||||
end
|
||||
if #props > 0 then
|
||||
propstr = '\n# Properties\n' .. table.concat(props, '\n') .. '\n'
|
||||
end
|
||||
desc = string.format(modDocFormat, modDesc, propstr)
|
||||
end
|
||||
print(desc .. formattedFuncs)
|
||||
f:close()
|
||||
|
||||
return
|
||||
end
|
||||
local modules = table.map(fs.readdir(moddocPath), function(f)
|
||||
return lunacolors.underline(lunacolors.blue(string.gsub(f, '.txt', '')))
|
||||
end)
|
||||
|
||||
io.write [[
|
||||
Welcome to Hilbish's doc tool! Here you can find documentation for builtin
|
||||
functions and other things.
|
||||
|
||||
Usage: doc <section> [subdoc]
|
||||
A section is a module or a literal section and a subdoc is a subsection for it.
|
||||
|
||||
Available sections: ]]
|
||||
io.flush()
|
||||
|
||||
print(table.concat(modules, ', '))
|
||||
end)
|
|
@ -0,0 +1,7 @@
|
|||
local bait = require 'bait'
|
||||
local commander = require 'commander'
|
||||
|
||||
commander.register('exit', function()
|
||||
bait.throw('hilbish.exit')
|
||||
os.exit(0)
|
||||
end)
|
|
@ -0,0 +1,54 @@
|
|||
local ansikit = require 'ansikit'
|
||||
local commander = require 'commander'
|
||||
|
||||
local helpTexts = {
|
||||
[[
|
||||
Hello there! Welcome to Hilbish, the comfy and nice little shell for
|
||||
Lua users and fans. Hilbish is configured with Lua, and its
|
||||
scripts are also in Lua. It also runs both Lua and shell script when
|
||||
interactive (aka normal usage).
|
||||
]],
|
||||
[[
|
||||
What does that mean for you, the user? It means that if you prefer to
|
||||
use Lua for scripting instead of shell script but still have ordinary
|
||||
shell usage for interactive use.
|
||||
]],
|
||||
[[
|
||||
If this is your first time using Hilbish and Lua, check out the
|
||||
Programming in Lua book here: https://www.lua.org/pil
|
||||
After (or if you already know Lua) check out the doc command.
|
||||
It is an in shell tool for documentation about Hilbish provided
|
||||
functions and modules.
|
||||
]],
|
||||
[[
|
||||
If you've updated from a pre-1.0 version (0.7.1 as an example)
|
||||
you'll want to move your config from ~/.hilbishrc.lua to
|
||||
]] ..
|
||||
hilbish.userDir.config .. '/hilbish/init.lua' ..
|
||||
[[
|
||||
|
||||
and also change all global functions (prompt, alias) to be
|
||||
in the hilbish module (hilbish.prompt, hilbish.alias as examples).
|
||||
|
||||
And if this is your first time (most likely), you can copy a config
|
||||
from ]] .. hilbish.dataDir,
|
||||
[[
|
||||
Since 1.0 is a big release, you'll want to check the changelog
|
||||
at https://github.com/Rosettea/Hilbish/releases/tag/v1.0.0
|
||||
to find more breaking changes.
|
||||
]]
|
||||
}
|
||||
commander.register('guide', function()
|
||||
ansikit.clear()
|
||||
ansikit.cursorTo(0, 0)
|
||||
for _, text in ipairs(helpTexts) do
|
||||
print(text)
|
||||
local out = hilbish.read('Hit enter to continue ')
|
||||
ansikit.clear()
|
||||
ansikit.cursorTo(0, 0)
|
||||
if not out then
|
||||
return
|
||||
end
|
||||
end
|
||||
print 'Hope you enjoy using Hilbish!'
|
||||
end)
|
|
@ -0,0 +1,6 @@
|
|||
-- Add command builtins
|
||||
require 'nature.commands.cd'
|
||||
require 'nature.commands.cdr'
|
||||
require 'nature.commands.doc'
|
||||
require 'nature.commands.exit'
|
||||
require 'nature.commands.guide'
|
|
@ -0,0 +1,75 @@
|
|||
local fs = require 'fs'
|
||||
|
||||
local dirs = {}
|
||||
|
||||
--- Last (current working) directory. Separate from recentDirs mainly for
|
||||
--- easier use.
|
||||
dirs.old = ''
|
||||
--- Table of recent directories. For use, look at public functions.
|
||||
dirs.recentDirs = {}
|
||||
--- Size of the recentDirs table.
|
||||
dirs.recentSize = 10
|
||||
|
||||
--- Get (and remove) a `num` of entries from recent directories.
|
||||
--- @param num number
|
||||
--- @param remove boolean Whether to remove items
|
||||
function dirRecents(num, remove)
|
||||
num = num or 1
|
||||
local entries = {}
|
||||
|
||||
if #dirs.recentDirs ~= 0 then
|
||||
for i = 1, num do
|
||||
local idx = remove and 1 or i
|
||||
if not dirs.recentDirs[idx] then break end
|
||||
table.insert(entries, dirs.recentDirs[idx])
|
||||
if remove then table.remove(dirs.recentDirs, 1) end
|
||||
end
|
||||
end
|
||||
|
||||
if #entries == 1 then
|
||||
return entries[1]
|
||||
end
|
||||
|
||||
return entries
|
||||
end
|
||||
|
||||
--- Look at `num` amount of recent directories, starting from the latest.
|
||||
--- @param num? number
|
||||
function dirs.peak(num)
|
||||
return dirRecents(num)
|
||||
end
|
||||
|
||||
--- Add `d` to the recent directories.
|
||||
function dirs.push(d)
|
||||
dirs.recentDirs[dirs.recentSize + 1] = nil
|
||||
if dirs.recentDirs[#dirs.recentDirs - 1] ~= d then
|
||||
ok, d = pcall(fs.abs, d)
|
||||
assert(ok, 'could not turn "' .. d .. '"into an absolute path')
|
||||
|
||||
table.insert(dirs.recentDirs, 1, d)
|
||||
end
|
||||
end
|
||||
|
||||
--- Remove `num` amount of dirs from the recent directories.
|
||||
--- @param num number
|
||||
function dirs.pop(num)
|
||||
return dirRecents(num, true)
|
||||
end
|
||||
|
||||
--- Get entry from recent directories.
|
||||
--- @param idx number
|
||||
function dirs.recent(idx)
|
||||
return dirs.recentDirs[idx]
|
||||
end
|
||||
|
||||
--- Sets the old directory.
|
||||
--- @param d string
|
||||
function dirs.setOld(d)
|
||||
ok, d = pcall(fs.abs, d)
|
||||
assert(ok, 'could not turn "' .. d .. '"into an absolute path')
|
||||
|
||||
os.setenv('OLDPWD', d)
|
||||
dirs.old = d
|
||||
end
|
||||
|
||||
return dirs
|
|
@ -0,0 +1,11 @@
|
|||
local bait = require 'bait'
|
||||
|
||||
-- Hook handles
|
||||
bait.catch('command.not-found', function(cmd)
|
||||
print(string.format('hilbish: %s not found', cmd))
|
||||
end)
|
||||
|
||||
bait.catch('command.not-executable', function(cmd)
|
||||
print(string.format('hilbish: %s: not executable', cmd))
|
||||
end)
|
||||
|
|
@ -0,0 +1,44 @@
|
|||
-- Prelude initializes everything else for our shell
|
||||
local _ = require 'succulent' -- Function additions
|
||||
|
||||
package.path = package.path .. ';' .. hilbish.dataDir .. '/?/init.lua'
|
||||
.. ';' .. hilbish.dataDir .. '/?/?.lua'
|
||||
|
||||
require 'nature.hooks'
|
||||
require 'nature.commands'
|
||||
|
||||
local shlvl = tonumber(os.getenv 'SHLVL')
|
||||
if shlvl ~= nil then
|
||||
os.setenv('SHLVL', tostring(shlvl + 1))
|
||||
else
|
||||
os.setenv('SHLVL', '0')
|
||||
end
|
||||
|
||||
do
|
||||
local virt_G = { }
|
||||
|
||||
setmetatable(_G, {
|
||||
__index = function (_, key)
|
||||
local got_virt = virt_G[key]
|
||||
if got_virt ~= nil then
|
||||
return got_virt
|
||||
end
|
||||
|
||||
virt_G[key] = os.getenv(key)
|
||||
return virt_G[key]
|
||||
end,
|
||||
|
||||
__newindex = function (_, key, value)
|
||||
if type(value) == 'string' then
|
||||
os.setenv(key, value)
|
||||
virt_G[key] = value
|
||||
else
|
||||
if type(virt_G[key]) == 'string' then
|
||||
os.setenv(key, '')
|
||||
end
|
||||
virt_G[key] = value
|
||||
end
|
||||
end,
|
||||
})
|
||||
end
|
||||
|
264
prelude/init.lua
264
prelude/init.lua
|
@ -1,264 +0,0 @@
|
|||
-- The preload file initializes everything else for our shell
|
||||
local ansikit = require 'ansikit'
|
||||
local bait = require 'bait'
|
||||
local commander = require 'commander'
|
||||
local fs = require 'fs'
|
||||
local lunacolors = require 'lunacolors'
|
||||
local _ = require 'succulent' -- Function additions
|
||||
local oldDir = hilbish.cwd()
|
||||
|
||||
local shlvl = tonumber(os.getenv 'SHLVL')
|
||||
if shlvl ~= nil then os.setenv('SHLVL', tostring(shlvl + 1)) else os.setenv('SHLVL', '0') end
|
||||
|
||||
-- Builtins
|
||||
local recentDirs = {}
|
||||
commander.register('cd', function (args)
|
||||
if #args > 0 then
|
||||
local path = table.concat(args, ' '):gsub('$%$','\0'):gsub('${([%w_]+)}', os.getenv)
|
||||
:gsub('$([%w_]+)', os.getenv):gsub('%z','$'):gsub('^%s*(.-)%s*$', '%1')
|
||||
|
||||
if path == '-' then
|
||||
path = oldDir
|
||||
print(path)
|
||||
end
|
||||
oldDir = hilbish.cwd()
|
||||
|
||||
local ok, err = pcall(function() fs.cd(path) end)
|
||||
if not ok then
|
||||
print(err:sub(17))
|
||||
return 1
|
||||
end
|
||||
bait.throw('cd', path)
|
||||
|
||||
-- add to table of recent dirs
|
||||
recentDirs[11] = nil
|
||||
if recentDirs[#recentDirs - 1] ~= path then
|
||||
table.insert(recentDirs, 1, path)
|
||||
end
|
||||
|
||||
return
|
||||
end
|
||||
fs.cd(hilbish.home)
|
||||
bait.throw('cd', hilbish.home)
|
||||
|
||||
table.insert(recentDirs, 1, hilbish.home)
|
||||
recentDirs[11] = nil
|
||||
end)
|
||||
|
||||
commander.register('exit', function()
|
||||
bait.throw('hilbish.exit')
|
||||
os.exit(0)
|
||||
end)
|
||||
|
||||
commander.register('doc', function(args)
|
||||
local moddocPath = hilbish.dataDir .. '/docs/'
|
||||
local modDocFormat = [[
|
||||
%s
|
||||
%s
|
||||
# Functions
|
||||
]]
|
||||
|
||||
if #args > 0 then
|
||||
local mod = args[1]
|
||||
|
||||
local f = io.open(moddocPath .. mod .. '.txt', 'rb')
|
||||
local funcdocs = nil
|
||||
if not f then
|
||||
-- assume subdir
|
||||
-- dataDir/docs/<mod>/<mod>.txt
|
||||
moddocPath = moddocPath .. mod .. '/'
|
||||
local subdocName = args[2]
|
||||
if not subdocName then
|
||||
subdocName = 'index'
|
||||
end
|
||||
f = io.open(moddocPath .. subdocName .. '.txt', 'rb')
|
||||
if not f then
|
||||
print('No documentation found for ' .. mod .. '.')
|
||||
return
|
||||
end
|
||||
funcdocs = f:read '*a'
|
||||
local moddocs = table.filter(fs.readdir(moddocPath), function(f) return f ~= 'index.txt' end)
|
||||
local subdocs = table.map(moddocs, function(fname)
|
||||
return lunacolors.underline(lunacolors.blue(string.gsub(fname, '.txt', '')))
|
||||
end)
|
||||
if subdocName == 'index' then
|
||||
funcdocs = funcdocs .. '\nSubdocs: ' .. table.concat(subdocs, ', ')
|
||||
end
|
||||
end
|
||||
|
||||
if not funcdocs then
|
||||
funcdocs = f:read '*a'
|
||||
end
|
||||
local desc = ''
|
||||
local ok = pcall(require, mod)
|
||||
local backtickOccurence = 0
|
||||
local formattedFuncs = lunacolors.format(funcdocs:sub(1, #funcdocs - 1):gsub('`', function()
|
||||
backtickOccurence = backtickOccurence + 1
|
||||
if backtickOccurence % 2 == 0 then
|
||||
return '{reset}'
|
||||
else
|
||||
return '{underline}{green}'
|
||||
end
|
||||
end))
|
||||
|
||||
if ok then
|
||||
local props = {}
|
||||
local propstr = ''
|
||||
local modDesc = ''
|
||||
local modmt = getmetatable(require(mod))
|
||||
modDesc = modmt.__doc
|
||||
if modmt.__docProp then
|
||||
-- not all modules have docs for properties
|
||||
props = table.map(modmt.__docProp, function(v, k)
|
||||
return lunacolors.underline(lunacolors.blue(k)) .. ' > ' .. v
|
||||
end)
|
||||
end
|
||||
if #props > 0 then
|
||||
propstr = '\n# Properties\n' .. table.concat(props, '\n') .. '\n'
|
||||
end
|
||||
desc = string.format(modDocFormat, modDesc, propstr)
|
||||
end
|
||||
print(desc .. formattedFuncs)
|
||||
f:close()
|
||||
|
||||
return
|
||||
end
|
||||
local modules = table.map(fs.readdir(moddocPath), function(f)
|
||||
return lunacolors.underline(lunacolors.blue(string.gsub(f, '.txt', '')))
|
||||
end)
|
||||
|
||||
io.write [[
|
||||
Welcome to Hilbish's doc tool! Here you can find documentation for builtin
|
||||
functions and other things.
|
||||
|
||||
Usage: doc <section> [subdoc]
|
||||
A section is a module or a literal section and a subdoc is a subsection for it.
|
||||
|
||||
Available sections: ]]
|
||||
|
||||
print(table.concat(modules, ', '))
|
||||
end)
|
||||
|
||||
local helpTexts = {
|
||||
[[
|
||||
Hello there! Welcome to Hilbish, the comfy and nice little shell for
|
||||
Lua users and fans. Hilbish is configured with Lua, and its
|
||||
scripts are also in Lua. It also runs both Lua and shell script when
|
||||
interactive (aka normal usage).
|
||||
]],
|
||||
[[
|
||||
What does that mean for you, the user? It means that if you prefer to
|
||||
use Lua for scripting instead of shell script but still have ordinary
|
||||
shell usage for interactive use.
|
||||
]],
|
||||
[[
|
||||
If this is your first time using Hilbish and Lua, check out the
|
||||
Programming in Lua book here: https://www.lua.org/pil
|
||||
After (or if you already know Lua) check out the doc command.
|
||||
It is an in shell tool for documentation about Hilbish provided
|
||||
functions and modules.
|
||||
]],
|
||||
[[
|
||||
If you've updated from a pre-1.0 version (0.7.1 as an example)
|
||||
you'll want to move your config from ~/.hilbishrc.lua to
|
||||
]] ..
|
||||
hilbish.userDir.config .. '/hilbish/init.lua' ..
|
||||
[[
|
||||
|
||||
and also change all global functions (prompt, alias) to be
|
||||
in the hilbish module (hilbish.prompt, hilbish.alias as examples).
|
||||
|
||||
And if this is your first time (most likely), you can copy a config
|
||||
from ]] .. hilbish.dataDir,
|
||||
[[
|
||||
Since 1.0 is a big release, you'll want to check the changelog
|
||||
at https://github.com/Rosettea/Hilbish/releases/tag/v1.0.0
|
||||
to find more breaking changes.
|
||||
]]
|
||||
}
|
||||
commander.register('guide', function()
|
||||
ansikit.clear()
|
||||
ansikit.cursorTo(0, 0)
|
||||
for _, text in ipairs(helpTexts) do
|
||||
print(text)
|
||||
local out = hilbish.read('Hit enter to continue ')
|
||||
ansikit.clear()
|
||||
ansikit.cursorTo(0, 0)
|
||||
if not out then
|
||||
return
|
||||
end
|
||||
end
|
||||
print 'Hope you enjoy using Hilbish!'
|
||||
end)
|
||||
|
||||
do
|
||||
local virt_G = { }
|
||||
|
||||
setmetatable(_G, {
|
||||
__index = function (_, key)
|
||||
local got_virt = virt_G[key]
|
||||
if got_virt ~= nil then
|
||||
return got_virt
|
||||
end
|
||||
|
||||
virt_G[key] = os.getenv(key)
|
||||
return virt_G[key]
|
||||
end,
|
||||
|
||||
__newindex = function (_, key, value)
|
||||
if type(value) == 'string' then
|
||||
os.setenv(key, value)
|
||||
virt_G[key] = value
|
||||
else
|
||||
if type(virt_G[key]) == 'string' then
|
||||
os.setenv(key, '')
|
||||
end
|
||||
virt_G[key] = value
|
||||
end
|
||||
end,
|
||||
})
|
||||
end
|
||||
|
||||
commander.register('cdr', function(args)
|
||||
if not args[1] then
|
||||
print(lunacolors.format [[
|
||||
cdr: change directory to one which has been recently visied
|
||||
|
||||
usage: cdr <index>
|
||||
|
||||
to get a list of recent directories, use {green}{underline}cdr list{reset}]])
|
||||
return
|
||||
end
|
||||
|
||||
if args[1] == 'list' then
|
||||
if #recentDirs == 0 then
|
||||
print 'No directories have been visited.'
|
||||
return 1
|
||||
end
|
||||
print(table.concat(recentDirs, '\n'))
|
||||
return
|
||||
end
|
||||
|
||||
local index = tonumber(args[1])
|
||||
if not index then
|
||||
print(string.format('received %s as index, which isn\'t a number', index))
|
||||
return 1
|
||||
end
|
||||
|
||||
if not recentDirs[index] then
|
||||
print(string.format('no recent directory found at index %s', index))
|
||||
return 1
|
||||
end
|
||||
|
||||
fs.cd(recentDirs[index])
|
||||
end)
|
||||
|
||||
-- Hook handles
|
||||
bait.catch('command.not-found', function(cmd)
|
||||
print(string.format('hilbish: %s not found', cmd))
|
||||
end)
|
||||
|
||||
bait.catch('command.not-executable', function(cmd)
|
||||
print(string.format('hilbish: %s: not executable', cmd))
|
||||
end)
|
||||
|
206
rl.go
206
rl.go
|
@ -84,151 +84,91 @@ func newLineReader(prompt string, noHist bool) *lineReader {
|
|||
return highlighted
|
||||
}
|
||||
rl.TabCompleter = func(line []rune, pos int, _ readline.DelayedTabContext) (string, []*readline.CompletionGroup) {
|
||||
ctx := string(line)
|
||||
term := rt.NewTerminationWith(l.MainThread().CurrentCont(), 2, false)
|
||||
compHandle := hshMod.Get(rt.StringValue("completion")).AsTable().Get(rt.StringValue("handler"))
|
||||
err := rt.Call(l.MainThread(), compHandle, []rt.Value{rt.StringValue(string(line)),
|
||||
rt.IntValue(int64(pos))}, term)
|
||||
|
||||
var compGroup []*readline.CompletionGroup
|
||||
|
||||
ctx = strings.TrimLeft(ctx, " ")
|
||||
if len(ctx) == 0 {
|
||||
return "", compGroup
|
||||
var compGroups []*readline.CompletionGroup
|
||||
if err != nil {
|
||||
return "", compGroups
|
||||
}
|
||||
|
||||
fields := strings.Split(ctx, " ")
|
||||
if len(fields) == 0 {
|
||||
return "", compGroup
|
||||
luaCompGroups := term.Get(0)
|
||||
luaPrefix := term.Get(1)
|
||||
|
||||
if luaCompGroups.Type() != rt.TableType {
|
||||
return "", compGroups
|
||||
}
|
||||
query := fields[len(fields) - 1]
|
||||
|
||||
ctx = aliases.Resolve(ctx)
|
||||
groups := luaCompGroups.AsTable()
|
||||
// prefix is optional
|
||||
pfx, _ := luaPrefix.TryString()
|
||||
|
||||
if len(fields) == 1 {
|
||||
completions, prefix := binaryComplete(query, ctx, fields)
|
||||
util.ForEach(groups, func(key rt.Value, val rt.Value) {
|
||||
if key.Type() != rt.IntType || val.Type() != rt.TableType {
|
||||
return
|
||||
}
|
||||
|
||||
compGroup = append(compGroup, &readline.CompletionGroup{
|
||||
TrimSlash: false,
|
||||
NoSpace: true,
|
||||
Suggestions: completions,
|
||||
valTbl := val.AsTable()
|
||||
luaCompType := valTbl.Get(rt.StringValue("type"))
|
||||
luaCompItems := valTbl.Get(rt.StringValue("items"))
|
||||
|
||||
if luaCompType.Type() != rt.StringType || luaCompItems.Type() != rt.TableType {
|
||||
return
|
||||
}
|
||||
|
||||
items := []string{}
|
||||
itemDescriptions := make(map[string]string)
|
||||
|
||||
util.ForEach(luaCompItems.AsTable(), func(lkey rt.Value, lval rt.Value) {
|
||||
if keytyp := lkey.Type(); keytyp == rt.StringType {
|
||||
// ['--flag'] = {'description', '--flag-alias'}
|
||||
itemName, ok := lkey.TryString()
|
||||
vlTbl, okk := lval.TryTable()
|
||||
if !ok && !okk {
|
||||
// TODO: error
|
||||
return
|
||||
}
|
||||
|
||||
items = append(items, itemName)
|
||||
itemDescription, ok := vlTbl.Get(rt.IntValue(1)).TryString()
|
||||
if !ok {
|
||||
// TODO: error
|
||||
return
|
||||
}
|
||||
itemDescriptions[itemName] = itemDescription
|
||||
} else if keytyp == rt.IntType {
|
||||
vlStr, ok := lval.TryString()
|
||||
if !ok {
|
||||
// TODO: error
|
||||
return
|
||||
}
|
||||
items = append(items, vlStr)
|
||||
} else {
|
||||
// TODO: error
|
||||
return
|
||||
}
|
||||
})
|
||||
|
||||
return prefix, compGroup
|
||||
} else {
|
||||
if completecb, ok := luaCompletions["command." + fields[0]]; ok {
|
||||
luaFields := rt.NewTable()
|
||||
for i, f := range fields {
|
||||
luaFields.Set(rt.IntValue(int64(i + 1)), rt.StringValue(f))
|
||||
}
|
||||
|
||||
// we must keep the holy 80 cols
|
||||
luacompleteTable, err := rt.Call1(l.MainThread(),
|
||||
rt.FunctionValue(completecb), rt.StringValue(query),
|
||||
rt.StringValue(ctx), rt.TableValue(luaFields))
|
||||
|
||||
if err != nil {
|
||||
return "", compGroup
|
||||
}
|
||||
|
||||
/*
|
||||
as an example with git,
|
||||
completion table should be structured like:
|
||||
{
|
||||
{
|
||||
items = {
|
||||
'add',
|
||||
'clone',
|
||||
'init'
|
||||
},
|
||||
type = 'grid'
|
||||
},
|
||||
{
|
||||
items = {
|
||||
'-c',
|
||||
'--git-dir'
|
||||
},
|
||||
type = 'list'
|
||||
}
|
||||
}
|
||||
^ a table of completion groups.
|
||||
it is the responsibility of the completer
|
||||
to work on subcommands and subcompletions
|
||||
*/
|
||||
if cmpTbl, ok := luacompleteTable.TryTable(); ok {
|
||||
util.ForEach(cmpTbl, func(key rt.Value, val rt.Value) {
|
||||
if key.Type() != rt.IntType && val.Type() != rt.TableType {
|
||||
return
|
||||
}
|
||||
|
||||
valTbl := val.AsTable()
|
||||
luaCompType := valTbl.Get(rt.StringValue("type"))
|
||||
luaCompItems := valTbl.Get(rt.StringValue("items"))
|
||||
|
||||
if luaCompType.Type() != rt.StringType && luaCompItems.Type() != rt.TableType {
|
||||
return
|
||||
}
|
||||
|
||||
items := []string{}
|
||||
itemDescriptions := make(map[string]string)
|
||||
|
||||
util.ForEach(luaCompItems.AsTable(), func(lkey rt.Value, lval rt.Value) {
|
||||
if keytyp := lkey.Type(); keytyp == rt.StringType {
|
||||
// ['--flag'] = {'description', '--flag-alias'}
|
||||
itemName, ok := lkey.TryString()
|
||||
vlTbl, okk := lval.TryTable()
|
||||
if !ok && !okk {
|
||||
// TODO: error
|
||||
return
|
||||
}
|
||||
|
||||
items = append(items, itemName)
|
||||
itemDescription, ok := vlTbl.Get(rt.IntValue(1)).TryString()
|
||||
if !ok {
|
||||
// TODO: error
|
||||
return
|
||||
}
|
||||
itemDescriptions[itemName] = itemDescription
|
||||
} else if keytyp == rt.IntType {
|
||||
vlStr, ok := lval.TryString()
|
||||
if !ok {
|
||||
// TODO: error
|
||||
return
|
||||
}
|
||||
items = append(items, vlStr)
|
||||
} else {
|
||||
// TODO: error
|
||||
return
|
||||
}
|
||||
})
|
||||
|
||||
var dispType readline.TabDisplayType
|
||||
switch luaCompType.AsString() {
|
||||
case "grid": dispType = readline.TabDisplayGrid
|
||||
case "list": dispType = readline.TabDisplayList
|
||||
// need special cases, will implement later
|
||||
//case "map": dispType = readline.TabDisplayMap
|
||||
}
|
||||
|
||||
compGroup = append(compGroup, &readline.CompletionGroup{
|
||||
DisplayType: dispType,
|
||||
Descriptions: itemDescriptions,
|
||||
Suggestions: items,
|
||||
TrimSlash: false,
|
||||
NoSpace: true,
|
||||
})
|
||||
})
|
||||
}
|
||||
var dispType readline.TabDisplayType
|
||||
switch luaCompType.AsString() {
|
||||
case "grid": dispType = readline.TabDisplayGrid
|
||||
case "list": dispType = readline.TabDisplayList
|
||||
// need special cases, will implement later
|
||||
//case "map": dispType = readline.TabDisplayMap
|
||||
}
|
||||
|
||||
if len(compGroup) == 0 {
|
||||
completions, p := fileComplete(query, ctx, fields)
|
||||
fcompGroup := []*readline.CompletionGroup{{
|
||||
TrimSlash: false,
|
||||
NoSpace: true,
|
||||
Suggestions: completions,
|
||||
}}
|
||||
compGroups = append(compGroups, &readline.CompletionGroup{
|
||||
DisplayType: dispType,
|
||||
Descriptions: itemDescriptions,
|
||||
Suggestions: items,
|
||||
TrimSlash: false,
|
||||
NoSpace: true,
|
||||
})
|
||||
})
|
||||
|
||||
return p, fcompGroup
|
||||
}
|
||||
}
|
||||
return "", compGroup
|
||||
return pfx, compGroups
|
||||
}
|
||||
|
||||
return &lineReader{
|
||||
|
|
18
util/util.go
18
util/util.go
|
@ -25,11 +25,17 @@ func Document(module *rt.Table, doc string) {
|
|||
// It is accessible via the __docProp metatable. It is a table of the names of the fields.
|
||||
func SetField(rtm *rt.Runtime, module *rt.Table, field string, value rt.Value, doc string) {
|
||||
// TODO: ^ rtm isnt needed, i should remove it
|
||||
SetFieldDoc(module, field, doc)
|
||||
module.Set(rt.StringValue(field), value)
|
||||
}
|
||||
|
||||
// SetFieldDoc sets the __docProp metatable for a field on the
|
||||
// module.
|
||||
func SetFieldDoc(module *rt.Table, field, doc string) {
|
||||
mt := module.Metatable()
|
||||
|
||||
if mt == nil {
|
||||
mt = rt.NewTable()
|
||||
|
||||
module.SetMetatable(mt)
|
||||
}
|
||||
|
||||
|
@ -41,7 +47,15 @@ func SetField(rtm *rt.Runtime, module *rt.Table, field string, value rt.Value, d
|
|||
}
|
||||
|
||||
docProp.AsTable().Set(rt.StringValue(field), rt.StringValue(doc))
|
||||
module.Set(rt.StringValue(field), value)
|
||||
}
|
||||
|
||||
// SetFieldProtected sets a field in a protected table. A protected table
|
||||
// is one which has a metatable proxy to ensure no overrides happen to it.
|
||||
// It sets the field in the table and sets the __docProp metatable on the
|
||||
// user facing table.
|
||||
func SetFieldProtected(module, realModule *rt.Table, field string, value rt.Value, doc string) {
|
||||
SetFieldDoc(module, field, doc)
|
||||
realModule.Set(rt.StringValue(field), value)
|
||||
}
|
||||
|
||||
// DoString runs the code string in the Lua runtime.
|
||||
|
|
|
@ -15,7 +15,7 @@ var (
|
|||
.. hilbish.userDir.config .. '/hilbish/?/?.lua;'
|
||||
.. hilbish.userDir.config .. '/hilbish/?.lua'`
|
||||
dataDir = "/usr/local/share/hilbish"
|
||||
preloadPath = dataDir + "/prelude/init.lua"
|
||||
preloadPath = dataDir + "/nature/init.lua"
|
||||
sampleConfPath = dataDir + "/.hilbishrc.lua" // Path to default/sample config
|
||||
defaultConfDir = getenv("XDG_CONFIG_HOME", "~/.config")
|
||||
)
|
||||
|
|
|
@ -15,7 +15,7 @@ var (
|
|||
.. hilbish.userDir.config .. '/hilbish/?/?.lua;'
|
||||
.. hilbish.userDir.config .. '/hilbish/?.lua'`
|
||||
dataDir = "/usr/share/hilbish"
|
||||
preloadPath = dataDir + "/prelude/init.lua"
|
||||
preloadPath = dataDir + "/nature/init.lua"
|
||||
sampleConfPath = dataDir + "/.hilbishrc.lua" // Path to default/sample config
|
||||
defaultConfDir = ""
|
||||
)
|
||||
|
|
|
@ -9,7 +9,7 @@ var (
|
|||
.. hilbish.userDir.config .. '\\Hilbish\\libs\\?\\?.lua;'
|
||||
.. hilbish.userDir.config .. '\\Hilbish\\libs\\?.lua;'`
|
||||
dataDir = "~\\Appdata\\Roaming\\Hilbish" // ~ and \ gonna cry?
|
||||
preloadPath = dataDir + "\\prelude\\init.lua"
|
||||
preloadPath = dataDir + "\\nature\\init.lua"
|
||||
sampleConfPath = dataDir + "\\hilbishrc.lua" // Path to default/sample config
|
||||
defaultConfDir = ""
|
||||
)
|
||||
|
|
Loading…
Reference in New Issue