mirror of
				https://github.com/sammy-ette/Hilbish
				synced 2025-08-10 02:52:03 +00:00 
			
		
		
		
	Compare commits
	
		
			15 Commits
		
	
	
		
			bbf5a93ca0
			...
			40c2933a95
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
|  | 40c2933a95 | ||
|  | 7434d270e4 | ||
|  | 3dae826578 | ||
|  | 001bd15ced | ||
|  | 09a8b41063 | ||
|  | 349380ae6b | ||
|  | f7806f5479 | ||
|  | c8c30e9861 | ||
|  | 083c266438 | ||
|  | dd9bdca5e0 | ||
|  | 9902560061 | ||
|  | dd9aa4b6ea | ||
|  | be8bdef9c8 | ||
|  | e185a32685 | ||
|  | 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' | ||||||
|  | |||||||
							
								
								
									
										5
									
								
								nature/opts/history.lua
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								nature/opts/history.lua
									
									
									
									
									
										Normal file
									
								
							| @ -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)) | ||||||
| 		rl.RawInputCallback(r[:i]) | 		if rl.RawInputCallback != nil { | ||||||
|  | 			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…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user