diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml
index e378376..6515d25 100644
--- a/.github/workflows/docs.yml
+++ b/.github/workflows/docs.yml
@@ -2,13 +2,14 @@ name: Generate docs
on:
push:
- branches: [master]
+ branches:
+ - master
jobs:
gen:
runs-on: ubuntu-latest
steps:
- - uses: actions/checkout@v2
+ - uses: actions/checkout@v3
- uses: actions/setup-go@v2
- name: Run docgen
run: go run cmd/docgen/docgen.go
diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml
index 9f9163d..4d9afba 100644
--- a/.github/workflows/release.yml
+++ b/.github/workflows/release.yml
@@ -33,6 +33,7 @@ jobs:
- uses: actions/checkout@v3
with:
submodules: true
+ fetch-depth: 0
- name: Download Task
run: 'sh -c "$(curl --location https://taskfile.dev/install.sh)" -- -d'
- uses: wangyoucao577/go-release-action@v1.25
diff --git a/.github/workflows/website.yml b/.github/workflows/website.yml
new file mode 100644
index 0000000..547673b
--- /dev/null
+++ b/.github/workflows/website.yml
@@ -0,0 +1,31 @@
+name: Build website
+
+on:
+ push:
+ branches:
+ - master
+ - docs-refactor
+
+jobs:
+ deploy:
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/checkout@v3
+ with:
+ submodules: true
+ fetch-depth: 0
+
+ - name: Setup Hugo
+ uses: peaceiris/actions-hugo@v2
+ with:
+ hugo-version: 'latest'
+ extended: true
+
+ - name: Build
+ run: 'cd website && hugo --minify'
+
+ - name: Deploy
+ uses: peaceiris/actions-gh-pages@v3
+ with:
+ github_token: ${{ secrets.GITHUB_TOKEN }}
+ publish_dir: ./website/public
diff --git a/.gitignore b/.gitignore
index 338ef97..b2be7c4 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,6 +1,8 @@
*.exe
hilbish
+!docs/api/hilbish
docgen
+!cmd/docgen
.vim
petals/
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 1c621d1..e856546 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,9 +1,16 @@
# 🎀 Changelog
## Unreleased
-**NOTE:** Hilbish now uses [Task] insead of Make for builds.
-Windows support is also now at a lower tier; The only thing guaranteed is
-Hilbish *compiling* on Windows.
+**NOTES FOR USERS/PACKAGERS UPDATING:**
+- Hilbish now uses [Task] insead of Make for builds.
+- The doc format has been changed from plain text to markdown.
+**YOU MUST reinstall Hilbish to remove the duplicate, old docs.**
+- Hilbish will by default install to **`/usr/local`** instead of just `/usr/`
+when building via Task. This is mainly to avoid conflict of distro packages
+and local installs, and is the correct place when building from git either way.
+To keep Hilbish in `/usr`, you must have `PREFIX="/usr/"` when running `task build` or `task install`
+- Windows is no longer supported. It will build and run, but **will** have problems.
+If you want to help fix the situation, start a discussion or open an issue and contribute.
[Task]: https://taskfile.dev/#/
@@ -103,6 +110,7 @@ of a dot. (ie. `job.stop()` -> `job:stop()`)
- All `fs` module functions which take paths now implicitly expand ~ to home.
- **Breaking Change:** `hilbish.greeting` has been moved to an opt (`hilbish.opts.greeting`) and is
always printed by default. To disable it, set the opt to false.
+- **Breaking Change:** `command.no-perm` hook has been replaced with `command.not-executable`
- History is now fetched from Lua, which means users can override `hilbish.history`
methods to make it act how they want.
- `guide` has been removed. See the [website](https://rosettea.github.io/Hilbish/)
@@ -161,6 +169,8 @@ will result in the files being completed.
- Cut off item names in grid menu if its longer than cell width
- Fix completion search menu disappearing
- Completion paths having duplicated characters if it's escaped
+- Get custom completion command properly to call from Lua
+- Put proper command on the line when using up and down arrow keys to go through command history
## [2.0.0-rc1] - 2022-09-14
This is a pre-release version of Hilbish for testing. To see the changelog,
diff --git a/README.md b/README.md
index 5ca8232..b4f85f7 100644
--- a/README.md
+++ b/README.md
@@ -69,7 +69,7 @@ If you're new to nix you should probably read up on how to do that [here](https:
## Manual Build
### Prerequisites
- [Go 1.17+](https://go.dev)
-- [Task](https://taskfile.dev/#/)
+- [Task](https://taskfile.dev/installation/) (**Go on the hyperlink here to see Task's install method for your OS.**)
### Build
First, clone Hilbish. The recursive is required, as some Lua libraries
diff --git a/Taskfile.yaml b/Taskfile.yaml
index 0170885..6bf17e0 100644
--- a/Taskfile.yaml
+++ b/Taskfile.yaml
@@ -3,12 +3,12 @@
version: '3'
vars:
- PREFIX: '{{default "/usr" .PREFIX}}'
+ PREFIX: '{{default "/usr/local" .PREFIX}}'
bindir__: '{{.PREFIX}}/bin'
BINDIR: '{{default .bindir__ .BINDIR}}'
libdir__: '{{.PREFIX}}/share/hilbish'
LIBDIR: '{{default .libdir__ .LIBDIR}}'
- goflags__: '-ldflags "-s -w"'
+ goflags__: '-ldflags "-s -w -X main.dataDir={{.LIBDIR}}"'
GOFLAGS: '{{default .goflags__ .GOFLAGS}}'
tasks:
@@ -16,7 +16,7 @@ tasks:
cmds:
- CGO_ENABLED=0 go build {{.GOFLAGS}}
vars:
- GOFLAGS: '-ldflags "-s -w -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:
cmds:
diff --git a/aliases.go b/aliases.go
index 3007cc3..741a6a3 100644
--- a/aliases.go
+++ b/aliases.go
@@ -9,40 +9,40 @@ import (
rt "github.com/arnodel/golua/runtime"
)
-var aliases *aliasHandler
+var aliases *aliasModule
-type aliasHandler struct {
+type aliasModule struct {
aliases map[string]string
mu *sync.RWMutex
}
// initialize aliases map
-func newAliases() *aliasHandler {
- return &aliasHandler{
+func newAliases() *aliasModule {
+ return &aliasModule{
aliases: make(map[string]string),
mu: &sync.RWMutex{},
}
}
-func (a *aliasHandler) Add(alias, cmd string) {
+func (a *aliasModule) Add(alias, cmd string) {
a.mu.Lock()
defer a.mu.Unlock()
a.aliases[alias] = cmd
}
-func (a *aliasHandler) All() map[string]string {
+func (a *aliasModule) All() map[string]string {
return a.aliases
}
-func (a *aliasHandler) Delete(alias string) {
+func (a *aliasModule) Delete(alias string) {
a.mu.Lock()
defer a.mu.Unlock()
delete(a.aliases, alias)
}
-func (a *aliasHandler) Resolve(cmdstr string) string {
+func (a *aliasModule) Resolve(cmdstr string) string {
a.mu.RLock()
defer a.mu.RUnlock()
@@ -66,7 +66,10 @@ func (a *aliasHandler) Resolve(cmdstr string) string {
// lua section
-func (a *aliasHandler) Loader(rtm *rt.Runtime) *rt.Table {
+// #interface aliases
+// command aliasing
+// The alias interface deals with all command aliases in Hilbish.
+func (a *aliasModule) Loader(rtm *rt.Runtime) *rt.Table {
// create a lua module with our functions
hshaliasesLua := map[string]util.LuaExport{
"add": util.LuaExport{hlalias, 2, false},
@@ -81,7 +84,17 @@ func (a *aliasHandler) Loader(rtm *rt.Runtime) *rt.Table {
return mod
}
-func (a *aliasHandler) luaList(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
+// #interface aliases
+// add(alias, cmd)
+// This is an alias (ha) for the `hilbish.alias` function.
+// --- @param alias string
+// --- @param cmd string
+func _hlalias() {}
+
+// #interface aliases
+// list()
+// Get a table of all aliases.
+func (a *aliasModule) luaList(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
aliasesList := rt.NewTable()
for k, v := range a.All() {
aliasesList.Set(rt.StringValue(k), rt.StringValue(v))
@@ -90,7 +103,11 @@ func (a *aliasHandler) luaList(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
return c.PushingNext1(t.Runtime, rt.TableValue(aliasesList)), nil
}
-func (a *aliasHandler) luaDelete(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
+// #interface aliases
+// delete(name)
+// Removes an alias.
+// --- @param name string
+func (a *aliasModule) luaDelete(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
if err := c.Check1Arg(); err != nil {
return nil, err
}
@@ -103,7 +120,11 @@ func (a *aliasHandler) luaDelete(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
return c.Next(), nil
}
-func (a *aliasHandler) luaResolve(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
+// #interface aliases
+// resolve(alias)
+// Tries to resolve an alias to its command.
+// --- @param alias string
+func (a *aliasModule) luaResolve(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
if err := c.Check1Arg(); err != nil {
return nil, err
}
diff --git a/api.go b/api.go
index 3e5f892..09df7c0 100644
--- a/api.go
+++ b/api.go
@@ -1,6 +1,14 @@
-// Here is the core api for the hilbi shell itself
-// Basically, stuff about the shell itself and other functions
-// go here.
+// the core Hilbish API
+// The Hilbish module includes the core API, containing
+// interfaces and functions which directly relate to shell functionality.
+// #field ver The version of Hilbish
+// #field user Username of the user
+// #field host Hostname of the machine
+// #field dataDir Directory for Hilbish data files, including the docs and default modules
+// #field interactive Is Hilbish in an interactive shell?
+// #field login Is Hilbish the login shell?
+// #field vimMode Current Vim input mode of Hilbish (will be nil if not in Vim input mode)
+// #field exitCode xit code of the last executed command
package main
import (
@@ -19,7 +27,6 @@ import (
rt "github.com/arnodel/golua/runtime"
"github.com/arnodel/golua/lib/packagelib"
"github.com/maxlandon/readline"
- "github.com/blackfireio/osinfo"
"mvdan.cc/sh/v3/interp"
)
@@ -114,20 +121,12 @@ func hilbishLoad(rtm *rt.Runtime) (rt.Value, func()) {
util.Document(fakeMod, "Hilbish's core API, containing submodules and functions which relate to the shell itself.")
// hilbish.userDir table
- hshuser := rt.NewTable()
-
- util.SetField(rtm, hshuser, "config", rt.StringValue(confDir), "User's config directory")
- util.SetField(rtm, hshuser, "data", rt.StringValue(userDataDir), "XDG data directory")
+ hshuser := userDirLoader(rtm)
util.Document(hshuser, "User directories to store configs and/or modules.")
mod.Set(rt.StringValue("userDir"), rt.TableValue(hshuser))
// hilbish.os table
- hshos := rt.NewTable()
- info, _ := osinfo.GetOSInfo()
-
- util.SetField(rtm, hshos, "family", rt.StringValue(info.Family), "Family name of the current OS")
- util.SetField(rtm, hshos, "name", rt.StringValue(info.Name), "Pretty name of the current OS")
- util.SetField(rtm, hshos, "version", rt.StringValue(info.Version), "Version of the current OS")
+ hshos := hshosLoader(rtm)
util.Document(hshos, "OS info interface")
mod.Set(rt.StringValue("os"), rt.TableValue(hshos))
@@ -159,10 +158,10 @@ func hilbishLoad(rtm *rt.Runtime) (rt.Value, func()) {
mod.Set(rt.StringValue("jobs"), rt.TableValue(jobModule))
// hilbish.timers table
- timers = newTimerHandler()
- timerModule := timers.loader(rtm)
- util.Document(timerModule, "Timer interface, for control of all intervals and timeouts.")
- mod.Set(rt.StringValue("timers"), rt.TableValue(timerModule))
+ timers = newTimersModule()
+ timersModule := timers.loader(rtm)
+ util.Document(timersModule, "Timer interface, for control of all intervals and timeouts.")
+ mod.Set(rt.StringValue("timers"), rt.TableValue(timersModule))
editorModule := editorLoader(rtm)
util.Document(editorModule, "")
@@ -250,11 +249,12 @@ func hlcwd(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
}
-// read(prompt?) -> input?
+// read(prompt) -> input
// Read input from the user, using Hilbish's line editor/input reader.
// This is a separate instance from the one Hilbish actually uses.
// Returns `input`, will be nil if ctrl + d is pressed, or an error occurs (which shouldn't happen)
-// --- @param prompt string
+// --- @param prompt string|nil
+// --- @returns string|nil
func hlread(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
luaprompt := c.Arg(0)
if typ := luaprompt.Type(); typ != rt.StringType && typ != rt.NilType {
@@ -281,7 +281,7 @@ func hlread(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
}
/*
-prompt(str, typ?)
+prompt(str, typ)
Changes the shell prompt to `str`
There are a few verbs that can be used in the prompt text.
These will be formatted and replaced with the appropriate values.
@@ -289,7 +289,7 @@ These will be formatted and replaced with the appropriate values.
`%u` - Name of current user
`%h` - Hostname of device
--- @param str string
---- @param typ string Type of prompt, being left or right. Left by default.
+--- @param typ string|nil Type of prompt, being left or right. Left by default.
*/
func hlprompt(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
err := c.Check1Arg()
diff --git a/cmd/docgen/docgen.go b/cmd/docgen/docgen.go
index 39a2a76..cf70840 100644
--- a/cmd/docgen/docgen.go
+++ b/cmd/docgen/docgen.go
@@ -9,26 +9,191 @@ import (
"go/token"
"strings"
"os"
+ "sync"
)
-type EmmyPiece struct {
- FuncName string
- Docs []string
+var header = `---
+title: %s %s
+description: %s
+layout: doc
+menu:
+ docs:
+ parent: "API"
+---
+
+`
+
+type emmyPiece struct {
+ DocPiece *docPiece
+ Annotations []string
Params []string // we only need to know param name to put in function
+ FuncName string
}
-type DocPiece struct {
+
+type module struct {
+ Docs []docPiece
+ Fields []docPiece
+ Properties []docPiece
+ ShortDescription string
+ Description string
+ ParentModule string
+ HasInterfaces bool
+}
+
+type docPiece struct {
Doc []string
FuncSig string
FuncName string
+ Interfacing string
+ ParentModule string
+ GoFuncName string
+ IsInterface bool
+ IsMember bool
+ Fields []docPiece
+ Properties []docPiece
+}
+
+type tag struct {
+ id string
+ fields []string
+}
+
+var docs = make(map[string]module)
+var interfaceDocs = make(map[string]module)
+var emmyDocs = make(map[string][]emmyPiece)
+var prefix = map[string]string{
+ "main": "hl",
+ "hilbish": "hl",
+ "fs": "f",
+ "commander": "c",
+ "bait": "b",
+ "terminal": "term",
+}
+
+func getTagsAndDocs(docs string) (map[string][]tag, []string) {
+ pts := strings.Split(docs, "\n")
+ parts := []string{}
+ tags := make(map[string][]tag)
+
+ for _, part := range pts {
+ if strings.HasPrefix(part, "#") {
+ tagParts := strings.Split(strings.TrimPrefix(part, "#"), " ")
+ if tags[tagParts[0]] == nil {
+ var id string
+ if len(tagParts) > 1 {
+ id = tagParts[1]
+ }
+ tags[tagParts[0]] = []tag{
+ {id: id},
+ }
+ if len(tagParts) >= 2 {
+ tags[tagParts[0]][0].fields = tagParts[2:]
+ }
+ } else {
+ fleds := []string{}
+ if len(tagParts) >= 2 {
+ fleds = tagParts[2:]
+ }
+ tags[tagParts[0]] = append(tags[tagParts[0]], tag{
+ id: tagParts[1],
+ fields: fleds,
+ })
+ }
+ } else {
+ parts = append(parts, part)
+ }
+ }
+
+ return tags, parts
+}
+
+func docPieceTag(tagName string, tags map[string][]tag) []docPiece {
+ dps := []docPiece{}
+ for _, tag := range tags[tagName] {
+ dps = append(dps, docPiece{
+ FuncName: tag.id,
+ Doc: tag.fields,
+ })
+ }
+
+ return dps
+}
+
+func setupDoc(mod string, fun *doc.Func) *docPiece {
+ docs := strings.TrimSpace(fun.Doc)
+ inInterface := strings.HasPrefix(docs, "#interface")
+ if (!strings.HasPrefix(fun.Name, prefix[mod]) && !inInterface) || (strings.ToLower(fun.Name) == "loader" && !inInterface) {
+ return nil
+ }
+
+ tags, parts := getTagsAndDocs(docs)
+
+ var interfaces string
+ funcsig := parts[0]
+ doc := parts[1:]
+ funcName := strings.TrimPrefix(fun.Name, prefix[mod])
+ funcdoc := []string{}
+
+ if inInterface {
+ interfaces = tags["interface"][0].id
+ funcName = interfaces + "." + strings.Split(funcsig, "(")[0]
+ }
+ em := emmyPiece{FuncName: funcName}
+
+ fields := docPieceTag("field", tags)
+ properties := docPieceTag("property", tags)
+
+ for _, d := range doc {
+ if strings.HasPrefix(d, "---") {
+ emmyLine := strings.TrimSpace(strings.TrimPrefix(d, "---"))
+ emmyLinePieces := strings.Split(emmyLine, " ")
+ emmyType := emmyLinePieces[0]
+ if emmyType == "@param" {
+ em.Params = append(em.Params, emmyLinePieces[1])
+ }
+ if emmyType == "@vararg" {
+ em.Params = append(em.Params, "...") // add vararg
+ }
+ em.Annotations = append(em.Annotations, d)
+ } else {
+ funcdoc = append(funcdoc, d)
+ }
+ }
+
+ var isMember bool
+ if tags["member"] != nil {
+ isMember = true
+ }
+ var parentMod string
+ if inInterface {
+ parentMod = mod
+ }
+ dps := &docPiece{
+ Doc: funcdoc,
+ FuncSig: funcsig,
+ FuncName: funcName,
+ Interfacing: interfaces,
+ GoFuncName: strings.ToLower(fun.Name),
+ IsInterface: inInterface,
+ IsMember: isMember,
+ ParentModule: parentMod,
+ Fields: fields,
+ Properties: properties,
+ }
+ if strings.HasSuffix(dps.GoFuncName, strings.ToLower("loader")) {
+ dps.Doc = parts
+ }
+ em.DocPiece = dps
+
+ emmyDocs[mod] = append(emmyDocs[mod], em)
+ return dps
}
-// feel free to clean this up
-// it works, dont really care about the code
func main() {
fset := token.NewFileSet()
os.Mkdir("docs", 0777)
+ os.Mkdir("docs/api", 0777)
os.Mkdir("emmyLuaDocs", 0777)
-
dirs := []string{"./"}
filepath.Walk("golibs/", func (path string, info os.FileInfo, err error) error {
@@ -51,120 +216,172 @@ func main() {
}
}
- prefix := map[string]string{
- "hilbish": "hl",
- "fs": "f",
- "commander": "c",
- "bait": "b",
- "terminal": "term",
- }
- docs := make(map[string][]DocPiece)
- emmyDocs := make(map[string][]EmmyPiece)
-
+ interfaceModules := make(map[string]*module)
for l, f := range pkgs {
p := doc.New(f, "./", doc.AllDecls)
+ pieces := []docPiece{}
+ mod := l
+ if mod == "main" {
+ mod = "hilbish"
+ }
+ var hasInterfaces bool
for _, t := range p.Funcs {
- mod := l
- if strings.HasPrefix(t.Name, "hl") { mod = "hilbish" }
- if !strings.HasPrefix(t.Name, prefix[mod]) || t.Name == "Loader" { continue }
- parts := strings.Split(strings.TrimSpace(t.Doc), "\n")
- funcsig := parts[0]
- doc := parts[1:]
- funcdoc := []string{}
- em := EmmyPiece{FuncName: strings.TrimPrefix(t.Name, prefix[mod])}
- for _, d := range doc {
- if strings.HasPrefix(d, "---") {
- emmyLine := strings.TrimSpace(strings.TrimPrefix(d, "---"))
- emmyLinePieces := strings.Split(emmyLine, " ")
- emmyType := emmyLinePieces[0]
- if emmyType == "@param" {
- em.Params = append(em.Params, emmyLinePieces[1])
- }
- if emmyType == "@vararg" {
- em.Params = append(em.Params, "...") // add vararg
- }
- em.Docs = append(em.Docs, d)
- } else {
- funcdoc = append(funcdoc, d)
- }
+ piece := setupDoc(mod, t)
+ if piece == nil {
+ continue
}
-
- dps := DocPiece{
- Doc: funcdoc,
- FuncSig: funcsig,
- FuncName: strings.TrimPrefix(t.Name, prefix[mod]),
+
+ pieces = append(pieces, *piece)
+ if piece.IsInterface {
+ hasInterfaces = true
}
-
- docs[mod] = append(docs[mod], dps)
- emmyDocs[mod] = append(emmyDocs[mod], em)
}
for _, t := range p.Types {
for _, m := range t.Methods {
- if !strings.HasPrefix(m.Name, prefix[l]) || m.Name == "Loader" { continue }
- parts := strings.Split(strings.TrimSpace(m.Doc), "\n")
- funcsig := parts[0]
- doc := parts[1:]
- funcdoc := []string{}
- em := EmmyPiece{FuncName: strings.TrimPrefix(m.Name, prefix[l])}
- for _, d := range doc {
- if strings.HasPrefix(d, "---") {
- emmyLine := strings.TrimSpace(strings.TrimPrefix(d, "---"))
- emmyLinePieces := strings.Split(emmyLine, " ")
- emmyType := emmyLinePieces[0]
- if emmyType == "@param" {
- em.Params = append(em.Params, emmyLinePieces[1])
- }
- if emmyType == "@vararg" {
- em.Params = append(em.Params, "...") // add vararg
- }
- em.Docs = append(em.Docs, d)
- } else {
- funcdoc = append(funcdoc, d)
- }
- }
- dps := DocPiece{
- Doc: funcdoc,
- FuncSig: funcsig,
- FuncName: strings.TrimPrefix(m.Name, prefix[l]),
+ piece := setupDoc(mod, m)
+ if piece == nil {
+ continue
}
- docs[l] = append(docs[l], dps)
- emmyDocs[l] = append(emmyDocs[l], em)
+ pieces = append(pieces, *piece)
+ if piece.IsInterface {
+ hasInterfaces = true
+ }
}
}
+
+ tags, descParts := getTagsAndDocs(strings.TrimSpace(p.Doc))
+ shortDesc := descParts[0]
+ desc := descParts[1:]
+ filteredPieces := []docPiece{}
+ for _, piece := range pieces {
+ if !piece.IsInterface {
+ filteredPieces = append(filteredPieces, piece)
+ continue
+ }
+
+ modname := piece.ParentModule + "." + piece.Interfacing
+ if interfaceModules[modname] == nil {
+ interfaceModules[modname] = &module{
+ ParentModule: piece.ParentModule,
+ }
+ }
+
+ if strings.HasSuffix(piece.GoFuncName, strings.ToLower("loader")) {
+ shortDesc := piece.Doc[0]
+ desc := piece.Doc[1:]
+ interfaceModules[modname].ShortDescription = shortDesc
+ interfaceModules[modname].Description = strings.Join(desc, "\n")
+ interfaceModules[modname].Fields = piece.Fields
+ interfaceModules[modname].Properties = piece.Properties
+ continue
+ }
+ interfaceModules[modname].Docs = append(interfaceModules[modname].Docs, piece)
+ }
+
+ docs[mod] = module{
+ Docs: filteredPieces,
+ ShortDescription: shortDesc,
+ Description: strings.Join(desc, "\n"),
+ HasInterfaces: hasInterfaces,
+ Properties: docPieceTag("property", tags),
+ Fields: docPieceTag("field", tags),
+ }
}
+ for key, mod := range interfaceModules {
+ docs[key] = *mod
+ }
+
+ var wg sync.WaitGroup
+ wg.Add(len(docs) * 2)
+
for mod, v := range docs {
- if mod == "main" { continue }
- f, _ := os.Create("docs/" + mod + ".txt")
- for _, dps := range v {
- f.WriteString(dps.FuncSig + " > ")
- for _, doc := range dps.Doc {
- if !strings.HasPrefix(doc, "---") {
- f.WriteString(doc + "\n")
- }
- }
- f.WriteString("\n")
+ docPath := "docs/api/" + mod + ".md"
+ if v.HasInterfaces {
+ os.Mkdir("docs/api/" + mod, 0777)
+ os.Remove(docPath) // remove old doc path if it exists
+ docPath = "docs/api/" + mod + "/_index.md"
}
- }
-
- for mod, v := range emmyDocs {
- if mod == "main" { continue }
- f, _ := os.Create("emmyLuaDocs/" + mod + ".lua")
- f.WriteString("--- @meta\n\nlocal " + mod + " = {}\n\n")
- for _, em := range v {
- var funcdocs []string
- for _, dps := range docs[mod] {
- if dps.FuncName == em.FuncName {
- funcdocs = dps.Doc
- }
- }
- f.WriteString("--- " + strings.Join(funcdocs, "\n--- ") + "\n")
- if len(em.Docs) != 0 {
- f.WriteString(strings.Join(em.Docs, "\n") + "\n")
- }
- f.WriteString("function " + mod + "." + em.FuncName + "(" + strings.Join(em.Params, ", ") + ") end\n\n")
+ if v.ParentModule != "" {
+ docPath = "docs/api/" + v.ParentModule + "/" + mod + ".md"
}
- f.WriteString("return " + mod + "\n")
+
+ go func(modname, docPath string, modu module) {
+ defer wg.Done()
+ modOrIface := "Module"
+ if modu.ParentModule != "" {
+ modOrIface = "Interface"
+ }
+
+ f, _ := os.Create(docPath)
+ f.WriteString(fmt.Sprintf(header, modOrIface, modname, modu.ShortDescription))
+ f.WriteString(fmt.Sprintf("## Introduction\n%s\n\n", modu.Description))
+ if len(modu.Fields) != 0 {
+ f.WriteString("## Interface fields\n")
+ for _, dps := range modu.Fields {
+ f.WriteString(fmt.Sprintf("- `%s`: ", dps.FuncName))
+ f.WriteString(strings.Join(dps.Doc, " "))
+ f.WriteString("\n")
+ }
+ f.WriteString("\n")
+ }
+ if len(modu.Properties) != 0 {
+ f.WriteString("## Object properties\n")
+ for _, dps := range modu.Properties {
+ f.WriteString(fmt.Sprintf("- `%s`: ", dps.FuncName))
+ f.WriteString(strings.Join(dps.Doc, " "))
+ f.WriteString("\n")
+ }
+ f.WriteString("\n")
+ }
+ if len(modu.Docs) != 0 {
+ f.WriteString("## Functions\n")
+ }
+ for _, dps := range modu.Docs {
+ f.WriteString(fmt.Sprintf("### %s\n", dps.FuncSig))
+ for _, doc := range dps.Doc {
+ if !strings.HasPrefix(doc, "---") {
+ f.WriteString(doc + "\n")
+ }
+ }
+ f.WriteString("\n")
+ }
+ }(mod, docPath, v)
+
+ go func(md, modname string, modu module) {
+ defer wg.Done()
+
+ if modu.ParentModule != "" {
+ return
+ }
+
+ ff, _ := os.Create("emmyLuaDocs/" + modname + ".lua")
+ ff.WriteString("--- @meta\n\nlocal " + modname + " = {}\n\n")
+ for _, em := range emmyDocs[modname] {
+ if strings.HasSuffix(em.DocPiece.GoFuncName, strings.ToLower("loader")) {
+ continue
+ }
+
+ dps := em.DocPiece
+ funcdocs := dps.Doc
+ ff.WriteString("--- " + strings.Join(funcdocs, "\n--- ") + "\n")
+ if len(em.Annotations) != 0 {
+ ff.WriteString(strings.Join(em.Annotations, "\n") + "\n")
+ }
+ accessor := "."
+ if dps.IsMember {
+ accessor = ":"
+ }
+ signature := strings.Split(dps.FuncSig, " ->")[0]
+ var intrface string
+ if dps.IsInterface {
+ intrface = "." + dps.Interfacing
+ }
+ ff.WriteString("function " + modname + intrface + accessor + signature + " end\n\n")
+ }
+ ff.WriteString("return " + modname + "\n")
+ }(mod, mod, v)
}
+ wg.Wait()
}
diff --git a/complete.go b/complete.go
index c2a107c..7c3f563 100644
--- a/complete.go
+++ b/complete.go
@@ -172,6 +172,9 @@ func escapeFilename(fname string) string {
return escapeReplaer.Replace(fname)
}
+// #interface completions
+// tab completions
+// The completions interface deals with tab completions.
func completionLoader(rtm *rt.Runtime) *rt.Table {
exports := map[string]util.LuaExport{
"files": {luaFileComplete, 3, false},
@@ -186,11 +189,19 @@ func completionLoader(rtm *rt.Runtime) *rt.Table {
return mod
}
-// left as a shim, might doc in the same way as hilbish functions
+// #interface completions
+// handler(line, pos)
+// The handler function is the callback for tab completion in Hilbish.
+// You can check the completions doc for more info.
func completionHandler(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
return c.Next(), nil
}
+// #interface completions
+// call(name, query, ctx, fields)
+// Calls a completer function. This is mainly used to call
+// a command completer, which will have a `name` in the form
+// of `command.name`, example: `command.git`
func callLuaCompleter(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
if err := c.CheckNArgs(4); err != nil {
return nil, err
@@ -230,6 +241,9 @@ func callLuaCompleter(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
return c.PushingNext1(t.Runtime, completerReturn), nil
}
+// #interface completions
+// files(query, ctx, fields)
+// Returns file completion candidates based on the provided query.
func luaFileComplete(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
query, ctx, fds, err := getCompleteParams(t, c)
if err != nil {
@@ -246,6 +260,9 @@ func luaFileComplete(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
return c.PushingNext(t.Runtime, rt.TableValue(luaComps), rt.StringValue(pfx)), nil
}
+// #interface completions
+// bins(query, ctx, fields)
+// Returns binary/executale completion candidates based on the provided query.
func luaBinaryComplete(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
query, ctx, fds, err := getCompleteParams(t, c)
if err != nil {
diff --git a/docs/api/_index.md b/docs/api/_index.md
new file mode 100644
index 0000000..5c8b722
--- /dev/null
+++ b/docs/api/_index.md
@@ -0,0 +1,7 @@
+---
+title: API
+layout: doc
+weight: -50
+menu: docs
+---
+
diff --git a/docs/api/bait.md b/docs/api/bait.md
new file mode 100644
index 0000000..fdf22b0
--- /dev/null
+++ b/docs/api/bait.md
@@ -0,0 +1,34 @@
+---
+title: Module bait
+description: the event emitter
+layout: doc
+menu:
+ docs:
+ parent: "API"
+---
+
+## Introduction
+Bait is the event emitter for Hilbish. Why name it bait? Why not.
+It throws hooks that you can catch. This is what you will use if
+you want to listen in on hooks to know when certain things have
+happened, like when you've changed directory, a command has failed,
+etc. To find all available hooks thrown by Hilbish, see doc hooks.
+
+## Functions
+### catch(name, cb)
+Catches a hook with `name`. Runs the `cb` when it is thrown
+
+### catchOnce(name, cb)
+Same as catch, but only runs the `cb` once and then removes the hook
+
+### hooks(name) -> {cb, cb...}
+Returns a table with hooks on the event with `name`.
+
+### release(name, catcher)
+Removes the `catcher` for the event with `name`
+For this to work, `catcher` has to be the same function used to catch
+an event, like one saved to a variable.
+
+### throw(name, ...args)
+Throws a hook with `name` with the provided `args`
+
diff --git a/docs/api/commander.md b/docs/api/commander.md
new file mode 100644
index 0000000..e3e5320
--- /dev/null
+++ b/docs/api/commander.md
@@ -0,0 +1,19 @@
+---
+title: Module commander
+description: library for custom commands
+layout: doc
+menu:
+ docs:
+ parent: "API"
+---
+
+## Introduction
+Commander is a library for writing custom commands in Lua.
+
+## Functions
+### deregister(name)
+Deregisters any command registered with `name`
+
+### register(name, cb)
+Register a command with `name` that runs `cb` when ran
+
diff --git a/docs/api/fs.md b/docs/api/fs.md
new file mode 100644
index 0000000..6ad11de
--- /dev/null
+++ b/docs/api/fs.md
@@ -0,0 +1,46 @@
+---
+title: Module fs
+description: filesystem interaction and functionality library
+layout: doc
+menu:
+ docs:
+ parent: "API"
+---
+
+## Introduction
+The fs module provides easy and simple access to filesystem functions
+and other things, and acts an addition to the Lua standard library's
+I/O and filesystem functions.
+
+## Functions
+### abs(path)
+Gives an absolute version of `path`.
+
+### basename(path)
+Gives the basename of `path`. For the rules,
+see Go's filepath.Base
+
+### cd(dir)
+Changes directory to `dir`
+
+### dir(path)
+Returns the directory part of `path`. For the rules, see Go's
+filepath.Dir
+
+### glob(pattern)
+Glob all files and directories that match the pattern.
+For the rules, see Go's filepath.Glob
+
+### join(paths...)
+Takes paths and joins them together with the OS's
+directory separator (forward or backward slash).
+
+### mkdir(name, recursive)
+Makes a directory called `name`. If `recursive` is true, it will create its parent directories.
+
+### readdir(dir)
+Returns a table of files in `dir`
+
+### stat(path)
+Returns info about `path`
+
diff --git a/docs/api/hilbish/_index.md b/docs/api/hilbish/_index.md
new file mode 100644
index 0000000..5cdcb4d
--- /dev/null
+++ b/docs/api/hilbish/_index.md
@@ -0,0 +1,104 @@
+---
+title: Module hilbish
+description: the core Hilbish API
+layout: doc
+menu:
+ docs:
+ parent: "API"
+---
+
+## Introduction
+The Hilbish module includes the core API, containing
+interfaces and functions which directly relate to shell functionality.
+
+## Interface fields
+- `ver`: The version of Hilbish
+- `user`: Username of the user
+- `host`: Hostname of the machine
+- `dataDir`: Directory for Hilbish data files, including the docs and default modules
+- `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
+
+## Functions
+### alias(cmd, orig)
+Sets an alias of `cmd` to `orig`
+
+### appendPath(dir)
+Appends `dir` to $PATH
+
+### complete(scope, cb)
+Registers a completion handler for `scope`.
+A `scope` is currently only expected to be `command.`,
+replacing with the name of the command (for example `command.git`).
+`cb` must be a function that returns a table of "completion groups."
+Check `doc completions` for more information.
+
+### cwd()
+Returns the current directory of the shell
+
+### exec(cmd)
+Replaces running hilbish with `cmd`
+
+### goro(fn)
+Puts `fn` in a goroutine
+
+### highlighter(line)
+Line highlighter handler. This is mainly for syntax highlighting, but in
+reality could set the input of the prompt to *display* anything. The
+callback is passed the current line and is expected to return a line that
+will be used as the input display.
+
+### hinter(line, pos)
+The command line hint handler. It gets called on every key insert to
+determine what text to use as an inline hint. It is passed the current
+line and cursor position. It is expected to return a string which is used
+as the text for the hint. This is by default a shim. To set hints,
+override this function with your custom handler.
+
+### inputMode(mode)
+Sets the input mode for Hilbish's line reader. Accepts either emacs or vim
+
+### interval(cb, time)
+Runs the `cb` function every `time` milliseconds.
+Returns a `timer` object (see `doc timers`).
+
+### multiprompt(str)
+Changes the continued line prompt to `str`
+
+### prependPath(dir)
+Prepends `dir` to $PATH
+
+### prompt(str, typ)
+Changes the shell prompt to `str`
+There are a few verbs that can be used in the prompt text.
+These will be formatted and replaced with the appropriate values.
+`%d` - Current working directory
+`%u` - Name of current user
+`%h` - Hostname of device
+
+### read(prompt) -> input
+Read input from the user, using Hilbish's line editor/input reader.
+This is a separate instance from the one Hilbish actually uses.
+Returns `input`, will be nil if ctrl + d is pressed, or an error occurs (which shouldn't happen)
+
+### run(cmd, returnOut) -> exitCode, stdout, stderr
+Runs `cmd` in Hilbish's sh interpreter.
+If returnOut is true, the outputs of `cmd` will be returned as the 2nd and
+3rd values instead of being outputted to the terminal.
+
+### runnerMode(mode)
+Sets the execution/runner mode for interactive Hilbish. This determines whether
+Hilbish wll try to run input as Lua and/or sh or only do one of either.
+Accepted values for mode are hybrid (the default), hybridRev (sh first then Lua),
+sh, and lua. It also accepts a function, to which if it is passed one
+will call it to execute user input instead.
+
+### timeout(cb, time)
+Runs the `cb` function after `time` in milliseconds
+Returns a `timer` object (see `doc timers`).
+
+### which(name)
+Checks if `name` is a valid command
+
diff --git a/docs/api/hilbish/hilbish.aliases.md b/docs/api/hilbish/hilbish.aliases.md
new file mode 100644
index 0000000..1ff766c
--- /dev/null
+++ b/docs/api/hilbish/hilbish.aliases.md
@@ -0,0 +1,25 @@
+---
+title: Interface hilbish.aliases
+description: command aliasing
+layout: doc
+menu:
+ docs:
+ parent: "API"
+---
+
+## Introduction
+The alias interface deals with all command aliases in Hilbish.
+
+## Functions
+### add(alias, cmd)
+This is an alias (ha) for the `hilbish.alias` function.
+
+### delete(name)
+Removes an alias.
+
+### list()
+Get a table of all aliases.
+
+### resolve(alias)
+Tries to resolve an alias to its command.
+
diff --git a/docs/api/hilbish/hilbish.completions.md b/docs/api/hilbish/hilbish.completions.md
new file mode 100644
index 0000000..bcfd2f9
--- /dev/null
+++ b/docs/api/hilbish/hilbish.completions.md
@@ -0,0 +1,28 @@
+---
+title: Interface hilbish.completions
+description: tab completions
+layout: doc
+menu:
+ docs:
+ parent: "API"
+---
+
+## Introduction
+The completions interface deals with tab completions.
+
+## Functions
+### call(name, query, ctx, fields)
+Calls a completer function. This is mainly used to call
+a command completer, which will have a `name` in the form
+of `command.name`, example: `command.git`
+
+### handler(line, pos)
+The handler function is the callback for tab completion in Hilbish.
+You can check the completions doc for more info.
+
+### bins(query, ctx, fields)
+Returns binary/executale completion candidates based on the provided query.
+
+### files(query, ctx, fields)
+Returns file completion candidates based on the provided query.
+
diff --git a/docs/api/hilbish/hilbish.editor.md b/docs/api/hilbish/hilbish.editor.md
new file mode 100644
index 0000000..bb0f257
--- /dev/null
+++ b/docs/api/hilbish/hilbish.editor.md
@@ -0,0 +1,26 @@
+---
+title: Interface hilbish.editor
+description: interactions for Hilbish's line reader
+layout: doc
+menu:
+ docs:
+ parent: "API"
+---
+
+## Introduction
+The hilbish.editor interface provides functions to
+directly interact with the line editor in use.
+
+## Functions
+### getLine()
+Returns the current input line.
+
+### getVimRegister(register)
+Returns the text that is at the register.
+
+### insert(text)
+Inserts text into the line.
+
+### setVimRegister(register, text)
+Sets the vim register at `register` to hold the passed text.
+
diff --git a/docs/api/hilbish/hilbish.history.md b/docs/api/hilbish/hilbish.history.md
new file mode 100644
index 0000000..f297ab2
--- /dev/null
+++ b/docs/api/hilbish/hilbish.history.md
@@ -0,0 +1,27 @@
+---
+title: Interface hilbish.history
+description: command history
+layout: doc
+menu:
+ docs:
+ parent: "API"
+---
+
+## Introduction
+The history interface deals with command history.
+This includes the ability to override functions to change the main
+method of saving history.
+
+## Functions
+### add(cmd)
+Adds a command to the history.
+
+### clear()
+Deletes all commands from the history.
+
+### get(idx)
+Retrieves a command from the history based on the `idx`.
+
+### size()
+Returns the amount of commands in the history.
+
diff --git a/docs/api/hilbish/hilbish.jobs.md b/docs/api/hilbish/hilbish.jobs.md
new file mode 100644
index 0000000..b180dd4
--- /dev/null
+++ b/docs/api/hilbish/hilbish.jobs.md
@@ -0,0 +1,54 @@
+---
+title: Interface hilbish.jobs
+description: background job management
+layout: doc
+menu:
+ docs:
+ parent: "API"
+---
+
+## Introduction
+
+Manage interactive jobs in Hilbish via Lua.
+
+Jobs are the name of background tasks/commands. A job can be started via
+interactive usage or with the functions defined below for use in external runners.
+
+## Object properties
+- `cmd`: The user entered command string for the job.
+- `running`: Whether the job is running or not.
+- `id`: The ID of the job in the job table
+- `pid`: The Process ID
+- `exitCode`: The last exit code of the job.
+- `stdout`: The standard output of the job. This just means the normal logs of the process.
+- `stderr`: The standard error stream of the process. This (usually) includes error messages of the job.
+
+## Functions
+### background()
+Puts a job in the background. This acts the same as initially running a job.
+
+### foreground()
+Puts a job in the foreground. This will cause it to run like it was
+executed normally and wait for it to complete.
+
+### start()
+Starts running the job.
+
+### stop()
+Stops the job from running.
+
+### add(cmdstr, args, execPath)
+Adds a new job to the job table. Note that this does not immediately run it.
+
+### all()
+Returns a table of all job objects.
+
+### disown(id)
+Disowns a job. This deletes it from the job table.
+
+### get(id)
+Get a job object via its ID.
+
+### last() -> Job
+Returns the last added job from the table.
+
diff --git a/docs/api/hilbish/hilbish.os.md b/docs/api/hilbish/hilbish.os.md
new file mode 100644
index 0000000..aa2198e
--- /dev/null
+++ b/docs/api/hilbish/hilbish.os.md
@@ -0,0 +1,19 @@
+---
+title: Interface hilbish.os
+description: OS Info
+layout: doc
+menu:
+ docs:
+ parent: "API"
+---
+
+## Introduction
+The `os` interface provides simple text information properties about
+the current OS on the systen. This mainly includes the name and
+version.
+
+## Interface fields
+- `family`: Family name of the current OS
+- `name`: Pretty name of the current OS
+- `version`: Version of the current OS
+
diff --git a/docs/api/hilbish/hilbish.runner.md b/docs/api/hilbish/hilbish.runner.md
new file mode 100644
index 0000000..68ffdc6
--- /dev/null
+++ b/docs/api/hilbish/hilbish.runner.md
@@ -0,0 +1,31 @@
+---
+title: Interface hilbish.runner
+description: interactive command runner customization
+layout: doc
+menu:
+ docs:
+ parent: "API"
+---
+
+## Introduction
+The runner interface contains functions that allow the user to change
+how Hilbish interprets interactive input.
+Users can add and change the default runner for interactive input to any
+language or script of their choosing. A good example is using it to
+write command in Fennel.
+
+## Functions
+### setMode(cb)
+This is the same as the `hilbish.runnerMode` function. It takes a callback,
+which will be used to execute all interactive input.
+In normal cases, neither callbacks should be overrided by the user,
+as the higher level functions listed below this will handle it.
+
+### lua(cmd)
+Evaluates `cmd` as Lua input. This is the same as using `dofile`
+or `load`, but is appropriated for the runner interface.
+
+### sh(cmd)
+Runs a command in Hilbish's shell script interpreter.
+This is the equivalent of using `source`.
+
diff --git a/docs/api/hilbish/hilbish.timers.md b/docs/api/hilbish/hilbish.timers.md
new file mode 100644
index 0000000..60bedb5
--- /dev/null
+++ b/docs/api/hilbish/hilbish.timers.md
@@ -0,0 +1,33 @@
+---
+title: Interface hilbish.timers
+description: timeout and interval API
+layout: doc
+menu:
+ docs:
+ parent: "API"
+---
+
+## Introduction
+The timers interface si one to easily set timeouts and intervals
+to run functions after a certain time or repeatedly without using
+odd tricks.
+
+## Object properties
+- `type`: What type of timer it is
+- `running`: If the timer is running
+- `duration`: The duration in milliseconds that the timer will run
+
+## Functions
+### start()
+Starts a timer.
+
+### stop()
+Stops a timer.
+
+### create(type, time, callback)
+Creates a timer that runs based on the specified `time` in milliseconds.
+The `type` can either be interval (value of 0) or timeout (value of 1).
+
+### get(id)
+Retrieves a timer via its ID.
+
diff --git a/docs/api/hilbish/hilbish.userDir.md b/docs/api/hilbish/hilbish.userDir.md
new file mode 100644
index 0000000..0b95057
--- /dev/null
+++ b/docs/api/hilbish/hilbish.userDir.md
@@ -0,0 +1,18 @@
+---
+title: Interface hilbish.userDir
+description: user-related directories
+layout: doc
+menu:
+ docs:
+ parent: "API"
+---
+
+## Introduction
+This interface just contains properties to know about certain user directories.
+It is equivalent to XDG on Linux and gets the user's preferred directories
+for configs and data.
+
+## Interface fields
+- `config`: The user's config directory
+- `data`: The user's directory for program data
+
diff --git a/docs/api/terminal.md b/docs/api/terminal.md
new file mode 100644
index 0000000..99d4b49
--- /dev/null
+++ b/docs/api/terminal.md
@@ -0,0 +1,26 @@
+---
+title: Module terminal
+description: low level terminal library
+layout: doc
+menu:
+ docs:
+ parent: "API"
+---
+
+## Introduction
+The terminal library is a simple and lower level library for certain terminal interactions.
+
+## Functions
+### restoreState()
+Restores the last saved state of the terminal
+
+### saveState()
+Saves the current state of the terminal
+
+### setRaw()
+Puts the terminal in raw mode
+
+### size()
+Gets the dimensions of the terminal. Returns a table with `width` and `height`
+Note: this is not the size in relation to the dimensions of the display
+
diff --git a/docs/bait.txt b/docs/bait.txt
deleted file mode 100644
index 2b6f7ae..0000000
--- a/docs/bait.txt
+++ /dev/null
@@ -1,12 +0,0 @@
-catch(name, cb) > Catches a hook with `name`. Runs the `cb` when it is thrown
-
-catchOnce(name, cb) > Same as catch, but only runs the `cb` once and then removes the hook
-
-hooks(name) -> {cb, cb...} > Returns a table with hooks on the event with `name`.
-
-release(name, catcher) > Removes the `catcher` for the event with `name`
-For this to work, `catcher` has to be the same function used to catch
-an event, like one saved to a variable.
-
-throw(name, ...args) > Throws a hook with `name` with the provided `args`
-
diff --git a/docs/commander.txt b/docs/commander.txt
deleted file mode 100644
index 8b4b329..0000000
--- a/docs/commander.txt
+++ /dev/null
@@ -1,4 +0,0 @@
-deregister(name) > Deregisters any command registered with `name`
-
-register(name, cb) > Register a command with `name` that runs `cb` when ran
-
diff --git a/docs/completions.txt b/docs/completions.md
similarity index 100%
rename from docs/completions.txt
rename to docs/completions.md
diff --git a/docs/fs.txt b/docs/fs.txt
deleted file mode 100644
index 8372afd..0000000
--- a/docs/fs.txt
+++ /dev/null
@@ -1,22 +0,0 @@
-abs(path) > Gives an absolute version of `path`.
-
-basename(path) > Gives the basename of `path`. For the rules,
-see Go's filepath.Base
-
-cd(dir) > Changes directory to `dir`
-
-dir(path) > Returns the directory part of `path`. For the rules, see Go's
-filepath.Dir
-
-glob(pattern) > Glob all files and directories that match the pattern.
-For the rules, see Go's filepath.Glob
-
-join(paths...) > Takes paths and joins them together with the OS's
-directory separator (forward or backward slash).
-
-mkdir(name, recursive) > Makes a directory called `name`. If `recursive` is true, it will create its parent directories.
-
-readdir(dir) > Returns a table of files in `dir`
-
-stat(path) > Returns info about `path`
-
diff --git a/docs/hilbish.txt b/docs/hilbish.txt
deleted file mode 100644
index 20a9bd7..0000000
--- a/docs/hilbish.txt
+++ /dev/null
@@ -1,62 +0,0 @@
-alias(cmd, orig) > Sets an alias of `cmd` to `orig`
-
-appendPath(dir) > Appends `dir` to $PATH
-
-complete(scope, cb) > Registers a completion handler for `scope`.
-A `scope` is currently only expected to be `command.`,
-replacing with the name of the command (for example `command.git`).
-`cb` must be a function that returns a table of "completion groups."
-Check `doc completions` for more information.
-
-cwd() > Returns the current directory of the shell
-
-exec(cmd) > Replaces running hilbish with `cmd`
-
-goro(fn) > Puts `fn` in a goroutine
-
-highlighter(line) > Line highlighter handler. This is mainly for syntax highlighting, but in
-reality could set the input of the prompt to *display* anything. The
-callback is passed the current line and is expected to return a line that
-will be used as the input display.
-
-hinter(line, pos) > The command line hint handler. It gets called on every key insert to
-determine what text to use as an inline hint. It is passed the current
-line and cursor position. It is expected to return a string which is used
-as the text for the hint. This is by default a shim. To set hints,
-override this function with your custom handler.
-
-inputMode(mode) > Sets the input mode for Hilbish's line reader. Accepts either emacs or vim
-
-interval(cb, time) > Runs the `cb` function every `time` milliseconds.
-Returns a `timer` object (see `doc timers`).
-
-multiprompt(str) > Changes the continued line prompt to `str`
-
-prependPath(dir) > Prepends `dir` to $PATH
-
-prompt(str, typ?) > Changes the shell prompt to `str`
-There are a few verbs that can be used in the prompt text.
-These will be formatted and replaced with the appropriate values.
-`%d` - Current working directory
-`%u` - Name of current user
-`%h` - Hostname of device
-
-read(prompt?) -> input? > Read input from the user, using Hilbish's line editor/input reader.
-This is a separate instance from the one Hilbish actually uses.
-Returns `input`, will be nil if ctrl + d is pressed, or an error occurs (which shouldn't happen)
-
-run(cmd, returnOut) -> exitCode, stdout, stderr > Runs `cmd` in Hilbish's sh interpreter.
-If returnOut is true, the outputs of `cmd` will be returned as the 2nd and
-3rd values instead of being outputted to the terminal.
-
-runnerMode(mode) > Sets the execution/runner mode for interactive Hilbish. This determines whether
-Hilbish wll try to run input as Lua and/or sh or only do one of either.
-Accepted values for mode are hybrid (the default), hybridRev (sh first then Lua),
-sh, and lua. It also accepts a function, to which if it is passed one
-will call it to execute user input instead.
-
-timeout(cb, time) > Runs the `cb` function after `time` in milliseconds
-Returns a `timer` object (see `doc timers`).
-
-which(name) > Checks if `name` is a valid command
-
diff --git a/docs/hooks/command.txt b/docs/hooks/command.md
similarity index 100%
rename from docs/hooks/command.txt
rename to docs/hooks/command.md
diff --git a/docs/hooks/hilbish.txt b/docs/hooks/hilbish.md
similarity index 100%
rename from docs/hooks/hilbish.txt
rename to docs/hooks/hilbish.md
diff --git a/docs/hooks/index.txt b/docs/hooks/index.md
similarity index 100%
rename from docs/hooks/index.txt
rename to docs/hooks/index.md
diff --git a/docs/hooks/job.txt b/docs/hooks/job.md
similarity index 100%
rename from docs/hooks/job.txt
rename to docs/hooks/job.md
diff --git a/docs/hooks/signal.txt b/docs/hooks/signal.md
similarity index 100%
rename from docs/hooks/signal.txt
rename to docs/hooks/signal.md
diff --git a/docs/jobs.txt b/docs/jobs.md
similarity index 100%
rename from docs/jobs.txt
rename to docs/jobs.md
diff --git a/docs/lunacolors.txt b/docs/lunacolors.md
similarity index 100%
rename from docs/lunacolors.txt
rename to docs/lunacolors.md
diff --git a/docs/nature/index.txt b/docs/nature/index.md
similarity index 100%
rename from docs/nature/index.txt
rename to docs/nature/index.md
diff --git a/docs/runner-mode.txt b/docs/runner-mode.md
similarity index 100%
rename from docs/runner-mode.txt
rename to docs/runner-mode.md
diff --git a/docs/terminal.txt b/docs/terminal.txt
deleted file mode 100644
index 7683bbb..0000000
--- a/docs/terminal.txt
+++ /dev/null
@@ -1,9 +0,0 @@
-restoreState() > Restores the last saved state of the terminal
-
-saveState() > Saves the current state of the terminal
-
-setRaw() > Puts the terminal in raw mode
-
-size() > Gets the dimensions of the terminal. Returns a table with `width` and `height`
-Note: this is not the size in relation to the dimensions of the display
-
diff --git a/docs/timers.txt b/docs/timers.md
similarity index 100%
rename from docs/timers.txt
rename to docs/timers.md
diff --git a/docs/vim-mode/actions.txt b/docs/vim-mode/actions.md
similarity index 100%
rename from docs/vim-mode/actions.txt
rename to docs/vim-mode/actions.md
diff --git a/docs/vim-mode/index.txt b/docs/vim-mode/index.md
similarity index 100%
rename from docs/vim-mode/index.txt
rename to docs/vim-mode/index.md
diff --git a/editor.go b/editor.go
index 868f458..4331dd9 100644
--- a/editor.go
+++ b/editor.go
@@ -6,6 +6,10 @@ import (
rt "github.com/arnodel/golua/runtime"
)
+// #interface editor
+// interactions for Hilbish's line reader
+// The hilbish.editor interface provides functions to
+// directly interact with the line editor in use.
func editorLoader(rtm *rt.Runtime) *rt.Table {
exports := map[string]util.LuaExport{
"insert": {editorInsert, 1, false},
@@ -20,6 +24,9 @@ func editorLoader(rtm *rt.Runtime) *rt.Table {
return mod
}
+// #interface editor
+// insert(text)
+// Inserts text into the line.
func editorInsert(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
if err := c.Check1Arg(); err != nil {
return nil, err
@@ -35,6 +42,9 @@ func editorInsert(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
return c.Next(), nil
}
+// #interface editor
+// setVimRegister(register, text)
+// Sets the vim register at `register` to hold the passed text.
func editorSetRegister(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
if err := c.Check1Arg(); err != nil {
return nil, err
@@ -55,6 +65,9 @@ func editorSetRegister(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
return c.Next(), nil
}
+// #interface editor
+// getVimRegister(register)
+// Returns the text that is at the register.
func editorGetRegister(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
if err := c.Check1Arg(); err != nil {
return nil, err
@@ -70,6 +83,9 @@ func editorGetRegister(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
return c.PushingNext1(t.Runtime, rt.StringValue(string(buf))), nil
}
+// #interface editor
+// getLine()
+// Returns the current input line.
func editorGetLine(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
buf := lr.rl.GetLine()
diff --git a/emmyLuaDocs/bait.lua b/emmyLuaDocs/bait.lua
index a957e00..65f9f83 100644
--- a/emmyLuaDocs/bait.lua
+++ b/emmyLuaDocs/bait.lua
@@ -27,6 +27,6 @@ function bait.release(name, catcher) end
--- Throws a hook with `name` with the provided `args`
--- @param name string
--- @vararg any
-function bait.throw(name, ...) end
+function bait.throw(name, ...args) end
return bait
diff --git a/emmyLuaDocs/fs.lua b/emmyLuaDocs/fs.lua
index 14e7be4..eb5743a 100644
--- a/emmyLuaDocs/fs.lua
+++ b/emmyLuaDocs/fs.lua
@@ -8,7 +8,7 @@ function fs.abs(path) end
--- Gives the basename of `path`. For the rules,
--- see Go's filepath.Base
-function fs.basename() end
+function fs.basename(path) end
--- Changes directory to `dir`
--- @param dir string
@@ -16,15 +16,15 @@ function fs.cd(dir) end
--- Returns the directory part of `path`. For the rules, see Go's
--- filepath.Dir
-function fs.dir() end
+function fs.dir(path) end
--- Glob all files and directories that match the pattern.
--- For the rules, see Go's filepath.Glob
-function fs.glob() end
+function fs.glob(pattern) end
--- Takes paths and joins them together with the OS's
--- directory separator (forward or backward slash).
-function fs.join() end
+function fs.join(paths...) end
--- Makes a directory called `name`. If `recursive` is true, it will create its parent directories.
--- @param name string
diff --git a/emmyLuaDocs/hilbish.lua b/emmyLuaDocs/hilbish.lua
index ca34425..7a6930d 100644
--- a/emmyLuaDocs/hilbish.lua
+++ b/emmyLuaDocs/hilbish.lua
@@ -2,6 +2,38 @@
local hilbish = {}
+--- This is an alias (ha) for the `hilbish.alias` function.
+--- @param alias string
+--- @param cmd string
+function hilbish.aliases.add(alias, cmd) end
+
+--- This is the same as the `hilbish.runnerMode` function. It takes a callback,
+--- which will be used to execute all interactive input.
+--- In normal cases, neither callbacks should be overrided by the user,
+--- as the higher level functions listed below this will handle it.
+function hilbish.runner.setMode(cb) end
+
+--- Calls a completer function. This is mainly used to call
+--- a command completer, which will have a `name` in the form
+--- of `command.name`, example: `command.git`
+function hilbish.completions.call(name, query, ctx, fields) end
+
+--- The handler function is the callback for tab completion in Hilbish.
+--- You can check the completions doc for more info.
+function hilbish.completions.handler(line, pos) end
+
+--- Returns the current input line.
+function hilbish.editor.getLine() end
+
+--- Returns the text that is at the register.
+function hilbish.editor.getVimRegister(register) end
+
+--- Inserts text into the line.
+function hilbish.editor.insert(text) end
+
+--- Sets the vim register at `register` to hold the passed text.
+function hilbish.editor.setVimRegister(register, text) end
+
--- Sets an alias of `cmd` to `orig`
--- @param cmd string
--- @param orig string
@@ -73,20 +105,21 @@ function hilbish.prependPath(dir) end
--- `%u` - Name of current user
--- `%h` - Hostname of device
--- @param str string
---- @param typ string Type of prompt, being left or right. Left by default.
+--- @param typ string|nil Type of prompt, being left or right. Left by default.
function hilbish.prompt(str, typ) end
--- Read input from the user, using Hilbish's line editor/input reader.
--- This is a separate instance from the one Hilbish actually uses.
--- Returns `input`, will be nil if ctrl + d is pressed, or an error occurs (which shouldn't happen)
---- @param prompt string
+--- @param prompt string|nil
+--- @returns string|nil
function hilbish.read(prompt) end
--- Runs `cmd` in Hilbish's sh interpreter.
--- If returnOut is true, the outputs of `cmd` will be returned as the 2nd and
--- 3rd values instead of being outputted to the terminal.
--- @param cmd string
-function hilbish.run(cmd) end
+function hilbish.run(cmd, returnOut) end
--- Sets the execution/runner mode for interactive Hilbish. This determines whether
--- Hilbish wll try to run input as Lua and/or sh or only do one of either.
@@ -105,6 +138,87 @@ function hilbish.timeout(cb, time) end
--- Checks if `name` is a valid command
--- @param binName string
-function hilbish.which(binName) end
+function hilbish.which(name) end
+
+--- Puts a job in the background. This acts the same as initially running a job.
+function hilbish.jobs:background() end
+
+--- Returns binary/executale completion candidates based on the provided query.
+function hilbish.completions.bins(query, ctx, fields) end
+
+--- Returns file completion candidates based on the provided query.
+function hilbish.completions.files(query, ctx, fields) end
+
+--- Puts a job in the foreground. This will cause it to run like it was
+--- executed normally and wait for it to complete.
+function hilbish.jobs:foreground() end
+
+--- Evaluates `cmd` as Lua input. This is the same as using `dofile`
+--- or `load`, but is appropriated for the runner interface.
+function hilbish.runner.lua(cmd) end
+
+--- Starts running the job.
+function hilbish.jobs:start() end
+
+--- Stops the job from running.
+function hilbish.jobs.stop() end
+
+--- Runs a command in Hilbish's shell script interpreter.
+--- This is the equivalent of using `source`.
+function hilbish.runner.sh(cmd) end
+
+--- Starts a timer.
+function hilbish.timers:start() end
+
+--- Stops a timer.
+function hilbish.timers:stop() end
+
+--- Removes an alias.
+--- @param name string
+function hilbish.aliases.delete(name) end
+
+--- Get a table of all aliases.
+function hilbish.aliases.list() end
+
+--- Tries to resolve an alias to its command.
+--- @param alias string
+function hilbish.aliases.resolve(alias) end
+
+--- Adds a new job to the job table. Note that this does not immediately run it.
+function hilbish.jobs.add(cmdstr, args, execPath) end
+
+--- Returns a table of all job objects.
+function hilbish.jobs.all() end
+
+--- Disowns a job. This deletes it from the job table.
+function hilbish.jobs.disown(id) end
+
+--- Get a job object via its ID.
+function hilbish.jobs.get(id) end
+
+--- Returns the last added job from the table.
+function hilbish.jobs.last() end
+
+--- Adds a command to the history.
+--- @param cmd string
+function hilbish.history.add(cmd) end
+
+--- Deletes all commands from the history.
+function hilbish.history.clear() end
+
+--- Retrieves a command from the history based on the `idx`.
+--- @param idx number
+function hilbish.history.get(idx) end
+
+--- Returns the amount of commands in the history.
+--- @returns number
+function hilbish.history.size() end
+
+--- Creates a timer that runs based on the specified `time` in milliseconds.
+--- The `type` can either be interval (value of 0) or timeout (value of 1).
+function hilbish.timers.create(type, time, callback) end
+
+--- Retrieves a timer via its ID.
+function hilbish.timers.get(id) end
return hilbish
diff --git a/exec.go b/exec.go
index caf7d1b..d668192 100644
--- a/exec.go
+++ b/exec.go
@@ -141,9 +141,9 @@ func runInput(input string, priv bool) {
if err != nil {
if exErr, ok := isExecError(err); ok {
hooks.Emit("command." + exErr.typ, exErr.cmd)
- err = exErr.sprint()
+ } else {
+ fmt.Fprintln(os.Stderr, err)
}
- fmt.Fprintln(os.Stderr, err)
}
cmdFinish(exitCode, input, priv)
}
diff --git a/go.mod b/go.mod
index 825dae0..52b274a 100644
--- a/go.mod
+++ b/go.mod
@@ -29,4 +29,4 @@ replace github.com/maxlandon/readline => ./readline
replace layeh.com/gopher-luar => github.com/layeh/gopher-luar v1.0.10
-replace github.com/arnodel/golua => github.com/Rosettea/golua v0.0.0-20220518005949-116371948fe3
+replace github.com/arnodel/golua => github.com/Rosettea/golua v0.0.0-20221213193027-cbf6d4e4d345
diff --git a/go.sum b/go.sum
index c313c19..74a351b 100644
--- a/go.sum
+++ b/go.sum
@@ -2,6 +2,10 @@ github.com/Rosettea/golua v0.0.0-20220419183026-6d22d6fec5ac h1:dtXrgjch8PQyf7C9
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=
diff --git a/golibs/bait/bait.go b/golibs/bait/bait.go
index 70e122c..8a6bf8c 100644
--- a/golibs/bait/bait.go
+++ b/golibs/bait/bait.go
@@ -1,3 +1,9 @@
+// the event emitter
+// Bait is the event emitter for Hilbish. Why name it bait? Why not.
+// It throws hooks that you can catch. This is what you will use if
+// you want to listen in on hooks to know when certain things have
+// happened, like when you've changed directory, a command has failed,
+// etc. To find all available hooks thrown by Hilbish, see doc hooks.
package bait
import (
diff --git a/golibs/commander/commander.go b/golibs/commander/commander.go
index 24f1c03..93785e2 100644
--- a/golibs/commander/commander.go
+++ b/golibs/commander/commander.go
@@ -1,3 +1,5 @@
+// library for custom commands
+// Commander is a library for writing custom commands in Lua.
package commander
import (
diff --git a/golibs/fs/fs.go b/golibs/fs/fs.go
index 5b12e73..94b8110 100644
--- a/golibs/fs/fs.go
+++ b/golibs/fs/fs.go
@@ -1,3 +1,7 @@
+// filesystem interaction and functionality library
+// The fs module provides easy and simple access to filesystem functions
+// and other things, and acts an addition to the Lua standard library's
+// I/O and filesystem functions.
package fs
import (
diff --git a/golibs/terminal/terminal.go b/golibs/terminal/terminal.go
index df1755c..4ae8f88 100644
--- a/golibs/terminal/terminal.go
+++ b/golibs/terminal/terminal.go
@@ -1,3 +1,5 @@
+// low level terminal library
+// The terminal library is a simple and lower level library for certain terminal interactions.
package terminal
import (
diff --git a/job.go b/job.go
index 709cc1f..b9400cd 100644
--- a/job.go
+++ b/job.go
@@ -110,6 +110,10 @@ func (j *job) getProc() *os.Process {
return nil
}
+// #interface jobs
+// #member
+// start()
+// Starts running the job.
func luaStartJob(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
if err := c.Check1Arg(); err != nil {
return nil, err
@@ -130,6 +134,9 @@ func luaStartJob(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
return c.Next(), nil
}
+// #interface jobs
+// stop()
+// Stops the job from running.
func luaStopJob(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
if err := c.Check1Arg(); err != nil {
return nil, err
@@ -148,6 +155,11 @@ func luaStopJob(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
return c.Next(), nil
}
+// #interface jobs
+// #member
+// foreground()
+// Puts a job in the foreground. This will cause it to run like it was
+// executed normally and wait for it to complete.
func luaForegroundJob(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
if err := c.Check1Arg(); err != nil {
return nil, err
@@ -180,6 +192,10 @@ func luaForegroundJob(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
return c.Next(), nil
}
+// #interface jobs
+// #member
+// background()
+// Puts a job in the background. This acts the same as initially running a job.
func luaBackgroundJob(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
if err := c.Check1Arg(); err != nil {
return nil, err
@@ -276,6 +292,20 @@ func (j *jobHandler) stopAll() {
}
}
+// #interface jobs
+// #property cmd The user entered command string for the job.
+// #property running Whether the job is running or not.
+// #property id The ID of the job in the job table
+// #property pid The Process ID
+// #property exitCode The last exit code of the job.
+// #property stdout The standard output of the job. This just means the normal logs of the process.
+// #property stderr The standard error stream of the process. This (usually) includes error messages of the job.
+// background job management
+/*
+Manage interactive jobs in Hilbish via Lua.
+
+Jobs are the name of background tasks/commands. A job can be started via
+interactive usage or with the functions defined below for use in external runners. */
func (j *jobHandler) loader(rtm *rt.Runtime) *rt.Table {
jobMethods := rt.NewTable()
jFuncs := map[string]util.LuaExport{
@@ -353,6 +383,9 @@ func jobUserData(j *job) *rt.UserData {
return rt.NewUserData(j, jobMeta.AsTable())
}
+// #interface jobs
+// get(id)
+// Get a job object via its ID.
func (j *jobHandler) luaGetJob(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
j.mu.RLock()
defer j.mu.RUnlock()
@@ -373,6 +406,9 @@ func (j *jobHandler) luaGetJob(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
return c.PushingNext(t.Runtime, rt.UserDataValue(job.ud)), nil
}
+// #interface jobs
+// add(cmdstr, args, execPath)
+// Adds a new job to the job table. Note that this does not immediately run it.
func (j *jobHandler) luaAddJob(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
if err := c.CheckNArgs(3); err != nil {
return nil, err
@@ -402,6 +438,9 @@ func (j *jobHandler) luaAddJob(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
return c.PushingNext1(t.Runtime, rt.UserDataValue(jb.ud)), nil
}
+// #interface jobs
+// all()
+// Returns a table of all job objects.
func (j *jobHandler) luaAllJobs(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
j.mu.RLock()
defer j.mu.RUnlock()
@@ -414,6 +453,9 @@ func (j *jobHandler) luaAllJobs(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
return c.PushingNext1(t.Runtime, rt.TableValue(jobTbl)), nil
}
+// #interface jobs
+// disown(id)
+// Disowns a job. This deletes it from the job table.
func (j *jobHandler) luaDisownJob(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
if err := c.Check1Arg(); err != nil {
return nil, err
@@ -431,6 +473,9 @@ func (j *jobHandler) luaDisownJob(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
return c.Next(), nil
}
+// #interface jobs
+// last() -> Job
+// Returns the last added job from the table.
func (j *jobHandler) luaLastJob(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
j.mu.RLock()
defer j.mu.RUnlock()
diff --git a/nature/commands/doc.lua b/nature/commands/doc.lua
index a290cd8..bc16dfe 100644
--- a/nature/commands/doc.lua
+++ b/nature/commands/doc.lua
@@ -4,34 +4,34 @@ local lunacolors = require 'lunacolors'
commander.register('doc', function(args)
local moddocPath = hilbish.dataDir .. '/docs/'
- local modDocFormat = [[
-%s
-%s
-# Functions
+ local apidocHeader = [[
+# %s
+{grayBg} {white}{italic}%s {reset}
+
]]
if #args > 0 then
local mod = args[1]
- local f = io.open(moddocPath .. mod .. '.txt', 'rb')
+ local f = io.open(moddocPath .. mod .. '.md', 'rb')
local funcdocs = nil
if not f then
-- assume subdir
- -- dataDir/docs//.txt
+ -- dataDir/docs//.md
moddocPath = moddocPath .. mod .. '/'
local subdocName = args[2]
if not subdocName then
subdocName = 'index'
end
- f = io.open(moddocPath .. subdocName .. '.txt', 'rb')
+ f = io.open(moddocPath .. subdocName .. '.md', 'rb')
if not f then
print('No documentation found for ' .. mod .. '.')
return
end
funcdocs = f:read '*a'
- local moddocs = table.filter(fs.readdir(moddocPath), function(f) return f ~= 'index.txt' end)
+ local moddocs = table.filter(fs.readdir(moddocPath), function(f) return f ~= 'index.md' end)
local subdocs = table.map(moddocs, function(fname)
- return lunacolors.underline(lunacolors.blue(string.gsub(fname, '.txt', '')))
+ return lunacolors.underline(lunacolors.blue(string.gsub(fname, '.md', '')))
end)
if subdocName == 'index' then
funcdocs = funcdocs .. '\nSubdocs: ' .. table.concat(subdocs, ', ')
@@ -41,8 +41,24 @@ commander.register('doc', function(args)
if not funcdocs then
funcdocs = f:read '*a'
end
- local desc = ''
- local ok = pcall(require, mod)
+ local valsStr = funcdocs:match '%-%-%-\n([^%-%-%-]+)\n'
+ local vals = {}
+ if valsStr then
+ local _, endpos = funcdocs:find('---\n' .. valsStr .. '\n---\n\n', 1, true)
+ funcdocs = funcdocs:sub(endpos + 1, #funcdocs)
+
+ -- parse vals
+ local lines = string.split(valsStr, '\n')
+ for _, line in ipairs(lines) do
+ local key = line:match '(%w+): '
+ local val = line:match '^%w+: (.-)$'
+
+ vals[key] = val
+ end
+ end
+ if mod == 'api' then
+ funcdocs = string.format(apidocHeader, vals.name, vals.description) .. funcdocs
+ end
local backtickOccurence = 0
local formattedFuncs = lunacolors.format(funcdocs:sub(1, #funcdocs - 1):gsub('`', function()
backtickOccurence = backtickOccurence + 1
@@ -51,34 +67,16 @@ commander.register('doc', function(args)
else
return '{underline}{green}'
end
+ end):gsub('#+.-\n', function(t)
+ return '{bold}{magenta}' .. t .. '{reset}'
end))
-
- if ok then
- local props = {}
- local propstr = ''
- local modDesc = ''
- local modmt = getmetatable(require(mod))
- if modmt then
- modDesc = modmt.__doc
- if modmt.__docProp then
- -- not all modules have docs for properties
- props = table.map(modmt.__docProp, function(v, k)
- return lunacolors.underline(lunacolors.blue(k)) .. ' > ' .. v
- end)
- end
- if #props > 0 then
- propstr = '\n# Properties\n' .. table.concat(props, '\n') .. '\n'
- end
- desc = string.format(modDocFormat, modDesc, propstr)
- end
- end
- print(desc .. formattedFuncs)
+ print(formattedFuncs)
f:close()
return
end
local modules = table.map(fs.readdir(moddocPath), function(f)
- return lunacolors.underline(lunacolors.blue(string.gsub(f, '.txt', '')))
+ return lunacolors.underline(lunacolors.blue(string.gsub(f, '.md', '')))
end)
io.write [[
diff --git a/nature/completions.lua b/nature/completions.lua
index d20cc59..f8127a1 100644
--- a/nature/completions.lua
+++ b/nature/completions.lua
@@ -24,7 +24,7 @@ function hilbish.completion.handler(line, pos)
return {compGroup}, pfx
else
local ok, compGroups, pfx = pcall(hilbish.completion.call,
- 'command.' .. #fields[1], query, ctx, fields)
+ 'command.' .. fields[1], query, ctx, fields)
if ok then
return compGroups, pfx
end
diff --git a/nature/init.lua b/nature/init.lua
index aa85a2e..ecd1054 100644
--- a/nature/init.lua
+++ b/nature/init.lua
@@ -69,3 +69,11 @@ end
bait.catch('error', function(event, handler, err)
bait.release(event, handler)
end)
+
+bait.catch('command.not-found', function(cmd)
+ print(string.format('hilbish: %s not found', cmd))
+end)
+
+bait.catch('command.not-executable', function(cmd)
+ print(string.format('hilbish: %s: not executable', cmd))
+end)
diff --git a/nature/runner.lua b/nature/runner.lua
index e155f63..9b62ad1 100644
--- a/nature/runner.lua
+++ b/nature/runner.lua
@@ -1,3 +1,4 @@
+--- hilbish.runner
local currentRunner = 'hybrid'
local runners = {}
diff --git a/os.go b/os.go
new file mode 100644
index 0000000..a214ea9
--- /dev/null
+++ b/os.go
@@ -0,0 +1,27 @@
+package main
+
+import (
+ "hilbish/util"
+
+ rt "github.com/arnodel/golua/runtime"
+ "github.com/blackfireio/osinfo"
+)
+
+// #interface os
+// OS Info
+// The `os` interface provides simple text information properties about
+// the current OS on the systen. This mainly includes the name and
+// version.
+// #field family Family name of the current OS
+// #field name Pretty name of the current OS
+// #field version Version of the current OS
+func hshosLoader(rtm *rt.Runtime) *rt.Table {
+ info, _ := osinfo.GetOSInfo()
+ mod := rt.NewTable()
+
+ util.SetField(rtm, mod, "family", rt.StringValue(info.Family), "Family name of the current OS")
+ util.SetField(rtm, mod, "name", rt.StringValue(info.Name), "Pretty name of the current OS")
+ util.SetField(rtm, mod, "version", rt.StringValue(info.Version), "Version of the current OS")
+
+ return mod
+}
diff --git a/readline/history.go b/readline/history.go
index 41200c6..f772813 100644
--- a/readline/history.go
+++ b/readline/history.go
@@ -123,23 +123,20 @@ func (rl *Instance) walkHistory(i int) {
// When we are exiting the current line buffer to move around
// the history, we make buffer the current line
- if rl.histPos == 0 && (rl.histPos+i) == 1 {
+ if rl.histOffset == 0 && rl.histOffset + i == 1 {
rl.lineBuf = string(rl.line)
}
- switch rl.histPos + i {
- case 0, history.Len() + 1:
- rl.histPos = 0
+ rl.histOffset += i
+ if rl.histOffset == 0 {
rl.line = []rune(rl.lineBuf)
rl.pos = len(rl.lineBuf)
- return
- case -1:
- rl.histPos = 0
- rl.lineBuf = string(rl.line)
- default:
+ } else if rl.histOffset <= -1 {
+ rl.histOffset = 0
+ } else {
dedup = true
old = string(rl.line)
- new, err = history.GetLine(history.Len() - rl.histPos - 1)
+ new, err = history.GetLine(history.Len() - rl.histOffset)
if err != nil {
rl.resetHelpers()
print("\r\n" + err.Error() + "\r\n")
@@ -148,7 +145,6 @@ func (rl *Instance) walkHistory(i int) {
}
rl.clearLine()
- rl.histPos += i
rl.line = []rune(new)
rl.pos = len(rl.line)
if rl.pos > 0 {
diff --git a/readline/instance.go b/readline/instance.go
index fcd8379..039f040 100644
--- a/readline/instance.go
+++ b/readline/instance.go
@@ -134,6 +134,7 @@ type Instance struct {
// history operating params
lineBuf string
histPos int
+ histOffset int
histNavIdx int // Used for quick history navigation.
//
diff --git a/readline/readline.go b/readline/readline.go
index 7397faf..f1d6c96 100644
--- a/readline/readline.go
+++ b/readline/readline.go
@@ -49,7 +49,7 @@ func (rl *Instance) Readline() (string, error) {
// History Init
// We need this set to the last command, so that we can access it quickly
- rl.histPos = 0
+ rl.histOffset = 0
rl.viUndoHistory = []undoItem{{line: "", pos: 0}}
// Multisplit
@@ -546,6 +546,10 @@ func (rl *Instance) Readline() (string, error) {
// entry readline is currently configured for and then update the line entries
// accordingly.
func (rl *Instance) editorInput(r []rune) {
+ if len(r) == 0 {
+ return
+ }
+
switch rl.modeViMode {
case VimKeys:
rl.vi(r[0])
diff --git a/rl.go b/rl.go
index f6cb6cd..6356f64 100644
--- a/rl.go
+++ b/rl.go
@@ -225,7 +225,11 @@ func (lr *lineReader) Resize() {
return
}
-// lua module
+// #interface history
+// command history
+// The history interface deals with command history.
+// This includes the ability to override functions to change the main
+// method of saving history.
func (lr *lineReader) Loader(rtm *rt.Runtime) *rt.Table {
lrLua := map[string]util.LuaExport{
"add": {lr.luaAddHistory, 1, false},
@@ -241,6 +245,10 @@ func (lr *lineReader) Loader(rtm *rt.Runtime) *rt.Table {
return mod
}
+// #interface history
+// add(cmd)
+// Adds a command to the history.
+// --- @param cmd string
func (lr *lineReader) luaAddHistory(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
if err := c.Check1Arg(); err != nil {
return nil, err
@@ -254,10 +262,18 @@ func (lr *lineReader) luaAddHistory(t *rt.Thread, c *rt.GoCont) (rt.Cont, error)
return c.Next(), nil
}
+// #interface history
+// size()
+// Returns the amount of commands in the history.
+// --- @returns number
func (lr *lineReader) luaSize(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
return c.PushingNext1(t.Runtime, rt.IntValue(int64(lr.fileHist.Len()))), nil
}
+// #interface history
+// get(idx)
+// Retrieves a command from the history based on the `idx`.
+// --- @param idx number
func (lr *lineReader) luaGetHistory(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
if err := c.Check1Arg(); err != nil {
return nil, err
@@ -284,6 +300,9 @@ func (lr *lineReader) luaAllHistory(t *rt.Thread, c *rt.GoCont) (rt.Cont, error)
return c.PushingNext1(t.Runtime, rt.TableValue(tbl)), nil
}
+// #interface history
+// clear()
+// Deletes all commands from the history.
func (lr *lineReader) luaClearHistory(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
lr.fileHist.clear()
return c.Next(), nil
diff --git a/runnermode.go b/runnermode.go
index c26ed03..e212604 100644
--- a/runnermode.go
+++ b/runnermode.go
@@ -6,6 +6,13 @@ import (
rt "github.com/arnodel/golua/runtime"
)
+// #interface runner
+// interactive command runner customization
+// The runner interface contains functions that allow the user to change
+// how Hilbish interprets interactive input.
+// Users can add and change the default runner for interactive input to any
+// language or script of their choosing. A good example is using it to
+// write command in Fennel.
func runnerModeLoader(rtm *rt.Runtime) *rt.Table {
exports := map[string]util.LuaExport{
"sh": {shRunner, 1, false},
@@ -19,6 +26,18 @@ func runnerModeLoader(rtm *rt.Runtime) *rt.Table {
return mod
}
+// #interface runner
+// setMode(cb)
+// This is the same as the `hilbish.runnerMode` function. It takes a callback,
+// which will be used to execute all interactive input.
+// In normal cases, neither callbacks should be overrided by the user,
+// as the higher level functions listed below this will handle it.
+func _runnerMode() {}
+
+// #interface runner
+// sh(cmd)
+// Runs a command in Hilbish's shell script interpreter.
+// This is the equivalent of using `source`.
func shRunner(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
if err := c.Check1Arg(); err != nil {
return nil, err
@@ -42,6 +61,10 @@ func shRunner(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
return c.PushingNext(t.Runtime, rt.TableValue(runnerRet)), nil
}
+// #interface runner
+// lua(cmd)
+// Evaluates `cmd` as Lua input. This is the same as using `dofile`
+// or `load`, but is appropriated for the runner interface.
func luaRunner(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
if err := c.Check1Arg(); err != nil {
return nil, err
diff --git a/timer.go b/timer.go
index 74d13c4..be8f270 100644
--- a/timer.go
+++ b/timer.go
@@ -21,7 +21,7 @@ type timer struct{
running bool
dur time.Duration
fun *rt.Closure
- th *timerHandler
+ th *timersModule
ticker *time.Ticker
ud *rt.UserData
channel chan struct{}
@@ -73,6 +73,10 @@ func (t *timer) stop() error {
return nil
}
+// #interface timers
+// #member
+// start()
+// Starts a timer.
func timerStart(thr *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
if err := c.Check1Arg(); err != nil {
return nil, err
@@ -91,6 +95,10 @@ func timerStart(thr *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
return c.Next(), nil
}
+// #interface timers
+// #member
+// stop()
+// Stops a timer.
func timerStop(thr *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
if err := c.Check1Arg(); err != nil {
return nil, err
diff --git a/timerhandler.go b/timerhandler.go
index 64caff8..92947e1 100644
--- a/timerhandler.go
+++ b/timerhandler.go
@@ -10,10 +10,10 @@ import (
rt "github.com/arnodel/golua/runtime"
)
-var timers *timerHandler
+var timers *timersModule
var timerMetaKey = rt.StringValue("hshtimer")
-type timerHandler struct {
+type timersModule struct {
mu *sync.RWMutex
wg *sync.WaitGroup
timers map[int]*timer
@@ -21,8 +21,8 @@ type timerHandler struct {
running int
}
-func newTimerHandler() *timerHandler {
- return &timerHandler{
+func newTimersModule() *timersModule {
+ return &timersModule{
timers: make(map[int]*timer),
latestID: 0,
mu: &sync.RWMutex{},
@@ -30,11 +30,11 @@ func newTimerHandler() *timerHandler {
}
}
-func (th *timerHandler) wait() {
+func (th *timersModule) wait() {
th.wg.Wait()
}
-func (th *timerHandler) create(typ timerType, dur time.Duration, fun *rt.Closure) *timer {
+func (th *timersModule) create(typ timerType, dur time.Duration, fun *rt.Closure) *timer {
th.mu.Lock()
defer th.mu.Unlock()
@@ -54,14 +54,18 @@ func (th *timerHandler) create(typ timerType, dur time.Duration, fun *rt.Closure
return t
}
-func (th *timerHandler) get(id int) *timer {
+func (th *timersModule) get(id int) *timer {
th.mu.RLock()
defer th.mu.RUnlock()
return th.timers[id]
}
-func (th *timerHandler) luaCreate(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
+// #interface timers
+// create(type, time, callback)
+// Creates a timer that runs based on the specified `time` in milliseconds.
+// The `type` can either be interval (value of 0) or timeout (value of 1).
+func (th *timersModule) luaCreate(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
if err := c.CheckNArgs(3); err != nil {
return nil, err
}
@@ -83,7 +87,10 @@ func (th *timerHandler) luaCreate(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
return c.PushingNext1(t.Runtime, rt.UserDataValue(tmr.ud)), nil
}
-func (th *timerHandler) luaGet(thr *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
+// #interface timers
+// get(id)
+// Retrieves a timer via its ID.
+func (th *timersModule) luaGet(thr *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
if err := c.Check1Arg(); err != nil {
return nil, err
}
@@ -100,7 +107,15 @@ func (th *timerHandler) luaGet(thr *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
return c.Next(), nil
}
-func (th *timerHandler) loader(rtm *rt.Runtime) *rt.Table {
+// #interface timers
+// #property type What type of timer it is
+// #property running If the timer is running
+// #property duration The duration in milliseconds that the timer will run
+// timeout and interval API
+// The timers interface si one to easily set timeouts and intervals
+// to run functions after a certain time or repeatedly without using
+// odd tricks.
+func (th *timersModule) loader(rtm *rt.Runtime) *rt.Table {
timerMethods := rt.NewTable()
timerFuncs := map[string]util.LuaExport{
"start": {timerStart, 1, false},
diff --git a/userdir.go b/userdir.go
new file mode 100644
index 0000000..b3581e2
--- /dev/null
+++ b/userdir.go
@@ -0,0 +1,23 @@
+package main
+
+import (
+ "hilbish/util"
+
+ rt "github.com/arnodel/golua/runtime"
+)
+
+// #interface userDir
+// user-related directories
+// This interface just contains properties to know about certain user directories.
+// It is equivalent to XDG on Linux and gets the user's preferred directories
+// for configs and data.
+// #field config The user's config directory
+// #field data The user's directory for program data
+func userDirLoader(rtm *rt.Runtime) *rt.Table {
+ mod := rt.NewTable()
+
+ util.SetField(rtm, mod, "config", rt.StringValue(confDir), "User's config directory")
+ util.SetField(rtm, mod, "data", rt.StringValue(userDataDir), "XDG data directory")
+
+ return mod
+}
diff --git a/vars_linux.go b/vars_linux.go
index 815ba6a..e1160ba 100644
--- a/vars_linux.go
+++ b/vars_linux.go
@@ -14,7 +14,7 @@ var (
.. hilbish.userDir.config .. '/hilbish/?/init.lua;'
.. hilbish.userDir.config .. '/hilbish/?/?.lua;'
.. hilbish.userDir.config .. '/hilbish/?.lua'`
- dataDir = "/usr/share/hilbish"
+ dataDir = "/usr/local/share/hilbish"
preloadPath = dataDir + "/nature/init.lua"
sampleConfPath = dataDir + "/.hilbishrc.lua" // Path to default/sample config
defaultConfDir = ""
diff --git a/website/.hugo_build.lock b/website/.hugo_build.lock
new file mode 100644
index 0000000..e69de29
diff --git a/website/archetypes/default.md b/website/archetypes/default.md
new file mode 100644
index 0000000..00e77bd
--- /dev/null
+++ b/website/archetypes/default.md
@@ -0,0 +1,6 @@
+---
+title: "{{ replace .Name "-" " " | title }}"
+date: {{ .Date }}
+draft: true
+---
+
diff --git a/website/config.toml b/website/config.toml
new file mode 100644
index 0000000..ff6b801
--- /dev/null
+++ b/website/config.toml
@@ -0,0 +1,25 @@
+baseURL = 'https://rosettea.github.io/Hilbish/'
+languageCode = 'en-us'
+title = 'Hilbish'
+theme = 'hsh'
+enableGitInfo = true
+
+[menu]
+[[menu.nav]]
+ identifier = 'home'
+ name = 'Home'
+ pageref = '/'
+ weight = 1
+[[menu.nav]]
+ identifier = 'install'
+ name = 'Install'
+ pageref = '/install'
+ weight = 2
+[[menu.nav]]
+ identifier = 'docs'
+ name = 'Docs'
+ pageref = '/docs'
+ weight = 3
+
+[markup.goldmark.renderer]
+unsafe = true
diff --git a/website/content/_index.md b/website/content/_index.md
new file mode 100644
index 0000000..2b1087b
--- /dev/null
+++ b/website/content/_index.md
@@ -0,0 +1,134 @@
+---
+description: 'Something Unique. Hilbish is the new interactive shell for Lua fans. Extensible, scriptable, configurable: All in Lua.'
+---
+
+[//]: <>
+
+
+
+
Something Unique.
+
+ Hilbish is the new interactive shell for Lua fans.
+ Extensible, scriptable, configurable: All in Lua.
+
+ Hilbish is configured and scripted in the Lua programming language.
+ This removes all the old, ugly things about Shell script and introduces
+ everything good about Lua, including other languages (Moonscript & Fennel).
+
+ Hilbish offers a bunch of features to make your interactive
+ shell experience rich. Things like syntax highlighting and hinting
+ available via the Lua API.
+
+
* Command hints shown in photo are not default.
+
+
+
+
+
+
+
+
+
+
+
+
Why not just Lua?
+
+ Hilbish is your interactive shell as well as a just a Lua interpreter
+ and enhanced REPL.
+
+
+
Batteries included Lua runtime that's also your user shell!
+
Hilbish is easily cross platform. It has OS agnostic interfaces for easy cross platform Lua code.
+
+
+
+
+
Try It Today!
+
+ Hilbish is known to run on the 3 major platforms (Windows, MacOS, Linux)
+ but likely builds on other Unixes!
+
+ Windows doesn't work as well as it should, so if you're a Windows user,
+ say something!
+
diff --git a/website/content/docs/_index.md b/website/content/docs/_index.md
new file mode 100644
index 0000000..4f30ab3
--- /dev/null
+++ b/website/content/docs/_index.md
@@ -0,0 +1,19 @@
+---
+title: Introduction
+layout: doc
+weight: -1
+menu: docs
+---
+
+Here lies the documentation for Hilbish, the hyper extensible Lua shell.
+Hilbish provides you with a few quality of life features and useful
+functions to ensure you can make the shell fully yours.
+
+These features include:
+- Completion and history search menus
+- Hinting and syntax highlighting (scripted by user)
+
+# Installation
+Steps on installing Hilbish will be at the Install page in the navigation bar
+at the top. This also included getting development builds from the GitHub
+repository.
diff --git a/website/content/docs/api b/website/content/docs/api
new file mode 120000
index 0000000..1c5c360
--- /dev/null
+++ b/website/content/docs/api
@@ -0,0 +1 @@
+../../../docs/api/
\ No newline at end of file
diff --git a/website/content/docs/faq.md b/website/content/docs/faq.md
new file mode 100644
index 0000000..d5cd1a2
--- /dev/null
+++ b/website/content/docs/faq.md
@@ -0,0 +1,25 @@
+---
+title: Frequently Asked Questions
+layout: doc
+weight: -20
+menu: docs
+---
+
+# Is Hilbish POSIX compliant?
+No, it is not. POSIX compliance is a non-goal. Perhaps in the future,
+someone would be able to write a native plugin to support shell scripting
+(which would be against it's main goal, but ....)
+
+# Windows Support?
+It compiles for Windows (CI ensures it does), but otherwise it is not
+directly supported. If you'd like to improve this situation,
+checkout [the discussion](https://github.com/Rosettea/Hilbish/discussions/165).
+
+# Where is the API documentation?
+The builtin `doc` command supplies all documentation of Hilbish provided
+APIs. This will be on the website in the near future.
+
+# Why?
+Hilbish emerged from the desire of a Lua configured shell.
+It was the initial reason that it was created, but now it's more:
+to be hyper extensible, simpler and more user friendly.
diff --git a/website/content/docs/features/_index.md b/website/content/docs/features/_index.md
new file mode 100644
index 0000000..0e14346
--- /dev/null
+++ b/website/content/docs/features/_index.md
@@ -0,0 +1,11 @@
+---
+title: Features
+layout: doc
+weight: -40
+menu: docs
+---
+
+Hilbish has a wide range of features to enhance the user's experience and
+is always adding new ones. If there is something missing here or something
+you would like to see, please [start a discussion](https://github.com/Rosettea/Hilbish/discussions)
+or comment on any existing ones which match your request.
diff --git a/website/content/docs/features/runner-mode.md b/website/content/docs/features/runner-mode.md
new file mode 100644
index 0000000..87ecc8b
--- /dev/null
+++ b/website/content/docs/features/runner-mode.md
@@ -0,0 +1,17 @@
+---
+title: Runner Mode
+description: Customize the interactive script/command runner.
+layout: doc
+menu:
+ docs:
+ parent: "Features"
+---
+
+Hilbish allows you to change how interactive text can be interpreted.
+This is mainly due to the fact that the default method Hilbish uses
+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.
diff --git a/website/content/docs/getting-started.md b/website/content/docs/getting-started.md
new file mode 100644
index 0000000..f0fe56d
--- /dev/null
+++ b/website/content/docs/getting-started.md
@@ -0,0 +1,59 @@
+---
+title: Getting Started
+layout: doc
+weight: -10
+menu: docs
+---
+
+To start Hilbish, open a terminal. If Hilbish has been installed and is not the
+default shell, you can simply run `hilbish` to start it. This will launch
+a normal interactive session.
+To exit, you can either run the `exit` command or hit Ctrl+D.
+
+# Setting as Default
+## Login shell
+There are a few ways to make Hilbish your default shell. A simple way is
+to make it your user/login shell.
+
+{{< warning `It is not recommended to set Hilbish as your login shell. That is expected to be a
+POSIX compliant shell, which Hilbish is not. At most, there will just be a
+few variables missing in your environment` >}}
+
+To do that, simply run `chsh -s /usr/bin/hilbish`.
+Some distros (namely Fedora) might have `lchsh` instead, which is used like `lchsh `.
+When prompted, you can put the path for Hilbish.
+
+## Default with terminal
+The simpler way is to set the default shell for your terminal. The way of
+doing this depends on how your terminal settings are configured.
+
+## Run after login shell
+Some shells (like zsh) have an rc file, like `.zlogin`, which is ran when the shell session
+is a login shell. In that file, you can run Hilbish. Example:
+
+```
+exec hilbish -S -l
+```
+
+This will replace the shell with Hilbish, set $SHELL to Hilbish and launch it as a login shell.
+
+# Configuration
+Once installation and setup has been done, you can then configure Hilbish.
+It is configured and scripted via Lua, so the config file is a Lua file.
+You can use any pure Lua library to do whatever you want.
+
+Hilbish's sample configuration is usually located in `hilbish.dataDir .. '/.hilbishrc.lua'`.
+You can print that path via Lua to see what it is: `print(hilbish.dataDir .. '/.hilbishrc.lua')`.
+As an example, it will usually will result in `/usr/share/hilbish/.hilbishrc.lua` on Linux.
+
+To edit your user configuration, you can copy that file to `hilbish.userDir.config .. '/hilbish/init.lua'`,
+which follows XDG on Linux and MacOS, and is located in %APPDATA% on Windows.
+
+As the directory is usually `~/.config` on Linux, you can run this command to copy it:
+`cp /usr/share/hilbish/.hilbishrc.lua ~/.config/hilbish/init.lua`
+
+Now you can get to editing it. Since it's just a Lua file, having basic
+knowledge of Lua would help. All of Lua's standard libraries and functions
+from Lua 5.4 are available. Hilbish has some custom and modules that are
+available. To see them, you can run the `doc` command. This also works as
+general documentation for other things.
diff --git a/website/content/install.md b/website/content/install.md
new file mode 100644
index 0000000..731b8c0
--- /dev/null
+++ b/website/content/install.md
@@ -0,0 +1,38 @@
+---
+title: Install
+description: Steps on how to install Hilbish on all the OSes and distros supported.
+layout: page
+---
+
+## Official Binaries
+The best way to get Hilbish is to get a build directly from GitHub.
+At any time, there are 2 versions of Hilbish recommended for download:
+the latest stable release, and development builds from the master branch.
+
+You can download both at any time, but note that the development builds may
+have breaking changes.
+
+For the latest **stable release**, check here: https://github.com/Rosettea/Hilbish/releases/latest
+For a **development build**: https://nightly.link/Rosettea/Hilbish/workflows/build/master
+
+## Package Repositories
+### Arch Linux (AUR)
+Hilbish is on the AUR. Setup an AUR helper, and install.
+Example with yay:
+
+```
+yay -S hilbish
+```
+
+Or, from master branch:
+```
+yay -S hilbish-git
+```
+
+### Alpine Linux
+Hilbish is currentlty in the testing/edge repository for Alpine.
+Follow the steps [here](https://wiki.alpinelinux.org/wiki/Enable_Community_Repository)
+(Using testing repositories) and install:
+```
+apk add hilbish
+```
diff --git a/website/static/hilbish-flower.png b/website/static/hilbish-flower.png
new file mode 100644
index 0000000..b4fb0f7
Binary files /dev/null and b/website/static/hilbish-flower.png differ
diff --git a/website/themes/hsh/LICENSE b/website/themes/hsh/LICENSE
new file mode 100644
index 0000000..da3c8c1
--- /dev/null
+++ b/website/themes/hsh/LICENSE
@@ -0,0 +1,21 @@
+MIT License
+
+Copyright (c) 2022 Rosettea
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/website/themes/hsh/archetypes/default.md b/website/themes/hsh/archetypes/default.md
new file mode 100644
index 0000000..ac36e06
--- /dev/null
+++ b/website/themes/hsh/archetypes/default.md
@@ -0,0 +1,2 @@
++++
++++
diff --git a/website/themes/hsh/layouts/404.html b/website/themes/hsh/layouts/404.html
new file mode 100644
index 0000000..06b3561
--- /dev/null
+++ b/website/themes/hsh/layouts/404.html
@@ -0,0 +1,7 @@
+{{ define "main"}}
+
+