mirror of
				https://github.com/sammy-ette/Hilbish
				synced 2025-08-10 02:52:03 +00:00 
			
		
		
		
	Compare commits
	
		
			13 Commits
		
	
	
		
			59963add14
			...
			f3f49fc398
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
|  | f3f49fc398 | ||
|  | 893d72a236 | ||
|  | 0637f2763b | ||
|  | 1cb536b1ac | ||
|  | 6740e012a5 | ||
|  | b1ad90443e | ||
|  | 76c94bfcce | ||
|  | 0ed365170c | ||
|  | 70724ec015 | ||
|  | f1dfd59c4c | ||
|  | a0dff5babf | ||
|  | 058d6ac456 | ||
|  | 9f206ebed0 | 
							
								
								
									
										29
									
								
								CHANGELOG.md
									
									
									
									
									
								
							
							
						
						
									
										29
									
								
								CHANGELOG.md
									
									
									
									
									
								
							| @ -1,6 +1,6 @@ | ||||
| # 🎀 Changelog | ||||
| 
 | ||||
| ## Unreleased | ||||
| ## [1.0.0] - 2021-03-04 | ||||
| ### Added | ||||
| - MacOS is now officialy supported, default compile time vars have been added | ||||
| for it | ||||
| @ -18,6 +18,7 @@ it finds the path to `binName` in $PATH | ||||
|   (like it always was) or Vim via `hilbish.inputMode()` | ||||
|   - Changing Vim mode throws a `hilbish.vimMode` hook | ||||
|   - The current Vim mode is also accessible with the `hilbish.vimMode` property | ||||
| - Print errors in `hilbish.timeout()` and `hilbish.goro()` callbacks | ||||
| 
 | ||||
| ### Fixed | ||||
| - Tab completion for executables | ||||
| @ -31,6 +32,7 @@ it finds the path to `binName` in $PATH | ||||
| - Alias expansion with quotes | ||||
| - Add full command to history in the case of incomplete input | ||||
| - `hilbish.exec()` now has a windows substitute | ||||
| - Fixed case of successful command after prompted for more input not writing to history | ||||
| 
 | ||||
| ### Changed | ||||
| - The minimal config is truly minimal now | ||||
| @ -53,6 +55,30 @@ as it functions the same but is OS agnostic | ||||
| - `hilbish.flag()` has been removed | ||||
| - `~/.hprofile.lua` has been removed, instead check in your config if `hilbish.login` | ||||
| is true | ||||
| - `hilbish.complete()` has had a slight refactor to fit with the new readline library. | ||||
| It now expects a table of "completion groups" which are just tables with the | ||||
| `type` and `items` keys. Here is a (more or less) complete example of how it works now: | ||||
|   ```lua | ||||
|     hilbish.complete('command.git', function() | ||||
|       return { | ||||
|         { | ||||
|           items = { | ||||
|             'add', | ||||
|             'clone' | ||||
|           }, | ||||
|           type = 'grid' | ||||
|         }, | ||||
|         { | ||||
|           items = { | ||||
|             ['--git-dir'] = {'Description of flag'}, | ||||
|             '-c' | ||||
|           }, | ||||
|           type = 'list' | ||||
|         } | ||||
|       } | ||||
|     end) | ||||
|   ``` | ||||
|   Completer functions are now also expected to handle subcommands/subcompletions | ||||
| 
 | ||||
| ## [0.7.1] - 2021-11-22 | ||||
| ### Fixed | ||||
| @ -341,6 +367,7 @@ This input for example will prompt for more input to complete: | ||||
| 
 | ||||
| First "stable" release of Hilbish. | ||||
| 
 | ||||
| [0.7.1]: https://github.com/Rosettea/Hilbish/compare/v0.7.1...v1.0.0 | ||||
| [0.7.1]: https://github.com/Rosettea/Hilbish/compare/v0.7.0...v0.7.1 | ||||
| [0.7.0]: https://github.com/Rosettea/Hilbish/compare/v0.6.1...v0.7.0 | ||||
| [0.6.1]: https://github.com/Rosettea/Hilbish/compare/v0.6.0...v0.6.1 | ||||
|  | ||||
							
								
								
									
										62
									
								
								api.go
									
									
									
									
									
								
							
							
						
						
									
										62
									
								
								api.go
									
									
									
									
									
								
							| @ -23,6 +23,7 @@ import ( | ||||
| var exports = map[string]lua.LGFunction { | ||||
| 	"alias": hlalias, | ||||
| 	"appendPath": hlappendPath, | ||||
| 	"complete": hlcomplete, | ||||
| 	"cwd": hlcwd, | ||||
| 	"exec": hlexec, | ||||
| 	"goro": hlgoro, | ||||
| @ -74,6 +75,7 @@ The nice lil shell for {blue}Lua{reset} fanatics! | ||||
| 	util.Document(L, hshuser, "User directories to store configs and/or modules.") | ||||
| 	L.SetField(mod, "userDir", hshuser) | ||||
| 
 | ||||
| 	// hilbish.os table | ||||
| 	hshos := L.NewTable() | ||||
| 	info, _ := osinfo.GetOSInfo() | ||||
| 
 | ||||
| @ -94,11 +96,63 @@ The nice lil shell for {blue}Lua{reset} fanatics! | ||||
| 	util.Document(L, historyModule, "History interface for Hilbish.") | ||||
| 	L.SetField(mod, "history", historyModule) | ||||
| 
 | ||||
| 	// hilbish.completions table | ||||
| 	hshcomp := L.NewTable() | ||||
| 
 | ||||
| 	util.SetField(L, hshcomp, "files", L.NewFunction(luaFileComplete), "Completer for files") | ||||
| 	util.SetField(L, hshcomp, "bins", L.NewFunction(luaBinaryComplete), "Completer for executables/binaries") | ||||
| 	util.Document(L, hshcomp, "Completions interface for Hilbish.") | ||||
| 	L.SetField(mod, "completion", hshcomp) | ||||
| 
 | ||||
| 	L.Push(mod) | ||||
| 
 | ||||
| 	return 1 | ||||
| } | ||||
| 
 | ||||
| func luaFileComplete(L *lua.LState) int { | ||||
| 	query := L.CheckString(1) | ||||
| 	ctx := L.CheckString(2) | ||||
| 	fields := L.CheckTable(3) | ||||
| 
 | ||||
| 	var fds []string | ||||
| 	fields.ForEach(func(k lua.LValue, v lua.LValue) { | ||||
| 		fds = append(fds, v.String()) | ||||
| 	}) | ||||
| 
 | ||||
| 	completions := fileComplete(query, ctx, fds) | ||||
| 	luaComps := L.NewTable() | ||||
| 
 | ||||
| 	for _, comp := range completions { | ||||
| 		luaComps.Append(lua.LString(comp)) | ||||
| 	} | ||||
| 
 | ||||
| 	L.Push(luaComps) | ||||
| 
 | ||||
| 	return 1 | ||||
| } | ||||
| 
 | ||||
| func luaBinaryComplete(L *lua.LState) int { | ||||
| 	query := L.CheckString(1) | ||||
| 	ctx := L.CheckString(2) | ||||
| 	fields := L.CheckTable(3) | ||||
| 
 | ||||
| 	var fds []string | ||||
| 	fields.ForEach(func(k lua.LValue, v lua.LValue) { | ||||
| 		fds = append(fds, v.String()) | ||||
| 	}) | ||||
| 
 | ||||
| 	completions, _ := binaryComplete(query, ctx, fds) | ||||
| 	luaComps := L.NewTable() | ||||
| 
 | ||||
| 	for _, comp := range completions { | ||||
| 		luaComps.Append(lua.LString(comp)) | ||||
| 	} | ||||
| 
 | ||||
| 	L.Push(luaComps) | ||||
| 
 | ||||
| 	return 1 | ||||
| } | ||||
| 
 | ||||
| func setVimMode(mode string) { | ||||
| 	hooks.Em.Emit("hilbish.vimMode", mode) | ||||
| 	util.SetField(l, hshMod, "vimMode", lua.LString(mode), "Current Vim mode of Hilbish (nil if not in Vim mode)") | ||||
| @ -174,7 +228,7 @@ These will be formatted and replaced with the appropriate values. | ||||
| --- @param str string | ||||
| */ | ||||
| func hlprompt(L *lua.LState) int { | ||||
| 	prompt := L.CheckString(1) | ||||
| 	prompt = L.CheckString(1) | ||||
| 	lr.SetPrompt(fmtPrompt(prompt)) | ||||
| 
 | ||||
| 	return 0 | ||||
| @ -346,8 +400,10 @@ func hlinterval(L *lua.LState) int { | ||||
| // 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 the entries to complete. | ||||
| // Nested tables will be used as sub-completions. | ||||
| // `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 of | ||||
| // `grid` (the normal file completion display) or `list` (with a description) | ||||
| // --- @param scope string | ||||
| // --- @param cb function | ||||
| func hlcomplete(L *lua.LState) int { | ||||
|  | ||||
							
								
								
									
										49
									
								
								complete.go
									
									
									
									
									
								
							
							
						
						
									
										49
									
								
								complete.go
									
									
									
									
									
								
							| @ -23,6 +23,55 @@ func fileComplete(query, ctx string, fields []string) []string { | ||||
| 	return completions | ||||
| } | ||||
| 
 | ||||
| func binaryComplete(query, ctx string, fields []string) ([]string, string) { | ||||
| 	var completions []string | ||||
| 
 | ||||
| 	prefixes := []string{"./", "../", "/", "~/"} | ||||
| 	for _, prefix := range prefixes { | ||||
| 		if strings.HasPrefix(query, prefix) { | ||||
| 			fileCompletions := fileComplete(query, ctx, fields) | ||||
| 			if len(fileCompletions) != 0 { | ||||
| 				for _, f := range fileCompletions { | ||||
| 					name := strings.Replace(query + f, "~", curuser.HomeDir, 1) | ||||
| 					if info, err := os.Stat(name); err == nil && info.Mode().Perm() & 0100 == 0 { | ||||
| 						continue | ||||
| 					} | ||||
| 					completions = append(completions, f) | ||||
| 				} | ||||
| 			} | ||||
| 			return completions, "" | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	// filter out executables, but in path | ||||
| 	for _, dir := range filepath.SplitList(os.Getenv("PATH")) { | ||||
| 		// print dir to stderr for debugging | ||||
| 		// search for an executable which matches our query string | ||||
| 		if matches, err := filepath.Glob(filepath.Join(dir, query + "*")); err == nil { | ||||
| 			// get basename from matches | ||||
| 			for _, match := range matches { | ||||
| 				// check if we have execute permissions for our match | ||||
| 				if info, err := os.Stat(match); err == nil && info.Mode().Perm() & 0100 == 0 { | ||||
| 					continue | ||||
| 				} | ||||
| 				// get basename from match | ||||
| 				name := filepath.Base(match) | ||||
| 				// add basename to completions | ||||
| 				completions = append(completions, name) | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	// add lua registered commands to completions | ||||
| 	for cmdName := range commands { | ||||
| 		if strings.HasPrefix(cmdName, query) { | ||||
| 			completions = append(completions, cmdName) | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	return completions, query | ||||
| } | ||||
| 
 | ||||
| func matchPath(path, pref string) ([]string, error) { | ||||
| 	var entries []string | ||||
| 	matches, err := filepath.Glob(path + "*") | ||||
|  | ||||
| @ -5,8 +5,10 @@ appendPath(dir) > Appends `dir` to $PATH | ||||
| 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 the entries to complete. | ||||
| Nested tables will be used as sub-completions. | ||||
| `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 of | ||||
| `grid` (the normal file completion display) or `list` (with a description) | ||||
| 
 | ||||
| cwd() > Returns the current directory of the shell | ||||
| 
 | ||||
|  | ||||
| @ -14,8 +14,10 @@ function hilbish.appendPath(dir) end | ||||
| --- 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 the entries to complete. | ||||
| --- Nested tables will be used as sub-completions. | ||||
| --- `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 of | ||||
| --- `grid` (the normal file completion display) or `list` (with a description) | ||||
| --- @param scope string | ||||
| --- @param cb function | ||||
| function hilbish.complete(scope, cb) end | ||||
|  | ||||
							
								
								
									
										2
									
								
								exec.go
									
									
									
									
									
								
							
							
						
						
									
										2
									
								
								exec.go
									
									
									
									
									
								
							| @ -61,6 +61,8 @@ func runInput(input, origInput string) { | ||||
| 				} else if err != nil { | ||||
| 					fmt.Fprintln(os.Stderr, err) | ||||
| 					cmdFinish(1, cmdString, origInput) | ||||
| 				} else { | ||||
| 					cmdFinish(0, cmdString, origInput) | ||||
| 				} | ||||
| 				break | ||||
| 			} | ||||
|  | ||||
							
								
								
									
										2
									
								
								go.mod
									
									
									
									
									
								
							
							
						
						
									
										2
									
								
								go.mod
									
									
									
									
									
								
							| @ -16,6 +16,6 @@ require ( | ||||
| 
 | ||||
| replace mvdan.cc/sh/v3 => github.com/Rosettea/sh/v3 v3.4.0-0.dev.0.20211022004519-f67a49cb50f5 | ||||
| 
 | ||||
| replace github.com/maxlandon/readline => github.com/Rosettea/readline-1 v0.0.0-20220305004552-071c22768119 | ||||
| replace github.com/maxlandon/readline => github.com/Rosettea/readline-1 v0.0.0-20220305123014-31d4d4214c93 | ||||
| 
 | ||||
| replace layeh.com/gopher-luar => github.com/layeh/gopher-luar v1.0.10 | ||||
|  | ||||
							
								
								
									
										2
									
								
								go.sum
									
									
									
									
									
								
							
							
						
						
									
										2
									
								
								go.sum
									
									
									
									
									
								
							| @ -2,6 +2,8 @@ github.com/Rosettea/readline-1 v0.0.0-20220302012429-9ce5d23760f7 h1:LoY+kBKqMQq | ||||
| github.com/Rosettea/readline-1 v0.0.0-20220302012429-9ce5d23760f7/go.mod h1:QiUAvbhg8PzCA4hlafCUl0bKD/0VmcocM4AjqtszAJs= | ||||
| github.com/Rosettea/readline-1 v0.0.0-20220305004552-071c22768119 h1:rGsc30WTD5hk+oiXrAKsAIwZn5qBeTAdr29y3HhJh9E= | ||||
| github.com/Rosettea/readline-1 v0.0.0-20220305004552-071c22768119/go.mod h1:QiUAvbhg8PzCA4hlafCUl0bKD/0VmcocM4AjqtszAJs= | ||||
| github.com/Rosettea/readline-1 v0.0.0-20220305123014-31d4d4214c93 h1:SmOkAEm3O7si8CURZSsSN0ZxCQ8IGiiulw8LMZ1V1Yc= | ||||
| github.com/Rosettea/readline-1 v0.0.0-20220305123014-31d4d4214c93/go.mod h1:QiUAvbhg8PzCA4hlafCUl0bKD/0VmcocM4AjqtszAJs= | ||||
| github.com/Rosettea/readline-1 v0.1.0-beta.0.20211207003625-341c7985ad7d h1:KBttN41h/tPahmpaZavviwQ8q4rCkt5CD0HdVmfgPVA= | ||||
| github.com/Rosettea/readline-1 v0.1.0-beta.0.20211207003625-341c7985ad7d/go.mod h1:QiUAvbhg8PzCA4hlafCUl0bKD/0VmcocM4AjqtszAJs= | ||||
| github.com/Rosettea/readline-1 v0.1.0-beta.0.20220228022904-61f5e4493011 h1:+a61iNamZiO3Xru+l/1qtpKqqltVfWEm2r/rxH9hXxY= | ||||
|  | ||||
| @ -24,12 +24,11 @@ func newFileHistory() (*fileHistory, error) { | ||||
| 	lines := strings.Split(string(data), "\n") | ||||
| 	for i, l := range lines { | ||||
| 		if i == len(lines) - 1 { | ||||
| 			println(i, l) | ||||
| 			continue | ||||
| 		} | ||||
| 		itms = append(itms, l) | ||||
| 	} | ||||
| 	f, err := os.OpenFile(defaultHistPath, os.O_RDWR | os.O_CREATE, 0755) | ||||
| 	f, err := os.OpenFile(defaultHistPath, os.O_APPEND | os.O_WRONLY | os.O_CREATE, 0755) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| @ -72,5 +71,5 @@ func (h *fileHistory) Len() int { | ||||
| } | ||||
| 
 | ||||
| func (h *fileHistory) Dump() interface{} { | ||||
| 	return nil | ||||
| 	return h.items | ||||
| } | ||||
|  | ||||
							
								
								
									
										1
									
								
								main.go
									
									
									
									
									
								
							
							
						
						
									
										1
									
								
								main.go
									
									
									
									
									
								
							| @ -165,6 +165,7 @@ func main() { | ||||
| 
 | ||||
| input: | ||||
| 	for interactive { | ||||
| 		lr.SetPrompt(fmtPrompt(prompt)) | ||||
| 		running = false | ||||
| 
 | ||||
| 		input, err := lr.Read() | ||||
|  | ||||
							
								
								
									
										225
									
								
								rl.go
									
									
									
									
									
								
							
							
						
						
									
										225
									
								
								rl.go
									
									
									
									
									
								
							| @ -3,9 +3,7 @@ package main | ||||
| import ( | ||||
| 	"fmt" | ||||
| 	"io" | ||||
| 	"path/filepath" | ||||
| 	"strings" | ||||
| 	"os" | ||||
| 
 | ||||
| 	"github.com/maxlandon/readline" | ||||
| 	"github.com/yuin/gopher-lua" | ||||
| @ -14,15 +12,18 @@ import ( | ||||
| type lineReader struct { | ||||
| 	rl *readline.Instance | ||||
| } | ||||
| var fileHist *fileHistory | ||||
| 
 | ||||
| // other gophers might hate this naming but this is local, shut up | ||||
| func newLineReader(prompt string) *lineReader { | ||||
| 	rl := readline.NewInstance() | ||||
| 	fileHist, err := newFileHistory() | ||||
| 	fh, err := newFileHistory() | ||||
| 	fileHist = fh // go stupid | ||||
| 	if err != nil { | ||||
| 		panic(err) | ||||
| 	} | ||||
| 	rl.SetHistoryCtrlR("file", fileHist) | ||||
| 	rl.HistoryAutoWrite = false | ||||
| 	rl.ShowVimMode = false | ||||
| 	rl.ViModeCallback = func(mode readline.ViMode) { | ||||
| 		modeStr := "" | ||||
| @ -39,12 +40,7 @@ func newLineReader(prompt string) *lineReader { | ||||
| 		ctx := string(line) | ||||
| 		var completions []string | ||||
| 
 | ||||
| 		compGroup := []*readline.CompletionGroup{ | ||||
| 			&readline.CompletionGroup{ | ||||
| 				TrimSlash: false, | ||||
| 				NoSpace: true, | ||||
| 			}, | ||||
| 		} | ||||
| 		var compGroup []*readline.CompletionGroup | ||||
| 
 | ||||
| 		ctx = strings.TrimLeft(ctx, " ") | ||||
| 		if len(ctx) == 0 { | ||||
| @ -60,60 +56,26 @@ func newLineReader(prompt string) *lineReader { | ||||
| 		ctx = aliases.Resolve(ctx) | ||||
| 
 | ||||
| 		if len(fields) == 1 { | ||||
| 			prefixes := []string{"./", "../", "/", "~/"} | ||||
| 			for _, prefix := range prefixes { | ||||
| 				if strings.HasPrefix(query, prefix) { | ||||
| 					fileCompletions := fileComplete(query, ctx, fields) | ||||
| 					if len(fileCompletions) != 0 { | ||||
| 						for _, f := range fileCompletions { | ||||
| 							name := strings.Replace(query + f, "~", curuser.HomeDir, 1) | ||||
| 							if info, err := os.Stat(name); err == nil && info.Mode().Perm() & 0100 == 0 { | ||||
| 								continue | ||||
| 							} | ||||
| 							completions = append(completions, f) | ||||
| 						} | ||||
| 						compGroup[0].Suggestions = completions | ||||
| 					} | ||||
| 					return "", compGroup | ||||
| 				} | ||||
| 			} | ||||
| 			completions, prefix := binaryComplete(query, ctx, fields) | ||||
| 
 | ||||
| 			// filter out executables, but in path | ||||
| 			for _, dir := range filepath.SplitList(os.Getenv("PATH")) { | ||||
| 				// print dir to stderr for debugging | ||||
| 				// search for an executable which matches our query string | ||||
| 				if matches, err := filepath.Glob(filepath.Join(dir, query + "*")); err == nil { | ||||
| 					// get basename from matches | ||||
| 					for _, match := range matches { | ||||
| 						// check if we have execute permissions for our match | ||||
| 						if info, err := os.Stat(match); err == nil && info.Mode().Perm() & 0100 == 0 { | ||||
| 							continue | ||||
| 						} | ||||
| 						// get basename from match | ||||
| 						name := filepath.Base(match) | ||||
| 						// print name to stderr for debugging | ||||
| 						// add basename to completions | ||||
| 						completions = append(completions, name) | ||||
| 					} | ||||
| 				} | ||||
| 			} | ||||
| 			compGroup = append(compGroup, &readline.CompletionGroup{ | ||||
| 				TrimSlash: false, | ||||
| 				NoSpace: true, | ||||
| 				Suggestions: completions, | ||||
| 			}) | ||||
| 
 | ||||
| 			// add lua registered commands to completions | ||||
| 			for cmdName := range commands { | ||||
| 				if strings.HasPrefix(cmdName, query) { | ||||
| 					completions = append(completions, cmdName) | ||||
| 				} | ||||
| 			} | ||||
| 			 | ||||
| 			compGroup[0].Suggestions = completions | ||||
| 			return query, compGroup | ||||
| 			return prefix, compGroup | ||||
| 		} else { | ||||
| 			if completecb, ok := luaCompletions["command." + fields[0]]; ok { | ||||
| 				luaFields := l.NewTable() | ||||
| 				for _, f := range fields { | ||||
| 					luaFields.Append(lua.LString(f)) | ||||
| 				} | ||||
| 				err := l.CallByParam(lua.P{ | ||||
| 					Fn: completecb, | ||||
| 					NRet: 1, | ||||
| 					Protect: true, | ||||
| 				}) | ||||
| 				}, lua.LString(query), lua.LString(ctx), luaFields) | ||||
| 
 | ||||
| 				if err != nil { | ||||
| 					return "", compGroup | ||||
| @ -122,88 +84,86 @@ func newLineReader(prompt string) *lineReader { | ||||
| 				luacompleteTable := l.Get(-1) | ||||
| 				l.Pop(1) | ||||
| 
 | ||||
| 				/* | ||||
| 					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.(*lua.LTable); ok { | ||||
| 					cmpTbl.ForEach(func(key lua.LValue, value lua.LValue) { | ||||
| 						// if key is a number (index), we just check and complete that | ||||
| 						if key.Type() == lua.LTNumber { | ||||
| 							// if we have only 2 fields then this is fine | ||||
| 							if len(fields) == 2 { | ||||
| 								if strings.HasPrefix(value.String(), fields[1]) { | ||||
| 									completions = append(completions, value.String()) | ||||
| 								} | ||||
| 							} | ||||
| 						} else if key.Type() == lua.LTString { | ||||
| 							if len(fields) == 2 { | ||||
| 								if strings.HasPrefix(key.String(), fields[1]) { | ||||
| 									completions = append(completions, key.String()) | ||||
| 								} | ||||
| 							} else { | ||||
| 								// if we have more than 2 fields, we need to check if the key matches | ||||
| 								// the current field and if it does, we need to check if the value is a string | ||||
| 								// or table (nested sub completions) | ||||
| 								if key.String() == fields[1] { | ||||
| 									// if value is a table, we need to iterate over it | ||||
| 									// and add each value to completions | ||||
| 									// check if value is either a table or function | ||||
| 							// completion group | ||||
| 							if value.Type() == lua.LTTable { | ||||
| 										valueTbl := value.(*lua.LTable) | ||||
| 										valueTbl.ForEach(func(key lua.LValue, value lua.LValue) { | ||||
| 											val := value.String() | ||||
| 											if val == "<file>" { | ||||
| 												// complete files | ||||
| 												completions = append(completions, fileComplete(query, ctx, fields)...) | ||||
| 								luaCmpGroup := value.(*lua.LTable) | ||||
| 								compType := luaCmpGroup.RawGet(lua.LString("type")) | ||||
| 								compItems := luaCmpGroup.RawGet(lua.LString("items")) | ||||
| 								if compType.Type() != lua.LTString { | ||||
| 									l.RaiseError("bad type name for completion (expected string, got %v)", compType.Type().String()) | ||||
| 								} | ||||
| 								if compItems.Type() != lua.LTTable { | ||||
| 									l.RaiseError("bad items for completion (expected table, got %v)", compItems.Type().String()) | ||||
| 								} | ||||
| 								var items []string | ||||
| 								itemDescriptions := make(map[string]string) | ||||
| 								compItems.(*lua.LTable).ForEach(func(k lua.LValue, v lua.LValue) { | ||||
| 									if k.Type() == lua.LTString { | ||||
| 										// ['--flag'] = {'description', '--flag-alias'} | ||||
| 										itm := v.(*lua.LTable) | ||||
| 										items = append(items, k.String()) | ||||
| 										itemDescriptions[k.String()] = itm.RawGet(lua.LNumber(1)).String() | ||||
| 									} else { | ||||
| 												if strings.HasPrefix(val, query) { | ||||
| 													completions = append(completions, val) | ||||
| 												} | ||||
| 										items = append(items, v.String()) | ||||
| 									} | ||||
| 								}) | ||||
| 									} else if value.Type() == lua.LTFunction { | ||||
| 										// if value is a function, we need to call it | ||||
| 										// and add each value to completions | ||||
| 										// completionsCtx is the context we pass to the function, | ||||
| 										// removing 2 fields from the fields array | ||||
| 										completionsCtx := strings.Join(fields[2:], " ") | ||||
| 										err := l.CallByParam(lua.P{ | ||||
| 											Fn: value, | ||||
| 											NRet: 1, | ||||
| 											Protect: true, | ||||
| 										}, lua.LString(query), lua.LString(completionsCtx)) | ||||
| 
 | ||||
| 										if err != nil { | ||||
| 											return | ||||
| 										} | ||||
| 
 | ||||
| 										luacompleteTable := l.Get(-1) | ||||
| 										l.Pop(1) | ||||
| 
 | ||||
| 										// just check if its actually a table and add it to the completions | ||||
| 										if cmpTbl, ok := luacompleteTable.(*lua.LTable); ok { | ||||
| 											cmpTbl.ForEach(func(key lua.LValue, value lua.LValue) { | ||||
| 												val := value.String() | ||||
| 												if strings.HasPrefix(val, query) { | ||||
| 													completions = append(completions, val) | ||||
| 								var dispType readline.TabDisplayType | ||||
| 								switch compType.String() { | ||||
| 									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, | ||||
| 								}) | ||||
| 							} | ||||
| 									} else { | ||||
| 										// throw lua error | ||||
| 										// complete.cmdname: error message... | ||||
| 										l.RaiseError("complete." + fields[0] + ": completion value is not a table or function") | ||||
| 									} | ||||
| 								} | ||||
| 							} | ||||
| 						} | ||||
| 					}) | ||||
| 				} | ||||
| 			} | ||||
| 
 | ||||
| 			if len(completions) == 0 { | ||||
| 			if len(compGroup) == 0 { | ||||
| 				completions = fileComplete(query, ctx, fields) | ||||
| 				compGroup = append(compGroup, &readline.CompletionGroup{ | ||||
| 					TrimSlash: false, | ||||
| 					NoSpace: true, | ||||
| 					Suggestions: completions, | ||||
| 				}) | ||||
| 			} | ||||
| 		} | ||||
| 
 | ||||
| 		compGroup[0].Suggestions = completions | ||||
| 		return "", compGroup | ||||
| 	} | ||||
| 
 | ||||
| @ -240,7 +200,7 @@ func (lr *lineReader) SetPrompt(prompt string) { | ||||
| } | ||||
| 
 | ||||
| func (lr *lineReader) AddHistory(cmd string) { | ||||
| 	return | ||||
| 	fileHist.Write(cmd) | ||||
| } | ||||
| 
 | ||||
| func (lr *lineReader) ClearInput() { | ||||
| @ -273,18 +233,35 @@ func (lr *lineReader) luaAddHistory(l *lua.LState) int { | ||||
| 	return 0 | ||||
| } | ||||
| 
 | ||||
| func (lr *lineReader) luaSize(l *lua.LState) int { | ||||
| func (lr *lineReader) luaSize(L *lua.LState) int { | ||||
| 	L.Push(lua.LNumber(fileHist.Len())) | ||||
| 
 | ||||
| 	return 1 | ||||
| } | ||||
| 
 | ||||
| func (lr *lineReader) luaGetHistory(L *lua.LState) int { | ||||
| 	idx := L.CheckInt(1) | ||||
| 	cmd, _ := fileHist.GetLine(idx) | ||||
| 	L.Push(lua.LString(cmd)) | ||||
| 
 | ||||
| 	return 0 | ||||
| } | ||||
| 
 | ||||
| func (lr *lineReader) luaGetHistory(l *lua.LState) int { | ||||
| 	return 0 | ||||
| } | ||||
| func (lr *lineReader) luaAllHistory(L *lua.LState) int { | ||||
| 	tbl := L.NewTable() | ||||
| 	size := fileHist.Len() | ||||
| 
 | ||||
| 	for i := 1; i < size; i++ { | ||||
| 		cmd, _ := fileHist.GetLine(i) | ||||
| 		tbl.Append(lua.LString(cmd)) | ||||
| 	} | ||||
| 
 | ||||
| 	L.Push(tbl) | ||||
| 
 | ||||
| func (lr *lineReader) luaAllHistory(l *lua.LState) int { | ||||
| 	return 0 | ||||
| } | ||||
| 
 | ||||
| func (lr *lineReader) luaClearHistory(l *lua.LState) int { | ||||
| 	return 0 | ||||
| 
 | ||||
| } | ||||
|  | ||||
							
								
								
									
										3
									
								
								vars.go
									
									
									
									
									
								
							
							
						
						
									
										3
									
								
								vars.go
									
									
									
									
									
								
							| @ -2,11 +2,12 @@ package main | ||||
| 
 | ||||
| // String vars that are free to be changed at compile time | ||||
| var ( | ||||
| 	version = "v0.7.1" | ||||
| 	version = "v1.0.0" | ||||
| 	defaultConfDir = "" // ~ will be substituted for home, path for user's default config | ||||
| 	defaultHistDir = "" | ||||
| 	commonRequirePaths = "';./libs/?/init.lua;./?/init.lua;./?/?.lua'" | ||||
| 
 | ||||
| 	prompt string | ||||
| 	multilinePrompt = "> " | ||||
| ) | ||||
| 
 | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user