sammyette 2023-12-02 12:23:54 +00:00 committed by GitHub
commit 16b875a4a7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
41 changed files with 1932 additions and 580 deletions

2
api.go
View File

@ -9,7 +9,7 @@
// #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
// #field exitCode Exit code of the last executed command
package main
import (

View File

@ -11,6 +11,8 @@ import (
"strings"
"os"
"sync"
md "github.com/atsushinee/go-markdown-generator/doc"
)
var header = `---
@ -43,6 +45,12 @@ type module struct {
HasTypes bool
}
type param struct{
Name string
Type string
Doc []string
}
type docPiece struct {
Doc []string
FuncSig string
@ -55,11 +63,14 @@ type docPiece struct {
IsType bool
Fields []docPiece
Properties []docPiece
Params []param
Tags map[string][]tag
}
type tag struct {
id string
fields []string
startIdx int
}
var docs = make(map[string]module)
@ -80,7 +91,7 @@ func getTagsAndDocs(docs string) (map[string][]tag, []string) {
parts := []string{}
tags := make(map[string][]tag)
for _, part := range pts {
for idx, part := range pts {
if strings.HasPrefix(part, "#") {
tagParts := strings.Split(strings.TrimPrefix(part, "#"), " ")
if tags[tagParts[0]] == nil {
@ -89,12 +100,21 @@ func getTagsAndDocs(docs string) (map[string][]tag, []string) {
id = tagParts[1]
}
tags[tagParts[0]] = []tag{
{id: id},
{id: id, startIdx: idx},
}
if len(tagParts) >= 2 {
tags[tagParts[0]][0].fields = tagParts[2:]
}
} else {
if tagParts[0] == "example" {
exampleIdx := tags["example"][0].startIdx
exampleCode := pts[exampleIdx+1:idx]
tags["example"][0].fields = exampleCode
parts = strings.Split(strings.Replace(strings.Join(parts, "\n"), strings.TrimPrefix(strings.Join(exampleCode, "\n"), "#example\n"), "", -1), "\n")
continue
}
fleds := []string{}
if len(tagParts) >= 2 {
fleds = tagParts[2:]
@ -179,6 +199,7 @@ func setupDocType(mod string, typ *doc.Type) *docPiece {
ParentModule: parentMod,
Fields: fields,
Properties: properties,
Tags: tags,
}
typeTable[strings.ToLower(typeName)] = []string{parentMod, interfaces}
@ -215,6 +236,17 @@ start:
fields := docPieceTag("field", tags)
properties := docPieceTag("property", tags)
var params []param
if paramsRaw := tags["param"]; paramsRaw != nil {
params = make([]param, len(paramsRaw))
for i, p := range paramsRaw {
params[i] = param{
Name: p.id,
Type: p.fields[0],
Doc: p.fields[1:],
}
}
}
for _, d := range doc {
if strings.HasPrefix(d, "---") {
@ -252,6 +284,8 @@ start:
ParentModule: parentMod,
Fields: fields,
Properties: properties,
Params: params,
Tags: tags,
}
if strings.HasSuffix(dps.GoFuncName, strings.ToLower("loader")) {
dps.Doc = parts
@ -412,13 +446,14 @@ func main() {
defer wg.Done()
modOrIface := "Module"
if modu.ParentModule != "" {
modOrIface = "Interface"
modOrIface = "Module"
}
lastHeader := ""
f, _ := os.Create(docPath)
f.WriteString(fmt.Sprintf(header, modOrIface, modname, modu.ShortDescription))
typeTag, _ := regexp.Compile(`\B@\w+`)
modDescription := typeTag.ReplaceAllStringFunc(strings.Replace(modu.Description, "<", `\<`, -1), func(typ string) string {
modDescription := typeTag.ReplaceAllStringFunc(strings.Replace(strings.Replace(modu.Description, "<", `\<`, -1), "{{\\<", "{{<", -1), func(typ string) string {
typName := typ[1:]
typLookup := typeTable[strings.ToLower(typName)]
ifaces := typLookup[0] + "." + typLookup[1] + "/"
@ -429,32 +464,77 @@ func main() {
return fmt.Sprintf(`<a href="%s" style="text-decoration: none;">%s</a>`, linkedTyp, typName)
})
f.WriteString(fmt.Sprintf("## Introduction\n%s\n\n", modDescription))
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")
funcCount := 0
for _, dps := range modu.Docs {
if dps.IsMember {
continue
}
htmlSig := typeTag.ReplaceAllStringFunc(strings.Replace(dps.FuncSig, "<", `\<`, -1), func(typ string) string {
funcCount++
}
f.WriteString("## Functions\n")
lastHeader = "functions"
mdTable := md.NewTable(funcCount, 2)
mdTable.SetTitle(0, "")
mdTable.SetTitle(1, "")
diff := 0
for i, dps := range modu.Docs {
if dps.IsMember {
diff++
continue
}
mdTable.SetContent(i - diff, 0, fmt.Sprintf(`<a href="#%s">%s</a>`, dps.FuncName, dps.FuncSig))
mdTable.SetContent(i - diff, 1, dps.Doc[0])
}
f.WriteString(mdTable.String())
f.WriteString("\n")
}
if len(modu.Fields) != 0 {
f.WriteString("## Static module fields\n")
mdTable := md.NewTable(len(modu.Fields), 2)
mdTable.SetTitle(0, "")
mdTable.SetTitle(1, "")
for i, dps := range modu.Fields {
mdTable.SetContent(i, 0, dps.FuncName)
mdTable.SetContent(i, 1, strings.Join(dps.Doc, " "))
}
f.WriteString(mdTable.String())
f.WriteString("\n")
}
if len(modu.Properties) != 0 {
f.WriteString("## Object properties\n")
mdTable := md.NewTable(len(modu.Fields), 2)
mdTable.SetTitle(0, "")
mdTable.SetTitle(1, "")
for i, dps := range modu.Properties {
mdTable.SetContent(i, 0, dps.FuncName)
mdTable.SetContent(i, 1, strings.Join(dps.Doc, " "))
}
f.WriteString(mdTable.String())
f.WriteString("\n")
}
if len(modu.Docs) != 0 {
if lastHeader != "functions" {
f.WriteString("## Functions\n")
}
for _, dps := range modu.Docs {
if dps.IsMember {
continue
}
f.WriteString(fmt.Sprintf("<hr><div id='%s'>", dps.FuncName))
htmlSig := typeTag.ReplaceAllStringFunc(strings.Replace(modname + "." + dps.FuncSig, "<", `\<`, -1), func(typ string) string {
typName := typ[1:]
typLookup := typeTable[strings.ToLower(typName)]
ifaces := typLookup[0] + "." + typLookup[1] + "/"
@ -462,21 +542,55 @@ func main() {
ifaces = ""
}
linkedTyp := fmt.Sprintf("/Hilbish/docs/api/%s/%s#%s", typLookup[0], ifaces, strings.ToLower(typName))
return fmt.Sprintf(`<a href="%s" style="text-decoration: none;">%s</a>`, linkedTyp, typName)
return fmt.Sprintf(`<a href="%s" style="text-decoration: none;" id="lol">%s</a>`, linkedTyp, typName)
})
f.WriteString(fmt.Sprintf("### %s\n", htmlSig))
f.WriteString(fmt.Sprintf(`
<h4 class='heading'>
%s
<a href="#%s" class='heading-link'>
<i class="fas fa-paperclip"></i>
</a>
</h4>
`, htmlSig, dps.FuncName))
for _, doc := range dps.Doc {
if !strings.HasPrefix(doc, "---") {
f.WriteString(doc + "\n")
f.WriteString(doc + " \n")
}
}
f.WriteString("\n")
f.WriteString("#### Parameters\n")
if len(dps.Params) == 0 {
f.WriteString("This function has no parameters. \n")
}
for _, p := range dps.Params {
isVariadic := false
typ := p.Type
if strings.HasPrefix(p.Type, "...") {
isVariadic = true
typ = p.Type[3:]
}
f.WriteString(fmt.Sprintf("`%s` **`%s`**", typ, p.Name))
if isVariadic {
f.WriteString(" (This type is variadic. You can pass an infinite amount of parameters with this type.)")
}
f.WriteString(" \n")
f.WriteString(strings.Join(p.Doc, " "))
f.WriteString("\n\n")
}
if codeExample := dps.Tags["example"]; codeExample != nil {
f.WriteString("#### Example\n")
f.WriteString(fmt.Sprintf("```lua\n%s\n````\n", strings.Join(codeExample[0].fields, "\n")))
}
f.WriteString("</div>")
f.WriteString("\n\n")
}
}
if len(modu.Types) != 0 {
f.WriteString("## Types\n")
for _, dps := range modu.Types {
f.WriteString("<hr>\n\n")
f.WriteString(fmt.Sprintf("## %s\n", dps.FuncName))
for _, doc := range dps.Doc {
if !strings.HasPrefix(doc, "---") {
@ -484,12 +598,18 @@ func main() {
}
}
if len(dps.Properties) != 0 {
f.WriteString("### Properties\n")
for _, dps := range dps.Properties {
f.WriteString(fmt.Sprintf("- `%s`: ", dps.FuncName))
f.WriteString(strings.Join(dps.Doc, " "))
f.WriteString("\n")
f.WriteString("## Object properties\n")
mdTable := md.NewTable(len(dps.Properties), 2)
mdTable.SetTitle(0, "")
mdTable.SetTitle(1, "")
for i, d := range dps.Properties {
mdTable.SetContent(i, 0, d.FuncName)
mdTable.SetContent(i, 1, strings.Join(d.Doc, " "))
}
f.WriteString(mdTable.String())
f.WriteString("\n")
}
f.WriteString("\n")
f.WriteString("### Methods\n")

View File

@ -8,27 +8,156 @@ menu:
---
## 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.
Bait is the event emitter for Hilbish. Much like Node.js and
its `events` system, many actions in Hilbish emit events.
Unlike Node.js, Hilbish events are global. So make sure to
pick a unique name!
Usage of the Bait module consists of userstanding
event-driven architecture, but it's pretty simple:
If you want to act on a certain event, you can `catch` it.
You can act on events via callback functions.
Examples of this are in the Hilbish default config!
Consider this part of it:
```lua
bait.catch('command.exit', function(code)
running = false
doPrompt(code ~= 0)
doNotifyPrompt()
end)
```
What this does is, whenever the `command.exit` event is thrown,
this function will set the user prompt.
## Functions
### catch(name, cb)
Catches a hook with `name`. Runs the `cb` when it is thrown
|||
|----|----|
|<a href="#catch">catch(name, cb)</a>|Catches an event. This function can be used to act on events.|
|<a href="#catchOnce">catchOnce(name, cb)</a>|Catches an event, but only once. This will remove the hook immediately after it runs for the first time.|
|<a href="#hooks">hooks(name) -> table</a>|Returns a list of callbacks that are hooked on an event with the corresponding `name`.|
|<a href="#release">release(name, catcher)</a>|Removes the `catcher` for the event with `name`.|
|<a href="#throw">throw(name, ...args)</a>|Throws a hook with `name` with the provided `args`.|
### catchOnce(name, cb)
Same as catch, but only runs the `cb` once and then removes the hook
<hr><div id='catch'>
<h4 class='heading'>
bait.catch(name, cb)
<a href="#catch" class='heading-link'>
<i class="fas fa-paperclip"></i>
</a>
</h4>
### hooks(name) -> table
Returns a table with hooks (callback functions) on the event with `name`.
Catches an event. This function can be used to act on events.
#### Parameters
`string` **`name`**
The name of the hook.
### 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.
`function` **`cb`**
The function that will be called when the hook is thrown.
### throw(name, ...args)
Throws a hook with `name` with the provided `args`
#### Example
```lua
bait.catch('hilbish.exit', function()
print 'Goodbye Hilbish!'
end)
````
</div>
<hr><div id='catchOnce'>
<h4 class='heading'>
bait.catchOnce(name, cb)
<a href="#catchOnce" class='heading-link'>
<i class="fas fa-paperclip"></i>
</a>
</h4>
Catches an event, but only once. This will remove the hook immediately after it runs for the first time.
#### Parameters
`string` **`name`**
The name of the event
`function` **`cb`**
The function that will be called when the event is thrown.
</div>
<hr><div id='hooks'>
<h4 class='heading'>
bait.hooks(name) -> table
<a href="#hooks" class='heading-link'>
<i class="fas fa-paperclip"></i>
</a>
</h4>
Returns a list of callbacks that are hooked on an event with the corresponding `name`.
#### Parameters
`string` **`name`**
The name of the function
</div>
<hr><div id='release'>
<h4 class='heading'>
bait.release(name, catcher)
<a href="#release" class='heading-link'>
<i class="fas fa-paperclip"></i>
</a>
</h4>
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.
#### Parameters
`string` **`name`**
Name of the event the hook is on
`function` **`catcher`**
Hook function to remove
#### Example
```lua
local hookCallback = function() print 'hi' end
bait.catch('event', hookCallback)
-- a little while later....
bait.release('event', hookCallback)
-- and now hookCallback will no longer be ran for the event.
````
</div>
<hr><div id='throw'>
<h4 class='heading'>
bait.throw(name, ...args)
<a href="#throw" class='heading-link'>
<i class="fas fa-paperclip"></i>
</a>
</h4>
Throws a hook with `name` with the provided `args`.
#### Parameters
`string` **`name`**
The name of the hook.
`any` **`args`** (This type is variadic. You can pass an infinite amount of parameters with this type.)
The arguments to pass to the hook.
#### Example
```lua
bait.throw('greeting', 'world')
-- This can then be listened to via
bait.catch('gretting', function(greetTo)
print('Hello ' .. greetTo)
end)
````
</div>

View File

@ -9,11 +9,10 @@ menu:
## Introduction
Commander is a library for writing custom commands in Lua.
In order to make it easier to write commands for Hilbish,
not require separate scripts and to be able to use in a config,
the Commander library exists. This is like a very simple wrapper
that works with Hilbish for writing commands. Example:
Commander is the library which handles Hilbish commands. This makes
the user able to add Lua-written commands to their shell without making
a separate script in a bin folder. Instead, you may simply use the Commander
library in your Hilbish config.
```lua
local commander = require 'commander'
@ -28,19 +27,65 @@ that will print `Hello world!` to output. One question you may
have is: What is the `sinks` parameter?
The `sinks` parameter is a table with 3 keys: `in`, `out`,
and `err`. The values of these is a <a href="/Hilbish/docs/api/hilbish/#sink" style="text-decoration: none;">Sink</a>.
and `err`. All of them are a <a href="/Hilbish/docs/api/hilbish/#sink" style="text-decoration: none;">Sink</a>.
- `in` is the standard input. You can read from this sink
to get user input. (**This is currently unimplemented.**)
- `out` is standard output. This is usually where text meant for
output should go.
- `err` is standard error. This sink is for writing errors, as the
name would suggest.
- `in` is the standard input.
You may use the read functions on this sink to get input from the user.
- `out` is standard output.
This is usually where command output should go.
- `err` is standard error.
This sink is for writing errors, as the name would suggest.
## Functions
### deregister(name)
Deregisters any command registered with `name`
|||
|----|----|
|<a href="#deregister">deregister(name)</a>|Removes the named command. Note that this will only remove Commander-registered commands.|
|<a href="#register">register(name, cb)</a>|Adds a new command with the given `name`. When Hilbish has to run a command with a name,|
### register(name, cb)
Register a command with `name` that runs `cb` when ran
<hr><div id='deregister'>
<h4 class='heading'>
commander.deregister(name)
<a href="#deregister" class='heading-link'>
<i class="fas fa-paperclip"></i>
</a>
</h4>
Removes the named command. Note that this will only remove Commander-registered commands.
#### Parameters
`string` **`name`**
Name of the command to remove.
</div>
<hr><div id='register'>
<h4 class='heading'>
commander.register(name, cb)
<a href="#register" class='heading-link'>
<i class="fas fa-paperclip"></i>
</a>
</h4>
Adds a new command with the given `name`. When Hilbish has to run a command with a name,
it will run the function providing the arguments and sinks.
#### Parameters
`string` **`name`**
Name of the command
`function` **`cb`**
Callback to handle command invocation
#### Example
```lua
-- When you run the command `hello` in the shell, it will print `Hello world`.
-- If you run it with, for example, `hello Hilbish`, it will print 'Hello Hilbish'
commander.register('hello', function(args, sinks)
local name = 'world'
if #args > 0 then name = args[1] end
sinks.out:writeln('Hello ' .. name)
end)
````
</div>

View File

@ -8,44 +8,223 @@ menu:
---
## 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.
The fs module provides filesystem functions to Hilbish. While Lua's standard
library has some I/O functions, they're missing a lot of the basics. The `fs`
library offers more functions and will work on any operating system Hilbish does.
## Functions
### abs(path) -> string
Gives an absolute version of `path`.
|||
|----|----|
|<a href="#abs">abs(path) -> string</a>|Returns an absolute version of the `path`.|
|<a href="#basename">basename(path) -> string</a>|Returns the "basename," or the last part of the provided `path`. If path is empty,|
|<a href="#cd">cd(dir)</a>|Changes Hilbish's directory to `dir`.|
|<a href="#dir">dir(path) -> string</a>|Returns the directory part of `path`. If a file path like|
|<a href="#glob">glob(pattern) -> matches (table)</a>|Match all files based on the provided `pattern`.|
|<a href="#join">join(...path) -> string</a>|Takes any list of paths and joins them based on the operating system's path separator.|
|<a href="#mkdir">mkdir(name, recursive)</a>|Creates a new directory with the provided `name`.|
|<a href="#readdir">readdir(path) -> table[string]</a>|Returns a list of all files and directories in the provided path.|
|<a href="#stat">stat(path) -> {}</a>|Returns the information about a given `path`.|
### basename(path) -> string
Gives the basename of `path`. For the rules,
see Go's filepath.Base
## Static module fields
|||
|----|----|
|pathSep|The operating system's path separator.|
### cd(dir)
Changes directory to `dir`
<hr><div id='abs'>
<h4 class='heading'>
fs.abs(path) -> string
<a href="#abs" class='heading-link'>
<i class="fas fa-paperclip"></i>
</a>
</h4>
### dir(path) -> string
Returns the directory part of `path`. For the rules, see Go's
filepath.Dir
Returns an absolute version of the `path`.
This can be used to resolve short paths like `..` to `/home/user`.
#### Parameters
`string` **`path`**
### glob(pattern) -> matches (table)
Glob all files and directories that match the pattern.
For the rules, see Go's filepath.Glob
### join(...) -> string
Takes paths and joins them together with the OS's
directory separator (forward or backward slash).
</div>
### mkdir(name, recursive)
Makes a directory called `name`. If `recursive` is true, it will create its parent directories.
<hr><div id='basename'>
<h4 class='heading'>
fs.basename(path) -> string
<a href="#basename" class='heading-link'>
<i class="fas fa-paperclip"></i>
</a>
</h4>
### readdir(dir) -> {}
Returns a table of files in `dir`.
Returns the "basename," or the last part of the provided `path`. If path is empty,
`.` will be returned.
#### Parameters
`string` **`path`**
Path to get the base name of.
### stat(path) -> {}
Returns a table of info about the `path`.
It contains the following keys:
name (string) - Name of the path
size (number) - Size of the path
mode (string) - Permission mode in an octal format string (with leading 0)
isDir (boolean) - If the path is a directory
</div>
<hr><div id='cd'>
<h4 class='heading'>
fs.cd(dir)
<a href="#cd" class='heading-link'>
<i class="fas fa-paperclip"></i>
</a>
</h4>
Changes Hilbish's directory to `dir`.
#### Parameters
`string` **`dir`**
Path to change directory to.
</div>
<hr><div id='dir'>
<h4 class='heading'>
fs.dir(path) -> string
<a href="#dir" class='heading-link'>
<i class="fas fa-paperclip"></i>
</a>
</h4>
Returns the directory part of `path`. If a file path like
`~/Documents/doc.txt` then this function will return `~/Documents`.
#### Parameters
`string` **`path`**
Path to get the directory for.
</div>
<hr><div id='glob'>
<h4 class='heading'>
fs.glob(pattern) -> matches (table)
<a href="#glob" class='heading-link'>
<i class="fas fa-paperclip"></i>
</a>
</h4>
Match all files based on the provided `pattern`.
For the syntax' refer to Go's filepath.Match function: https://pkg.go.dev/path/filepath#Match
#### Parameters
`string` **`pattern`**
Pattern to compare files with.
#### Example
```lua
--[[
Within a folder that contains the following files:
a.txt
init.lua
code.lua
doc.pdf
]]--
local matches = fs.glob './*.lua'
print(matches)
-- -> {'init.lua', 'code.lua'}
````
</div>
<hr><div id='join'>
<h4 class='heading'>
fs.join(...path) -> string
<a href="#join" class='heading-link'>
<i class="fas fa-paperclip"></i>
</a>
</h4>
Takes any list of paths and joins them based on the operating system's path separator.
#### Parameters
`string` **`path`** (This type is variadic. You can pass an infinite amount of parameters with this type.)
Paths to join together
#### Example
```lua
-- This prints the directory for Hilbish's config!
print(fs.join(hilbish.userDir.config, 'hilbish'))
-- -> '/home/user/.config/hilbish' on Linux
````
</div>
<hr><div id='mkdir'>
<h4 class='heading'>
fs.mkdir(name, recursive)
<a href="#mkdir" class='heading-link'>
<i class="fas fa-paperclip"></i>
</a>
</h4>
Creates a new directory with the provided `name`.
With `recursive`, mkdir will create parent directories.
-- This will create the directory foo, then create the directory bar in the
-- foo directory. If recursive is false in this case, it will fail.
fs.mkdir('./foo/bar', true)
#### Parameters
`string` **`name`**
Name of the directory
`boolean` **`recursive`**
Whether to create parent directories for the provided name
#### Example
```lua
````
</div>
<hr><div id='readdir'>
<h4 class='heading'>
fs.readdir(path) -> table[string]
<a href="#readdir" class='heading-link'>
<i class="fas fa-paperclip"></i>
</a>
</h4>
Returns a list of all files and directories in the provided path.
#### Parameters
`string` **`dir`**
</div>
<hr><div id='stat'>
<h4 class='heading'>
fs.stat(path) -> {}
<a href="#stat" class='heading-link'>
<i class="fas fa-paperclip"></i>
</a>
</h4>
Returns the information about a given `path`.
The returned table contains the following values:
name (string) - Name of the path
size (number) - Size of the path in bytes
mode (string) - Unix permission mode in an octal format string (with leading 0)
isDir (boolean) - If the path is a directory
#### Parameters
`string` **`path`**
#### Example
```lua
local inspect = require 'inspect'
local stat = fs.stat '~'
print(inspect(stat))
--[[
Would print the following:
{
isDir = true,
mode = "0755",
name = "username",
size = 12288
}
]]--
````
</div>

View File

@ -11,108 +11,313 @@ menu:
The Hilbish module includes the core API, containing
interfaces and functions which directly relate to shell functionality.
## Interface fields
- `ver`: The version of Hilbish
- `goVersion`: The version of Go that Hilbish was compiled with
- `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`
|||
|----|----|
|<a href="#alias">alias(cmd, orig)</a>|Sets an alias of `cmd` to `orig`|
|<a href="#appendPath">appendPath(dir)</a>|Appends `dir` to $PATH|
|<a href="#complete">complete(scope, cb)</a>|Registers a completion handler for `scope`.|
|<a href="#cwd">cwd() -> string</a>|Returns the current directory of the shell|
|<a href="#exec">exec(cmd)</a>|Replaces running hilbish with `cmd`|
|<a href="#goro">goro(fn)</a>|Puts `fn` in a goroutine|
|<a href="#highlighter">highlighter(line)</a>|Line highlighter handler. This is mainly for syntax highlighting, but in|
|<a href="#hinter">hinter(line, pos)</a>|The command line hint handler. It gets called on every key insert to|
|<a href="#inputMode">inputMode(mode)</a>|Sets the input mode for Hilbish's line reader. Accepts either emacs or vim|
|<a href="#interval">interval(cb, time) -> @Timer</a>|Runs the `cb` function every `time` milliseconds.|
|<a href="#multiprompt">multiprompt(str)</a>|Changes the continued line prompt to `str`|
|<a href="#prependPath">prependPath(dir)</a>|Prepends `dir` to $PATH|
|<a href="#prompt">prompt(str, typ)</a>|Changes the shell prompt to `str`|
|<a href="#read">read(prompt) -> input (string)</a>|Read input from the user, using Hilbish's line editor/input reader.|
|<a href="#run">run(cmd, returnOut) -> exitCode (number), stdout (string), stderr (string)</a>|Runs `cmd` in Hilbish's sh interpreter.|
|<a href="#runnerMode">runnerMode(mode)</a>|Sets the execution/runner mode for interactive Hilbish. This determines whether|
|<a href="#timeout">timeout(cb, time) -> @Timer</a>|Runs the `cb` function after `time` in milliseconds.|
|<a href="#which">which(name) -> string</a>|Checks if `name` is a valid command.|
### appendPath(dir)
Appends `dir` to $PATH
## Static module fields
|||
|----|----|
|ver|The version of Hilbish|
|goVersion|The version of Go that Hilbish was compiled with|
|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|Exit code of the last executed command|
### complete(scope, cb)
Registers a completion handler for `scope`.
A `scope` is currently only expected to be `command.<cmd>`,
replacing <cmd> with the name of the command (for example `command.git`).
`cb` must be a function that returns a table of "completion groups."
Check `doc completions` for more information.
<hr><div id='alias'>
<h4 class='heading'>
hilbish.alias(cmd, orig)
<a href="#alias" class='heading-link'>
<i class="fas fa-paperclip"></i>
</a>
</h4>
### cwd() -> string
Returns the current directory of the shell
Sets an alias of `cmd` to `orig`
#### Parameters
This function has no parameters.
</div>
### exec(cmd)
Replaces running hilbish with `cmd`
<hr><div id='appendPath'>
<h4 class='heading'>
hilbish.appendPath(dir)
<a href="#appendPath" class='heading-link'>
<i class="fas fa-paperclip"></i>
</a>
</h4>
### goro(fn)
Puts `fn` in a goroutine
Appends `dir` to $PATH
#### Parameters
This function has no parameters.
</div>
### 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.
Note that to set a highlighter, one has to override this function.
Example:
```
function hilbish.highlighter(line)
return line:gsub('"%w+"', function(c) return lunacolors.green(c) end)
end
```
This code will highlight all double quoted strings in green.
<hr><div id='complete'>
<h4 class='heading'>
hilbish.complete(scope, cb)
<a href="#complete" class='heading-link'>
<i class="fas fa-paperclip"></i>
</a>
</h4>
### 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.
Registers a completion handler for `scope`.
A `scope` is currently only expected to be `command.<cmd>`,
replacing <cmd> with the name of the command (for example `command.git`).
`cb` must be a function that returns a table of "completion groups."
Check `doc completions` for more information.
#### Parameters
This function has no parameters.
</div>
### inputMode(mode)
Sets the input mode for Hilbish's line reader. Accepts either emacs or vim
<hr><div id='cwd'>
<h4 class='heading'>
hilbish.cwd() -> string
<a href="#cwd" class='heading-link'>
<i class="fas fa-paperclip"></i>
</a>
</h4>
### interval(cb, time) -> <a href="/Hilbish/docs/api/hilbish/hilbish.timers/#timer" style="text-decoration: none;">Timer</a>
Runs the `cb` function every `time` milliseconds.
This creates a timer that starts immediately.
Returns the current directory of the shell
#### Parameters
This function has no parameters.
</div>
### multiprompt(str)
Changes the continued line prompt to `str`
<hr><div id='exec'>
<h4 class='heading'>
hilbish.exec(cmd)
<a href="#exec" class='heading-link'>
<i class="fas fa-paperclip"></i>
</a>
</h4>
### prependPath(dir)
Prepends `dir` to $PATH
Replaces running hilbish with `cmd`
#### Parameters
This function has no parameters.
</div>
### 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
<hr><div id='goro'>
<h4 class='heading'>
hilbish.goro(fn)
<a href="#goro" class='heading-link'>
<i class="fas fa-paperclip"></i>
</a>
</h4>
### read(prompt) -> input (string)
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)
Puts `fn` in a goroutine
#### Parameters
This function has no parameters.
</div>
### run(cmd, returnOut) -> exitCode (number), stdout (string), stderr (string)
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.
<hr><div id='highlighter'>
<h4 class='heading'>
hilbish.highlighter(line)
<a href="#highlighter" class='heading-link'>
<i class="fas fa-paperclip"></i>
</a>
</h4>
### 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.
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.
Note that to set a highlighter, one has to override this function.
Example:
```
function hilbish.highlighter(line)
return line:gsub('"%w+"', function(c) return lunacolors.green(c) end)
end
```
This code will highlight all double quoted strings in green.
#### Parameters
This function has no parameters.
</div>
### timeout(cb, time) -> <a href="/Hilbish/docs/api/hilbish/hilbish.timers/#timer" style="text-decoration: none;">Timer</a>
Runs the `cb` function after `time` in milliseconds.
This creates a timer that starts immediately.
<hr><div id='hinter'>
<h4 class='heading'>
hilbish.hinter(line, pos)
<a href="#hinter" class='heading-link'>
<i class="fas fa-paperclip"></i>
</a>
</h4>
### which(name) -> string
Checks if `name` is a valid command.
Will return the path of the binary, or a basename if it's a commander.
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.
#### Parameters
This function has no parameters.
</div>
<hr><div id='inputMode'>
<h4 class='heading'>
hilbish.inputMode(mode)
<a href="#inputMode" class='heading-link'>
<i class="fas fa-paperclip"></i>
</a>
</h4>
Sets the input mode for Hilbish's line reader. Accepts either emacs or vim
#### Parameters
This function has no parameters.
</div>
<hr><div id='interval'>
<h4 class='heading'>
hilbish.interval(cb, time) -> <a href="/Hilbish/docs/api/hilbish/hilbish.timers/#timer" style="text-decoration: none;" id="lol">Timer</a>
<a href="#interval" class='heading-link'>
<i class="fas fa-paperclip"></i>
</a>
</h4>
Runs the `cb` function every `time` milliseconds.
This creates a timer that starts immediately.
#### Parameters
This function has no parameters.
</div>
<hr><div id='multiprompt'>
<h4 class='heading'>
hilbish.multiprompt(str)
<a href="#multiprompt" class='heading-link'>
<i class="fas fa-paperclip"></i>
</a>
</h4>
Changes the continued line prompt to `str`
#### Parameters
This function has no parameters.
</div>
<hr><div id='prependPath'>
<h4 class='heading'>
hilbish.prependPath(dir)
<a href="#prependPath" class='heading-link'>
<i class="fas fa-paperclip"></i>
</a>
</h4>
Prepends `dir` to $PATH
#### Parameters
This function has no parameters.
</div>
<hr><div id='prompt'>
<h4 class='heading'>
hilbish.prompt(str, typ)
<a href="#prompt" class='heading-link'>
<i class="fas fa-paperclip"></i>
</a>
</h4>
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
#### Parameters
This function has no parameters.
</div>
<hr><div id='read'>
<h4 class='heading'>
hilbish.read(prompt) -> input (string)
<a href="#read" class='heading-link'>
<i class="fas fa-paperclip"></i>
</a>
</h4>
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)
#### Parameters
This function has no parameters.
</div>
<hr><div id='run'>
<h4 class='heading'>
hilbish.run(cmd, returnOut) -> exitCode (number), stdout (string), stderr (string)
<a href="#run" class='heading-link'>
<i class="fas fa-paperclip"></i>
</a>
</h4>
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.
#### Parameters
This function has no parameters.
</div>
<hr><div id='runnerMode'>
<h4 class='heading'>
hilbish.runnerMode(mode)
<a href="#runnerMode" class='heading-link'>
<i class="fas fa-paperclip"></i>
</a>
</h4>
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.
#### Parameters
This function has no parameters.
</div>
<hr><div id='timeout'>
<h4 class='heading'>
hilbish.timeout(cb, time) -> <a href="/Hilbish/docs/api/hilbish/hilbish.timers/#timer" style="text-decoration: none;" id="lol">Timer</a>
<a href="#timeout" class='heading-link'>
<i class="fas fa-paperclip"></i>
</a>
</h4>
Runs the `cb` function after `time` in milliseconds.
This creates a timer that starts immediately.
#### Parameters
This function has no parameters.
</div>
<hr><div id='which'>
<h4 class='heading'>
hilbish.which(name) -> string
<a href="#which" class='heading-link'>
<i class="fas fa-paperclip"></i>
</a>
</h4>
Checks if `name` is a valid command.
Will return the path of the binary, or a basename if it's a commander.
#### Parameters
This function has no parameters.
</div>
## Types
<hr>
## Sink
A sink is a structure that has input and/or output to/from
a desination.

View File

@ -1,5 +1,5 @@
---
title: Interface hilbish.aliases
title: Module hilbish.aliases
description: command aliasing
layout: doc
menu:
@ -11,15 +11,62 @@ menu:
The alias interface deals with all command aliases in Hilbish.
## Functions
### add(alias, cmd)
This is an alias (ha) for the `hilbish.alias` function.
|||
|----|----|
|<a href="#aliases.add">add(alias, cmd)</a>|This is an alias (ha) for the `hilbish.alias` function.|
|<a href="#aliases.delete">delete(name)</a>|Removes an alias.|
|<a href="#aliases.list">list() -> table<string, string></a>|Get a table of all aliases, with string keys as the alias and the value as the command.|
|<a href="#aliases.resolve">resolve(alias) -> command (string)</a>|Tries to resolve an alias to its command.|
### delete(name)
Removes an alias.
<hr><div id='aliases.add'>
<h4 class='heading'>
hilbish.aliases.add(alias, cmd)
<a href="#aliases.add" class='heading-link'>
<i class="fas fa-paperclip"></i>
</a>
</h4>
### list() -> table\<string, string>
Get a table of all aliases, with string keys as the alias and the value as the command.
This is an alias (ha) for the `hilbish.alias` function.
#### Parameters
This function has no parameters.
</div>
### resolve(alias) -> command (string)
Tries to resolve an alias to its command.
<hr><div id='aliases.delete'>
<h4 class='heading'>
hilbish.aliases.delete(name)
<a href="#aliases.delete" class='heading-link'>
<i class="fas fa-paperclip"></i>
</a>
</h4>
Removes an alias.
#### Parameters
This function has no parameters.
</div>
<hr><div id='aliases.list'>
<h4 class='heading'>
hilbish.aliases.list() -> table\<string, string>
<a href="#aliases.list" class='heading-link'>
<i class="fas fa-paperclip"></i>
</a>
</h4>
Get a table of all aliases, with string keys as the alias and the value as the command.
#### Parameters
This function has no parameters.
</div>
<hr><div id='aliases.resolve'>
<h4 class='heading'>
hilbish.aliases.resolve(alias) -> command (string)
<a href="#aliases.resolve" class='heading-link'>
<i class="fas fa-paperclip"></i>
</a>
</h4>
Tries to resolve an alias to its command.
#### Parameters
This function has no parameters.
</div>

View File

@ -1,5 +1,5 @@
---
title: Interface hilbish.completions
title: Module hilbish.completions
description: tab completions
layout: doc
menu:
@ -11,19 +11,66 @@ menu:
The completions interface deals with tab completions.
## Functions
### call(name, query, ctx, fields) -> completionGroups (table), prefix (string)
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`.
You can check `doc completions` for info on the `completionGroups` return value.
|||
|----|----|
|<a href="#completions.call">call(name, query, ctx, fields) -> completionGroups (table), prefix (string)</a>|Calls a completer function. This is mainly used to call|
|<a href="#completions.handler">handler(line, pos)</a>|The handler function is the callback for tab completion in Hilbish.|
|<a href="#completions.bins">bins(query, ctx, fields) -> entries (table), prefix (string)</a>|Returns binary/executale completion candidates based on the provided query.|
|<a href="#completions.files">files(query, ctx, fields) -> entries (table), prefix (string)</a>|Returns file completion candidates based on the provided query.|
### handler(line, pos)
The handler function is the callback for tab completion in Hilbish.
You can check the completions doc for more info.
<hr><div id='completions.call'>
<h4 class='heading'>
hilbish.completions.call(name, query, ctx, fields) -> completionGroups (table), prefix (string)
<a href="#completions.call" class='heading-link'>
<i class="fas fa-paperclip"></i>
</a>
</h4>
### bins(query, ctx, fields) -> entries (table), prefix (string)
Returns binary/executale completion candidates based on the provided query.
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`.
You can check `doc completions` for info on the `completionGroups` return value.
#### Parameters
This function has no parameters.
</div>
### files(query, ctx, fields) -> entries (table), prefix (string)
Returns file completion candidates based on the provided query.
<hr><div id='completions.handler'>
<h4 class='heading'>
hilbish.completions.handler(line, pos)
<a href="#completions.handler" class='heading-link'>
<i class="fas fa-paperclip"></i>
</a>
</h4>
The handler function is the callback for tab completion in Hilbish.
You can check the completions doc for more info.
#### Parameters
This function has no parameters.
</div>
<hr><div id='completions.bins'>
<h4 class='heading'>
hilbish.completions.bins(query, ctx, fields) -> entries (table), prefix (string)
<a href="#completions.bins" class='heading-link'>
<i class="fas fa-paperclip"></i>
</a>
</h4>
Returns binary/executale completion candidates based on the provided query.
#### Parameters
This function has no parameters.
</div>
<hr><div id='completions.files'>
<h4 class='heading'>
hilbish.completions.files(query, ctx, fields) -> entries (table), prefix (string)
<a href="#completions.files" class='heading-link'>
<i class="fas fa-paperclip"></i>
</a>
</h4>
Returns file completion candidates based on the provided query.
#### Parameters
This function has no parameters.
</div>

View File

@ -1,5 +1,5 @@
---
title: Interface hilbish.editor
title: Module hilbish.editor
description: interactions for Hilbish's line reader
layout: doc
menu:
@ -12,19 +12,77 @@ The hilbish.editor interface provides functions to
directly interact with the line editor in use.
## Functions
### getLine() -> string
Returns the current input line.
|||
|----|----|
|<a href="#editor.getLine">getLine() -> string</a>|Returns the current input line.|
|<a href="#editor.getVimRegister">getVimRegister(register) -> string</a>|Returns the text that is at the register.|
|<a href="#editor.insert">insert(text)</a>|Inserts text into the line.|
|<a href="#editor.getChar">getChar() -> string</a>|Reads a keystroke from the user. This is in a format|
|<a href="#editor.setVimRegister">setVimRegister(register, text)</a>|Sets the vim register at `register` to hold the passed text.|
### getVimRegister(register) -> string
Returns the text that is at the register.
<hr><div id='editor.getLine'>
<h4 class='heading'>
hilbish.editor.getLine() -> string
<a href="#editor.getLine" class='heading-link'>
<i class="fas fa-paperclip"></i>
</a>
</h4>
### insert(text)
Inserts text into the line.
Returns the current input line.
#### Parameters
This function has no parameters.
</div>
### getChar() -> string
Reads a keystroke from the user. This is in a format
of something like Ctrl-L..
<hr><div id='editor.getVimRegister'>
<h4 class='heading'>
hilbish.editor.getVimRegister(register) -> string
<a href="#editor.getVimRegister" class='heading-link'>
<i class="fas fa-paperclip"></i>
</a>
</h4>
### setVimRegister(register, text)
Sets the vim register at `register` to hold the passed text.
Returns the text that is at the register.
#### Parameters
This function has no parameters.
</div>
<hr><div id='editor.insert'>
<h4 class='heading'>
hilbish.editor.insert(text)
<a href="#editor.insert" class='heading-link'>
<i class="fas fa-paperclip"></i>
</a>
</h4>
Inserts text into the line.
#### Parameters
This function has no parameters.
</div>
<hr><div id='editor.getChar'>
<h4 class='heading'>
hilbish.editor.getChar() -> string
<a href="#editor.getChar" class='heading-link'>
<i class="fas fa-paperclip"></i>
</a>
</h4>
Reads a keystroke from the user. This is in a format
of something like Ctrl-L..
#### Parameters
This function has no parameters.
</div>
<hr><div id='editor.setVimRegister'>
<h4 class='heading'>
hilbish.editor.setVimRegister(register, text)
<a href="#editor.setVimRegister" class='heading-link'>
<i class="fas fa-paperclip"></i>
</a>
</h4>
Sets the vim register at `register` to hold the passed text.
#### Parameters
This function has no parameters.
</div>

View File

@ -1,5 +1,5 @@
---
title: Interface hilbish.history
title: Module hilbish.history
description: command history
layout: doc
menu:
@ -13,18 +13,76 @@ This includes the ability to override functions to change the main
method of saving history.
## Functions
### add(cmd)
Adds a command to the history.
|||
|----|----|
|<a href="#history.add">add(cmd)</a>|Adds a command to the history.|
|<a href="#history.all">all() -> table</a>|Retrieves all history.|
|<a href="#history.clear">clear()</a>|Deletes all commands from the history.|
|<a href="#history.get">get(idx)</a>|Retrieves a command from the history based on the `idx`.|
|<a href="#history.size">size() -> number</a>|Returns the amount of commands in the history.|
### all() -> table
Retrieves all history.
<hr><div id='history.add'>
<h4 class='heading'>
hilbish.history.add(cmd)
<a href="#history.add" class='heading-link'>
<i class="fas fa-paperclip"></i>
</a>
</h4>
### clear()
Deletes all commands from the history.
Adds a command to the history.
#### Parameters
This function has no parameters.
</div>
### get(idx)
Retrieves a command from the history based on the `idx`.
<hr><div id='history.all'>
<h4 class='heading'>
hilbish.history.all() -> table
<a href="#history.all" class='heading-link'>
<i class="fas fa-paperclip"></i>
</a>
</h4>
### size() -> number
Returns the amount of commands in the history.
Retrieves all history.
#### Parameters
This function has no parameters.
</div>
<hr><div id='history.clear'>
<h4 class='heading'>
hilbish.history.clear()
<a href="#history.clear" class='heading-link'>
<i class="fas fa-paperclip"></i>
</a>
</h4>
Deletes all commands from the history.
#### Parameters
This function has no parameters.
</div>
<hr><div id='history.get'>
<h4 class='heading'>
hilbish.history.get(idx)
<a href="#history.get" class='heading-link'>
<i class="fas fa-paperclip"></i>
</a>
</h4>
Retrieves a command from the history based on the `idx`.
#### Parameters
This function has no parameters.
</div>
<hr><div id='history.size'>
<h4 class='heading'>
hilbish.history.size() -> number
<a href="#history.size" class='heading-link'>
<i class="fas fa-paperclip"></i>
</a>
</h4>
Returns the amount of commands in the history.
#### Parameters
This function has no parameters.
</div>

View File

@ -1,5 +1,5 @@
---
title: Interface hilbish.jobs
title: Module hilbish.jobs
description: background job management
layout: doc
menu:
@ -15,32 +15,95 @@ 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.
## Functions
### add(cmdstr, args, execPath)
Adds a new job to the job table. Note that this does not immediately run it.
|||
|----|----|
|<a href="#jobs.add">add(cmdstr, args, execPath)</a>|Adds a new job to the job table. Note that this does not immediately run it.|
|<a href="#jobs.all">all() -> table<@Job></a>|Returns a table of all job objects.|
|<a href="#jobs.disown">disown(id)</a>|Disowns a job. This deletes it from the job table.|
|<a href="#jobs.get">get(id) -> @Job</a>|Get a job object via its ID.|
|<a href="#jobs.last">last() -> @Job</a>|Returns the last added job from the table.|
### all() -> table\<<a href="/Hilbish/docs/api/hilbish/hilbish.jobs/#job" style="text-decoration: none;">Job</a>>
Returns a table of all job objects.
<hr><div id='jobs.add'>
<h4 class='heading'>
hilbish.jobs.add(cmdstr, args, execPath)
<a href="#jobs.add" class='heading-link'>
<i class="fas fa-paperclip"></i>
</a>
</h4>
### disown(id)
Disowns a job. This deletes it from the job table.
Adds a new job to the job table. Note that this does not immediately run it.
#### Parameters
This function has no parameters.
</div>
### get(id) -> <a href="/Hilbish/docs/api/hilbish/hilbish.jobs/#job" style="text-decoration: none;">Job</a>
Get a job object via its ID.
<hr><div id='jobs.all'>
<h4 class='heading'>
hilbish.jobs.all() -> table\<<a href="/Hilbish/docs/api/hilbish/hilbish.jobs/#job" style="text-decoration: none;" id="lol">Job</a>>
<a href="#jobs.all" class='heading-link'>
<i class="fas fa-paperclip"></i>
</a>
</h4>
### last() -> <a href="/Hilbish/docs/api/hilbish/hilbish.jobs/#job" style="text-decoration: none;">Job</a>
Returns the last added job from the table.
Returns a table of all job objects.
#### Parameters
This function has no parameters.
</div>
<hr><div id='jobs.disown'>
<h4 class='heading'>
hilbish.jobs.disown(id)
<a href="#jobs.disown" class='heading-link'>
<i class="fas fa-paperclip"></i>
</a>
</h4>
Disowns a job. This deletes it from the job table.
#### Parameters
This function has no parameters.
</div>
<hr><div id='jobs.get'>
<h4 class='heading'>
hilbish.jobs.get(id) -> <a href="/Hilbish/docs/api/hilbish/hilbish.jobs/#job" style="text-decoration: none;" id="lol">Job</a>
<a href="#jobs.get" class='heading-link'>
<i class="fas fa-paperclip"></i>
</a>
</h4>
Get a job object via its ID.
#### Parameters
This function has no parameters.
</div>
<hr><div id='jobs.last'>
<h4 class='heading'>
hilbish.jobs.last() -> <a href="/Hilbish/docs/api/hilbish/hilbish.jobs/#job" style="text-decoration: none;" id="lol">Job</a>
<a href="#jobs.last" class='heading-link'>
<i class="fas fa-paperclip"></i>
</a>
</h4>
Returns the last added job from the table.
#### Parameters
This function has no parameters.
</div>
## Types
<hr>
## Job
The Job type describes a Hilbish job.
### 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.
## 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.|
### Methods
#### background()

View File

@ -1,5 +1,5 @@
---
title: Interface hilbish.module
title: Module hilbish.module
description: native module loading
layout: doc
menu:
@ -43,11 +43,27 @@ func Loader(rtm *rt.Runtime) rt.Value {
This can be compiled with `go build -buildmode=plugin plugin.go`.
If you attempt to require and print the result (`print(require 'plugin')`), it will show "hello world!"
## Interface fields
- `paths`: A list of paths to search when loading native modules. This is in the style of Lua search paths and will be used when requiring native modules. Example: `?.so;?/?.so`
## Functions
### load(path)
Loads a module at the designated `path`.
It will throw if any error occurs.
|||
|----|----|
|<a href="#module.load">load(path)</a>|Loads a module at the designated `path`.|
## Static module fields
|||
|----|----|
|paths|A list of paths to search when loading native modules. This is in the style of Lua search paths and will be used when requiring native modules. Example: `?.so;?/?.so`|
<hr><div id='module.load'>
<h4 class='heading'>
hilbish.module.load(path)
<a href="#module.load" class='heading-link'>
<i class="fas fa-paperclip"></i>
</a>
</h4>
Loads a module at the designated `path`.
It will throw if any error occurs.
#### Parameters
This function has no parameters.
</div>

View File

@ -1,5 +1,5 @@
---
title: Interface hilbish.os
title: Module hilbish.os
description: OS Info
layout: doc
menu:
@ -12,8 +12,10 @@ 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
## Static module fields
|||
|----|----|
|family|Family name of the current OS|
|name|Pretty name of the current OS|
|version|Version of the current OS|

View File

@ -1,5 +1,5 @@
---
title: Interface hilbish.runner
title: Module hilbish.runner
description: interactive command runner customization
layout: doc
menu:
@ -15,17 +15,53 @@ 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.
|||
|----|----|
|<a href="#runner.setMode">setMode(cb)</a>|This is the same as the `hilbish.runnerMode` function. It takes a callback,|
|<a href="#runner.lua">lua(cmd)</a>|Evaluates `cmd` as Lua input. This is the same as using `dofile`|
|<a href="#runner.sh">sh(cmd)</a>|Runs a command in Hilbish's shell script interpreter.|
### lua(cmd)
Evaluates `cmd` as Lua input. This is the same as using `dofile`
or `load`, but is appropriated for the runner interface.
<hr><div id='runner.setMode'>
<h4 class='heading'>
hilbish.runner.setMode(cb)
<a href="#runner.setMode" class='heading-link'>
<i class="fas fa-paperclip"></i>
</a>
</h4>
### sh(cmd)
Runs a command in Hilbish's shell script interpreter.
This is the equivalent of using `source`.
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.
#### Parameters
This function has no parameters.
</div>
<hr><div id='runner.lua'>
<h4 class='heading'>
hilbish.runner.lua(cmd)
<a href="#runner.lua" class='heading-link'>
<i class="fas fa-paperclip"></i>
</a>
</h4>
Evaluates `cmd` as Lua input. This is the same as using `dofile`
or `load`, but is appropriated for the runner interface.
#### Parameters
This function has no parameters.
</div>
<hr><div id='runner.sh'>
<h4 class='heading'>
hilbish.runner.sh(cmd)
<a href="#runner.sh" class='heading-link'>
<i class="fas fa-paperclip"></i>
</a>
</h4>
Runs a command in Hilbish's shell script interpreter.
This is the equivalent of using `source`.
#### Parameters
This function has no parameters.
</div>

View File

@ -1,5 +1,5 @@
---
title: Interface hilbish.timers
title: Module hilbish.timers
description: timeout and interval API
layout: doc
menu:
@ -30,25 +30,57 @@ t:start()
print(t.running) // true
```
## Interface fields
- `INTERVAL`: Constant for an interval timer type
- `TIMEOUT`: Constant for a timeout timer type
## Functions
### create(type, time, callback) -> <a href="/Hilbish/docs/api/hilbish/hilbish.timers/#timer" style="text-decoration: none;">Timer</a>
Creates a timer that runs based on the specified `time` in milliseconds.
The `type` can either be `hilbish.timers.INTERVAL` or `hilbish.timers.TIMEOUT`
|||
|----|----|
|<a href="#timers.create">create(type, time, callback) -> @Timer</a>|Creates a timer that runs based on the specified `time` in milliseconds.|
|<a href="#timers.get">get(id) -> @Timer</a>|Retrieves a timer via its ID.|
### get(id) -> <a href="/Hilbish/docs/api/hilbish/hilbish.timers/#timer" style="text-decoration: none;">Timer</a>
Retrieves a timer via its ID.
## Static module fields
|||
|----|----|
|INTERVAL|Constant for an interval timer type|
|TIMEOUT|Constant for a timeout timer type|
<hr><div id='timers.create'>
<h4 class='heading'>
hilbish.timers.create(type, time, callback) -> <a href="/Hilbish/docs/api/hilbish/hilbish.timers/#timer" style="text-decoration: none;" id="lol">Timer</a>
<a href="#timers.create" class='heading-link'>
<i class="fas fa-paperclip"></i>
</a>
</h4>
Creates a timer that runs based on the specified `time` in milliseconds.
The `type` can either be `hilbish.timers.INTERVAL` or `hilbish.timers.TIMEOUT`
#### Parameters
This function has no parameters.
</div>
<hr><div id='timers.get'>
<h4 class='heading'>
hilbish.timers.get(id) -> <a href="/Hilbish/docs/api/hilbish/hilbish.timers/#timer" style="text-decoration: none;" id="lol">Timer</a>
<a href="#timers.get" class='heading-link'>
<i class="fas fa-paperclip"></i>
</a>
</h4>
Retrieves a timer via its ID.
#### Parameters
This function has no parameters.
</div>
## Types
<hr>
## Timer
The Job type describes a Hilbish timer.
### Properties
- `type`: What type of timer it is
- `running`: If the timer is running
- `duration`: The duration in milliseconds that the timer will run
## 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|
### Methods
#### start()

View File

@ -1,5 +1,5 @@
---
title: Interface hilbish.userDir
title: Module hilbish.userDir
description: user-related directories
layout: doc
menu:
@ -12,7 +12,9 @@ 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
## Static module fields
|||
|----|----|
|config|The user's config directory|
|data|The user's directory for program data|

View File

@ -11,16 +11,63 @@ menu:
The terminal library is a simple and lower level library for certain terminal interactions.
## Functions
### restoreState()
Restores the last saved state of the terminal
|||
|----|----|
|<a href="#restoreState">restoreState()</a>|Restores the last saved state of the terminal|
|<a href="#saveState">saveState()</a>|Saves the current state of the terminal|
|<a href="#setRaw">setRaw()</a>|Puts the terminal in raw mode|
|<a href="#size">size()</a>|Gets the dimensions of the terminal. Returns a table with `width` and `height`|
### saveState()
Saves the current state of the terminal
<hr><div id='restoreState'>
<h4 class='heading'>
terminal.restoreState()
<a href="#restoreState" class='heading-link'>
<i class="fas fa-paperclip"></i>
</a>
</h4>
### setRaw()
Puts the terminal in raw mode
Restores the last saved state of the terminal
#### Parameters
This function has no parameters.
</div>
### 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
<hr><div id='saveState'>
<h4 class='heading'>
terminal.saveState()
<a href="#saveState" class='heading-link'>
<i class="fas fa-paperclip"></i>
</a>
</h4>
Saves the current state of the terminal
#### Parameters
This function has no parameters.
</div>
<hr><div id='setRaw'>
<h4 class='heading'>
terminal.setRaw()
<a href="#setRaw" class='heading-link'>
<i class="fas fa-paperclip"></i>
</a>
</h4>
Puts the terminal in raw mode
#### Parameters
This function has no parameters.
</div>
<hr><div id='size'>
<h4 class='heading'>
terminal.size()
<a href="#size" class='heading-link'>
<i class="fas fa-paperclip"></i>
</a>
</h4>
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
#### Parameters
This function has no parameters.
</div>

View File

@ -15,11 +15,12 @@ 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. You can also check the sidebar.
# 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.
# Does it have "autocompletion" or "tab completion"
Of course! This is a modern shell. Hilbish provides a way for users
to write tab completion for any command and/or the whole shell.
Inline hinting and syntax highlighting are also available.

View File

@ -1,13 +1,11 @@
Here is a list of bait hooks that are thrown by Hilbish. If a hook is related
to a command, it will have the `command` scope, as example.
---
title: Hooks
description:
layout: doc
weight: -50
menu:
docs
---
Here is the format for a doc for a hook:
+ <hook name> -> <args> > <description>
`<args>` just means the arguments of the hook. If a hook doc has the format
of `arg...`, it means the hook can take/recieve any number of `arg`.
+ error -> eventName, handler, err > Emitted when there is an error in
an event handler. The `eventName` is the name of the event the handler
is for, the `handler` is the callback function, and `err` is the error
message.
Hooks are Hilbish's versions of events, which are used via the [Bait](../api/bait) module.
For more detail on how to act on these hooks, you may check the Bait page.

View File

@ -1,12 +1,21 @@
+ `command.preexec` -> input, cmdStr > Thrown before a command
---
title: Command
description:
layout: doc
menu:
docs:
parent: "Hooks"
---
- `command.preexec` -> input, cmdStr > Thrown before a command
is executed. The `input` is the user written command, while `cmdStr`
is what will be executed (`input` will have aliases while `cmdStr`
will have alias resolved input).
+ `command.exit` -> code, cmdStr > Thrown when a command exits.
- `command.exit` -> code, cmdStr > Thrown when a command exits.
`code` is the exit code of the command, and `cmdStr` is the command that was run.
+ `command.not-found` -> cmdStr > Thrown when a command is not found.
- `command.not-found` -> cmdStr > Thrown when a command is not found.
+ `command.not-executable` -> cmdStr > Thrown when Hilbish attempts to run a file
- `command.not-executable` -> cmdStr > Thrown when Hilbish attempts to run a file
that is not executable.

View File

@ -1,3 +1,12 @@
---
title: Hilbish
description:
layout: doc
menu:
docs:
parent: "Hooks"
---
+ `hilbish.exit` > Sent when Hilbish is about to exit.
+ `hilbish.vimMode` -> modeName > Sent when Hilbish's Vim mode is changed (example insert to normal mode),

View File

@ -1,3 +1,12 @@
---
title: Signal
description:
layout: doc
menu:
docs:
parent: "Hooks"
---
+ `signal.sigint` > Sent when Hilbish receives SIGINT (on Ctrl-C).
+ `signal.resize` > Sent when the terminal is resized.

View File

@ -2,31 +2,27 @@
local bait = {}
--- Catches a hook with `name`. Runs the `cb` when it is thrown
--- @param name string
--- @param cb function
--- Catches an event. This function can be used to act on events.
---
---
function bait.catch(name, cb) end
--- Same as catch, but only runs the `cb` once and then removes the hook
--- @param name string
--- @param cb function
--- Catches an event, but only once. This will remove the hook immediately after it runs for the first time.
function bait.catchOnce(name, cb) end
--- Returns a table with hooks (callback functions) on the event with `name`.
--- @param name string
--- @returns table<function>
--- Returns a list of callbacks that are hooked on an event with the corresponding `name`.
function bait.hooks(name) end
--- 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.
--- @param name string
--- @param catcher function
---
---
function bait.release(name, catcher) end
--- Throws a hook with `name` with the provided `args`
--- @param name string
--- @vararg any
--- Throws a hook with `name` with the provided `args`.
---
---
function bait.throw(name, ...args) end
return bait

View File

@ -2,13 +2,13 @@
local commander = {}
--- Deregisters any command registered with `name`
--- @param name string
--- Removes the named command. Note that this will only remove Commander-registered commands.
function commander.deregister(name) end
--- Register a command with `name` that runs `cb` when ran
--- @param name string
--- @param cb function
--- Adds a new command with the given `name`. When Hilbish has to run a command with a name,
--- it will run the function providing the arguments and sinks.
---
---
function commander.register(name, cb) end
return commander

View File

@ -2,56 +2,51 @@
local fs = {}
--- Gives an absolute version of `path`.
--- @param path string
--- @returns string
--- Returns an absolute version of the `path`.
--- This can be used to resolve short paths like `..` to `/home/user`.
function fs.abs(path) end
--- Gives the basename of `path`. For the rules,
--- see Go's filepath.Base
--- @returns string
--- Returns the "basename," or the last part of the provided `path`. If path is empty,
--- `.` will be returned.
function fs.basename(path) end
--- Changes directory to `dir`
--- @param dir string
--- Changes Hilbish's directory to `dir`.
function fs.cd(dir) end
--- Returns the directory part of `path`. For the rules, see Go's
--- filepath.Dir
--- @param path string
--- @returns string
--- Returns the directory part of `path`. If a file path like
--- `~/Documents/doc.txt` then this function will return `~/Documents`.
function fs.dir(path) end
--- Glob all files and directories that match the pattern.
--- For the rules, see Go's filepath.Glob
--- @param pattern string
--- @returns table
--- Match all files based on the provided `pattern`.
--- For the syntax' refer to Go's filepath.Match function: https://pkg.go.dev/path/filepath#Match
---
---
function fs.glob(pattern) end
--- Takes paths and joins them together with the OS's
--- directory separator (forward or backward slash).
--- @vararg string
--- @returns string
function fs.join(...) end
--- Takes any list of paths and joins them based on the operating system's path separator.
---
---
function fs.join(...path) end
--- Makes a directory called `name`. If `recursive` is true, it will create its parent directories.
--- @param name string
--- @param recursive boolean
--- Creates a new directory with the provided `name`.
--- With `recursive`, mkdir will create parent directories.
---
--- -- This will create the directory foo, then create the directory bar in the
--- -- foo directory. If recursive is false in this case, it will fail.
--- fs.mkdir('./foo/bar', true)
function fs.mkdir(name, recursive) end
--- Returns a table of files in `dir`.
--- @param dir string
--- @return table
function fs.readdir(dir) end
--- Returns a list of all files and directories in the provided path.
function fs.readdir(path) end
--- Returns a table of info about the `path`.
--- It contains the following keys:
--- Returns the information about a given `path`.
--- The returned table contains the following values:
--- name (string) - Name of the path
--- size (number) - Size of the path
--- mode (string) - Permission mode in an octal format string (with leading 0)
--- size (number) - Size of the path in bytes
--- mode (string) - Unix permission mode in an octal format string (with leading 0)
--- isDir (boolean) - If the path is a directory
--- @param path string
--- @returns table
---
---
function fs.stat(path) end
return fs

1
go.mod
View File

@ -4,6 +4,7 @@ go 1.17
require (
github.com/arnodel/golua v0.0.0-20220221163911-dfcf252b6f86
github.com/atsushinee/go-markdown-generator v0.0.0-20191121114853-83f9e1f68504
github.com/blackfireio/osinfo v1.0.3
github.com/maxlandon/readline v0.1.0-beta.0.20211027085530-2b76cabb8036
github.com/pborman/getopt v1.1.0

2
go.sum
View File

@ -8,6 +8,8 @@ github.com/arnodel/edit v0.0.0-20220202110212-dfc8d7a13890/go.mod h1:AcpttpuZBaL
github.com/arnodel/strftime v0.1.6 h1:0hc0pUvk8KhEMXE+htyaOUV42zNcf/csIbjzEFCJqsw=
github.com/arnodel/strftime v0.1.6/go.mod h1:5NbK5XqYK8QpRZpqKNt4OlxLtIB8cotkLk4KTKzJfWs=
github.com/atotto/clipboard v0.1.4/go.mod h1:ZY9tmq7sm5xIbd9bOK4onWV4S6X0u6GY7Vn0Yu86PYI=
github.com/atsushinee/go-markdown-generator v0.0.0-20191121114853-83f9e1f68504 h1:R1/AOzdMbopSliUTTEHvHbyNmnZ3YxY5GvdhTkpPsSY=
github.com/atsushinee/go-markdown-generator v0.0.0-20191121114853-83f9e1f68504/go.mod h1:kHBCvAXJIatTX1pw6tLiOspjGc3MhUDRlog9yrCUS+k=
github.com/blackfireio/osinfo v1.0.3 h1:Yk2t2GTPjBcESv6nDSWZKO87bGMQgO+Hi9OoXPpxX8c=
github.com/blackfireio/osinfo v1.0.3/go.mod h1:Pd987poVNmd5Wsx6PRPw4+w7kLlf9iJxoRKPtPAjOrA=
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=

View File

@ -1,9 +1,28 @@
// 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.
/*
Bait is the event emitter for Hilbish. Much like Node.js and
its `events` system, many actions in Hilbish emit events.
Unlike Node.js, Hilbish events are global. So make sure to
pick a unique name!
Usage of the Bait module consists of userstanding
event-driven architecture, but it's pretty simple:
If you want to act on a certain event, you can `catch` it.
You can act on events via callback functions.
Examples of this are in the Hilbish default config!
Consider this part of it:
```lua
bait.catch('command.exit', function(code)
running = false
doPrompt(code ~= 0)
doNotifyPrompt()
end)
```
What this does is, whenever the `command.exit` event is thrown,
this function will set the user prompt.
*/
package bait
import (
@ -228,31 +247,17 @@ func handleHook(t *rt.Thread, c *rt.GoCont, name string, catcher *rt.Closure, ar
}
}
// throw(name, ...args)
// Throws a hook with `name` with the provided `args`
// --- @param name string
// --- @vararg any
func (b *Bait) bthrow(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
if err := c.Check1Arg(); err != nil {
return nil, err
}
name, err := c.StringArg(0)
if err != nil {
return nil, err
}
ifaceSlice := make([]interface{}, len(c.Etc()))
for i, v := range c.Etc() {
ifaceSlice[i] = v
}
b.Emit(name, ifaceSlice...)
return c.Next(), nil
}
// catch(name, cb)
// Catches a hook with `name`. Runs the `cb` when it is thrown
// --- @param name string
// --- @param cb function
// Catches an event. This function can be used to act on events.
// #param name string The name of the hook.
// #param cb function The function that will be called when the hook is thrown.
/*
#example
bait.catch('hilbish.exit', function()
print 'Goodbye Hilbish!'
end)
#example
*/
func (b *Bait) bcatch(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
name, catcher, err := util.HandleStrCallback(t, c)
if err != nil {
@ -265,9 +270,9 @@ func (b *Bait) bcatch(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
}
// catchOnce(name, cb)
// Same as catch, but only runs the `cb` once and then removes the hook
// --- @param name string
// --- @param cb function
// Catches an event, but only once. This will remove the hook immediately after it runs for the first time.
// #param name string The name of the event
// #param cb function The function that will be called when the event is thrown.
func (b *Bait) bcatchOnce(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
name, catcher, err := util.HandleStrCallback(t, c)
if err != nil {
@ -279,27 +284,10 @@ func (b *Bait) bcatchOnce(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
return c.Next(), nil
}
// 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.
// --- @param name string
// --- @param catcher function
func (b *Bait) brelease(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
name, catcher, err := util.HandleStrCallback(t, c)
if err != nil {
return nil, err
}
b.OffLua(name, catcher)
return c.Next(), nil
}
// hooks(name) -> table
// Returns a table with hooks (callback functions) on the event with `name`.
// --- @param name string
// --- @returns table<function>
// Returns a list of callbacks that are hooked on an event with the corresponding `name`.
// #param name string The name of the function
// #returns table<function>
func (b *Bait) bhooks(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
if err := c.Check1Arg(); err != nil {
return nil, err
@ -327,3 +315,62 @@ func (b *Bait) bhooks(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
return c.PushingNext1(t.Runtime, rt.TableValue(luaHandlers)), nil
}
// 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.
// #param name string Name of the event the hook is on
// #param catcher function Hook function to remove
/*
#example
local hookCallback = function() print 'hi' end
bait.catch('event', hookCallback)
-- a little while later....
bait.release('event', hookCallback)
-- and now hookCallback will no longer be ran for the event.
#example
*/
func (b *Bait) brelease(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
name, catcher, err := util.HandleStrCallback(t, c)
if err != nil {
return nil, err
}
b.OffLua(name, catcher)
return c.Next(), nil
}
// throw(name, ...args)
// #param name string The name of the hook.
// #param args ...any The arguments to pass to the hook.
// Throws a hook with `name` with the provided `args`.
/*
#example
bait.throw('greeting', 'world')
-- This can then be listened to via
bait.catch('gretting', function(greetTo)
print('Hello ' .. greetTo)
end)
#example
*/
func (b *Bait) bthrow(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
if err := c.Check1Arg(); err != nil {
return nil, err
}
name, err := c.StringArg(0)
if err != nil {
return nil, err
}
ifaceSlice := make([]interface{}, len(c.Etc()))
for i, v := range c.Etc() {
ifaceSlice[i] = v
}
b.Emit(name, ifaceSlice...)
return c.Next(), nil
}

View File

@ -1,10 +1,9 @@
// library for custom commands
/*
Commander is a library for writing custom commands in Lua.
In order to make it easier to write commands for Hilbish,
not require separate scripts and to be able to use in a config,
the Commander library exists. This is like a very simple wrapper
that works with Hilbish for writing commands. Example:
Commander is the library which handles Hilbish commands. This makes
the user able to add Lua-written commands to their shell without making
a separate script in a bin folder. Instead, you may simply use the Commander
library in your Hilbish config.
```lua
local commander = require 'commander'
@ -19,14 +18,14 @@ that will print `Hello world!` to output. One question you may
have is: What is the `sinks` parameter?
The `sinks` parameter is a table with 3 keys: `in`, `out`,
and `err`. The values of these is a @Sink.
and `err`. All of them are a @Sink.
- `in` is the standard input. You can read from this sink
to get user input. (**This is currently unimplemented.**)
- `out` is standard output. This is usually where text meant for
output should go.
- `err` is standard error. This sink is for writing errors, as the
name would suggest.
- `in` is the standard input.
You may use the read functions on this sink to get input from the user.
- `out` is standard output.
This is usually where command output should go.
- `err` is standard error.
This sink is for writing errors, as the name would suggest.
*/
package commander
@ -67,9 +66,22 @@ func (c *Commander) loaderFunc(rtm *rt.Runtime) (rt.Value, func()) {
}
// register(name, cb)
// Register a command with `name` that runs `cb` when ran
// --- @param name string
// --- @param cb function
// Adds a new command with the given `name`. When Hilbish has to run a command with a name,
// it will run the function providing the arguments and sinks.
// #param name string Name of the command
// #param cb function Callback to handle command invocation
/*
#example
-- When you run the command `hello` in the shell, it will print `Hello world`.
-- If you run it with, for example, `hello Hilbish`, it will print 'Hello Hilbish'
commander.register('hello', function(args, sinks)
local name = 'world'
if #args > 0 then name = args[1] end
sinks.out:writeln('Hello ' .. name)
end)
#example
*/
func (c *Commander) cregister(t *rt.Thread, ct *rt.GoCont) (rt.Cont, error) {
cmdName, cmd, err := util.HandleStrCallback(t, ct)
if err != nil {
@ -82,8 +94,8 @@ func (c *Commander) cregister(t *rt.Thread, ct *rt.GoCont) (rt.Cont, error) {
}
// deregister(name)
// Deregisters any command registered with `name`
// --- @param name string
// Removes the named command. Note that this will only remove Commander-registered commands.
// #param name string Name of the command to remove.
func (c *Commander) cderegister(t *rt.Thread, ct *rt.GoCont) (rt.Cont, error) {
if err := ct.Check1Arg(); err != nil {
return nil, err

View File

@ -1,7 +1,10 @@
// 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.
/*
The fs module provides filesystem functions to Hilbish. While Lua's standard
library has some I/O functions, they're missing a lot of the basics. The `fs`
library offers more functions and will work on any operating system Hilbish does.
#field pathSep The operating system's path separator.
*/
package fs
import (
@ -42,9 +45,46 @@ func loaderFunc(rtm *rt.Runtime) (rt.Value, func()) {
return rt.TableValue(mod), nil
}
// abs(path) -> string
// Returns an absolute version of the `path`.
// This can be used to resolve short paths like `..` to `/home/user`.
// #param path string
// #returns string
func fabs(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
path, err := c.StringArg(0)
if err != nil {
return nil, err
}
path = util.ExpandHome(path)
abspath, err := filepath.Abs(path)
if err != nil {
return nil, err
}
return c.PushingNext1(t.Runtime, rt.StringValue(abspath)), nil
}
// basename(path) -> string
// Returns the "basename," or the last part of the provided `path`. If path is empty,
// `.` will be returned.
// #param path string Path to get the base name of.
// #returns string
func fbasename(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
if err := c.Check1Arg(); err != nil {
return nil, err
}
path, err := c.StringArg(0)
if err != nil {
return nil, err
}
return c.PushingNext(t.Runtime, rt.StringValue(filepath.Base(path))), nil
}
// cd(dir)
// Changes directory to `dir`
// --- @param dir string
// Changes Hilbish's directory to `dir`.
// #param dir string Path to change directory to.
func fcd(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
if err := c.Check1Arg(); err != nil {
return nil, err
@ -63,10 +103,102 @@ func fcd(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
return c.Next(), err
}
// dir(path) -> string
// Returns the directory part of `path`. If a file path like
// `~/Documents/doc.txt` then this function will return `~/Documents`.
// #param path string Path to get the directory for.
// #returns string
func fdir(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
if err := c.Check1Arg(); err != nil {
return nil, err
}
path, err := c.StringArg(0)
if err != nil {
return nil, err
}
return c.PushingNext(t.Runtime, rt.StringValue(filepath.Dir(path))), nil
}
// glob(pattern) -> matches (table)
// Match all files based on the provided `pattern`.
// For the syntax' refer to Go's filepath.Match function: https://pkg.go.dev/path/filepath#Match
// #param pattern string Pattern to compare files with.
// #returns table A list of file names/paths that match.
/*
#example
--[[
Within a folder that contains the following files:
a.txt
init.lua
code.lua
doc.pdf
]]--
local matches = fs.glob './*.lua'
print(matches)
-- -> {'init.lua', 'code.lua'}
#example
*/
func fglob(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
if err := c.Check1Arg(); err != nil {
return nil, err
}
pattern, err := c.StringArg(0)
if err != nil {
return nil, err
}
matches, err := filepath.Glob(pattern)
if err != nil {
return nil, err
}
luaMatches := rt.NewTable()
for i, match := range matches {
luaMatches.Set(rt.IntValue(int64(i + 1)), rt.StringValue(match))
}
return c.PushingNext(t.Runtime, rt.TableValue(luaMatches)), nil
}
// join(...path) -> string
// Takes any list of paths and joins them based on the operating system's path separator.
// #param path ...string Paths to join together
// #returns string The joined path.
/*
#example
-- This prints the directory for Hilbish's config!
print(fs.join(hilbish.userDir.config, 'hilbish'))
-- -> '/home/user/.config/hilbish' on Linux
#example
*/
func fjoin(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
strs := make([]string, len(c.Etc()))
for i, v := range c.Etc() {
if v.Type() != rt.StringType {
// +2; go indexes of 0 and first arg from above
return nil, fmt.Errorf("bad argument #%d to run (expected string, got %s)", i + 1, v.TypeName())
}
strs[i] = v.AsString()
}
res := filepath.Join(strs...)
return c.PushingNext(t.Runtime, rt.StringValue(res)), nil
}
// mkdir(name, recursive)
// Makes a directory called `name`. If `recursive` is true, it will create its parent directories.
// --- @param name string
// --- @param recursive boolean
// Creates a new directory with the provided `name`.
// With `recursive`, mkdir will create parent directories.
// #param name string Name of the directory
// #param recursive boolean Whether to create parent directories for the provided name
/*
#example
-- This will create the directory foo, then create the directory bar in the
-- foo directory. If recursive is false in this case, it will fail.
fs.mkdir('./foo/bar', true)
*/
func fmkdir(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
if err := c.CheckNArgs(2); err != nil {
return nil, err
@ -93,15 +225,58 @@ func fmkdir(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
return c.Next(), err
}
// readdir(path) -> table[string]
// Returns a list of all files and directories in the provided path.
// #param dir string
// #returns table
func freaddir(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
if err := c.Check1Arg(); err != nil {
return nil, err
}
dir, err := c.StringArg(0)
if err != nil {
return nil, err
}
dir = util.ExpandHome(dir)
names := rt.NewTable()
dirEntries, err := os.ReadDir(dir)
if err != nil {
return nil, err
}
for i, entry := range dirEntries {
names.Set(rt.IntValue(int64(i + 1)), rt.StringValue(entry.Name()))
}
return c.PushingNext1(t.Runtime, rt.TableValue(names)), nil
}
// stat(path) -> {}
// Returns a table of info about the `path`.
// It contains the following keys:
// Returns the information about a given `path`.
// The returned table contains the following values:
// name (string) - Name of the path
// size (number) - Size of the path
// mode (string) - Permission mode in an octal format string (with leading 0)
// size (number) - Size of the path in bytes
// mode (string) - Unix permission mode in an octal format string (with leading 0)
// isDir (boolean) - If the path is a directory
// --- @param path string
// --- @returns table
// #param path string
// #returns table
/*
#example
local inspect = require 'inspect'
local stat = fs.stat '~'
print(inspect(stat))
--[[
Would print the following:
{
isDir = true,
mode = "0755",
name = "username",
size = 12288
}
]]--
#example
*/
func fstat(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
if err := c.Check1Arg(); err != nil {
return nil, err
@ -125,128 +300,3 @@ func fstat(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
return c.PushingNext1(t.Runtime, rt.TableValue(statTbl)), nil
}
// readdir(dir) -> {}
// Returns a table of files in `dir`.
// --- @param dir string
// --- @return table
func freaddir(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
if err := c.Check1Arg(); err != nil {
return nil, err
}
dir, err := c.StringArg(0)
if err != nil {
return nil, err
}
dir = util.ExpandHome(dir)
names := rt.NewTable()
dirEntries, err := os.ReadDir(dir)
if err != nil {
return nil, err
}
for i, entry := range dirEntries {
names.Set(rt.IntValue(int64(i + 1)), rt.StringValue(entry.Name()))
}
return c.PushingNext1(t.Runtime, rt.TableValue(names)), nil
}
// abs(path) -> string
// Gives an absolute version of `path`.
// --- @param path string
// --- @returns string
func fabs(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
path, err := c.StringArg(0)
if err != nil {
return nil, err
}
path = util.ExpandHome(path)
abspath, err := filepath.Abs(path)
if err != nil {
return nil, err
}
return c.PushingNext1(t.Runtime, rt.StringValue(abspath)), nil
}
// basename(path) -> string
// Gives the basename of `path`. For the rules,
// see Go's filepath.Base
// --- @returns string
func fbasename(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
if err := c.Check1Arg(); err != nil {
return nil, err
}
path, err := c.StringArg(0)
if err != nil {
return nil, err
}
return c.PushingNext(t.Runtime, rt.StringValue(filepath.Base(path))), nil
}
// dir(path) -> string
// Returns the directory part of `path`. For the rules, see Go's
// filepath.Dir
// --- @param path string
// --- @returns string
func fdir(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
if err := c.Check1Arg(); err != nil {
return nil, err
}
path, err := c.StringArg(0)
if err != nil {
return nil, err
}
return c.PushingNext(t.Runtime, rt.StringValue(filepath.Dir(path))), nil
}
// glob(pattern) -> matches (table)
// Glob all files and directories that match the pattern.
// For the rules, see Go's filepath.Glob
// --- @param pattern string
// --- @returns table
func fglob(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
if err := c.Check1Arg(); err != nil {
return nil, err
}
pattern, err := c.StringArg(0)
if err != nil {
return nil, err
}
matches, err := filepath.Glob(pattern)
if err != nil {
return nil, err
}
luaMatches := rt.NewTable()
for i, match := range matches {
luaMatches.Set(rt.IntValue(int64(i + 1)), rt.StringValue(match))
}
return c.PushingNext(t.Runtime, rt.TableValue(luaMatches)), nil
}
// join(...) -> string
// Takes paths and joins them together with the OS's
// directory separator (forward or backward slash).
// --- @vararg string
// --- @returns string
func fjoin(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
strs := make([]string, len(c.Etc()))
for i, v := range c.Etc() {
if v.Type() != rt.StringType {
// +2; go indexes of 0 and first arg from above
return nil, fmt.Errorf("bad argument #%d to run (expected string, got %s)", i + 1, v.TypeName())
}
strs[i] = v.AsString()
}
res := filepath.Join(strs...)
return c.PushingNext(t.Runtime, rt.StringValue(res)), nil
}

View File

@ -89,7 +89,7 @@ Available sections: ]] .. table.concat(modules, ', ')
local size = terminal.size()
self.region = {
width = size.width,
height = size.height - 3
height = size.height - 2
}
end
gh:resize()
@ -102,7 +102,8 @@ Available sections: ]] .. table.concat(modules, ', ')
workingPage = self.specialPage
end
self.sink:write(ansikit.getCSI(self.region.height + 2 .. ';1', 'H'))
self.sink:write(ansikit.getCSI(self.region.height + 1 .. ';1', 'H'))
self.sink:write(ansikit.getCSI(0, 'J'))
if not self.isSpecial then
if args[1] == 'api' then
self.sink:writeln(lunacolors.reset(string.format('%s', workingPage.title)))

View File

@ -1,5 +1,5 @@
baseURL = 'https://rosettea.github.io/Hilbish/'
languageCode = 'en-us'
baseURL = 'https://rosettea.github.io/Hilbish/'
title = 'Hilbish'
theme = 'hsh'
enableGitInfo = true
@ -29,6 +29,13 @@ enableGitInfo = true
[markup.goldmark.renderer]
unsafe = true
[markup.highlight]
lineNos = true
lineNumbersInTable = false
noClasses = false
codeFences = true
guessSyntax = true
[author]
[author.sammyette]
name = 'sammyette'

View File

@ -0,0 +1 @@
../../docs

View File

@ -1 +0,0 @@
../../../docs/api/

View File

@ -0,0 +1,89 @@
.chroma {
display: inline-block;
padding: 0.5em;
}
/* Background */ .bg { background-color: #F7F7F7; }
/* PreWrapper */ .chroma { background-color: #F7F7F7; }
/* Other */ .chroma .x { }
/* Error */ .chroma .err { color: #a61717; background-color: #e3d2d2 }
/* CodeLine */ .chroma .cl { }
/* LineTableTD */ .chroma .lntd { vertical-align: top; padding: 0; margin: 0; border: 0; }
/* LineTable */ .chroma .lntable { border-spacing: 0; padding: 0; margin: 0; border: 0; }
/* LineHighlight */ .chroma .hl { background-color: #F7F7F7 }
/* LineNumbersTable */ .chroma .lnt { white-space: pre; user-select: none; margin-right: 0.4em; padding: 0 0.4em 0 0.4em;color: #7f7f7f }
/* LineNumbers */ .chroma .ln { white-space: pre; user-select: none; margin-right: 0.4em; padding: 0 0.4em 0 0.4em;color: #7f7f7f }
/* Line */ .chroma .line { display: flex; }
/* Keyword */ .chroma .k { color: #008800; font-weight: bold }
/* KeywordConstant */ .chroma .kc { color: #008800; font-weight: bold }
/* KeywordDeclaration */ .chroma .kd { color: #008800; font-weight: bold }
/* KeywordNamespace */ .chroma .kn { color: #008800; font-weight: bold }
/* KeywordPseudo */ .chroma .kp { color: #008800 }
/* KeywordReserved */ .chroma .kr { color: #008800; font-weight: bold }
/* KeywordType */ .chroma .kt { color: #888888; font-weight: bold }
/* Name */ .chroma .n { }
/* NameAttribute */ .chroma .na { color: #336699 }
/* NameBuiltin */ .chroma .nb { color: #003388 }
/* NameBuiltinPseudo */ .chroma .bp { }
/* NameClass */ .chroma .nc { color: #bb0066; font-weight: bold }
/* NameConstant */ .chroma .no { color: #003366; font-weight: bold }
/* NameDecorator */ .chroma .nd { color: #555555 }
/* NameEntity */ .chroma .ni { }
/* NameException */ .chroma .ne { color: #bb0066; font-weight: bold }
/* NameFunction */ .chroma .nf { color: #0066bb; font-weight: bold }
/* NameFunctionMagic */ .chroma .fm { }
/* NameLabel */ .chroma .nl { color: #336699; font-style: italic }
/* NameNamespace */ .chroma .nn { color: #bb0066; font-weight: bold }
/* NameOther */ .chroma .nx { }
/* NameProperty */ .chroma .py { color: #336699; font-weight: bold }
/* NameTag */ .chroma .nt { color: #bb0066; font-weight: bold }
/* NameVariable */ .chroma .nv { color: #336699 }
/* NameVariableClass */ .chroma .vc { color: #336699 }
/* NameVariableGlobal */ .chroma .vg { color: #dd7700 }
/* NameVariableInstance */ .chroma .vi { color: #3333bb }
/* NameVariableMagic */ .chroma .vm { }
/* Literal */ .chroma .l { }
/* LiteralDate */ .chroma .ld { }
/* LiteralString */ .chroma .s { color: #dd2200; background-color: #fff0f0 }
/* LiteralStringAffix */ .chroma .sa { color: #dd2200; background-color: #fff0f0 }
/* LiteralStringBacktick */ .chroma .sb { color: #dd2200; background-color: #fff0f0 }
/* LiteralStringChar */ .chroma .sc { color: #dd2200; background-color: #fff0f0 }
/* LiteralStringDelimiter */ .chroma .dl { color: #dd2200; background-color: #fff0f0 }
/* LiteralStringDoc */ .chroma .sd { color: #dd2200; background-color: #fff0f0 }
/* LiteralStringDouble */ .chroma .s2 { color: #dd2200; background-color: #fff0f0 }
/* LiteralStringEscape */ .chroma .se { color: #0044dd; background-color: #fff0f0 }
/* LiteralStringHeredoc */ .chroma .sh { color: #dd2200; background-color: #fff0f0 }
/* LiteralStringInterpol */ .chroma .si { color: #3333bb; background-color: #fff0f0 }
/* LiteralStringOther */ .chroma .sx { color: #22bb22; background-color: #f0fff0 }
/* LiteralStringRegex */ .chroma .sr { color: #008800; background-color: #fff0ff }
/* LiteralStringSingle */ .chroma .s1 { color: #dd2200; background-color: #fff0f0 }
/* LiteralStringSymbol */ .chroma .ss { color: #aa6600; background-color: #fff0f0 }
/* LiteralNumber */ .chroma .m { color: #0000dd; font-weight: bold }
/* LiteralNumberBin */ .chroma .mb { color: #0000dd; font-weight: bold }
/* LiteralNumberFloat */ .chroma .mf { color: #0000dd; font-weight: bold }
/* LiteralNumberHex */ .chroma .mh { color: #0000dd; font-weight: bold }
/* LiteralNumberInteger */ .chroma .mi { color: #0000dd; font-weight: bold }
/* LiteralNumberIntegerLong */ .chroma .il { color: #0000dd; font-weight: bold }
/* LiteralNumberOct */ .chroma .mo { color: #0000dd; font-weight: bold }
/* Operator */ .chroma .o { }
/* OperatorWord */ .chroma .ow { color: #008800 }
/* Punctuation */ .chroma .p { }
/* Comment */ .chroma .c { color: #888888 }
/* CommentHashbang */ .chroma .ch { color: #888888 }
/* CommentMultiline */ .chroma .cm { color: #888888 }
/* CommentSingle */ .chroma .c1 { color: #888888 }
/* CommentSpecial */ .chroma .cs { color: #cc0000; background-color: #fff0f0; font-weight: bold }
/* CommentPreproc */ .chroma .cp { color: #cc0000; font-weight: bold }
/* CommentPreprocFile */ .chroma .cpf { color: #cc0000; font-weight: bold }
/* Generic */ .chroma .g { }
/* GenericDeleted */ .chroma .gd { color: #000000; background-color: #ffdddd }
/* GenericEmph */ .chroma .ge { font-style: italic }
/* GenericError */ .chroma .gr { color: #aa0000 }
/* GenericHeading */ .chroma .gh { color: #333333 }
/* GenericInserted */ .chroma .gi { color: #000000; background-color: #ddffdd }
/* GenericOutput */ .chroma .go { color: #888888 }
/* GenericPrompt */ .chroma .gp { color: #555555 }
/* GenericStrong */ .chroma .gs { font-weight: bold }
/* GenericSubheading */ .chroma .gu { color: #666666 }
/* GenericTraceback */ .chroma .gt { color: #aa0000 }
/* GenericUnderline */ .chroma .gl { text-decoration: underline }
/* TextWhitespace */ .chroma .w { color: #bbbbbb }

View File

@ -23,7 +23,10 @@
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.2.0-beta1/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-0evHe/X+R7YkIZDRvuzKMRqM+OrBnVFBL6DOitfPri4tjfHxaWutUpFmBp4vmVor" crossorigin="anonymous">
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.2.0-beta1/dist/js/bootstrap.bundle.min.js" integrity="sha384-pprn3073KE6tl6bjs2QrFaJGz5/SUsLqktiwsUTF55Jfv3qYSDhgCecCxMW52nD2" crossorigin="anonymous"></script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.1.1/css/all.min.css" integrity="sha512-KfkfwYDsLkIlwQp6LFnl8zNdLGxu9YAA1QvwINks4PhcElQSvqcyVLLD9aMhXd13uQjoXtEKNosOWaZqXgel0g==" crossorigin="anonymous" referrerpolicy="no-referrer" />
{{ $syntax := resources.Get "css/syntax.css" | resources.Minify | resources.Fingerprint }}
<link rel="stylesheet" href="{{ $syntax.RelPermalink }}" integrity="{{ $syntax.Data.Integrity }}">
</link>
<style>
.heading > .heading-link {
opacity: 0
@ -34,5 +37,42 @@
opacity: 1;
transition: all .1s ease-in;
}
@keyframes highlight {
0% {
background: none
}
50% {
background: #fff2cf;
}
100% {
background: none;
}
}
div:target {
animation: highlight 1.2s;
animation-timing-function: cubic-bezier(1,-0.02,.45,.89);
}
table {
border-width: 1px;
border-style: solid;
border-color: #565c64;;
border-collapse: collapse;
margin-bottom: 12px;
}
table td {
padding: 5px;
}
table tr {
border-width: 1px;
}
thead {
display: none;
}
</style>
</head>