diff --git a/aliases.go b/aliases.go index 87757c9..2ce5db0 100644 --- a/aliases.go +++ b/aliases.go @@ -66,8 +66,9 @@ func (a *aliasModule) Resolve(cmdstr string) string { // lua section -// #interface -// ALIAS LOADER TEST +// #interface aliases +// command aliasing +// The alias interface deals with all command aliases in Hilbish. func (a *aliasModule) Loader(rtm *rt.Runtime) *rt.Table { // create a lua module with our functions hshaliasesLua := map[string]util.LuaExport{ @@ -83,6 +84,9 @@ func (a *aliasModule) Loader(rtm *rt.Runtime) *rt.Table { return mod } +// #interface aliases +// list() +// Get a table of all aliases. func (a *aliasModule) luaList(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) { aliasesList := rt.NewTable() for k, v := range a.All() { diff --git a/api.go b/api.go index 57993f6..a0d5346 100644 --- a/api.go +++ b/api.go @@ -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. // This is a separate instance from the one Hilbish actually uses. // Returns `input`, will be nil if ctrl + d is pressed, or an error occurs (which shouldn't happen) -// --- @param prompt string +// --- @param prompt string|nil +// --- @returns string|nil func hlread(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) { luaprompt := c.Arg(0) if typ := luaprompt.Type(); typ != rt.StringType && typ != rt.NilType { @@ -281,7 +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` There are a few verbs that can be used in the prompt text. These will be formatted and replaced with the appropriate values. @@ -289,7 +290,7 @@ These will be formatted and replaced with the appropriate values. `%u` - Name of current user `%h` - Hostname of device --- @param str string ---- @param typ string Type of prompt, being left or right. Left by default. +--- @param typ string|nil Type of prompt, being left or right. Left by default. */ func hlprompt(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) { err := c.Check1Arg() diff --git a/cmd/docgen/docgen.go b/cmd/docgen/docgen.go index e0bc148..6372101 100644 --- a/cmd/docgen/docgen.go +++ b/cmd/docgen/docgen.go @@ -13,7 +13,7 @@ import ( ) var header = `--- -name: Module %s +name: %s %s description: %s layout: apidoc --- @@ -21,24 +21,33 @@ layout: apidoc ` type emmyPiece struct { - FuncName string - Docs []string + DocPiece *docPiece + Annotations []string Params []string // we only need to know param name to put in function + FuncName string } type module struct { Docs []docPiece ShortDescription string Description string - Interface bool + ParentModule string + HasInterfaces bool } + type docPiece struct { Doc []string FuncSig string FuncName string + Interfacing string + ParentModule string + GoFuncName string + IsInterface bool + IsMember bool } var docs = make(map[string]module) +var interfaceDocs = make(map[string]module) var emmyDocs = make(map[string][]emmyPiece) var prefix = map[string]string{ "main": "hl", @@ -50,17 +59,36 @@ var prefix = map[string]string{ } 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 } - 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] doc := parts[1:] + funcName := strings.TrimPrefix(fun.Name, prefix[mod]) 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 { if strings.HasPrefix(d, "---") { emmyLine := strings.TrimSpace(strings.TrimPrefix(d, "---")) @@ -72,24 +100,39 @@ func setupDoc(mod string, fun *doc.Func) *docPiece { if emmyType == "@vararg" { em.Params = append(em.Params, "...") // add vararg } - em.Docs = append(em.Docs, d) + em.Annotations = append(em.Annotations, d) } else { 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, 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) - return &dps + return dps } -// feel free to clean this up -// it works, dont really care about the code func main() { fset := token.NewFileSet() os.Mkdir("docs", 0777) @@ -117,21 +160,36 @@ func main() { } } + interfaceModules := make(map[string]*module) for l, f := range pkgs { p := doc.New(f, "./", doc.AllDecls) pieces := []docPiece{} mod := l + if mod == "main" { + mod = "hilbish" + } + var hasInterfaces bool for _, t := range p.Funcs { piece := setupDoc(mod, t) - if piece != nil { - pieces = append(pieces, *piece) + if piece == nil { + continue + } + + pieces = append(pieces, *piece) + if piece.IsInterface { + hasInterfaces = true } } for _, t := range p.Types { for _, m := range t.Methods { piece := setupDoc(mod, m) - if piece != nil { - pieces = append(pieces, *piece) + if piece == nil { + continue + } + + pieces = append(pieces, *piece) + if piece.IsInterface { + hasInterfaces = true } } } @@ -139,27 +197,65 @@ func main() { descParts := strings.Split(strings.TrimSpace(p.Doc), "\n") shortDesc := descParts[0] desc := descParts[1:] + filteredPieces := []docPiece{} + for _, piece := range pieces { + if !piece.IsInterface { + filteredPieces = append(filteredPieces, piece) + continue + } + + modname := piece.ParentModule + "." + piece.Interfacing + if interfaceModules[modname] == nil { + interfaceModules[modname] = &module{ + ParentModule: piece.ParentModule, + } + } + + if strings.HasSuffix(piece.GoFuncName, strings.ToLower("loader")) { + shortDesc := piece.Doc[0] + desc := piece.Doc[1:] + interfaceModules[modname].ShortDescription = shortDesc + interfaceModules[modname].Description = strings.Join(desc, "\n") + continue + } + interfaceModules[modname].Docs = append(interfaceModules[modname].Docs, piece) + } + docs[mod] = module{ - Docs: pieces, + Docs: filteredPieces, ShortDescription: shortDesc, Description: strings.Join(desc, "\n"), + HasInterfaces: hasInterfaces, } } + for key, mod := range interfaceModules { + docs[key] = *mod + } + var wg sync.WaitGroup wg.Add(len(docs) * 2) for mod, v := range docs { - modN := mod - if mod == "main" { - modN = "hilbish" + docPath := "docs/api/" + mod + ".md" + if v.HasInterfaces { + os.Mkdir("docs/api/" + mod, 0777) + os.Remove(docPath) // remove old doc path if it exists + docPath = "docs/api/" + mod + "/_index.md" + } + 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() + modOrIface := "Module" + if modu.ParentModule != "" { + modOrIface = "Interface" + } - f, _ := os.Create("docs/api/" + modName + ".md") - f.WriteString(fmt.Sprintf(header, modName, modu.ShortDescription)) + f, _ := os.Create(docPath) + f.WriteString(fmt.Sprintf(header, modOrIface, modname, modu.ShortDescription)) f.WriteString(fmt.Sprintf("## Introduction\n%s\n\n## Functions\n", modu.Description)) for _, dps := range modu.Docs { f.WriteString(fmt.Sprintf("### %s\n", dps.FuncSig)) @@ -170,28 +266,41 @@ func main() { } f.WriteString("\n") } - }(modN, v) + }(mod, docPath, v) - go func(md, modName string) { + go func(md, modname string, modu module) { defer wg.Done() - ff, _ := os.Create("emmyLuaDocs/" + modName + ".lua") - ff.WriteString("--- @meta\n\nlocal " + modName + " = {}\n\n") - 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") + if modu.ParentModule != "" { + return } - 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() } diff --git a/complete.go b/complete.go index c2a107c..5777c10 100644 --- a/complete.go +++ b/complete.go @@ -172,6 +172,9 @@ func escapeFilename(fname string) string { return escapeReplaer.Replace(fname) } +// #interface completions +// tab completions +// The completions interface deals with tab completions. func completionLoader(rtm *rt.Runtime) *rt.Table { exports := map[string]util.LuaExport{ "files": {luaFileComplete, 3, false}, diff --git a/docs/api/hilbish.md b/docs/api/hilbish.md deleted file mode 100644 index 96746ae..0000000 --- a/docs/api/hilbish.md +++ /dev/null @@ -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.`, -replacing with the name of the command (for example `command.git`). -`cb` must be a function that returns a table of "completion groups." -Check `doc completions` for more information. - -### cwd() -Returns the current directory of the shell - -### exec(cmd) -Replaces running hilbish with `cmd` - -### goro(fn) -Puts `fn` in a goroutine - -### highlighter(line) -Line highlighter handler. This is mainly for syntax highlighting, but in -reality could set the input of the prompt to *display* anything. The -callback is passed the current line and is expected to return a line that -will be used as the input display. - -### hinter(line, pos) -The command line hint handler. It gets called on every key insert to -determine what text to use as an inline hint. It is passed the current -line and cursor position. It is expected to return a string which is used -as the text for the hint. This is by default a shim. To set hints, -override this function with your custom handler. - -### inputMode(mode) -Sets the input mode for Hilbish's line reader. Accepts either emacs or vim - -### interval(cb, time) -Runs the `cb` function every `time` milliseconds. -Returns a `timer` object (see `doc timers`). - -### multiprompt(str) -Changes the continued line prompt to `str` - -### prependPath(dir) -Prepends `dir` to $PATH - -### prompt(str, typ?) -Changes the shell prompt to `str` -There are a few verbs that can be used in the prompt text. -These will be formatted and replaced with the appropriate values. -`%d` - Current working directory -`%u` - Name of current user -`%h` - Hostname of device - -### read(prompt?) -> input? -Read input from the user, using Hilbish's line editor/input reader. -This is a separate instance from the one Hilbish actually uses. -Returns `input`, will be nil if ctrl + d is pressed, or an error occurs (which shouldn't happen) - -### run(cmd, returnOut) -> exitCode, stdout, stderr -Runs `cmd` in Hilbish's sh interpreter. -If returnOut is true, the outputs of `cmd` will be returned as the 2nd and -3rd values instead of being outputted to the terminal. - -### runnerMode(mode) -Sets the execution/runner mode for interactive Hilbish. This determines whether -Hilbish wll try to run input as Lua and/or sh or only do one of either. -Accepted values for mode are hybrid (the default), hybridRev (sh first then Lua), -sh, and lua. It also accepts a function, to which if it is passed one -will call it to execute user input instead. - -### timeout(cb, time) -Runs the `cb` function after `time` in milliseconds -Returns a `timer` object (see `doc timers`). - -### which(name) -Checks if `name` is a valid command - diff --git a/emmyLuaDocs/bait.lua b/emmyLuaDocs/bait.lua index a957e00..65f9f83 100644 --- a/emmyLuaDocs/bait.lua +++ b/emmyLuaDocs/bait.lua @@ -27,6 +27,6 @@ function bait.release(name, catcher) end --- Throws a hook with `name` with the provided `args` --- @param name string --- @vararg any -function bait.throw(name, ...) end +function bait.throw(name, ...args) end return bait diff --git a/emmyLuaDocs/fs.lua b/emmyLuaDocs/fs.lua index 14e7be4..eb5743a 100644 --- a/emmyLuaDocs/fs.lua +++ b/emmyLuaDocs/fs.lua @@ -8,7 +8,7 @@ function fs.abs(path) end --- Gives the basename of `path`. For the rules, --- see Go's filepath.Base -function fs.basename() end +function fs.basename(path) end --- Changes directory to `dir` --- @param dir string @@ -16,15 +16,15 @@ function fs.cd(dir) end --- Returns the directory part of `path`. For the rules, see Go's --- filepath.Dir -function fs.dir() end +function fs.dir(path) end --- Glob all files and directories that match the pattern. --- For the rules, see Go's filepath.Glob -function fs.glob() end +function fs.glob(pattern) end --- Takes paths and joins them together with the OS's --- directory separator (forward or backward slash). -function fs.join() end +function fs.join(paths...) end --- Makes a directory called `name`. If `recursive` is true, it will create its parent directories. --- @param name string diff --git a/emmyLuaDocs/hilbish.lua b/emmyLuaDocs/hilbish.lua index ca34425..7f39709 100644 --- a/emmyLuaDocs/hilbish.lua +++ b/emmyLuaDocs/hilbish.lua @@ -73,20 +73,21 @@ function hilbish.prependPath(dir) end --- `%u` - Name of current user --- `%h` - Hostname of device --- @param str string ---- @param typ string Type of prompt, being left or right. Left by default. +--- @param typ string|nil Type of prompt, being left or right. Left by default. function hilbish.prompt(str, typ) end --- Read input from the user, using Hilbish's line editor/input reader. --- This is a separate instance from the one Hilbish actually uses. --- Returns `input`, will be nil if ctrl + d is pressed, or an error occurs (which shouldn't happen) ---- @param prompt string +--- @param prompt string|nil +--- @returns string|nil function hilbish.read(prompt) end --- Runs `cmd` in Hilbish's sh interpreter. --- If returnOut is true, the outputs of `cmd` will be returned as the 2nd and --- 3rd values instead of being outputted to the terminal. --- @param cmd string -function hilbish.run(cmd) end +function hilbish.run(cmd, returnOut) end --- Sets the execution/runner mode for interactive Hilbish. This determines whether --- Hilbish wll try to run input as Lua and/or sh or only do one of either. @@ -105,6 +106,12 @@ function hilbish.timeout(cb, time) end --- Checks if `name` is a valid command --- @param binName string -function hilbish.which(binName) end +function hilbish.which(name) end + +--- Stops a timer. +function hilbish.timers:stop() end + +--- Get a table of all aliases. +function hilbish.aliases.list() end return hilbish diff --git a/rl.go b/rl.go index f6cb6cd..8ec711c 100644 --- a/rl.go +++ b/rl.go @@ -225,7 +225,11 @@ func (lr *lineReader) Resize() { return } -// lua module +// #interface history +// command history +// The history interface deals with command history. +// This includes the ability to override functions to change the main +// method of saving history. func (lr *lineReader) Loader(rtm *rt.Runtime) *rt.Table { lrLua := map[string]util.LuaExport{ "add": {lr.luaAddHistory, 1, false}, diff --git a/timer.go b/timer.go index f5ab9a3..f59749e 100644 --- a/timer.go +++ b/timer.go @@ -91,6 +91,10 @@ func timerStart(thr *rt.Thread, c *rt.GoCont) (rt.Cont, error) { return c.Next(), nil } +// #interface timers +// #member +// stop() +// Stops a timer. func timerStop(thr *rt.Thread, c *rt.GoCont) (rt.Cont, error) { if err := c.Check1Arg(); err != nil { return nil, err diff --git a/timerhandler.go b/timerhandler.go index 29c7a41..b03435b 100644 --- a/timerhandler.go +++ b/timerhandler.go @@ -100,6 +100,11 @@ func (th *timersModule) luaGet(thr *rt.Thread, c *rt.GoCont) (rt.Cont, error) { 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 { timerMethods := rt.NewTable() timerFuncs := map[string]util.LuaExport{