Compare commits

...

20 Commits

Author SHA1 Message Date
sammyette df980f5fff
Merge 2af38c3bab into 78eb657897 2023-11-01 06:06:18 -04:00
sammyette 78eb657897
feat: hilbish native pager (#240) 2023-10-25 00:41:53 -04:00
sammyette 2af38c3bab
docs(hilbish.module): update autogen docs 2023-07-11 10:45:07 -04:00
sammyette dfc3942087
docs: add more details to module docs 2023-07-10 23:34:09 -04:00
sammyette e8e75ab27b
docs: add more details to path prop 2023-07-10 23:27:24 -04:00
sammyette 3774a77870
docs: add paths field to module interface docs 2023-07-10 23:24:52 -04:00
sammyette 3f29dfecb2
feat: add user dirs to hilbish module search paths 2023-07-10 23:24:33 -04:00
sammyette 6d936506c8
feat: add hilbish native module loader to package searcher 2023-07-10 23:20:28 -04:00
sammyette 42446fbf57
docs: make some minor fixes for module interface description 2023-07-10 22:46:06 -04:00
sammyette dcbb65a611
chore: merge from master 2023-07-10 22:42:22 -04:00
sammyette ac747d04e7
chore: merge from master 2023-07-10 22:38:43 -04:00
sammyette 36934aa33a
docs: document module interface 2023-07-10 22:32:59 -04:00
sammyette 6a09aa8f68
chore: merge from master 2023-07-10 22:07:01 -04:00
sammyette 109eac528c
build: use cgo by default 2023-07-10 21:41:35 -04:00
sammyette a0a22d6e93
fix: remove use of old util document function 2023-02-19 15:30:05 -04:00
sammyette 8aa9f3cb3a
refactor!: use go plugins instead of hashicorp plugins 2023-02-19 15:27:25 -04:00
sammyette f8d66f4b81
chore: merge from master 2023-02-19 15:27:00 -04:00
TorchedSammy 1e2c88f4a4
chore: merge from master 2022-09-02 23:29:34 -04:00
TorchedSammy 477fcaf980
chore: update branch 2022-07-13 18:51:15 -04:00
TorchedSammy bd693a4057
feat: load native modules/plugins with go-plugin 2022-07-07 00:32:00 -04:00
22 changed files with 968 additions and 81 deletions

View File

@ -8,6 +8,7 @@
- `pipe` property to check if a sink with input is a pipe (like stdin) - `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`) - Add fuzzy search to history search (enable via `hilbish.opts.fuzzy = true`)
- Show indexes on cdr list - 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.messages` interface (details in [#219])
- `hilbish.notification` signal when a message/notification is sent - `hilbish.notification` signal when a message/notification is sent
- `notifyJobFinish` opt to send a notification when background jobs are - `notifyJobFinish` opt to send a notification when background jobs are
@ -15,6 +16,10 @@ completed.
- Allow numbered arg substitutions in aliases. - Allow numbered arg substitutions in aliases.
- Example: `hilbish.alias('hello', 'echo %1 says hello')` allows the user to run `hello hilbish` - Example: `hilbish.alias('hello', 'echo %1 says hello')` allows the user to run `hello hilbish`
which will output `hilbish says hello`. 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.
### Fixed ### Fixed
- Return the prefix when calling `hilbish.completions.call` - Return the prefix when calling `hilbish.completions.call`

View File

@ -13,12 +13,22 @@ vars:
tasks: tasks:
default: 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: cmds:
- CGO_ENABLED=0 go build {{.GOFLAGS}} - CGO_ENABLED=0 go build {{.GOFLAGS}}
vars: 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)"' 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: build:
cmds:
- go build {{.GOFLAGS}}
build-nocgo:
cmds: cmds:
- CGO_ENABLED=0 go build {{.GOFLAGS}} - CGO_ENABLED=0 go build {{.GOFLAGS}}

3
api.go
View File

@ -166,6 +166,9 @@ func hilbishLoad(rtm *rt.Runtime) (rt.Value, func()) {
util.SetField(rtm, versionModule, "release", rt.StringValue(releaseName)) util.SetField(rtm, versionModule, "release", rt.StringValue(releaseName))
mod.Set(rt.StringValue("version"), rt.TableValue(versionModule)) mod.Set(rt.StringValue("version"), rt.TableValue(versionModule))
pluginModule := moduleLoader(rtm)
mod.Set(rt.StringValue("module"), rt.TableValue(pluginModule))
return rt.TableValue(fakeMod), nil return rt.TableValue(fakeMod), nil
} }

View File

@ -417,7 +417,7 @@ func main() {
f, _ := os.Create(docPath) f, _ := os.Create(docPath)
f.WriteString(fmt.Sprintf(header, modOrIface, modname, modu.ShortDescription)) f.WriteString(fmt.Sprintf(header, modOrIface, modname, modu.ShortDescription))
typeTag, _ := regexp.Compile(`@\w+`) typeTag, _ := regexp.Compile(`\B@\w+`)
modDescription := typeTag.ReplaceAllStringFunc(strings.Replace(modu.Description, "<", `\<`, -1), func(typ string) string { modDescription := typeTag.ReplaceAllStringFunc(strings.Replace(modu.Description, "<", `\<`, -1), func(typ string) string {
typName := typ[1:] typName := typ[1:]
typLookup := typeTable[strings.ToLower(typName)] typLookup := typeTable[strings.ToLower(typName)]

View File

@ -126,7 +126,10 @@ A call with no argument will toggle the value.
Flush writes all buffered input to the sink. Flush writes all buffered input to the sink.
#### read() -> string #### 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) #### write(str)
Writes data to a sink. Writes data to a sink.

View File

@ -21,6 +21,10 @@ Returns the text that is at the register.
### insert(text) ### insert(text)
Inserts text into the line. Inserts text into the line.
### getChar() -> string
Reads a keystroke from the user. This is in a format
of something like Ctrl-L..
### setVimRegister(register, text) ### setVimRegister(register, text)
Sets the vim register at `register` to hold the passed text. Sets the vim register at `register` to hold the passed text.

View File

@ -0,0 +1,52 @@
---
title: Interface 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!"
## Interface 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`
## Functions
### load(path)
Loads a module at the designated `path`.
It will throw if any error occurs.

View File

@ -16,6 +16,7 @@ func editorLoader(rtm *rt.Runtime) *rt.Table {
"setVimRegister": {editorSetRegister, 1, false}, "setVimRegister": {editorSetRegister, 1, false},
"getVimRegister": {editorGetRegister, 2, false}, "getVimRegister": {editorGetRegister, 2, false},
"getLine": {editorGetLine, 0, false}, "getLine": {editorGetLine, 0, false},
"readChar": {editorReadChar, 0, false},
} }
mod := rt.NewTable() 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 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
}

View File

@ -40,6 +40,10 @@ function hilbish.editor.getVimRegister(register) end
--- Inserts text into the line. --- Inserts text into the line.
function hilbish.editor.insert(text) end 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. --- Sets the vim register at `register` to hold the passed text.
--- @param register string --- @param register string
--- @param text string --- @param text string
@ -196,10 +200,14 @@ function hilbish:autoFlush(auto) end
--- Flush writes all buffered input to the sink. --- Flush writes all buffered input to the sink.
function hilbish:flush() end function hilbish:flush() end
--- Reads input from the sink. --- Reads a liine of input from the sink.
--- @returns string --- @returns string
function hilbish:read() end function hilbish:read() end
--- Reads all input from the sink.
--- @returns string
function hilbish:readAll() end
--- Writes data to a sink. --- Writes data to a sink.
function hilbish:write(str) end function hilbish:write(str) end
@ -212,6 +220,10 @@ function hilbish.jobs:start() end
--- Stops the job from running. --- Stops the job from running.
function hilbish.jobs:stop() end 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. --- Runs a command in Hilbish's shell script interpreter.
--- This is the equivalent of using `source`. --- This is the equivalent of using `source`.
--- @param cmd string --- @param cmd string

2
go.mod
View File

@ -5,7 +5,6 @@ go 1.17
require ( require (
github.com/arnodel/golua v0.0.0-20220221163911-dfcf252b6f86 github.com/arnodel/golua v0.0.0-20220221163911-dfcf252b6f86
github.com/blackfireio/osinfo v1.0.3 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/maxlandon/readline v0.1.0-beta.0.20211027085530-2b76cabb8036
github.com/pborman/getopt v1.1.0 github.com/pborman/getopt v1.1.0
github.com/sahilm/fuzzy v0.1.0 github.com/sahilm/fuzzy v0.1.0
@ -18,6 +17,7 @@ require (
github.com/acarl005/stripansi v0.0.0-20180116102854-5a71ef0e047d // indirect github.com/acarl005/stripansi v0.0.0-20180116102854-5a71ef0e047d // indirect
github.com/arnodel/strftime v0.1.6 // indirect github.com/arnodel/strftime v0.1.6 // indirect
github.com/evilsocket/islazy v1.10.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/olekukonko/ts v0.0.0-20171002115256-78ecb04241c0 // indirect
github.com/rivo/uniseg v0.2.0 // indirect github.com/rivo/uniseg v0.2.0 // indirect
golang.org/x/sync v0.0.0-20220513210516-0976fa681c29 // indirect golang.org/x/sync v0.0.0-20220513210516-0976fa681c29 // indirect

18
go.sum
View File

@ -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 h1:QNYjYDogUSiNUkffbhFSrSCtpZhofeiVYGFN2FI4wSs=
github.com/Rosettea/golua v0.0.0-20221213193027-cbf6d4e4d345/go.mod h1:9jzpYPiU2is0HVGCiuIOBSXdergHUW44IEjmuN1UrIE= 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 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/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= github.com/acarl005/stripansi v0.0.0-20180116102854-5a71ef0e047d h1:licZJFw2RwpHMqeKTCYkitsPqHNxTmd4SNR5r94FGM8=
@ -18,8 +10,6 @@ github.com/arnodel/strftime v0.1.6/go.mod h1:5NbK5XqYK8QpRZpqKNt4OlxLtIB8cotkLk4
github.com/atotto/clipboard v0.1.4/go.mod h1:ZY9tmq7sm5xIbd9bOK4onWV4S6X0u6GY7Vn0Yu86PYI= github.com/atotto/clipboard v0.1.4/go.mod h1:ZY9tmq7sm5xIbd9bOK4onWV4S6X0u6GY7Vn0Yu86PYI=
github.com/blackfireio/osinfo v1.0.3 h1:Yk2t2GTPjBcESv6nDSWZKO87bGMQgO+Hi9OoXPpxX8c= github.com/blackfireio/osinfo v1.0.3 h1:Yk2t2GTPjBcESv6nDSWZKO87bGMQgO+Hi9OoXPpxX8c=
github.com/blackfireio/osinfo v1.0.3/go.mod h1:Pd987poVNmd5Wsx6PRPw4+w7kLlf9iJxoRKPtPAjOrA= 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.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
github.com/creack/pty v1.1.15 h1:cKRCLMj3Ddm54bKSpemfQ8AtYFBhAI2MPmdys22fBdc= github.com/creack/pty v1.1.15 h1:cKRCLMj3Ddm54bKSpemfQ8AtYFBhAI2MPmdys22fBdc=
github.com/creack/pty v1.1.15/go.mod h1:MOBLtS5ELjhRRrroQr9kyvTxUAFNvYEK993ew/Vr4O4= github.com/creack/pty v1.1.15/go.mod h1:MOBLtS5ELjhRRrroQr9kyvTxUAFNvYEK993ew/Vr4O4=
@ -36,6 +26,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.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 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= 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/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/mattn/go-runewidth v0.0.10/go.mod h1:RAqKPSqVFrSLVXbA8x7dzmKdmGzieGRCM46jaSJTDAk=
github.com/olekukonko/ts v0.0.0-20171002115256-78ecb04241c0 h1:LiZB1h0GIcudcDci2bxbqI6DXV8bF8POAnArqvRrIyw= github.com/olekukonko/ts v0.0.0-20171002115256-78ecb04241c0 h1:LiZB1h0GIcudcDci2bxbqI6DXV8bF8POAnArqvRrIyw=
@ -51,7 +43,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/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 h1:FzWGaw2Opqyu+794ZQ9SYifWv2EIXpwP4q8dY1kDAwI=
github.com/sahilm/fuzzy v0.1.0/go.mod h1:VFvziUEIMCrT6A6tw2RFIXPXXmzXbOsSHF0DOI8ZK9Y= 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-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 h1:w8s32wxx3sY+OjLlv9qltkLU5yvJzxjjgiHWLjdIcw4=
golang.org/x/sync v0.0.0-20220513210516-0976fa681c29/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220513210516-0976fa681c29/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
@ -60,18 +51,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-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-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-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 h1:dGzPydgVsqGcTRVwiLJ1jVbufYwmzD3LfVPLKsKg+0k=
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 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-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-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 h1:EH1Deb8WZJ0xc0WK//leUHXcX9aLE5SymusoTmMZye8=
golang.org/x/term v0.0.0-20220411215600-e5f449aeb171/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= 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.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.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk= golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk=
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=

91
module.go 100644
View File

@ -0,0 +1,91 @@
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
}

View File

@ -1,6 +1,9 @@
local ansikit = require 'ansikit'
local commander = require 'commander' local commander = require 'commander'
local fs = require 'fs' local fs = require 'fs'
local lunacolors = require 'lunacolors' local lunacolors = require 'lunacolors'
local Greenhouse = require 'nature.greenhouse'
local Page = require 'nature.greenhouse.page'
commander.register('doc', function(args, sinks) commander.register('doc', function(args, sinks)
local moddocPath = hilbish.dataDir .. '/docs/' local moddocPath = hilbish.dataDir .. '/docs/'
@ -9,11 +12,6 @@ commander.register('doc', function(args, sinks)
-- hilbish git -- hilbish git
moddocPath = './docs/' moddocPath = './docs/'
end end
local apidocHeader = [[
# %s
{grayBg} {white}{italic}%s {reset}
]]
local modules = table.map(fs.readdir(moddocPath), function(f) local modules = table.map(fs.readdir(moddocPath), function(f)
return lunacolors.underline(lunacolors.blue(string.gsub(f, '.md', ''))) return lunacolors.underline(lunacolors.blue(string.gsub(f, '.md', '')))
@ -25,47 +23,15 @@ to Hilbish.
Usage: doc <section> [subdoc] Usage: doc <section> [subdoc]
Available sections: ]] .. table.concat(modules, ', ') Available sections: ]] .. table.concat(modules, ', ')
if #args > 0 then local f
local mod = args[1] local function handleYamlInfo(d)
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 vals = {} local vals = {}
local docs = d
local valsStr = docs:match '%-%-%-\n([^%-%-%-]+)\n'
print(valsStr)
if valsStr then if valsStr then
local _, endpos = funcdocs:find('---\n' .. valsStr .. '\n---\n\n', 1, true) docs = docs:sub(valsStr:len() + 10, #docs)
funcdocs = funcdocs:sub(endpos + 1, #funcdocs)
-- parse vals -- parse vals
local lines = string.split(valsStr, '\n') local lines = string.split(valsStr, '\n')
@ -78,23 +44,113 @@ Available sections: ]] .. table.concat(modules, ', ')
end end
end end
end end
if mod == 'api' then
funcdocs = string.format(apidocHeader, vals.title, vals.description or 'no description.') .. funcdocs --docs = docs:sub(1, #docs - 1)
end return docs, vals
doc = funcdocs:sub(1, #funcdocs - 1)
f:close()
end end
local backtickOccurence = 0 if #args > 0 then
sinks.out:writeln(lunacolors.format(doc:gsub('`', function() local mod = args[1]
backtickOccurence = backtickOccurence + 1
if backtickOccurence % 2 == 0 then f = io.open(moddocPath .. mod .. '.md', 'rb')
return '{reset}' local funcdocs = nil
else local subdocName = args[2]
return '{underline}{green}' 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
end):gsub('\n#+.-\n', function(t)
local signature = t:gsub('<.->(.-)</.->', '{underline}%1'):gsub('\\', '<') end
return '{bold}{yellow}' .. signature .. '{reset}'
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) end)

View 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)

View 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

View 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

View File

@ -6,6 +6,18 @@ local fs = require 'fs'
package.path = package.path .. ';' .. hilbish.dataDir .. '/?/init.lua' package.path = package.path .. ';' .. hilbish.dataDir .. '/?/init.lua'
.. ';' .. hilbish.dataDir .. '/?/?.lua' .. ";" .. hilbish.dataDir .. '/?.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.commands'
require 'nature.completions' require 'nature.completions'
require 'nature.opts' require 'nature.opts'

59
nature/object.lua 100644
View 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

View File

@ -1,5 +1,7 @@
package readline package readline
import "os"
// Character codes // Character codes
const ( const (
charCtrlA = iota + 1 charCtrlA = iota + 1
@ -134,3 +136,57 @@ const (
const ( const (
seqCtermFg255 = "\033[48;5;255m" 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
}

36
sink.go
View File

@ -5,6 +5,7 @@ import (
"fmt" "fmt"
"io" "io"
"os" "os"
"strings"
"hilbish/util" "hilbish/util"
@ -31,6 +32,7 @@ func setupSinkType(rtm *rt.Runtime) {
sinkFuncs := map[string]util.LuaExport{ sinkFuncs := map[string]util.LuaExport{
"flush": {luaSinkFlush, 1, false}, "flush": {luaSinkFlush, 1, false},
"read": {luaSinkRead, 1, false}, "read": {luaSinkRead, 1, false},
"readAll": {luaSinkReadAll, 1, false},
"autoFlush": {luaSinkAutoFlush, 2, false}, "autoFlush": {luaSinkAutoFlush, 2, false},
"write": {luaSinkWrite, 2, false}, "write": {luaSinkWrite, 2, false},
"writeln": {luaSinkWriteln, 2, false}, "writeln": {luaSinkWriteln, 2, false},
@ -65,10 +67,42 @@ func setupSinkType(rtm *rt.Runtime) {
l.SetRegistry(sinkMetaKey, rt.TableValue(sinkMeta)) 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 // #member
// read() -> string // read() -> string
// --- @returns 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) { func luaSinkRead(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
if err := c.Check1Arg(); err != nil { if err := c.Check1Arg(); err != nil {
return nil, err return nil, err

View 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!")
}

Binary file not shown.