mirror of https://github.com/Hilbis/Hilbish
Compare commits
15 Commits
bbf5a93ca0
...
40c2933a95
Author | SHA1 | Date |
---|---|---|
TorchedSammy | 40c2933a95 | |
TorchedSammy | 7434d270e4 | |
TorchedSammy | 3dae826578 | |
TorchedSammy | 001bd15ced | |
TorchedSammy | 09a8b41063 | |
sammy | 349380ae6b | |
TorchedSammy | f7806f5479 | |
TorchedSammy | c8c30e9861 | |
TorchedSammy | 083c266438 | |
TorchedSammy | dd9bdca5e0 | |
TorchedSammy | 9902560061 | |
TorchedSammy | dd9aa4b6ea | |
TorchedSammy | be8bdef9c8 | |
TorchedSammy | e185a32685 | |
TorchedSammy | 2b480e50e6 |
16
CHANGELOG.md
16
CHANGELOG.md
|
@ -56,6 +56,7 @@ having and using multiple runners.
|
||||||
- `fs.basename(path)` gets the basename of path
|
- `fs.basename(path)` gets the basename of path
|
||||||
- `fs.dir(path)` gets the directory part of path
|
- `fs.dir(path)` gets the directory part of path
|
||||||
- `fs.glob(pattern)` globs files and directories based on patterns
|
- `fs.glob(pattern)` globs files and directories based on patterns
|
||||||
|
- `fs.join(dirs...)` joins directories by OS dir separator
|
||||||
- .. and 2 properties
|
- .. and 2 properties
|
||||||
- `fs.pathSep` is the separator for filesystem paths and directories
|
- `fs.pathSep` is the separator for filesystem paths and directories
|
||||||
- `fs.pathListSep` is the separator for $PATH env entries
|
- `fs.pathListSep` is the separator for $PATH env entries
|
||||||
|
@ -65,7 +66,10 @@ will be ran on startup
|
||||||
- Message of the day on startup (`hilbish.motd`), mainly intended as quick
|
- Message of the day on startup (`hilbish.motd`), mainly intended as quick
|
||||||
small news pieces for releases. It is printed by default. To disable it,
|
small news pieces for releases. It is printed by default. To disable it,
|
||||||
set `hilbish.opts.motd` to false.
|
set `hilbish.opts.motd` to false.
|
||||||
|
- `history` opt has been added and is true by default. Setting it to false
|
||||||
|
disables commands being added to history.
|
||||||
- `hilbish.rawInput` hook for input from the readline library
|
- `hilbish.rawInput` hook for input from the readline library
|
||||||
|
- Completion of files in quotes
|
||||||
|
|
||||||
### Changed
|
### Changed
|
||||||
- **Breaking Change:** Upgraded to Lua 5.4.
|
- **Breaking Change:** Upgraded to Lua 5.4.
|
||||||
|
@ -88,6 +92,10 @@ of a dot. (ie. `job.stop()` -> `job:stop()`)
|
||||||
- All `fs` module functions which take paths now implicitly expand ~ to home.
|
- All `fs` module functions which take paths now implicitly expand ~ to home.
|
||||||
- **Breaking Change:** `hilbish.greeting` has been moved to an opt (`hilbish.opts.greeting`) and is
|
- **Breaking Change:** `hilbish.greeting` has been moved to an opt (`hilbish.opts.greeting`) and is
|
||||||
always printed by default. To disable it, set the opt to false.
|
always printed by default. To disable it, set the opt to false.
|
||||||
|
- History is now fetched from Lua, which means users can override `hilbish.history`
|
||||||
|
methods to make it act how they want.
|
||||||
|
- `guide` has been removed. See the [website](https://rosettea.github.io/Hilbish/)
|
||||||
|
for general tips and documentation
|
||||||
|
|
||||||
### Fixed
|
### Fixed
|
||||||
- If in Vim replace mode, input at the end of the line inserts instead of
|
- If in Vim replace mode, input at the end of the line inserts instead of
|
||||||
|
@ -122,6 +130,14 @@ for explanation.
|
||||||
Lua `job.stop` function.
|
Lua `job.stop` function.
|
||||||
- Jobs are always started in sh exec handler now instead of only successful start.
|
- Jobs are always started in sh exec handler now instead of only successful start.
|
||||||
- SIGTERM is handled properly now, which means stopping jobs and timers.
|
- SIGTERM is handled properly now, which means stopping jobs and timers.
|
||||||
|
- Fix panic on trailing newline on pasted multiline text.
|
||||||
|
- Completions will no longer be refreshed if the prompt refreshes while the
|
||||||
|
menu is open.
|
||||||
|
- Print error on search fail instead of panicking
|
||||||
|
- Windows related fixes:
|
||||||
|
- `hilbish.dataDir` now has tilde (`~`) expanded.
|
||||||
|
- Arrow keys now work on Windows terminals.
|
||||||
|
- Escape codes now work.
|
||||||
|
|
||||||
## [1.2.0] - 2022-03-17
|
## [1.2.0] - 2022-03-17
|
||||||
### Added
|
### Added
|
||||||
|
|
|
@ -11,6 +11,9 @@ filepath.Dir
|
||||||
glob(pattern) > Glob all files and directories that match the pattern.
|
glob(pattern) > Glob all files and directories that match the pattern.
|
||||||
For the rules, see Go's filepath.Glob
|
For the rules, see Go's filepath.Glob
|
||||||
|
|
||||||
|
join(paths...) > Takes paths and joins them together with the OS's
|
||||||
|
directory separator (forward or backward slash).
|
||||||
|
|
||||||
mkdir(name, recursive) > Makes a directory called `name`. If `recursive` is true, it will create its parent directories.
|
mkdir(name, recursive) > Makes a directory called `name`. If `recursive` is true, it will create its parent directories.
|
||||||
|
|
||||||
readdir(dir) > Returns a table of files in `dir`
|
readdir(dir) > Returns a table of files in `dir`
|
||||||
|
|
|
@ -22,6 +22,10 @@ function fs.dir() end
|
||||||
--- For the rules, see Go's filepath.Glob
|
--- For the rules, see Go's filepath.Glob
|
||||||
function fs.glob() end
|
function fs.glob() end
|
||||||
|
|
||||||
|
--- Takes paths and joins them together with the OS's
|
||||||
|
--- directory separator (forward or backward slash).
|
||||||
|
function fs.join() end
|
||||||
|
|
||||||
--- Makes a directory called `name`. If `recursive` is true, it will create its parent directories.
|
--- Makes a directory called `name`. If `recursive` is true, it will create its parent directories.
|
||||||
--- @param name string
|
--- @param name string
|
||||||
--- @param recursive boolean
|
--- @param recursive boolean
|
||||||
|
|
6
exec.go
6
exec.go
|
@ -540,13 +540,9 @@ func splitInput(input string) ([]string, string) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func cmdFinish(code uint8, cmdstr string, private bool) {
|
func cmdFinish(code uint8, cmdstr string, private bool) {
|
||||||
// if input has space at the beginning, dont put in history
|
|
||||||
if interactive && !private {
|
|
||||||
handleHistory(cmdstr)
|
|
||||||
}
|
|
||||||
util.SetField(l, hshMod, "exitCode", rt.IntValue(int64(code)), "Exit code of last exected command")
|
util.SetField(l, hshMod, "exitCode", rt.IntValue(int64(code)), "Exit code of last exected command")
|
||||||
// using AsValue (to convert to lua type) on an interface which is an int
|
// using AsValue (to convert to lua type) on an interface which is an int
|
||||||
// results in it being unknown in lua .... ????
|
// results in it being unknown in lua .... ????
|
||||||
// so we allow the hook handler to take lua runtime Values
|
// so we allow the hook handler to take lua runtime Values
|
||||||
hooks.Em.Emit("command.exit", rt.IntValue(int64(code)), cmdstr)
|
hooks.Em.Emit("command.exit", rt.IntValue(int64(code)), cmdstr, private)
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
package fs
|
package fs
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"strconv"
|
"strconv"
|
||||||
"os"
|
"os"
|
||||||
|
@ -27,6 +28,7 @@ func loaderFunc(rtm *rt.Runtime) (rt.Value, func()) {
|
||||||
"basename": util.LuaExport{fbasename, 1, false},
|
"basename": util.LuaExport{fbasename, 1, false},
|
||||||
"dir": util.LuaExport{fdir, 1, false},
|
"dir": util.LuaExport{fdir, 1, false},
|
||||||
"glob": util.LuaExport{fglob, 1, false},
|
"glob": util.LuaExport{fglob, 1, false},
|
||||||
|
"join": util.LuaExport{fjoin, 0, true},
|
||||||
}
|
}
|
||||||
mod := rt.NewTable()
|
mod := rt.NewTable()
|
||||||
util.SetExports(rtm, mod, exports)
|
util.SetExports(rtm, mod, exports)
|
||||||
|
@ -216,3 +218,21 @@ func fglob(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
|
||||||
|
|
||||||
return c.PushingNext(t.Runtime, rt.TableValue(luaMatches)), nil
|
return c.PushingNext(t.Runtime, rt.TableValue(luaMatches)), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// join(paths...)
|
||||||
|
// Takes paths and joins them together with the OS's
|
||||||
|
// directory separator (forward or backward slash).
|
||||||
|
func fjoin(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
|
||||||
|
strs := make([]string, len(c.Etc()))
|
||||||
|
for i, v := range c.Etc() {
|
||||||
|
if v.Type() != rt.StringType {
|
||||||
|
// +2; go indexes of 0 and first arg from above
|
||||||
|
return nil, fmt.Errorf("bad argument #%d to run (expected string, got %s)", i + 1, v.TypeName())
|
||||||
|
}
|
||||||
|
strs[i] = v.AsString()
|
||||||
|
}
|
||||||
|
|
||||||
|
res := filepath.Join(strs...)
|
||||||
|
|
||||||
|
return c.PushingNext(t.Runtime, rt.StringValue(res)), nil
|
||||||
|
}
|
||||||
|
|
56
history.go
56
history.go
|
@ -4,21 +4,69 @@ import (
|
||||||
"errors"
|
"errors"
|
||||||
"io/fs"
|
"io/fs"
|
||||||
"os"
|
"os"
|
||||||
|
"path/filepath"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
rt "github.com/arnodel/golua/runtime"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type luaHistory struct {}
|
||||||
|
|
||||||
|
func (h *luaHistory) Write(line string) (int, error) {
|
||||||
|
histWrite := hshMod.Get(rt.StringValue("history")).AsTable().Get(rt.StringValue("add"))
|
||||||
|
ln, err := rt.Call1(l.MainThread(), histWrite, rt.StringValue(line))
|
||||||
|
|
||||||
|
var num int64
|
||||||
|
if ln.Type() == rt.IntType {
|
||||||
|
num = ln.AsInt()
|
||||||
|
}
|
||||||
|
|
||||||
|
return int(num), err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *luaHistory) GetLine(idx int) (string, error) {
|
||||||
|
histGet := hshMod.Get(rt.StringValue("history")).AsTable().Get(rt.StringValue("get"))
|
||||||
|
lcmd, err := rt.Call1(l.MainThread(), histGet, rt.IntValue(int64(idx)))
|
||||||
|
|
||||||
|
var cmd string
|
||||||
|
if lcmd.Type() == rt.StringType {
|
||||||
|
cmd = lcmd.AsString()
|
||||||
|
}
|
||||||
|
|
||||||
|
return cmd, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *luaHistory) Len() int {
|
||||||
|
histSize := hshMod.Get(rt.StringValue("history")).AsTable().Get(rt.StringValue("size"))
|
||||||
|
ln, _ := rt.Call1(l.MainThread(), histSize)
|
||||||
|
|
||||||
|
var num int64
|
||||||
|
if ln.Type() == rt.IntType {
|
||||||
|
num = ln.AsInt()
|
||||||
|
}
|
||||||
|
|
||||||
|
return int(num)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *luaHistory) Dump() interface{} {
|
||||||
|
// hilbish.history interface already has all function, this isnt used in readline
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
type fileHistory struct {
|
type fileHistory struct {
|
||||||
items []string
|
items []string
|
||||||
f *os.File
|
f *os.File
|
||||||
}
|
}
|
||||||
|
|
||||||
func newFileHistory() *fileHistory {
|
func newFileHistory(path string) *fileHistory {
|
||||||
err := os.MkdirAll(defaultHistDir, 0755)
|
dir := filepath.Dir(path)
|
||||||
|
|
||||||
|
err := os.MkdirAll(dir, 0755)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
data, err := os.ReadFile(defaultHistPath)
|
data, err := os.ReadFile(path)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if !errors.Is(err, fs.ErrNotExist) {
|
if !errors.Is(err, fs.ErrNotExist) {
|
||||||
panic(err)
|
panic(err)
|
||||||
|
@ -33,7 +81,7 @@ func newFileHistory() *fileHistory {
|
||||||
}
|
}
|
||||||
itms = append(itms, l)
|
itms = append(itms, l)
|
||||||
}
|
}
|
||||||
f, err := os.OpenFile(defaultHistPath, os.O_APPEND | os.O_WRONLY | os.O_CREATE, 0755)
|
f, err := os.OpenFile(path, os.O_APPEND | os.O_WRONLY | os.O_CREATE, 0755)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,7 +5,13 @@ package main
|
||||||
import "golang.org/x/sys/windows"
|
import "golang.org/x/sys/windows"
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
var mode uint32
|
// vt output (escape codes)
|
||||||
windows.GetConsoleMode(windows.Stdout, &mode)
|
var outMode uint32
|
||||||
windows.SetConsoleMode(windows.Stdout, mode | windows.ENABLE_VIRTUAL_TERMINAL_PROCESSING)
|
windows.GetConsoleMode(windows.Stdout, &outMode)
|
||||||
|
windows.SetConsoleMode(windows.Stdout, outMode | windows.ENABLE_VIRTUAL_TERMINAL_PROCESSING)
|
||||||
|
|
||||||
|
// vt input
|
||||||
|
var inMode uint32
|
||||||
|
windows.GetConsoleMode(windows.Stdin, &inMode)
|
||||||
|
windows.SetConsoleMode(windows.Stdin, inMode | windows.ENABLE_VIRTUAL_TERMINAL_INPUT)
|
||||||
}
|
}
|
||||||
|
|
4
lua.go
4
lua.go
|
@ -12,12 +12,16 @@ import (
|
||||||
|
|
||||||
rt "github.com/arnodel/golua/runtime"
|
rt "github.com/arnodel/golua/runtime"
|
||||||
"github.com/arnodel/golua/lib"
|
"github.com/arnodel/golua/lib"
|
||||||
|
"github.com/arnodel/golua/lib/debuglib"
|
||||||
)
|
)
|
||||||
|
|
||||||
var minimalconf = `hilbish.prompt '& '`
|
var minimalconf = `hilbish.prompt '& '`
|
||||||
|
|
||||||
func luaInit() {
|
func luaInit() {
|
||||||
l = rt.New(os.Stdout)
|
l = rt.New(os.Stdout)
|
||||||
|
l.PushContext(rt.RuntimeContextDef{
|
||||||
|
MessageHandler: debuglib.Traceback,
|
||||||
|
})
|
||||||
lib.LoadAll(l)
|
lib.LoadAll(l)
|
||||||
|
|
||||||
lib.LoadLibs(l, hilbishLoader)
|
lib.LoadLibs(l, hilbishLoader)
|
||||||
|
|
5
main.go
5
main.go
|
@ -269,11 +269,6 @@ func fmtPrompt(prompt string) string {
|
||||||
return nprompt
|
return nprompt
|
||||||
}
|
}
|
||||||
|
|
||||||
func handleHistory(cmd string) {
|
|
||||||
lr.AddHistory(cmd)
|
|
||||||
// TODO: load history again (history shared between sessions like this ye)
|
|
||||||
}
|
|
||||||
|
|
||||||
func removeDupes(slice []string) []string {
|
func removeDupes(slice []string) []string {
|
||||||
all := make(map[string]bool)
|
all := make(map[string]bool)
|
||||||
newSlice := []string{}
|
newSlice := []string{}
|
||||||
|
|
|
@ -1,54 +0,0 @@
|
||||||
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)
|
|
|
@ -3,7 +3,6 @@ require 'nature.commands.cd'
|
||||||
require 'nature.commands.cdr'
|
require 'nature.commands.cdr'
|
||||||
require 'nature.commands.doc'
|
require 'nature.commands.doc'
|
||||||
require 'nature.commands.exit'
|
require 'nature.commands.exit'
|
||||||
require 'nature.commands.guide'
|
|
||||||
require 'nature.commands.disown'
|
require 'nature.commands.disown'
|
||||||
require 'nature.commands.fg'
|
require 'nature.commands.fg'
|
||||||
require 'nature.commands.bg'
|
require 'nature.commands.bg'
|
||||||
|
|
|
@ -0,0 +1,5 @@
|
||||||
|
local bait = require 'bait'
|
||||||
|
|
||||||
|
bait.catch('command.exit', function(_, cmd, priv)
|
||||||
|
if not priv and hilbish.opts.history then hilbish.history.add(cmd) end
|
||||||
|
end)
|
|
@ -21,6 +21,7 @@ end
|
||||||
|
|
||||||
local defaultOpts = {
|
local defaultOpts = {
|
||||||
autocd = false,
|
autocd = false,
|
||||||
|
history = true,
|
||||||
greeting = string.format([[Welcome to {magenta}Hilbish{reset}, {cyan}%s{reset}.
|
greeting = string.format([[Welcome to {magenta}Hilbish{reset}, {cyan}%s{reset}.
|
||||||
The nice lil shell for {blue}Lua{reset} fanatics!
|
The nice lil shell for {blue}Lua{reset} fanatics!
|
||||||
]], hilbish.user),
|
]], hilbish.user),
|
||||||
|
|
|
@ -88,7 +88,7 @@ func (g *CompletionGroup) updateTabFind(rl *Instance) {
|
||||||
if rl.searchMode != HistoryFind {
|
if rl.searchMode != HistoryFind {
|
||||||
g.Suggestions = g.filterSuggestions(rl)
|
g.Suggestions = g.filterSuggestions(rl)
|
||||||
} else {
|
} else {
|
||||||
g.Suggestions = rl.HistorySearcher(string(rl.tfLine))
|
g.Suggestions = rl.HistorySearcher(string(rl.tfLine), g.Suggestions)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Finally, the group computes its new printing settings
|
// Finally, the group computes its new printing settings
|
||||||
|
|
|
@ -201,7 +201,7 @@ type Instance struct {
|
||||||
|
|
||||||
RawInputCallback func([]rune) // called on all input
|
RawInputCallback func([]rune) // called on all input
|
||||||
|
|
||||||
HistorySearcher func(string) []string
|
HistorySearcher func(string, []string) []string
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewInstance is used to create a readline instance and initialise it with sane defaults.
|
// NewInstance is used to create a readline instance and initialise it with sane defaults.
|
||||||
|
@ -231,9 +231,13 @@ func NewInstance() *Instance {
|
||||||
rl.evtKeyPress = make(map[string]func(string, []rune, int) *EventReturn)
|
rl.evtKeyPress = make(map[string]func(string, []rune, int) *EventReturn)
|
||||||
rl.TempDirectory = os.TempDir()
|
rl.TempDirectory = os.TempDir()
|
||||||
|
|
||||||
rl.HistorySearcher = func(filter string) []string {
|
rl.HistorySearcher = func(filter string, suggestions []string) []string {
|
||||||
grps := rl.completeHistory()
|
grp := CompletionGroup{
|
||||||
return grps[0].filterSuggestions(rl)
|
DisplayType: TabDisplayMap,
|
||||||
|
MaxLength: 10,
|
||||||
|
Suggestions: suggestions,
|
||||||
|
}
|
||||||
|
return grp.filterSuggestions(rl)
|
||||||
}
|
}
|
||||||
// Registers
|
// Registers
|
||||||
rl.initRegisters()
|
rl.initRegisters()
|
||||||
|
|
|
@ -94,7 +94,9 @@ func (rl *Instance) Readline() (string, error) {
|
||||||
|
|
||||||
rl.skipStdinRead = false
|
rl.skipStdinRead = false
|
||||||
r := []rune(string(b))
|
r := []rune(string(b))
|
||||||
|
if rl.RawInputCallback != nil {
|
||||||
rl.RawInputCallback(r[:i])
|
rl.RawInputCallback(r[:i])
|
||||||
|
}
|
||||||
|
|
||||||
if isMultiline(r[:i]) || len(rl.multiline) > 0 {
|
if isMultiline(r[:i]) || len(rl.multiline) > 0 {
|
||||||
rl.multiline = append(rl.multiline, b[:i]...)
|
rl.multiline = append(rl.multiline, b[:i]...)
|
||||||
|
|
77
rl.go
77
rl.go
|
@ -13,29 +13,74 @@ import (
|
||||||
|
|
||||||
type lineReader struct {
|
type lineReader struct {
|
||||||
rl *readline.Instance
|
rl *readline.Instance
|
||||||
|
fileHist *fileHistory
|
||||||
}
|
}
|
||||||
var fileHist *fileHistory
|
|
||||||
var hinter *rt.Closure
|
var hinter *rt.Closure
|
||||||
var highlighter *rt.Closure
|
var highlighter *rt.Closure
|
||||||
|
|
||||||
func newLineReader(prompt string, noHist bool) *lineReader {
|
func newLineReader(prompt string, noHist bool) *lineReader {
|
||||||
rl := readline.NewInstance()
|
rl := readline.NewInstance()
|
||||||
|
lr := &lineReader{
|
||||||
|
rl: rl,
|
||||||
|
}
|
||||||
|
|
||||||
// we don't mind hilbish.read rl instances having completion,
|
// we don't mind hilbish.read rl instances having completion,
|
||||||
// but it cant have shared history
|
// but it cant have shared history
|
||||||
if !noHist {
|
if !noHist {
|
||||||
fileHist = newFileHistory()
|
lr.fileHist = newFileHistory(defaultHistPath)
|
||||||
rl.SetHistoryCtrlR("History", fileHist)
|
rl.SetHistoryCtrlR("History", &luaHistory{})
|
||||||
rl.HistoryAutoWrite = false
|
rl.HistoryAutoWrite = false
|
||||||
}
|
}
|
||||||
|
|
||||||
oldSearcher := rl.HistorySearcher
|
oldSearcher := rl.HistorySearcher
|
||||||
rl.HistorySearcher = func(filter string) []string {
|
rl.HistorySearcher = func(query string, suggestions []string) []string {
|
||||||
searcherHandler := hshMod.Get(rt.StringValue("history")).AsTable().Get(rt.StringValue("searcher"))
|
return oldSearcher(query, suggestions)
|
||||||
if searcherHandler == rt.NilValue {
|
searcherBool := hshMod.Get(rt.StringValue("opts")).AsTable().Get(rt.StringValue("searcher"))
|
||||||
return oldSearcher(filter)
|
if b, _ := searcherBool.TryBool(); !b {
|
||||||
}
|
}
|
||||||
|
|
||||||
ret, err := rt.Call1(l.MainThread(), searcherHandler, rt.StringValue(filter))
|
searcherHandler := hshMod.Get(rt.StringValue("history")).AsTable().Get(rt.StringValue("searcher"))
|
||||||
entries := []string{}
|
entries := []string{}
|
||||||
|
if searcherHandler == rt.NilValue {
|
||||||
|
// if no searcher, just do a simple filter function
|
||||||
|
filter := hshMod.Get(rt.StringValue("history")).AsTable().Get(rt.StringValue("filter"))
|
||||||
|
if filter == rt.NilValue {
|
||||||
|
return oldSearcher(query, suggestions)
|
||||||
|
}
|
||||||
|
|
||||||
|
histAll := hshMod.Get(rt.StringValue("history")).AsTable().Get(rt.StringValue("all"))
|
||||||
|
cmds, err := rt.Call1(l.MainThread(), histAll)
|
||||||
|
if err != nil || cmds.Type() != rt.TableType {
|
||||||
|
return entries
|
||||||
|
}
|
||||||
|
|
||||||
|
util.ForEach(cmds.AsTable(), func(k rt.Value, cmd rt.Value) {
|
||||||
|
if k.Type() != rt.IntType && cmd.Type() != rt.StringType {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
ret, err := rt.Call1(l.MainThread(), filter, rt.StringValue(query), cmd)
|
||||||
|
if err != nil {
|
||||||
|
return // TODO: true to stop for each (implement in util)
|
||||||
|
}
|
||||||
|
if ret.Type() != rt.BoolType {
|
||||||
|
return // just skip normally
|
||||||
|
}
|
||||||
|
|
||||||
|
if ret.AsBool() {
|
||||||
|
entries = append(entries, cmd.AsString())
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
return entries
|
||||||
|
}
|
||||||
|
|
||||||
|
luaSuggs := rt.NewTable()
|
||||||
|
for i, sug := range suggestions {
|
||||||
|
luaSuggs.Set(rt.IntValue(int64(i + 1)), rt.StringValue(sug))
|
||||||
|
}
|
||||||
|
|
||||||
|
ret, err := rt.Call1(l.MainThread(), searcherHandler, rt.StringValue(query), luaSuggs)
|
||||||
if err == nil && ret.Type() == rt.TableType {
|
if err == nil && ret.Type() == rt.TableType {
|
||||||
util.ForEach(ret.AsTable(), func(k rt.Value, v rt.Value) {
|
util.ForEach(ret.AsTable(), func(k rt.Value, v rt.Value) {
|
||||||
if k.Type() == rt.IntType && v.Type() == rt.StringType {
|
if k.Type() == rt.IntType && v.Type() == rt.StringType {
|
||||||
|
@ -190,9 +235,7 @@ func newLineReader(prompt string, noHist bool) *lineReader {
|
||||||
return pfx, compGroups
|
return pfx, compGroups
|
||||||
}
|
}
|
||||||
|
|
||||||
return &lineReader{
|
return lr
|
||||||
rl,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (lr *lineReader) Read() (string, error) {
|
func (lr *lineReader) Read() (string, error) {
|
||||||
|
@ -231,7 +274,7 @@ func (lr *lineReader) SetRightPrompt(p string) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (lr *lineReader) AddHistory(cmd string) {
|
func (lr *lineReader) AddHistory(cmd string) {
|
||||||
fileHist.Write(cmd)
|
lr.fileHist.Write(cmd)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (lr *lineReader) ClearInput() {
|
func (lr *lineReader) ClearInput() {
|
||||||
|
@ -272,7 +315,7 @@ func (lr *lineReader) luaAddHistory(t *rt.Thread, c *rt.GoCont) (rt.Cont, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (lr *lineReader) luaSize(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
|
func (lr *lineReader) luaSize(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
|
||||||
return c.PushingNext1(t.Runtime, rt.IntValue(int64(fileHist.Len()))), nil
|
return c.PushingNext1(t.Runtime, rt.IntValue(int64(lr.fileHist.Len()))), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (lr *lineReader) luaGetHistory(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
|
func (lr *lineReader) luaGetHistory(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
|
||||||
|
@ -284,17 +327,17 @@ func (lr *lineReader) luaGetHistory(t *rt.Thread, c *rt.GoCont) (rt.Cont, error)
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
cmd, _ := fileHist.GetLine(int(idx))
|
cmd, _ := lr.fileHist.GetLine(int(idx))
|
||||||
|
|
||||||
return c.PushingNext1(t.Runtime, rt.StringValue(cmd)), nil
|
return c.PushingNext1(t.Runtime, rt.StringValue(cmd)), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (lr *lineReader) luaAllHistory(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
|
func (lr *lineReader) luaAllHistory(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
|
||||||
tbl := rt.NewTable()
|
tbl := rt.NewTable()
|
||||||
size := fileHist.Len()
|
size := lr.fileHist.Len()
|
||||||
|
|
||||||
for i := 1; i < size; i++ {
|
for i := 1; i < size; i++ {
|
||||||
cmd, _ := fileHist.GetLine(i)
|
cmd, _ := lr.fileHist.GetLine(i)
|
||||||
tbl.Set(rt.IntValue(int64(i)), rt.StringValue(cmd))
|
tbl.Set(rt.IntValue(int64(i)), rt.StringValue(cmd))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -302,6 +345,6 @@ func (lr *lineReader) luaAllHistory(t *rt.Thread, c *rt.GoCont) (rt.Cont, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (lr *lineReader) luaClearHistory(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
|
func (lr *lineReader) luaClearHistory(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
|
||||||
fileHist.clear()
|
lr.fileHist.clear()
|
||||||
return c.Next(), nil
|
return c.Next(), nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,13 +2,15 @@
|
||||||
|
|
||||||
package main
|
package main
|
||||||
|
|
||||||
|
import "hilbish/util"
|
||||||
|
|
||||||
// String vars that are free to be changed at compile time
|
// String vars that are free to be changed at compile time
|
||||||
var (
|
var (
|
||||||
requirePaths = commonRequirePaths + `.. ';'
|
requirePaths = commonRequirePaths + `.. ';'
|
||||||
.. hilbish.userDir.config .. '\\Hilbish\\libs\\?\\init.lua;'
|
.. hilbish.userDir.config .. '\\Hilbish\\libs\\?\\init.lua;'
|
||||||
.. hilbish.userDir.config .. '\\Hilbish\\libs\\?\\?.lua;'
|
.. hilbish.userDir.config .. '\\Hilbish\\libs\\?\\?.lua;'
|
||||||
.. hilbish.userDir.config .. '\\Hilbish\\libs\\?.lua;'`
|
.. hilbish.userDir.config .. '\\Hilbish\\libs\\?.lua;'`
|
||||||
dataDir = "~\\Appdata\\Roaming\\Hilbish" // ~ and \ gonna cry?
|
dataDir = util.ExpandHome("~\\Appdata\\Roaming\\Hilbish") // ~ and \ gonna cry?
|
||||||
preloadPath = dataDir + "\\nature\\init.lua"
|
preloadPath = dataDir + "\\nature\\init.lua"
|
||||||
sampleConfPath = dataDir + "\\hilbishrc.lua" // Path to default/sample config
|
sampleConfPath = dataDir + "\\hilbishrc.lua" // Path to default/sample config
|
||||||
defaultConfDir = ""
|
defaultConfDir = ""
|
||||||
|
|
Loading…
Reference in New Issue