mirror of
				https://github.com/sammy-ette/Hilbish
				synced 2025-08-10 02:52:03 +00:00 
			
		
		
		
	chore: merge from master
This commit is contained in:
		
						commit
						0f923a6f80
					
				
							
								
								
									
										11
									
								
								CHANGELOG.md
									
									
									
									
									
								
							
							
						
						
									
										11
									
								
								CHANGELOG.md
									
									
									
									
									
								
							| @ -8,13 +8,22 @@ | ||||
|   - `pipe` property to check if a sink with input is a pipe (like stdin) | ||||
| - Add fuzzy search to history search (enable via `hilbish.opts.fuzzy = true`) | ||||
| - Show indexes on cdr list | ||||
| - Fix doc command not displaying correct subdocs when using shorthand api doc access (`doc api hilbish.jobs` as an example) | ||||
| - `hilbish.messages` interface (details in [#219]) | ||||
| - `hilbish.notification` signal when a message/notification is sent | ||||
| - `notifyJobFinish` opt to send a notification when background jobs are | ||||
| completed. | ||||
| - Allow numbered arg substitutions in aliases. | ||||
|   - Example: `hilbish.alias('hello', 'echo %1 says hello')` allows the user to run `hello hilbish` | ||||
|   which will output `hilbish says hello`. | ||||
| - Greenhouse | ||||
|   - Greenhouse is a pager library and program. Basic usage is `greenhouse <file>` | ||||
|   - Using this also brings enhancements to the `doc` command like easy | ||||
|   navigation of neighboring doc files. | ||||
| 
 | ||||
| [#219]: https://github.com/Rosettea/Hilbish/issues/219 | ||||
| ### Fixed | ||||
| - Fix infinite loop when navigating history without any history. [#252](https://github.com/Rosettea/Hilbish/issues/252) | ||||
| - Return the prefix when calling `hilbish.completions.call`. [#219](https://github.com/Rosettea/Hilbish/issues/219) | ||||
| - Replaced `sed` in-place editing with `grep` and `mv` for compatibility with BSD utils | ||||
| 
 | ||||
| ## [2.1.2] - 2022-04-10 | ||||
|  | ||||
| @ -13,12 +13,22 @@ vars: | ||||
| 
 | ||||
| tasks: | ||||
|   default: | ||||
|     cmds: | ||||
|       - go build {{.GOFLAGS}} | ||||
|     vars: | ||||
|       GOFLAGS: '-ldflags "-s -w -X main.dataDir={{.LIBDIR}} -X main.gitCommit=$(git rev-parse --short HEAD) -X main.gitBranch=$(git rev-parse --abbrev-ref HEAD)"' | ||||
| 
 | ||||
|   default-nocgo: | ||||
|     cmds: | ||||
|       - CGO_ENABLED=0 go build {{.GOFLAGS}} | ||||
|     vars: | ||||
|       GOFLAGS: '-ldflags "-s -w -X main.dataDir={{.LIBDIR}} -X main.gitCommit=$(git rev-parse --short HEAD) -X main.gitBranch=$(git rev-parse --abbrev-ref HEAD)"' | ||||
| 
 | ||||
|   build: | ||||
|     cmds: | ||||
|       - go build {{.GOFLAGS}} | ||||
| 
 | ||||
|   build-nocgo: | ||||
|     cmds: | ||||
|       - CGO_ENABLED=0 go build {{.GOFLAGS}} | ||||
| 
 | ||||
|  | ||||
							
								
								
									
										27
									
								
								aliases.go
									
									
									
									
									
								
							
							
						
						
									
										27
									
								
								aliases.go
									
									
									
									
									
								
							| @ -1,6 +1,8 @@ | ||||
| package main | ||||
| 
 | ||||
| import ( | ||||
| 	"regexp" | ||||
| 	"strconv" | ||||
| 	"strings" | ||||
| 	"sync" | ||||
| 
 | ||||
| @ -46,9 +48,32 @@ func (a *aliasModule) Resolve(cmdstr string) string { | ||||
| 	a.mu.RLock() | ||||
| 	defer a.mu.RUnlock() | ||||
| 
 | ||||
| 	args := strings.Split(cmdstr, " ") | ||||
| 	arg, _ := regexp.Compile(`[\\]?%\d+`) | ||||
| 
 | ||||
| 	args, _ := splitInput(cmdstr) | ||||
| 	if len(args) == 0 { | ||||
| 		// this shouldnt reach but...???? | ||||
| 		return cmdstr | ||||
| 	} | ||||
| 
 | ||||
| 	for a.aliases[args[0]] != "" { | ||||
| 		alias := a.aliases[args[0]] | ||||
| 		alias = arg.ReplaceAllStringFunc(alias, func(a string) string { | ||||
| 			idx, _ := strconv.Atoi(a[1:]) | ||||
| 			if strings.HasPrefix(a, "\\") || idx == 0 { | ||||
| 				return strings.TrimPrefix(a, "\\") | ||||
| 			} | ||||
| 
 | ||||
| 			if idx + 1 > len(args) { | ||||
| 				return a | ||||
| 			} | ||||
| 			val := args[idx] | ||||
| 			args = cut(args, idx) | ||||
| 			cmdstr = strings.Join(args, " ") | ||||
| 
 | ||||
| 			return val | ||||
| 		}) | ||||
| 		 | ||||
| 		cmdstr = alias + strings.TrimPrefix(cmdstr, args[0]) | ||||
| 		cmdArgs, _ := splitInput(cmdstr) | ||||
| 		args = cmdArgs | ||||
|  | ||||
							
								
								
									
										3
									
								
								api.go
									
									
									
									
									
								
							
							
						
						
									
										3
									
								
								api.go
									
									
									
									
									
								
							| @ -166,6 +166,9 @@ func hilbishLoad(rtm *rt.Runtime) (rt.Value, func()) { | ||||
| 	util.SetField(rtm, versionModule, "release", rt.StringValue(releaseName)) | ||||
| 	mod.Set(rt.StringValue("version"), rt.TableValue(versionModule)) | ||||
| 
 | ||||
| 	pluginModule := moduleLoader(rtm) | ||||
| 	mod.Set(rt.StringValue("module"), rt.TableValue(pluginModule)) | ||||
| 
 | ||||
| 	return rt.TableValue(fakeMod), nil | ||||
| } | ||||
| 
 | ||||
|  | ||||
| @ -439,7 +439,7 @@ func main() { | ||||
| 
 | ||||
| 			f, _ := os.Create(docPath) | ||||
| 			f.WriteString(fmt.Sprintf(header, modOrIface, modname, modu.ShortDescription)) | ||||
| 			typeTag, _ := regexp.Compile(`@\w+`) | ||||
| 			typeTag, _ := regexp.Compile(`\B@\w+`) | ||||
| 			modDescription := typeTag.ReplaceAllStringFunc(strings.Replace(strings.Replace(modu.Description, "<", `\<`, -1), "{{\\<", "{{<", -1), func(typ string) string { | ||||
| 				typName := typ[1:] | ||||
| 				typLookup := typeTable[strings.ToLower(typName)] | ||||
|  | ||||
| @ -253,15 +253,16 @@ func callLuaCompleter(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) { | ||||
| 	} | ||||
| 
 | ||||
| 	// we must keep the holy 80 cols | ||||
| 	completerReturn, err := rt.Call1(l.MainThread(), | ||||
| 	rt.FunctionValue(completecb), rt.StringValue(query), | ||||
| 	rt.StringValue(ctx), rt.TableValue(fields)) | ||||
| 	cont := c.Next() | ||||
| 	err = rt.Call(l.MainThread(), rt.FunctionValue(completecb), | ||||
| 	[]rt.Value{rt.StringValue(query), rt.StringValue(ctx), rt.TableValue(fields)}, | ||||
| 	cont) | ||||
| 
 | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 
 | ||||
| 	return c.PushingNext1(t.Runtime, completerReturn), nil | ||||
| 	return cont, nil | ||||
| } | ||||
| 
 | ||||
| // #interface completions | ||||
|  | ||||
| @ -44,7 +44,7 @@ interfaces and functions which directly relate to shell functionality. | ||||
| |interactive|Is Hilbish in an interactive shell?| | ||||
| |login|Is Hilbish the login shell?| | ||||
| |vimMode|Current Vim input mode of Hilbish (will be nil if not in Vim input mode)| | ||||
| |exitCode|xit code of the last executed command| | ||||
| |exitCode|Exit code of the last executed command| | ||||
| 
 | ||||
| <hr><div id='alias'> | ||||
| <h4 class='heading'> | ||||
| @ -331,7 +331,10 @@ A call with no argument will toggle the value. | ||||
| Flush writes all buffered input to the sink. | ||||
| 
 | ||||
| #### read() -> string | ||||
| Reads input from the sink. | ||||
| Reads a liine of input from the sink. | ||||
| 
 | ||||
| #### readAll() -> string | ||||
| Reads all input from the sink. | ||||
| 
 | ||||
| #### write(str) | ||||
| Writes data to a sink. | ||||
|  | ||||
| @ -17,6 +17,7 @@ directly interact with the line editor in use. | ||||
| |<a href="#editor.getLine">getLine() -> string</a>|Returns the current input line.| | ||||
| |<a href="#editor.getVimRegister">getVimRegister(register) -> string</a>|Returns the text that is at the register.| | ||||
| |<a href="#editor.insert">insert(text)</a>|Inserts text into the line.| | ||||
| |<a href="#editor.getChar">getChar() -> string</a>|Reads a keystroke from the user. This is in a format| | ||||
| |<a href="#editor.setVimRegister">setVimRegister(register, text)</a>|Sets the vim register at `register` to hold the passed text.| | ||||
| 
 | ||||
| <hr><div id='editor.getLine'> | ||||
| @ -58,6 +59,20 @@ Inserts text into the line. | ||||
| This function has no parameters.   | ||||
| </div> | ||||
| 
 | ||||
| <hr><div id='editor.getChar'> | ||||
| <h4 class='heading'> | ||||
| hilbish.editor.getChar() -> string | ||||
| <a href="#editor.getChar" class='heading-link'> | ||||
| 	<i class="fas fa-paperclip"></i> | ||||
| </a> | ||||
| </h4> | ||||
| 
 | ||||
| Reads a keystroke from the user. This is in a format | ||||
| of something like Ctrl-L.. | ||||
| #### Parameters | ||||
| This function has no parameters.   | ||||
| </div> | ||||
| 
 | ||||
| <hr><div id='editor.setVimRegister'> | ||||
| <h4 class='heading'> | ||||
| hilbish.editor.setVimRegister(register, text) | ||||
|  | ||||
							
								
								
									
										69
									
								
								docs/api/hilbish/hilbish.module.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										69
									
								
								docs/api/hilbish/hilbish.module.md
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,69 @@ | ||||
| --- | ||||
| title: Module hilbish.module | ||||
| description: native module loading | ||||
| layout: doc | ||||
| menu: | ||||
|   docs: | ||||
|     parent: "API" | ||||
| --- | ||||
| 
 | ||||
| ## Introduction | ||||
| 
 | ||||
| The hilbish.module interface provides a function to load | ||||
| Hilbish plugins/modules. Hilbish modules are Go-written | ||||
| plugins (see https://pkg.go.dev/plugin) that are used to add functionality | ||||
| to Hilbish that cannot be written in Lua for any reason. | ||||
| 
 | ||||
| Note that you don't ever need to use the load function that is here as | ||||
| modules can be loaded with a `require` call like Lua C modules, and the | ||||
| search paths can be changed with the `paths` property here. | ||||
| 
 | ||||
| To make a valid native module, the Go plugin has to export a Loader function | ||||
| with a signature like so: `func(*rt.Runtime) rt.Value`. | ||||
| 
 | ||||
| `rt` in this case refers to the Runtime type at | ||||
| https://pkg.go.dev/github.com/arnodel/golua@master/runtime#Runtime | ||||
| 
 | ||||
| Hilbish uses this package as its Lua runtime. You will need to read | ||||
| it to use it for a native plugin. | ||||
| 
 | ||||
| Here is some code for an example plugin: | ||||
| ```go | ||||
| package main | ||||
| 
 | ||||
| import ( | ||||
| 	rt "github.com/arnodel/golua/runtime" | ||||
| ) | ||||
| 
 | ||||
| func Loader(rtm *rt.Runtime) rt.Value { | ||||
| 	return rt.StringValue("hello world!") | ||||
| } | ||||
| ``` | ||||
| 
 | ||||
| This can be compiled with `go build -buildmode=plugin plugin.go`. | ||||
| If you attempt to require and print the result (`print(require 'plugin')`), it will show "hello world!" | ||||
| 
 | ||||
| ## Functions | ||||
| ||| | ||||
| |----|----| | ||||
| |<a href="#module.load">load(path)</a>|Loads a module at the designated `path`.| | ||||
| 
 | ||||
| ## Static module fields | ||||
| ||| | ||||
| |----|----| | ||||
| |paths|A list of paths to search when loading native modules. This is in the style of Lua search paths and will be used when requiring native modules. Example: `?.so;?/?.so`| | ||||
| 
 | ||||
| <hr><div id='module.load'> | ||||
| <h4 class='heading'> | ||||
| hilbish.module.load(path) | ||||
| <a href="#module.load" class='heading-link'> | ||||
| 	<i class="fas fa-paperclip"></i> | ||||
| </a> | ||||
| </h4> | ||||
| 
 | ||||
| Loads a module at the designated `path`. | ||||
| It will throw if any error occurs. | ||||
| #### Parameters | ||||
| This function has no parameters.   | ||||
| </div> | ||||
| 
 | ||||
							
								
								
									
										11
									
								
								editor.go
									
									
									
									
									
								
							
							
						
						
									
										11
									
								
								editor.go
									
									
									
									
									
								
							| @ -16,6 +16,7 @@ func editorLoader(rtm *rt.Runtime) *rt.Table { | ||||
| 		"setVimRegister": {editorSetRegister, 1, false}, | ||||
| 		"getVimRegister": {editorGetRegister, 2, false}, | ||||
| 		"getLine": {editorGetLine, 0, false}, | ||||
| 		"readChar": {editorReadChar, 0, false}, | ||||
| 	} | ||||
| 
 | ||||
| 	mod := rt.NewTable() | ||||
| @ -94,3 +95,13 @@ func editorGetLine(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) { | ||||
| 
 | ||||
| 	return c.PushingNext1(t.Runtime, rt.StringValue(string(buf))), nil | ||||
| } | ||||
| 
 | ||||
| // #interface editor | ||||
| // getChar() -> string | ||||
| // Reads a keystroke from the user. This is in a format | ||||
| // of something like Ctrl-L.. | ||||
| func editorReadChar(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) { | ||||
| 	buf := lr.rl.ReadChar() | ||||
| 
 | ||||
| 	return c.PushingNext1(t.Runtime, rt.StringValue(string(buf))), nil | ||||
| } | ||||
|  | ||||
| @ -40,6 +40,10 @@ function hilbish.editor.getVimRegister(register) end | ||||
| --- Inserts text into the line. | ||||
| function hilbish.editor.insert(text) end | ||||
| 
 | ||||
| --- Reads a keystroke from the user. This is in a format | ||||
| --- of something like Ctrl-L.. | ||||
| function hilbish.editor.getChar() end | ||||
| 
 | ||||
| --- Sets the vim register at `register` to hold the passed text. | ||||
| --- @param register string | ||||
| --- @param text string | ||||
| @ -196,10 +200,14 @@ function hilbish:autoFlush(auto) end | ||||
| --- Flush writes all buffered input to the sink. | ||||
| function hilbish:flush() end | ||||
| 
 | ||||
| --- Reads input from the sink. | ||||
| --- Reads a liine of input from the sink. | ||||
| --- @returns string | ||||
| function hilbish:read() end | ||||
| 
 | ||||
| --- Reads all input from the sink. | ||||
| --- @returns string | ||||
| function hilbish:readAll() end | ||||
| 
 | ||||
| --- Writes data to a sink. | ||||
| function hilbish:write(str) end | ||||
| 
 | ||||
| @ -212,6 +220,10 @@ function hilbish.jobs:start() end | ||||
| --- Stops the job from running. | ||||
| function hilbish.jobs:stop() end | ||||
| 
 | ||||
| --- Loads a module at the designated `path`. | ||||
| --- It will throw if any error occurs. | ||||
| function hilbish.module.load(path) end | ||||
| 
 | ||||
| --- Runs a command in Hilbish's shell script interpreter. | ||||
| --- This is the equivalent of using `source`. | ||||
| --- @param cmd string | ||||
|  | ||||
							
								
								
									
										2
									
								
								go.mod
									
									
									
									
									
								
							
							
						
						
									
										2
									
								
								go.mod
									
									
									
									
									
								
							| @ -6,7 +6,6 @@ require ( | ||||
| 	github.com/arnodel/golua v0.0.0-20220221163911-dfcf252b6f86 | ||||
| 	github.com/atsushinee/go-markdown-generator v0.0.0-20191121114853-83f9e1f68504 | ||||
| 	github.com/blackfireio/osinfo v1.0.3 | ||||
| 	github.com/chuckpreslar/emission v0.0.0-20170206194824-a7ddd980baf9 | ||||
| 	github.com/maxlandon/readline v0.1.0-beta.0.20211027085530-2b76cabb8036 | ||||
| 	github.com/pborman/getopt v1.1.0 | ||||
| 	github.com/sahilm/fuzzy v0.1.0 | ||||
| @ -19,6 +18,7 @@ require ( | ||||
| 	github.com/acarl005/stripansi v0.0.0-20180116102854-5a71ef0e047d // indirect | ||||
| 	github.com/arnodel/strftime v0.1.6 // indirect | ||||
| 	github.com/evilsocket/islazy v1.10.6 // indirect | ||||
| 	github.com/kylelemons/godebug v1.1.0 // indirect | ||||
| 	github.com/olekukonko/ts v0.0.0-20171002115256-78ecb04241c0 // indirect | ||||
| 	github.com/rivo/uniseg v0.2.0 // indirect | ||||
| 	golang.org/x/sync v0.0.0-20220513210516-0976fa681c29 // indirect | ||||
|  | ||||
							
								
								
									
										18
									
								
								go.sum
									
									
									
									
									
								
							
							
						
						
									
										18
									
								
								go.sum
									
									
									
									
									
								
							| @ -1,13 +1,5 @@ | ||||
| github.com/Rosettea/golua v0.0.0-20220419183026-6d22d6fec5ac h1:dtXrgjch8PQyf7C90anZUquB5U3dr8AcMGJofeuirrI= | ||||
| github.com/Rosettea/golua v0.0.0-20220419183026-6d22d6fec5ac/go.mod h1:9jzpYPiU2is0HVGCiuIOBSXdergHUW44IEjmuN1UrIE= | ||||
| github.com/Rosettea/golua v0.0.0-20220518005949-116371948fe3 h1:I/wWr40FFLFF9pbT3wLb1FAEZhKb/hUWE+nJ5uHBK2g= | ||||
| github.com/Rosettea/golua v0.0.0-20220518005949-116371948fe3/go.mod h1:9jzpYPiU2is0HVGCiuIOBSXdergHUW44IEjmuN1UrIE= | ||||
| github.com/Rosettea/golua v0.0.0-20220621002945-b05143999437 h1:6lWu4YVLeKuZ8jR9xwHONhkHBsrIbw5dpfG1gtOVw0A= | ||||
| github.com/Rosettea/golua v0.0.0-20220621002945-b05143999437/go.mod h1:9jzpYPiU2is0HVGCiuIOBSXdergHUW44IEjmuN1UrIE= | ||||
| github.com/Rosettea/golua v0.0.0-20221213193027-cbf6d4e4d345 h1:QNYjYDogUSiNUkffbhFSrSCtpZhofeiVYGFN2FI4wSs= | ||||
| github.com/Rosettea/golua v0.0.0-20221213193027-cbf6d4e4d345/go.mod h1:9jzpYPiU2is0HVGCiuIOBSXdergHUW44IEjmuN1UrIE= | ||||
| github.com/Rosettea/sh/v3 v3.4.0-0.dev.0.20220306140409-795a84b00b4e h1:P2XupP8SaylWaudD1DqbWtZ3mIa8OsE9635LmR+Q+lg= | ||||
| github.com/Rosettea/sh/v3 v3.4.0-0.dev.0.20220306140409-795a84b00b4e/go.mod h1:R09vh/04ILvP2Gj8/Z9Jd0Dh0ZIvaucowMEs6abQpWs= | ||||
| github.com/Rosettea/sh/v3 v3.4.0-0.dev.0.20220524215627-dfd9a4fa219b h1:s5eDMhBk6H1BgipgLub/gv9qeyBaTuiHM0k3h2/9TSE= | ||||
| github.com/Rosettea/sh/v3 v3.4.0-0.dev.0.20220524215627-dfd9a4fa219b/go.mod h1:R09vh/04ILvP2Gj8/Z9Jd0Dh0ZIvaucowMEs6abQpWs= | ||||
| github.com/acarl005/stripansi v0.0.0-20180116102854-5a71ef0e047d h1:licZJFw2RwpHMqeKTCYkitsPqHNxTmd4SNR5r94FGM8= | ||||
| @ -20,8 +12,6 @@ github.com/atsushinee/go-markdown-generator v0.0.0-20191121114853-83f9e1f68504 h | ||||
| github.com/atsushinee/go-markdown-generator v0.0.0-20191121114853-83f9e1f68504/go.mod h1:kHBCvAXJIatTX1pw6tLiOspjGc3MhUDRlog9yrCUS+k= | ||||
| github.com/blackfireio/osinfo v1.0.3 h1:Yk2t2GTPjBcESv6nDSWZKO87bGMQgO+Hi9OoXPpxX8c= | ||||
| github.com/blackfireio/osinfo v1.0.3/go.mod h1:Pd987poVNmd5Wsx6PRPw4+w7kLlf9iJxoRKPtPAjOrA= | ||||
| github.com/chuckpreslar/emission v0.0.0-20170206194824-a7ddd980baf9 h1:xz6Nv3zcwO2Lila35hcb0QloCQsc38Al13RNEzWRpX4= | ||||
| github.com/chuckpreslar/emission v0.0.0-20170206194824-a7ddd980baf9/go.mod h1:2wSM9zJkl1UQEFZgSd68NfCgRz1VL1jzy/RjCg+ULrs= | ||||
| github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= | ||||
| github.com/creack/pty v1.1.15 h1:cKRCLMj3Ddm54bKSpemfQ8AtYFBhAI2MPmdys22fBdc= | ||||
| github.com/creack/pty v1.1.15/go.mod h1:MOBLtS5ELjhRRrroQr9kyvTxUAFNvYEK993ew/Vr4O4= | ||||
| @ -38,6 +28,8 @@ github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= | ||||
| github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= | ||||
| github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= | ||||
| github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= | ||||
| github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc= | ||||
| github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw= | ||||
| github.com/lucasb-eyer/go-colorful v1.0.3/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0= | ||||
| github.com/mattn/go-runewidth v0.0.10/go.mod h1:RAqKPSqVFrSLVXbA8x7dzmKdmGzieGRCM46jaSJTDAk= | ||||
| github.com/olekukonko/ts v0.0.0-20171002115256-78ecb04241c0 h1:LiZB1h0GIcudcDci2bxbqI6DXV8bF8POAnArqvRrIyw= | ||||
| @ -53,7 +45,6 @@ github.com/rogpeppe/go-internal v1.8.1-0.20210923151022-86f73c517451 h1:d1PiN4Rx | ||||
| github.com/rogpeppe/go-internal v1.8.1-0.20210923151022-86f73c517451/go.mod h1:JeRgkft04UBgHMgCIwADu4Pn6Mtm5d4nPKWu0nJ5d+o= | ||||
| github.com/sahilm/fuzzy v0.1.0 h1:FzWGaw2Opqyu+794ZQ9SYifWv2EIXpwP4q8dY1kDAwI= | ||||
| github.com/sahilm/fuzzy v0.1.0/go.mod h1:VFvziUEIMCrT6A6tw2RFIXPXXmzXbOsSHF0DOI8ZK9Y= | ||||
| golang.org/x/sync v0.0.0-20210220032951-036812b2e83c h1:5KslGYwFpkhGh+Q16bwMP3cOontH8FOep7tGV86Y7SQ= | ||||
| golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= | ||||
| golang.org/x/sync v0.0.0-20220513210516-0976fa681c29 h1:w8s32wxx3sY+OjLlv9qltkLU5yvJzxjjgiHWLjdIcw4= | ||||
| golang.org/x/sync v0.0.0-20220513210516-0976fa681c29/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= | ||||
| @ -62,18 +53,13 @@ golang.org/x/sys v0.0.0-20210320140829-1e4c9ba3b0c4/go.mod h1:h1NjWce9XRLGQEsW7w | ||||
| golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= | ||||
| golang.org/x/sys v0.0.0-20210925032602-92d5a993a665/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= | ||||
| golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= | ||||
| golang.org/x/sys v0.0.0-20220227234510-4e6760a101f9 h1:nhht2DYV/Sn3qOayu8lM+cU1ii9sTLUeBQwQQfUHtrs= | ||||
| golang.org/x/sys v0.0.0-20220227234510-4e6760a101f9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= | ||||
| golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a h1:dGzPydgVsqGcTRVwiLJ1jVbufYwmzD3LfVPLKsKg+0k= | ||||
| golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= | ||||
| golang.org/x/term v0.0.0-20201210144234-2321bbc49cbf/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= | ||||
| golang.org/x/term v0.0.0-20210916214954-140adaaadfaf/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= | ||||
| golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 h1:JGgROgKl9N8DuW20oFS5gxc+lE67/N3FcwmBPMe7ArY= | ||||
| golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= | ||||
| golang.org/x/term v0.0.0-20220411215600-e5f449aeb171 h1:EH1Deb8WZJ0xc0WK//leUHXcX9aLE5SymusoTmMZye8= | ||||
| golang.org/x/term v0.0.0-20220411215600-e5f449aeb171/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= | ||||
| golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= | ||||
| golang.org/x/text v0.3.6 h1:aRYxNxv6iGQlyVaZmk6ZgYEDa+Jg18DxebPSrd6bg1M= | ||||
| golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= | ||||
| golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk= | ||||
| golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= | ||||
|  | ||||
							
								
								
									
										6
									
								
								main.go
									
									
									
									
									
								
							
							
						
						
									
										6
									
								
								main.go
									
									
									
									
									
								
							| @ -289,7 +289,7 @@ func removeDupes(slice []string) []string { | ||||
| 
 | ||||
| func contains(s []string, e string) bool { | ||||
| 	for _, a := range s { | ||||
| 		if a == e { | ||||
| 		if strings.ToLower(a) == strings.ToLower(e) { | ||||
| 			return true | ||||
| 		} | ||||
| 	} | ||||
| @ -324,3 +324,7 @@ func getVersion() string { | ||||
| 
 | ||||
| 	return v.String() | ||||
| } | ||||
| 
 | ||||
| func cut(slice []string, idx int) []string { | ||||
| 	return append(slice[:idx], slice[idx + 1:]...) | ||||
| } | ||||
|  | ||||
							
								
								
									
										92
									
								
								module.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										92
									
								
								module.go
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,92 @@ | ||||
| package main | ||||
| 
 | ||||
| import ( | ||||
| 	"plugin" | ||||
| 
 | ||||
| 	"hilbish/util" | ||||
| 
 | ||||
| 	rt "github.com/arnodel/golua/runtime" | ||||
| ) | ||||
| 
 | ||||
| // #interface module | ||||
| // native module loading | ||||
| // #field paths A list of paths to search when loading native modules. This is in the style of Lua search paths and will be used when requiring native modules. Example: `?.so;?/?.so` | ||||
| /* | ||||
| The hilbish.module interface provides a function to load | ||||
| Hilbish plugins/modules. Hilbish modules are Go-written | ||||
| plugins (see https://pkg.go.dev/plugin) that are used to add functionality | ||||
| to Hilbish that cannot be written in Lua for any reason. | ||||
| 
 | ||||
| Note that you don't ever need to use the load function that is here as | ||||
| modules can be loaded with a `require` call like Lua C modules, and the | ||||
| search paths can be changed with the `paths` property here. | ||||
| 
 | ||||
| To make a valid native module, the Go plugin has to export a Loader function | ||||
| with a signature like so: `func(*rt.Runtime) rt.Value`. | ||||
| 
 | ||||
| `rt` in this case refers to the Runtime type at | ||||
| https://pkg.go.dev/github.com/arnodel/golua@master/runtime#Runtime | ||||
| 
 | ||||
| Hilbish uses this package as its Lua runtime. You will need to read | ||||
| it to use it for a native plugin. | ||||
| 
 | ||||
| Here is some code for an example plugin: | ||||
| ```go | ||||
| package main | ||||
| 
 | ||||
| import ( | ||||
| 	rt "github.com/arnodel/golua/runtime" | ||||
| ) | ||||
| 
 | ||||
| func Loader(rtm *rt.Runtime) rt.Value { | ||||
| 	return rt.StringValue("hello world!") | ||||
| } | ||||
| ``` | ||||
| 
 | ||||
| This can be compiled with `go build -buildmode=plugin plugin.go`. | ||||
| If you attempt to require and print the result (`print(require 'plugin')`), it will show "hello world!" | ||||
| */ | ||||
| func moduleLoader(rtm *rt.Runtime) *rt.Table { | ||||
| 	exports := map[string]util.LuaExport{ | ||||
| 		"load": {moduleLoad, 2, false}, | ||||
| 	} | ||||
| 
 | ||||
| 	mod := rt.NewTable() | ||||
| 	util.SetExports(rtm, mod, exports) | ||||
| 
 | ||||
| 	return mod | ||||
| } | ||||
| 
 | ||||
| // #interface module | ||||
| // load(path) | ||||
| // Loads a module at the designated `path`. | ||||
| // It will throw if any error occurs. | ||||
| func moduleLoad(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) { | ||||
| 	if err := c.CheckNArgs(1); err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	 | ||||
| 	path, err := c.StringArg(0) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 
 | ||||
| 	p, err := plugin.Open(path) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 
 | ||||
| 	value, err := p.Lookup("Loader") | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 
 | ||||
| 	loader, ok := value.(func(*rt.Runtime) rt.Value) | ||||
| 	if !ok { | ||||
| 		return nil, nil | ||||
| 	} | ||||
| 
 | ||||
| 	val := loader(t.Runtime) | ||||
| 
 | ||||
| 	return c.PushingNext1(t.Runtime, val), nil | ||||
| } | ||||
| @ -1,6 +1,9 @@ | ||||
| local ansikit = require 'ansikit' | ||||
| local commander = require 'commander' | ||||
| local fs = require 'fs' | ||||
| local lunacolors = require 'lunacolors' | ||||
| local Greenhouse = require 'nature.greenhouse' | ||||
| local Page = require 'nature.greenhouse.page' | ||||
| 
 | ||||
| commander.register('doc', function(args, sinks) | ||||
| 	local moddocPath = hilbish.dataDir .. '/docs/' | ||||
| @ -9,11 +12,6 @@ commander.register('doc', function(args, sinks) | ||||
| 		-- hilbish git | ||||
| 		moddocPath = './docs/' | ||||
| 	end | ||||
| 	local apidocHeader = [[ | ||||
| # %s | ||||
| {grayBg}  {white}{italic}%s  {reset} | ||||
| 
 | ||||
| ]] | ||||
| 
 | ||||
| 	local modules = table.map(fs.readdir(moddocPath), function(f) | ||||
| 		return lunacolors.underline(lunacolors.blue(string.gsub(f, '.md', ''))) | ||||
| @ -25,47 +23,15 @@ to Hilbish. | ||||
| 
 | ||||
| Usage: doc <section> [subdoc] | ||||
| Available sections: ]] .. table.concat(modules, ', ') | ||||
| 	if #args > 0 then | ||||
| 		local mod = args[1] | ||||
| 
 | ||||
| 		local f = io.open(moddocPath .. mod .. '.md', 'rb') | ||||
| 		local funcdocs = nil | ||||
| 		local subdocName = args[2] | ||||
| 		if not f then | ||||
| 			-- assume subdir | ||||
| 			-- dataDir/docs/<mod>/<mod>.md | ||||
| 			moddocPath = moddocPath .. mod .. '/' | ||||
| 			if not subdocName then | ||||
| 				subdocName = '_index' | ||||
| 			end | ||||
| 			f = io.open(moddocPath .. subdocName .. '.md', 'rb') | ||||
| 			if not f then | ||||
| 				f = io.open(moddocPath .. subdocName:match '%w+' .. '/' .. subdocName .. '.md', 'rb') | ||||
| 			end | ||||
| 			if not f then | ||||
| 				moddocPath = moddocPath .. subdocName .. '/' | ||||
| 				subdocName = args[3] or '_index' | ||||
| 				f = io.open(moddocPath .. subdocName .. '.md', 'rb') | ||||
| 			end | ||||
| 			if not f then | ||||
| 				sinks.out:writeln('No documentation found for ' .. mod .. '.') | ||||
| 				return 1 | ||||
| 			end | ||||
| 		end | ||||
| 		funcdocs = f:read '*a':gsub('-([%d]+)', '%1') | ||||
| 		local moddocs = table.filter(fs.readdir(moddocPath), function(f) return f ~= '_index.md' and f ~= 'index.md' end) | ||||
| 		local subdocs = table.map(moddocs, function(fname) | ||||
| 			return lunacolors.underline(lunacolors.blue(string.gsub(fname, '.md', ''))) | ||||
| 		end) | ||||
| 		if #moddocs ~= 0 then | ||||
| 			funcdocs = funcdocs .. '\nSubdocs: ' .. table.concat(subdocs, ', ') | ||||
| 		end | ||||
| 
 | ||||
| 		local valsStr = funcdocs:match '%-%-%-\n([^%-%-%-]+)\n' | ||||
| 	local f | ||||
| 	local function handleYamlInfo(d) | ||||
| 		local vals = {} | ||||
| 		local docs = d | ||||
| 
 | ||||
| 		local valsStr = docs:match '%-%-%-\n([^%-%-%-]+)\n' | ||||
| 		print(valsStr) | ||||
| 		if valsStr then | ||||
| 			local _, endpos = funcdocs:find('---\n' .. valsStr .. '\n---\n\n', 1, true) | ||||
| 			funcdocs = funcdocs:sub(endpos + 1, #funcdocs) | ||||
| 			docs = docs:sub(valsStr:len() + 10, #docs) | ||||
| 
 | ||||
| 			-- parse vals | ||||
| 			local lines = string.split(valsStr, '\n') | ||||
| @ -78,23 +44,113 @@ Available sections: ]] .. table.concat(modules, ', ') | ||||
| 				end | ||||
| 			end | ||||
| 		end | ||||
| 		if mod == 'api' then | ||||
| 			funcdocs = string.format(apidocHeader, vals.title, vals.description or 'no description.') .. funcdocs | ||||
| 		end | ||||
| 		doc = funcdocs:sub(1, #funcdocs - 1) | ||||
| 		f:close() | ||||
| 
 | ||||
| 		--docs = docs:sub(1, #docs - 1) | ||||
| 		return docs, vals | ||||
| 	end | ||||
| 
 | ||||
| 	local backtickOccurence = 0 | ||||
| 	sinks.out:writeln(lunacolors.format(doc:gsub('`', function() | ||||
| 		backtickOccurence = backtickOccurence + 1 | ||||
| 		if backtickOccurence % 2 == 0 then | ||||
| 			return '{reset}' | ||||
| 		else | ||||
| 			return '{underline}{green}' | ||||
| 	if #args > 0 then | ||||
| 		local mod = args[1] | ||||
| 
 | ||||
| 		f = io.open(moddocPath .. mod .. '.md', 'rb') | ||||
| 		local funcdocs = nil | ||||
| 		local subdocName = args[2] | ||||
| 		if not f then | ||||
| 			moddocPath = moddocPath .. mod .. '/' | ||||
| 			if not subdocName then | ||||
| 				subdocName = '_index' | ||||
| 			end | ||||
| 			f = io.open(moddocPath .. subdocName .. '.md', 'rb') | ||||
| 			local oldmoddocPath = moddocPath | ||||
| 			if not f then | ||||
| 				moddocPath = moddocPath .. subdocName:match '%w+' .. '/' | ||||
| 				f = io.open(moddocPath .. subdocName .. '.md', 'rb') | ||||
| 			end | ||||
| 			if not f then | ||||
| 				moddocPath = oldmoddocPath .. subdocName .. '/' | ||||
| 				subdocName = args[3] or '_index' | ||||
| 				f = io.open(moddocPath .. subdocName .. '.md', 'rb') | ||||
| 			end | ||||
| 			if not f then | ||||
| 				sinks.out:writeln('No documentation found for ' .. mod .. '.') | ||||
| 				return 1 | ||||
| 			end | ||||
| 		end | ||||
| 	end):gsub('\n#+.-\n', function(t) | ||||
| 		local signature = t:gsub('<.->(.-)</.->', '{underline}%1'):gsub('\\', '<') | ||||
| 		return '{bold}{yellow}' .. signature .. '{reset}' | ||||
| 	end))) | ||||
| 
 | ||||
| 	end | ||||
| 
 | ||||
| 	local moddocs = table.filter(fs.readdir(moddocPath), function(f) return f ~= '_index.md' and f ~= 'index.md' end) | ||||
| 	local subdocs = table.map(moddocs, function(fname) | ||||
| 		return lunacolors.underline(lunacolors.blue(string.gsub(fname, '.md', ''))) | ||||
| 	end) | ||||
| 
 | ||||
| 	local gh = Greenhouse(sinks.out) | ||||
| 	function gh:resize() | ||||
| 		local size = terminal.size() | ||||
| 		self.region = { | ||||
| 			width = size.width, | ||||
| 			height = size.height - 3 | ||||
| 		} | ||||
| 	end | ||||
| 	gh:resize() | ||||
| 
 | ||||
| 	function gh:render() | ||||
| 		local workingPage = self.pages[self.curPage] | ||||
| 		local offset = self.offset | ||||
| 		if self.isSpecial then | ||||
| 			offset = self.specialOffset | ||||
| 			workingPage = self.specialPage | ||||
| 		end | ||||
| 
 | ||||
| 		self.sink:write(ansikit.getCSI(self.region.height + 2 .. ';1', 'H')) | ||||
| 		if not self.isSpecial then | ||||
| 			if args[1] == 'api' then | ||||
| 				self.sink:writeln(lunacolors.reset(string.format('%s', workingPage.title))) | ||||
| 				self.sink:write(lunacolors.format(string.format('{grayBg} ↳ {white}{italic}%s {reset}', workingPage.description or 'No description.'))) | ||||
| 			else | ||||
| 				self.sink:write(lunacolors.reset(string.format('Viewing doc page %s', moddocPath))) | ||||
| 			end | ||||
| 		end | ||||
| 	end | ||||
| 	local backtickOccurence = 0 | ||||
| 	local function formatDocText(d) | ||||
| 		return lunacolors.format(d:gsub('`', function() | ||||
| 			backtickOccurence = backtickOccurence + 1 | ||||
| 			if backtickOccurence % 2 == 0 then | ||||
| 				return '{reset}' | ||||
| 			else | ||||
| 				return '{underline}{green}' | ||||
| 			end | ||||
| 		end):gsub('\n#+.-\n', function(t) | ||||
| 			local signature = t:gsub('<.->(.-)</.->', '{underline}%1'):gsub('\\', '<') | ||||
| 			return '{bold}{yellow}' .. signature .. '{reset}' | ||||
| 		end)) | ||||
| 	end | ||||
| 
 | ||||
| 
 | ||||
| 	local doc, vals = handleYamlInfo(#args == 0 and doc or formatDocText(f:read '*a':gsub('-([%d]+)', '%1'))) | ||||
| 	if #moddocs ~= 0 and f then | ||||
| 		doc = doc .. '\nSubdocs: ' .. table.concat(subdocs, ', ') .. '\n\n' | ||||
| 	end | ||||
| 	if f then f:close() end | ||||
| 
 | ||||
| 	local page = Page(vals.title, doc) | ||||
| 	page.description = vals.description | ||||
| 	gh:addPage(page) | ||||
| 
 | ||||
| 	-- add subdoc pages | ||||
| 	for _, sdName in ipairs(moddocs) do | ||||
| 		local sdFile = fs.join(sdName, '_index.md') | ||||
| 		if sdName:match '.md$' then | ||||
| 			sdFile = sdName | ||||
| 		end | ||||
| 
 | ||||
| 		local f = io.open(moddocPath .. sdFile, 'rb') | ||||
| 		local doc, vals = handleYamlInfo(f:read '*a':gsub('-([%d]+)', '%1')) | ||||
| 		local page = Page(vals.title, formatDocText(doc)) | ||||
| 		page.description = vals.description | ||||
| 		gh:addPage(page) | ||||
| 	end | ||||
| 	ansikit.hideCursor() | ||||
| 	gh:initUi() | ||||
| end) | ||||
|  | ||||
							
								
								
									
										124
									
								
								nature/commands/greenhouse.lua
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										124
									
								
								nature/commands/greenhouse.lua
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,124 @@ | ||||
| local ansikit = require 'ansikit' | ||||
| local bait = require 'bait' | ||||
| local commander = require 'commander' | ||||
| local hilbish = require 'hilbish' | ||||
| local lunacolors = require 'lunacolors' | ||||
| local terminal = require 'terminal' | ||||
| local Greenhouse = require 'nature.greenhouse' | ||||
| local Page = require 'nature.greenhouse.page' | ||||
| 
 | ||||
| commander.register('greenhouse', function(args, sinks) | ||||
| 	local gh = Greenhouse(sinks.out) | ||||
| 
 | ||||
| 	local buffer = '' | ||||
| 	local display = '' | ||||
| 	local command = false | ||||
| 	local commands = { | ||||
| 		q = function() | ||||
| 			gh.keybinds['Ctrl-D'](gh) | ||||
| 		end, | ||||
| 		['goto'] = function(args) | ||||
| 			if not args[1] then | ||||
| 				return 'nuh uh' | ||||
| 			end | ||||
| 			gh:jump(tonumber(args[1])) | ||||
| 		end | ||||
| 	} | ||||
| 
 | ||||
| 	function gh:resize() | ||||
| 		local size = terminal.size() | ||||
| 		self.region = { | ||||
| 			width = size.width, | ||||
| 			height = size.height - 2 | ||||
| 		} | ||||
| 	end | ||||
| 
 | ||||
| 	function gh:render() | ||||
| 		local workingPage = self.pages[self.curPage] | ||||
| 		local offset = self.offset | ||||
| 		if self.isSpecial then | ||||
| 			offset = self.specialOffset | ||||
| 			workingPage = self.specialPage | ||||
| 		end | ||||
| 
 | ||||
| 		self.sink:write(ansikit.getCSI(self.region.height + 1 .. ';1', 'H')) | ||||
| 		if not self.isSpecial then | ||||
| 			self.sink:writeln(lunacolors.format(string.format('{grayBg} ↳ Page %d%s{reset}', self.curPage, workingPage.title and ' — ' .. workingPage.title .. ' ' or ''))) | ||||
| 		end | ||||
| 		self.sink:write(buffer == '' and display or buffer) | ||||
| 	end | ||||
| 	function gh:input(c) | ||||
| 		-- command handling | ||||
| 		if c == ':' and not command then | ||||
| 			command = true | ||||
| 		end | ||||
| 		if c == 'Escape' then | ||||
| 			if command then | ||||
| 				command = false | ||||
| 				buffer = '' | ||||
| 			else | ||||
| 				if self.isSpecial then gh:special() end | ||||
| 			end | ||||
| 		elseif c == 'Backspace' then | ||||
| 			buffer = buffer:sub(0, -2) | ||||
| 			if buffer == '' then | ||||
| 				command = false | ||||
| 			else | ||||
| 				goto update | ||||
| 			end | ||||
| 		end | ||||
| 
 | ||||
| 		if command then | ||||
| 			ansikit.showCursor() | ||||
| 			if buffer:match '^:' then buffer = buffer .. c else buffer = c end | ||||
| 		else | ||||
| 			ansikit.hideCursor() | ||||
| 		end | ||||
| 
 | ||||
| 		::update:: | ||||
| 		gh:update() | ||||
| 	end | ||||
| 	gh:resize() | ||||
| 
 | ||||
| 	gh:keybind('Enter', function(self) | ||||
| 		if self.isSpecial then | ||||
| 			self:jump(self.specialPageIdx) | ||||
| 			self:special(false) | ||||
| 		else | ||||
| 			if buffer:len() < 2 then return end | ||||
| 
 | ||||
| 			local splitBuf = string.split(buffer, " ") | ||||
| 			local command = commands[splitBuf[1]:sub(2)] | ||||
| 			if command then | ||||
| 				table.remove(splitBuf, 1) | ||||
| 				buffer = command(splitBuf) or '' | ||||
| 			end | ||||
| 			self:update() | ||||
| 		end | ||||
| 	end) | ||||
| 
 | ||||
| 	if sinks['in'].pipe then | ||||
| 		local page = Page('stdin', sinks['in']:readAll()) | ||||
| 		gh:addPage(page) | ||||
| 	end | ||||
| 
 | ||||
| 	for _, name in ipairs(args) do | ||||
| 		local f <close> = io.open(name, 'r') | ||||
| 		if not f then | ||||
| 			sinks.err:writeln(string.format('could not open file %s', name)) | ||||
| 		end | ||||
| 		local page = Page(name, f:read '*a') | ||||
| 		gh:addPage(page) | ||||
| 	end | ||||
| 
 | ||||
| 	if #gh.pages == 0 then | ||||
| 		sinks.out:writeln [[greenhouse is the Hilbish pager library and command! | ||||
| usage: greenhouse <file>... | ||||
| 
 | ||||
| example: greenhouse hello.md]] | ||||
| 		return 1 | ||||
| 	end | ||||
| 
 | ||||
| 	ansikit.hideCursor() | ||||
| 	gh:initUi() | ||||
| end) | ||||
							
								
								
									
										328
									
								
								nature/greenhouse/init.lua
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										328
									
								
								nature/greenhouse/init.lua
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,328 @@ | ||||
| -- Greenhouse is a simple text scrolling handler for terminal programs. | ||||
| -- The idea is that it can be set a region to do its scrolling and paging | ||||
| -- job and then the user can draw whatever outside it. | ||||
| -- This reduces code duplication for the message viewer | ||||
| -- and flowerbook. | ||||
| 
 | ||||
| local ansikit = require 'ansikit' | ||||
| local lunacolors = require 'lunacolors' | ||||
| local terminal = require 'terminal' | ||||
| local Page = require 'nature.greenhouse.page' | ||||
| local Object = require 'nature.object' | ||||
| 
 | ||||
| local Greenhouse = Object:extend() | ||||
| 
 | ||||
| function Greenhouse:new(sink) | ||||
| 	local size = terminal.size() | ||||
| 	self.region = size | ||||
| 	self.contents = nil -- or can be a table | ||||
| 	self.start = 1 -- where to start drawing from (should replace with self.region.y) | ||||
| 	self.offset = 1 -- vertical text offset | ||||
| 	self.sink = sink | ||||
| 	self.pages = {} | ||||
| 	self.curPage = 1 | ||||
| 	self.keybinds = { | ||||
| 		['Up'] = function(self) self:scroll 'up' end, | ||||
| 		['Down'] = function(self) self:scroll 'down' end, | ||||
| 		['Ctrl-Left'] = self.previous, | ||||
| 		['Ctrl-Right'] = self.next, | ||||
| 		['Ctrl-N'] = function(self) self:toc(true) end, | ||||
| 		['Enter'] = function(self) | ||||
| 			if self.isSpecial then | ||||
| 				self:jump(self.specialPageIdx) | ||||
| 				self:special(false) | ||||
| 			end | ||||
| 		end | ||||
| 	} | ||||
| 	self.isSpecial = false | ||||
| 	self.specialPage = nil | ||||
| 	self.specialPageIdx = 1 | ||||
| 	self.specialOffset = 1 | ||||
| 
 | ||||
| 	return self | ||||
| end | ||||
| 
 | ||||
| function Greenhouse:addPage(page) | ||||
| 	table.insert(self.pages, page) | ||||
| end | ||||
| 
 | ||||
| function Greenhouse:updateCurrentPage(text) | ||||
| 	local page = self.pages[self.curPage] | ||||
| 	page:setText(text) | ||||
| end | ||||
| 
 | ||||
| local function sub(str, limit) | ||||
| 	local overhead = 0 | ||||
| 	local function addOverhead(s) | ||||
| 		overhead = overhead + string.len(s) | ||||
| 	end | ||||
| 
 | ||||
| 	local s = str:gsub('\x1b%[%d+;%d+;%d+;%d+;%d+%w', addOverhead) | ||||
|      :gsub('\x1b%[%d+;%d+;%d+;%d+%w', addOverhead) | ||||
|      :gsub('\x1b%[%d+;%d+;%d+%w',addOverhead) | ||||
|      :gsub('\x1b%[%d+;%d+%w', addOverhead) | ||||
|      :gsub('\x1b%[%d+%w', addOverhead) | ||||
| 
 | ||||
| 	return s:sub(0, limit + overhead) | ||||
| end | ||||
| 
 | ||||
| function Greenhouse:draw() | ||||
| 	local workingPage = self.pages[self.curPage] | ||||
| 	local offset = self.offset | ||||
| 	if self.isSpecial then | ||||
| 		offset = self.specialOffset | ||||
| 		workingPage = self.specialPage | ||||
| 	end | ||||
| 
 | ||||
| 	if workingPage.lazy and not workingPage.loaded then | ||||
| 		workingPage.initialize() | ||||
| 	end | ||||
| 
 | ||||
| 	local lines = workingPage.lines | ||||
| 	self.sink:write(ansikit.getCSI(self.start .. ';1', 'H')) | ||||
| 	self.sink:write(ansikit.getCSI(2, 'J')) | ||||
| 
 | ||||
| 	for i = offset, offset + self.region.height - 1 do | ||||
| 		if i > #lines then break end | ||||
| 
 | ||||
| 		local writer = self.sink.writeln | ||||
| 		if i == offset + self.region.height - 1 then writer = self.sink.write end | ||||
| 
 | ||||
| 		writer(self.sink, sub(lines[i]:gsub('\t', '        '), self.region.width)) | ||||
| 	end | ||||
| 	self:render() | ||||
| end | ||||
| 
 | ||||
| function Greenhouse:render() | ||||
| end | ||||
| 
 | ||||
| function Greenhouse:scroll(direction) | ||||
| 	if self.isSpecial then | ||||
| 		if direction == 'down' then | ||||
| 			self:next(true) | ||||
| 		elseif direction == 'up' then | ||||
| 			self:previous(true) | ||||
| 		end | ||||
| 		return | ||||
| 	end | ||||
| 
 | ||||
| 	local lines = self.pages[self.curPage].lines | ||||
| 
 | ||||
| 	local oldOffset = self.offset | ||||
| 	if direction == 'down' then | ||||
| 		self.offset = math.min(self.offset + 1, math.max(1, #lines - self.region.height)) | ||||
| 	elseif direction == 'up' then | ||||
| 		self.offset = math.max(self.offset - 1, 1) | ||||
| 	end | ||||
| 
 | ||||
| 	if self.offset ~= oldOffset then self:draw() end | ||||
| end | ||||
| 
 | ||||
| function Greenhouse:update() | ||||
| 	self:resize() | ||||
| 	if self.isSpecial then | ||||
| 		self:updateSpecial() | ||||
| 	end | ||||
| 
 | ||||
| 	self:draw() | ||||
| end | ||||
| 
 | ||||
| 
 | ||||
| function Greenhouse:special(val) | ||||
| 	self.isSpecial = val | ||||
| 	self:update() | ||||
| end | ||||
| 
 | ||||
| function Greenhouse:toggleSpecial() | ||||
| 	self:special(not self.isSpecial) | ||||
| end | ||||
| 
 | ||||
| --- This function will be called when the special page | ||||
| --- is on and needs to be updated. | ||||
| function Greenhouse:updateSpecial() | ||||
| end | ||||
| 
 | ||||
| function Greenhouse:contents() | ||||
| end | ||||
| 
 | ||||
| function Greenhouse:toc(toggle) | ||||
| 	if not self.isSpecial then | ||||
| 		self.specialPageIdx = self.curPage | ||||
| 	end | ||||
| 	if toggle then self.isSpecial = not self.isSpecial end | ||||
| 	-- Generate a special page for our table of contents | ||||
| 	local tocText = string.format([[ | ||||
| %s | ||||
| 
 | ||||
| ]], lunacolors.cyan(lunacolors.bold '―― Table of Contents ――')) | ||||
| 
 | ||||
| 	local genericPageCount = 1 | ||||
| 	local contents = self:contents() | ||||
| 	if contents then | ||||
| 		for i, c in ipairs(contents) do | ||||
| 			local title = c.title | ||||
| 			if c.active then | ||||
| 				title = lunacolors.invert(title) | ||||
| 			end | ||||
| 
 | ||||
| 			tocText = tocText .. title .. '\n' | ||||
| 		end | ||||
| 	else | ||||
| 		for i, page in ipairs(self.pages) do | ||||
| 			local title = page.title | ||||
| 			if title == 'Page' then | ||||
| 				title = 'Page #' .. genericPageCount | ||||
| 				genericPageCount = genericPageCount + 1 | ||||
| 			end | ||||
| 			if i == self.specialPageIdx then | ||||
| 				title = lunacolors.invert(title) | ||||
| 			end | ||||
| 
 | ||||
| 			tocText = tocText .. title .. '\n' | ||||
| 		end | ||||
| 	end | ||||
| 	self.specialPage = Page('TOC', tocText) | ||||
| 	function self:updateSpecial() | ||||
| 		self:toc() | ||||
| 	end | ||||
| 	self:draw() | ||||
| end | ||||
| 
 | ||||
| function Greenhouse:resize() | ||||
| 	local size = terminal.size() | ||||
| 	self.region = size | ||||
| end | ||||
| 
 | ||||
| function Greenhouse:next(special) | ||||
| 	local oldCurrent = special and self.specialPageIdx or self.curPage | ||||
| 	local pageIdx = math.min(oldCurrent + 1, #self.pages) | ||||
| 
 | ||||
| 	if special then | ||||
| 		self.specialPageIdx = pageIdx | ||||
| 	else | ||||
| 		self.curPage = pageIdx | ||||
| 	end | ||||
| 
 | ||||
| 	if pageIdx ~= oldCurrent then | ||||
| 		self.offset = 1 | ||||
| 		self:update() | ||||
| 	end | ||||
| end | ||||
| 
 | ||||
| function Greenhouse:previous(special) | ||||
| 	local oldCurrent = special and self.specialPageIdx or self.curPage | ||||
| 	local pageIdx = math.max(self.curPage - 1, 1) | ||||
| 
 | ||||
| 	if special then | ||||
| 		self.specialPageIdx = pageIdx | ||||
| 	else | ||||
| 		self.curPage = pageIdx | ||||
| 	end | ||||
| 
 | ||||
| 	if pageIdx ~= oldCurrent then | ||||
| 		self.offset = 1 | ||||
| 		self:update() | ||||
| 	end | ||||
| end | ||||
| 
 | ||||
| function Greenhouse:jump(idx) | ||||
| 	if idx ~= self.curPage then | ||||
| 		self.offset = 1 | ||||
| 	end | ||||
| 	self.curPage = idx | ||||
| 	self:update() | ||||
| end | ||||
| 
 | ||||
| function Greenhouse:keybind(key, callback) | ||||
| 	self.keybinds[key] = callback | ||||
| end | ||||
| 
 | ||||
| function Greenhouse:input(char) | ||||
| end | ||||
| 
 | ||||
| function Greenhouse:initUi() | ||||
| 	local ansikit = require 'ansikit' | ||||
| 	local bait = require 'bait' | ||||
| 	local commander = require 'commander' | ||||
| 	local hilbish = require 'hilbish' | ||||
| 	local terminal = require 'terminal' | ||||
| 	local Page = require 'nature.greenhouse.page' | ||||
| 	local done = false | ||||
| 
 | ||||
| 	bait.catch('signal.sigint', function() | ||||
| 		ansikit.clear() | ||||
| 		done = true | ||||
| 	end) | ||||
| 
 | ||||
| 	bait.catch('signal.resize', function() | ||||
| 		self:update() | ||||
| 	end) | ||||
| 
 | ||||
| 	ansikit.screenAlt() | ||||
| 	ansikit.clear(true) | ||||
| 	self:draw() | ||||
| 
 | ||||
| 	hilbish.goro(function() | ||||
| 		while not done do | ||||
| 			local c = read() | ||||
| 			self:keybind('Ctrl-D', function() | ||||
| 				done = true | ||||
| 			end) | ||||
| 
 | ||||
| 			if self.keybinds[c] then | ||||
| 				self.keybinds[c](self) | ||||
| 			else | ||||
| 				self:input(c) | ||||
| 			end | ||||
| 
 | ||||
| 	--[[ | ||||
| 			if c == 27 then | ||||
| 				local c1 = read() | ||||
| 				if c1 == 91 then | ||||
| 					local c2 = read() | ||||
| 					if c2 == 66 then -- arrow down | ||||
| 						self:scroll 'down' | ||||
| 					elseif c2 == 65 then -- arrow up | ||||
| 						self:scroll 'up' | ||||
| 					end | ||||
| 
 | ||||
| 					if c2 == 49 then | ||||
| 						local c3 = read() | ||||
| 						if c3 == 59 then | ||||
| 							local c4 = read() | ||||
| 							if c4 == 53 then | ||||
| 								local c5 = read() | ||||
| 								if c5 == 67 then | ||||
| 									self:next() | ||||
| 								elseif c5 == 68 then | ||||
| 									self:previous() | ||||
| 								end | ||||
| 							end | ||||
| 						end | ||||
| 					end | ||||
| 				end | ||||
| 				goto continue | ||||
| 			end | ||||
| 			]]-- | ||||
| 
 | ||||
| 			::continue:: | ||||
| 		end | ||||
| 	end) | ||||
| 
 | ||||
| 	while not done do | ||||
| 		-- | ||||
| 	end | ||||
| 	ansikit.showCursor() | ||||
| 	ansikit.screenMain() | ||||
| end | ||||
| 
 | ||||
| function read() | ||||
| 	terminal.saveState() | ||||
| 	terminal.setRaw() | ||||
| 	local c = hilbish.editor.readChar() | ||||
| 
 | ||||
| 	terminal.restoreState() | ||||
| 	return c | ||||
| end | ||||
| 
 | ||||
| return Greenhouse | ||||
							
								
								
									
										32
									
								
								nature/greenhouse/page.lua
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										32
									
								
								nature/greenhouse/page.lua
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,32 @@ | ||||
| local Object = require 'nature.object' | ||||
| 
 | ||||
| local Page = Object:extend() | ||||
| 
 | ||||
| function Page:new(title, text) | ||||
| 	self:setText(text) | ||||
| 	self.title = title or 'Page' | ||||
| 	self.lazy = false | ||||
| 	self.loaded = true | ||||
| 	self.children = {} | ||||
| end | ||||
| 
 | ||||
| function Page:setText(text) | ||||
| 	self.lines = string.split(text, '\n') | ||||
| end | ||||
| 
 | ||||
| function Page:setTitle(title) | ||||
| 	self.title = title | ||||
| end | ||||
| 
 | ||||
| function Page:dynamic(initializer) | ||||
| 	self.initializer = initializer | ||||
| 	self.lazy = true | ||||
| 	self.loaded = false | ||||
| end | ||||
| 
 | ||||
| function Page:initialize() | ||||
| 	self.initializer() | ||||
| 	self.loaded = true | ||||
| end | ||||
| 
 | ||||
| return Page | ||||
| @ -6,6 +6,18 @@ local fs = require 'fs' | ||||
| package.path = package.path .. ';' .. hilbish.dataDir .. '/?/init.lua' | ||||
| .. ';' .. hilbish.dataDir .. '/?/?.lua' .. ";" .. hilbish.dataDir .. '/?.lua' | ||||
| 
 | ||||
| hilbish.module.paths = '?.so;?/?.so;' | ||||
| .. hilbish.userDir.data .. 'hilbish/libs/?/?.so' | ||||
| .. ";" .. hilbish.userDir.data .. 'hilbish/libs/?.so' | ||||
| 
 | ||||
| table.insert(package.searchers, function(module) | ||||
| 	local path = package.searchpath(module, hilbish.module.paths) | ||||
| 	if not path then return nil end | ||||
| 
 | ||||
| 	-- it didnt work normally, idk | ||||
| 	return function() return hilbish.module.load(path) end, path | ||||
| end) | ||||
| 
 | ||||
| require 'nature.commands' | ||||
| require 'nature.completions' | ||||
| require 'nature.opts' | ||||
|  | ||||
							
								
								
									
										59
									
								
								nature/object.lua
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										59
									
								
								nature/object.lua
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,59 @@ | ||||
| ---@class nature.object | ||||
| ---@field super nature.object | ||||
| local Object = {} | ||||
| Object.__index = Object | ||||
| 
 | ||||
| ---Can be overrided by child objects to implement a constructor. | ||||
| function Object:new() end | ||||
| 
 | ||||
| ---@return nature.object | ||||
| function Object:extend() | ||||
|   local cls = {} | ||||
|   for k, v in pairs(self) do | ||||
|     if k:find("__") == 1 then | ||||
|       cls[k] = v | ||||
|     end | ||||
|   end | ||||
|   cls.__index = cls | ||||
|   cls.super = self | ||||
|   setmetatable(cls, self) | ||||
|   return cls | ||||
| end | ||||
| 
 | ||||
| ---Check if the object is strictly of the given type. | ||||
| ---@param T any | ||||
| ---@return boolean | ||||
| function Object:is(T) | ||||
|   return getmetatable(self) == T | ||||
| end | ||||
| 
 | ||||
| ---Check if the object inherits from the given type. | ||||
| ---@param T any | ||||
| ---@return boolean | ||||
| function Object:extends(T) | ||||
|   local mt = getmetatable(self) | ||||
|   while mt do | ||||
|     if mt == T then | ||||
|       return true | ||||
|     end | ||||
|     mt = getmetatable(mt) | ||||
|   end | ||||
|   return false | ||||
| end | ||||
| 
 | ||||
| ---Metamethod to get a string representation of an object. | ||||
| ---@return string | ||||
| function Object:__tostring() | ||||
|   return "Object" | ||||
| end | ||||
| 
 | ||||
| ---Methamethod to allow using the object call as a constructor. | ||||
| ---@return nature.object | ||||
| function Object:__call(...) | ||||
|   local obj = setmetatable({}, self) | ||||
|   obj:new(...) | ||||
|   return obj | ||||
| end | ||||
| 
 | ||||
| 
 | ||||
| return Object | ||||
| @ -1,5 +1,7 @@ | ||||
| package readline | ||||
| 
 | ||||
| import "os" | ||||
| 
 | ||||
| // Character codes | ||||
| const ( | ||||
| 	charCtrlA = iota + 1 | ||||
| @ -134,3 +136,57 @@ const ( | ||||
| const ( | ||||
| 	seqCtermFg255 = "\033[48;5;255m" | ||||
| ) | ||||
| 
 | ||||
| // TODO: return whether its actually a sequence or not | ||||
| // remedies the edge case of someone literally typing Ctrl-A for example. | ||||
| func (rl *Instance) ReadChar() string { | ||||
| 	b := make([]byte, 1024) | ||||
| 	i, _ := os.Stdin.Read(b) | ||||
| 	r := []rune(string(b)) | ||||
| 	s := string(r[:i]) | ||||
| 
 | ||||
| 	switch b[0] { | ||||
| 		case charCtrlA: return "Ctrl-A" | ||||
| 		case charCtrlB: return "Ctrl-B" | ||||
| 		case charCtrlC: return "Ctrl-C" | ||||
| 		case charEOF: return "Ctrl-D" | ||||
| 		case charCtrlE: return "Ctrl-E" | ||||
| 		case charCtrlF: return "Ctrl-F" | ||||
| 		case charCtrlG: return "Ctrl-G" | ||||
| 		case charBackspace, charBackspace2: return "Backspace" | ||||
| 		case charTab: return "Tab" | ||||
| 		case charCtrlK: return "Ctrl-K" | ||||
| 		case charCtrlL: return "Ctrl-L" | ||||
| 		case charCtrlN: return "Ctrl-N" | ||||
| 		case charCtrlO: return "Ctrl-O" | ||||
| 		case charCtrlP: return "Ctrl-P" | ||||
| 		case charCtrlQ: return "Ctrl-Q" | ||||
| 		case charCtrlR: return "Ctrl-R" | ||||
| 		case charCtrlS: return "Ctrl-S" | ||||
| 		case charCtrlT: return "Ctrl-T" | ||||
| 		case charCtrlU: return "Ctrl-U" | ||||
| 		case charCtrlV: return "Ctrl-V" | ||||
| 		case charCtrlW: return "Ctrl-W" | ||||
| 		case charCtrlX: return "Ctrl-X" | ||||
| 		case charCtrlY: return "Ctrl-Y" | ||||
| 		case charCtrlZ: return "Ctrl-Z" | ||||
| 		case '\r': fallthrough | ||||
| 		case '\n': return "Enter" | ||||
| 		case charEscape: | ||||
| 			switch s { | ||||
| 				case string(charEscape): return "Escape" | ||||
| 				case seqUp: return "Up" | ||||
| 				case seqDown: return "Down" | ||||
| 				case seqBackwards: return "Left" | ||||
| 				case seqForwards: return "Right" | ||||
| 				case seqCtrlLeftArrow: return "Ctrl-Left" | ||||
| 				case seqCtrlRightArrow: return "Ctrl-Right" | ||||
| 				case seqCtrlDelete, seqCtrlDelete2: return "Ctrl-Delete" | ||||
| 				case seqHome, seqHomeSc: return "Home" | ||||
| 				case seqEnd, seqEndSc: return "End" | ||||
| 				case seqDelete, seqDelete2: return "Delete" | ||||
| 			} | ||||
| 	} | ||||
| 
 | ||||
| 	return s | ||||
| } | ||||
|  | ||||
| @ -156,8 +156,8 @@ func (rl *Instance) walkHistory(i int) { | ||||
| 	rl.updateHelpers() | ||||
| 
 | ||||
| 	// In order to avoid having to type j/k twice each time for history navigation, | ||||
| 	// we walk once again. This only ever happens when we aren't out of bounds. | ||||
| 	if dedup && old == new { | ||||
| 	// we walk once again. This only ever happens when we aren't out of bounds and the last history item was not a empty string. | ||||
| 	if new != "" && dedup && old == new { | ||||
| 		rl.walkHistory(i) | ||||
| 	} | ||||
| } | ||||
|  | ||||
							
								
								
									
										36
									
								
								sink.go
									
									
									
									
									
								
							
							
						
						
									
										36
									
								
								sink.go
									
									
									
									
									
								
							| @ -5,6 +5,7 @@ import ( | ||||
| 	"fmt" | ||||
| 	"io" | ||||
| 	"os" | ||||
| 	"strings" | ||||
| 
 | ||||
| 	"hilbish/util" | ||||
| 
 | ||||
| @ -31,6 +32,7 @@ func setupSinkType(rtm *rt.Runtime) { | ||||
| 	sinkFuncs := map[string]util.LuaExport{ | ||||
| 		"flush": {luaSinkFlush, 1, false}, | ||||
| 		"read": {luaSinkRead, 1, false}, | ||||
| 		"readAll": {luaSinkReadAll, 1, false}, | ||||
| 		"autoFlush": {luaSinkAutoFlush, 2, false}, | ||||
| 		"write": {luaSinkWrite, 2, false}, | ||||
| 		"writeln": {luaSinkWriteln, 2, false}, | ||||
| @ -65,10 +67,42 @@ func setupSinkType(rtm *rt.Runtime) { | ||||
| 	l.SetRegistry(sinkMetaKey, rt.TableValue(sinkMeta)) | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| // #member | ||||
| // readAll() -> string | ||||
| // --- @returns string | ||||
| // Reads all input from the sink. | ||||
| func luaSinkReadAll(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) { | ||||
| 	if err := c.Check1Arg(); err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 
 | ||||
| 	s, err := sinkArg(c, 0) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 
 | ||||
| 	lines := []string{} | ||||
| 	for { | ||||
| 		line, err := s.reader.ReadString('\n') | ||||
| 		if err != nil { | ||||
| 			if err == io.EOF { | ||||
| 				break | ||||
| 			} | ||||
| 
 | ||||
| 			return nil, err | ||||
| 		} | ||||
| 
 | ||||
| 		lines = append(lines, line) | ||||
| 	} | ||||
| 
 | ||||
| 	return c.PushingNext1(t.Runtime, rt.StringValue(strings.Join(lines, ""))), nil | ||||
| } | ||||
| 
 | ||||
| // #member | ||||
| // read() -> string | ||||
| // --- @returns string | ||||
| // Reads input from the sink. | ||||
| // Reads a liine of input from the sink. | ||||
| func luaSinkRead(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) { | ||||
| 	if err := c.Check1Arg(); err != nil { | ||||
| 		return nil, err | ||||
|  | ||||
							
								
								
									
										9
									
								
								testplugin/testplugin.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								testplugin/testplugin.go
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,9 @@ | ||||
| package main | ||||
| 
 | ||||
| import ( | ||||
| 	rt "github.com/arnodel/golua/runtime" | ||||
| ) | ||||
| 
 | ||||
| func Loader(rtm *rt.Runtime) rt.Value { | ||||
| 	return rt.StringValue("hello world!") | ||||
| } | ||||
							
								
								
									
										
											BIN
										
									
								
								testplugin/testplugin.so
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								testplugin/testplugin.so
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| @ -13,8 +13,8 @@ is that it runs Lua first and then falls back to shell script. | ||||
| 
 | ||||
| In some cases, someone might want to switch to just shell script to avoid | ||||
| it while interactive but still have a Lua config, or go full Lua to use | ||||
| Hilbish as a REPL. This also allows users to add alternative languages, | ||||
| instead of either like Fennel. | ||||
| Hilbish as a REPL. This also allows users to add alternative languages like | ||||
| Fennel as the interactive script runner. | ||||
| 
 | ||||
| Runner mode can also be used to handle specific kinds of input before | ||||
| evaluating like normal, which is how [Link.hsh](https://github.com/TorchedSammy/Link.hsh) | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user