feat: add interface docs

docs-refactor
TorchedSammy 2022-12-03 22:50:15 -04:00
parent 23d18ef11c
commit 0b1024de19
Signed by: sammyette
GPG Key ID: 904FC49417B44DCD
11 changed files with 198 additions and 152 deletions

View File

@ -66,8 +66,9 @@ func (a *aliasModule) Resolve(cmdstr string) string {
// lua section // lua section
// #interface // #interface aliases
// ALIAS LOADER TEST // command aliasing
// The alias interface deals with all command aliases in Hilbish.
func (a *aliasModule) Loader(rtm *rt.Runtime) *rt.Table { func (a *aliasModule) Loader(rtm *rt.Runtime) *rt.Table {
// create a lua module with our functions // create a lua module with our functions
hshaliasesLua := map[string]util.LuaExport{ hshaliasesLua := map[string]util.LuaExport{
@ -83,6 +84,9 @@ func (a *aliasModule) Loader(rtm *rt.Runtime) *rt.Table {
return mod return mod
} }
// #interface aliases
// list()
// Get a table of all aliases.
func (a *aliasModule) luaList(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) { func (a *aliasModule) luaList(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
aliasesList := rt.NewTable() aliasesList := rt.NewTable()
for k, v := range a.All() { for k, v := range a.All() {

9
api.go
View File

@ -250,11 +250,12 @@ func hlcwd(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
} }
// read(prompt?) -> input? // read(prompt) -> input
// Read input from the user, using Hilbish's line editor/input reader. // Read input from the user, using Hilbish's line editor/input reader.
// This is a separate instance from the one Hilbish actually uses. // 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) // Returns `input`, will be nil if ctrl + d is pressed, or an error occurs (which shouldn't happen)
// --- @param prompt string // --- @param prompt string|nil
// --- @returns string|nil
func hlread(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) { func hlread(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
luaprompt := c.Arg(0) luaprompt := c.Arg(0)
if typ := luaprompt.Type(); typ != rt.StringType && typ != rt.NilType { if typ := luaprompt.Type(); typ != rt.StringType && typ != rt.NilType {
@ -281,7 +282,7 @@ func hlread(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
} }
/* /*
prompt(str, typ?) prompt(str, typ)
Changes the shell prompt to `str` Changes the shell prompt to `str`
There are a few verbs that can be used in the prompt text. There are a few verbs that can be used in the prompt text.
These will be formatted and replaced with the appropriate values. These will be formatted and replaced with the appropriate values.
@ -289,7 +290,7 @@ These will be formatted and replaced with the appropriate values.
`%u` - Name of current user `%u` - Name of current user
`%h` - Hostname of device `%h` - Hostname of device
--- @param str string --- @param str string
--- @param typ string Type of prompt, being left or right. Left by default. --- @param typ string|nil Type of prompt, being left or right. Left by default.
*/ */
func hlprompt(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) { func hlprompt(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
err := c.Check1Arg() err := c.Check1Arg()

View File

@ -13,7 +13,7 @@ import (
) )
var header = `--- var header = `---
name: Module %s name: %s %s
description: %s description: %s
layout: apidoc layout: apidoc
--- ---
@ -21,24 +21,33 @@ layout: apidoc
` `
type emmyPiece struct { type emmyPiece struct {
FuncName string DocPiece *docPiece
Docs []string Annotations []string
Params []string // we only need to know param name to put in function Params []string // we only need to know param name to put in function
FuncName string
} }
type module struct { type module struct {
Docs []docPiece Docs []docPiece
ShortDescription string ShortDescription string
Description string Description string
Interface bool ParentModule string
HasInterfaces bool
} }
type docPiece struct { type docPiece struct {
Doc []string Doc []string
FuncSig string FuncSig string
FuncName string FuncName string
Interfacing string
ParentModule string
GoFuncName string
IsInterface bool
IsMember bool
} }
var docs = make(map[string]module) var docs = make(map[string]module)
var interfaceDocs = make(map[string]module)
var emmyDocs = make(map[string][]emmyPiece) var emmyDocs = make(map[string][]emmyPiece)
var prefix = map[string]string{ var prefix = map[string]string{
"main": "hl", "main": "hl",
@ -50,17 +59,36 @@ var prefix = map[string]string{
} }
func setupDoc(mod string, fun *doc.Func) *docPiece { func setupDoc(mod string, fun *doc.Func) *docPiece {
if !strings.HasPrefix(fun.Name, "hl") && mod == "main" { docs := strings.TrimSpace(fun.Doc)
inInterface := strings.HasPrefix(docs, "#interface")
if (!strings.HasPrefix(fun.Name, prefix[mod]) && !inInterface) || (strings.ToLower(fun.Name) == "loader" && !inInterface) {
return nil return nil
} }
if !strings.HasPrefix(fun.Name, prefix[mod]) || fun.Name == "Loader" {
return nil pts := strings.Split(docs, "\n")
parts := []string{}
tags := make(map[string][]string)
for _, part := range pts {
if strings.HasPrefix(part, "#") {
tagParts := strings.Split(strings.TrimPrefix(part, "#"), " ")
tags[tagParts[0]] = tagParts[1:]
} else {
parts = append(parts, part)
}
} }
parts := strings.Split(strings.TrimSpace(fun.Doc), "\n")
var interfaces string
funcsig := parts[0] funcsig := parts[0]
doc := parts[1:] doc := parts[1:]
funcName := strings.TrimPrefix(fun.Name, prefix[mod])
funcdoc := []string{} funcdoc := []string{}
em := emmyPiece{FuncName: strings.TrimPrefix(fun.Name, prefix[mod])}
if inInterface {
interfaces = tags["interface"][0]
funcName = interfaces + "." + strings.Split(funcsig, "(")[0]
}
em := emmyPiece{FuncName: funcName}
for _, d := range doc { for _, d := range doc {
if strings.HasPrefix(d, "---") { if strings.HasPrefix(d, "---") {
emmyLine := strings.TrimSpace(strings.TrimPrefix(d, "---")) emmyLine := strings.TrimSpace(strings.TrimPrefix(d, "---"))
@ -72,24 +100,39 @@ func setupDoc(mod string, fun *doc.Func) *docPiece {
if emmyType == "@vararg" { if emmyType == "@vararg" {
em.Params = append(em.Params, "...") // add vararg em.Params = append(em.Params, "...") // add vararg
} }
em.Docs = append(em.Docs, d) em.Annotations = append(em.Annotations, d)
} else { } else {
funcdoc = append(funcdoc, d) funcdoc = append(funcdoc, d)
} }
} }
dps := docPiece{ var isMember bool
if tags["member"] != nil {
isMember = true
}
var parentMod string
if inInterface {
parentMod = mod
}
dps := &docPiece{
Doc: funcdoc, Doc: funcdoc,
FuncSig: funcsig, FuncSig: funcsig,
FuncName: strings.TrimPrefix(fun.Name, prefix[mod]), FuncName: funcName,
Interfacing: interfaces,
GoFuncName: strings.ToLower(fun.Name),
IsInterface: inInterface,
IsMember: isMember,
ParentModule: parentMod,
} }
if strings.HasSuffix(dps.GoFuncName, strings.ToLower("loader")) {
dps.Doc = parts
}
em.DocPiece = dps
emmyDocs[mod] = append(emmyDocs[mod], em) emmyDocs[mod] = append(emmyDocs[mod], em)
return &dps return dps
} }
// feel free to clean this up
// it works, dont really care about the code
func main() { func main() {
fset := token.NewFileSet() fset := token.NewFileSet()
os.Mkdir("docs", 0777) os.Mkdir("docs", 0777)
@ -117,21 +160,36 @@ func main() {
} }
} }
interfaceModules := make(map[string]*module)
for l, f := range pkgs { for l, f := range pkgs {
p := doc.New(f, "./", doc.AllDecls) p := doc.New(f, "./", doc.AllDecls)
pieces := []docPiece{} pieces := []docPiece{}
mod := l mod := l
if mod == "main" {
mod = "hilbish"
}
var hasInterfaces bool
for _, t := range p.Funcs { for _, t := range p.Funcs {
piece := setupDoc(mod, t) piece := setupDoc(mod, t)
if piece != nil { if piece == nil {
pieces = append(pieces, *piece) continue
}
pieces = append(pieces, *piece)
if piece.IsInterface {
hasInterfaces = true
} }
} }
for _, t := range p.Types { for _, t := range p.Types {
for _, m := range t.Methods { for _, m := range t.Methods {
piece := setupDoc(mod, m) piece := setupDoc(mod, m)
if piece != nil { if piece == nil {
pieces = append(pieces, *piece) continue
}
pieces = append(pieces, *piece)
if piece.IsInterface {
hasInterfaces = true
} }
} }
} }
@ -139,27 +197,65 @@ func main() {
descParts := strings.Split(strings.TrimSpace(p.Doc), "\n") descParts := strings.Split(strings.TrimSpace(p.Doc), "\n")
shortDesc := descParts[0] shortDesc := descParts[0]
desc := descParts[1:] desc := descParts[1:]
filteredPieces := []docPiece{}
for _, piece := range pieces {
if !piece.IsInterface {
filteredPieces = append(filteredPieces, piece)
continue
}
modname := piece.ParentModule + "." + piece.Interfacing
if interfaceModules[modname] == nil {
interfaceModules[modname] = &module{
ParentModule: piece.ParentModule,
}
}
if strings.HasSuffix(piece.GoFuncName, strings.ToLower("loader")) {
shortDesc := piece.Doc[0]
desc := piece.Doc[1:]
interfaceModules[modname].ShortDescription = shortDesc
interfaceModules[modname].Description = strings.Join(desc, "\n")
continue
}
interfaceModules[modname].Docs = append(interfaceModules[modname].Docs, piece)
}
docs[mod] = module{ docs[mod] = module{
Docs: pieces, Docs: filteredPieces,
ShortDescription: shortDesc, ShortDescription: shortDesc,
Description: strings.Join(desc, "\n"), Description: strings.Join(desc, "\n"),
HasInterfaces: hasInterfaces,
} }
} }
for key, mod := range interfaceModules {
docs[key] = *mod
}
var wg sync.WaitGroup var wg sync.WaitGroup
wg.Add(len(docs) * 2) wg.Add(len(docs) * 2)
for mod, v := range docs { for mod, v := range docs {
modN := mod docPath := "docs/api/" + mod + ".md"
if mod == "main" { if v.HasInterfaces {
modN = "hilbish" os.Mkdir("docs/api/" + mod, 0777)
os.Remove(docPath) // remove old doc path if it exists
docPath = "docs/api/" + mod + "/_index.md"
}
if v.ParentModule != "" {
docPath = "docs/api/" + v.ParentModule + "/" + mod + ".md"
} }
go func(modName string, modu module) { go func(modname, docPath string, modu module) {
defer wg.Done() defer wg.Done()
modOrIface := "Module"
if modu.ParentModule != "" {
modOrIface = "Interface"
}
f, _ := os.Create("docs/api/" + modName + ".md") f, _ := os.Create(docPath)
f.WriteString(fmt.Sprintf(header, modName, modu.ShortDescription)) f.WriteString(fmt.Sprintf(header, modOrIface, modname, modu.ShortDescription))
f.WriteString(fmt.Sprintf("## Introduction\n%s\n\n## Functions\n", modu.Description)) f.WriteString(fmt.Sprintf("## Introduction\n%s\n\n## Functions\n", modu.Description))
for _, dps := range modu.Docs { for _, dps := range modu.Docs {
f.WriteString(fmt.Sprintf("### %s\n", dps.FuncSig)) f.WriteString(fmt.Sprintf("### %s\n", dps.FuncSig))
@ -170,28 +266,41 @@ func main() {
} }
f.WriteString("\n") f.WriteString("\n")
} }
}(modN, v) }(mod, docPath, v)
go func(md, modName string) { go func(md, modname string, modu module) {
defer wg.Done() defer wg.Done()
ff, _ := os.Create("emmyLuaDocs/" + modName + ".lua") if modu.ParentModule != "" {
ff.WriteString("--- @meta\n\nlocal " + modName + " = {}\n\n") return
for _, em := range emmyDocs[md] {
funcdocs := []string{}
for _, dps := range docs[md].Docs {
if dps.FuncName == em.FuncName {
funcdocs = dps.Doc
}
}
ff.WriteString("--- " + strings.Join(funcdocs, "\n--- ") + "\n")
if len(em.Docs) != 0 {
ff.WriteString(strings.Join(em.Docs, "\n") + "\n")
}
ff.WriteString("function " + modName + "." + em.FuncName + "(" + strings.Join(em.Params, ", ") + ") end\n\n")
} }
ff.WriteString("return " + modName + "\n")
}(mod, modN) ff, _ := os.Create("emmyLuaDocs/" + modname + ".lua")
ff.WriteString("--- @meta\n\nlocal " + modname + " = {}\n\n")
for _, em := range emmyDocs[modname] {
if strings.HasSuffix(em.DocPiece.GoFuncName, strings.ToLower("loader")) {
continue
}
dps := em.DocPiece
funcdocs := dps.Doc
ff.WriteString("--- " + strings.Join(funcdocs, "\n--- ") + "\n")
if len(em.Annotations) != 0 {
ff.WriteString(strings.Join(em.Annotations, "\n") + "\n")
}
accessor := "."
if dps.IsMember {
accessor = ":"
}
signature := strings.Split(dps.FuncSig, " ->")[0]
var intrface string
if dps.IsInterface {
intrface = "." + dps.Interfacing
}
ff.WriteString("function " + modname + intrface + accessor + signature + " end\n\n")
}
ff.WriteString("return " + modname + "\n")
}(mod, mod, v)
} }
wg.Wait() wg.Wait()
} }

View File

@ -172,6 +172,9 @@ func escapeFilename(fname string) string {
return escapeReplaer.Replace(fname) return escapeReplaer.Replace(fname)
} }
// #interface completions
// tab completions
// The completions interface deals with tab completions.
func completionLoader(rtm *rt.Runtime) *rt.Table { func completionLoader(rtm *rt.Runtime) *rt.Table {
exports := map[string]util.LuaExport{ exports := map[string]util.LuaExport{
"files": {luaFileComplete, 3, false}, "files": {luaFileComplete, 3, false},

View File

@ -1,91 +0,0 @@
---
name: Module hilbish
description: the core Hilbish API
layout: apidoc
---
## Introduction
The Hilbish module includes the core API, containing
interfaces and functions which directly relate to shell functionality.
## Functions
### alias(cmd, orig)
Sets an alias of `cmd` to `orig`
### appendPath(dir)
Appends `dir` to $PATH
### complete(scope, cb)
Registers a completion handler for `scope`.
A `scope` is currently only expected to be `command.<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.
### cwd()
Returns the current directory of the shell
### exec(cmd)
Replaces running hilbish with `cmd`
### goro(fn)
Puts `fn` in a goroutine
### highlighter(line)
Line highlighter handler. This is mainly for syntax highlighting, but in
reality could set the input of the prompt to *display* anything. The
callback is passed the current line and is expected to return a line that
will be used as the input display.
### hinter(line, pos)
The command line hint handler. It gets called on every key insert to
determine what text to use as an inline hint. It is passed the current
line and cursor position. It is expected to return a string which is used
as the text for the hint. This is by default a shim. To set hints,
override this function with your custom handler.
### inputMode(mode)
Sets the input mode for Hilbish's line reader. Accepts either emacs or vim
### interval(cb, time)
Runs the `cb` function every `time` milliseconds.
Returns a `timer` object (see `doc timers`).
### multiprompt(str)
Changes the continued line prompt to `str`
### prependPath(dir)
Prepends `dir` to $PATH
### prompt(str, typ?)
Changes the shell prompt to `str`
There are a few verbs that can be used in the prompt text.
These will be formatted and replaced with the appropriate values.
`%d` - Current working directory
`%u` - Name of current user
`%h` - Hostname of device
### read(prompt?) -> input?
Read input from the user, using Hilbish's line editor/input reader.
This is a separate instance from the one Hilbish actually uses.
Returns `input`, will be nil if ctrl + d is pressed, or an error occurs (which shouldn't happen)
### run(cmd, returnOut) -> exitCode, stdout, stderr
Runs `cmd` in Hilbish's sh interpreter.
If returnOut is true, the outputs of `cmd` will be returned as the 2nd and
3rd values instead of being outputted to the terminal.
### runnerMode(mode)
Sets the execution/runner mode for interactive Hilbish. This determines whether
Hilbish wll try to run input as Lua and/or sh or only do one of either.
Accepted values for mode are hybrid (the default), hybridRev (sh first then Lua),
sh, and lua. It also accepts a function, to which if it is passed one
will call it to execute user input instead.
### timeout(cb, time)
Runs the `cb` function after `time` in milliseconds
Returns a `timer` object (see `doc timers`).
### which(name)
Checks if `name` is a valid command

View File

@ -27,6 +27,6 @@ function bait.release(name, catcher) end
--- Throws a hook with `name` with the provided `args` --- Throws a hook with `name` with the provided `args`
--- @param name string --- @param name string
--- @vararg any --- @vararg any
function bait.throw(name, ...) end function bait.throw(name, ...args) end
return bait return bait

View File

@ -8,7 +8,7 @@ function fs.abs(path) end
--- Gives the basename of `path`. For the rules, --- Gives the basename of `path`. For the rules,
--- see Go's filepath.Base --- see Go's filepath.Base
function fs.basename() end function fs.basename(path) end
--- Changes directory to `dir` --- Changes directory to `dir`
--- @param dir string --- @param dir string
@ -16,15 +16,15 @@ function fs.cd(dir) end
--- Returns the directory part of `path`. For the rules, see Go's --- Returns the directory part of `path`. For the rules, see Go's
--- filepath.Dir --- filepath.Dir
function fs.dir() end function fs.dir(path) end
--- Glob all files and directories that match the pattern. --- Glob all files and directories that match the pattern.
--- For the rules, see Go's filepath.Glob --- For the rules, see Go's filepath.Glob
function fs.glob() end function fs.glob(pattern) end
--- Takes paths and joins them together with the OS's --- Takes paths and joins them together with the OS's
--- directory separator (forward or backward slash). --- directory separator (forward or backward slash).
function fs.join() end function fs.join(paths...) end
--- Makes a directory called `name`. If `recursive` is true, it will create its parent directories. --- Makes a directory called `name`. If `recursive` is true, it will create its parent directories.
--- @param name string --- @param name string

View File

@ -73,20 +73,21 @@ function hilbish.prependPath(dir) end
--- `%u` - Name of current user --- `%u` - Name of current user
--- `%h` - Hostname of device --- `%h` - Hostname of device
--- @param str string --- @param str string
--- @param typ string Type of prompt, being left or right. Left by default. --- @param typ string|nil Type of prompt, being left or right. Left by default.
function hilbish.prompt(str, typ) end function hilbish.prompt(str, typ) end
--- Read input from the user, using Hilbish's line editor/input reader. --- Read input from the user, using Hilbish's line editor/input reader.
--- This is a separate instance from the one Hilbish actually uses. --- 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) --- Returns `input`, will be nil if ctrl + d is pressed, or an error occurs (which shouldn't happen)
--- @param prompt string --- @param prompt string|nil
--- @returns string|nil
function hilbish.read(prompt) end function hilbish.read(prompt) end
--- Runs `cmd` in Hilbish's sh interpreter. --- Runs `cmd` in Hilbish's sh interpreter.
--- If returnOut is true, the outputs of `cmd` will be returned as the 2nd and --- If returnOut is true, the outputs of `cmd` will be returned as the 2nd and
--- 3rd values instead of being outputted to the terminal. --- 3rd values instead of being outputted to the terminal.
--- @param cmd string --- @param cmd string
function hilbish.run(cmd) end function hilbish.run(cmd, returnOut) end
--- Sets the execution/runner mode for interactive Hilbish. This determines whether --- 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. --- Hilbish wll try to run input as Lua and/or sh or only do one of either.
@ -105,6 +106,12 @@ function hilbish.timeout(cb, time) end
--- Checks if `name` is a valid command --- Checks if `name` is a valid command
--- @param binName string --- @param binName string
function hilbish.which(binName) end function hilbish.which(name) end
--- Stops a timer.
function hilbish.timers:stop() end
--- Get a table of all aliases.
function hilbish.aliases.list() end
return hilbish return hilbish

6
rl.go
View File

@ -225,7 +225,11 @@ func (lr *lineReader) Resize() {
return return
} }
// lua module // #interface history
// command history
// The history interface deals with command history.
// This includes the ability to override functions to change the main
// method of saving history.
func (lr *lineReader) Loader(rtm *rt.Runtime) *rt.Table { func (lr *lineReader) Loader(rtm *rt.Runtime) *rt.Table {
lrLua := map[string]util.LuaExport{ lrLua := map[string]util.LuaExport{
"add": {lr.luaAddHistory, 1, false}, "add": {lr.luaAddHistory, 1, false},

View File

@ -91,6 +91,10 @@ func timerStart(thr *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
return c.Next(), nil return c.Next(), nil
} }
// #interface timers
// #member
// stop()
// Stops a timer.
func timerStop(thr *rt.Thread, c *rt.GoCont) (rt.Cont, error) { func timerStop(thr *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
if err := c.Check1Arg(); err != nil { if err := c.Check1Arg(); err != nil {
return nil, err return nil, err

View File

@ -100,6 +100,11 @@ func (th *timersModule) luaGet(thr *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
return c.Next(), nil return c.Next(), nil
} }
// #interface timers
// timeout and interval API
// The timers interface si one to easily set timeouts and intervals
// to run functions after a certain time or repeatedly without using
// odd tricks.
func (th *timersModule) loader(rtm *rt.Runtime) *rt.Table { func (th *timersModule) loader(rtm *rt.Runtime) *rt.Table {
timerMethods := rt.NewTable() timerMethods := rt.NewTable()
timerFuncs := map[string]util.LuaExport{ timerFuncs := map[string]util.LuaExport{