diff --git a/.gitignore b/.gitignore index b2be7c4..1abf82c 100644 --- a/.gitignore +++ b/.gitignore @@ -6,3 +6,4 @@ docgen .vim petals/ +.hugo_build.lock diff --git a/CHANGELOG.md b/CHANGELOG.md index 885cefd..2db665b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,19 @@ # 🎀 Changelog +## Unreleased +### Added +- Documented custom userdata types (Job and Timer Objects) + - Coming with fix is also adding the return types for some functions that were missing it + +### Fixed +- `hilbish.which` not working correctly with aliases + +## [2.0.1] - 2022-12-28 +### Fixed +- Corrected documentation for hooks, removing outdated `command.no-perm` +- Fixed an issue where `cd` with no args would not update the old pwd +- Tiny documentation enhancements for the `hilbish.timer` interface + ## [2.0.0] - 2022-12-20 **NOTES FOR USERS/PACKAGERS UPDATING:** - Hilbish now uses [Task] insead of Make for builds. @@ -611,6 +625,7 @@ This input for example will prompt for more input to complete: First "stable" release of Hilbish. +[2.0.1]: https://github.com/Rosettea/Hilbish/compare/v2.0.0...v2.0.1 [2.0.0]: https://github.com/Rosettea/Hilbish/compare/v1.2.0...v2.0.0 [2.0.0-rc1]: https://github.com/Rosettea/Hilbish/compare/v1.2.0...v2.0.0-rc1 [1.2.0]: https://github.com/Rosettea/Hilbish/compare/v1.1.4...v1.2.0 diff --git a/README.md b/README.md index b4f85f7..3a3dbbb 100644 --- a/README.md +++ b/README.md @@ -26,52 +26,30 @@ and aims to be infinitely configurable. If something isn't, open an issue! # Table of Contents - [Screenshots](#Screenshots) -- [Installation](#Installation) - - [Prebuilt Bins](#Prebuilt-binaries) - - [AUR](#AUR) - - [Nixpkgs](#Nixpkgs) - - [Manual Build](#Manual-Build) +- [Getting Hilbish](#Getting-Hilbish) - [Contributing](#Contributing) # Screenshots
-



+

-# Installation +# Getting Hilbish **NOTE:** Hilbish is not guaranteed to work properly on Windows, starting from the 2.0 version. It will still be able to compile, but functionality may be lacking. -## Prebuilt binaries -Go [here](https://nightly.link/Rosettea/Hilbish/workflows/build/master) for -builds on the master branch. +You can check the [install page](https://rosettea.github.io/Hilbish/install/) +on the website for distributed binaries from GitHub or other package repositories. +Otherwise, continue reading for steps on compiling. -## AUR -[![AUR maintainer](https://img.shields.io/aur/maintainer/hilbish?logo=arch-linux&style=flat-square)](https://aur.archlinux.org/packages/hilbish) -Arch Linux users can install Hilbish from the AUR with the following command: -```sh -yay -S hilbish -``` - -[![AUR maintainer](https://img.shields.io/aur/maintainer/hilbish?logo=arch-linux&style=flat-square)](https://aur.archlinux.org/packages/hilbish-git) -Or from the latest `master` commit with: -```sh -yay -S hilbish-git -``` - -## Nixpkgs -Nix/NixOS users can install Hilbish from the central repository, nixpkgs, through the usual ways. -If you're new to nix you should probably read up on how to do that [here](https://nixos.wiki/wiki/Cheatsheet). - -## Manual Build -### Prerequisites +## Prerequisites - [Go 1.17+](https://go.dev) - [Task](https://taskfile.dev/installation/) (**Go on the hyperlink here to see Task's install method for your OS.**) -### Build +## Build First, clone Hilbish. The recursive is required, as some Lua libraries are submodules. ```sh diff --git a/aliases.go b/aliases.go index d9416d9..bfacc43 100644 --- a/aliases.go +++ b/aliases.go @@ -92,9 +92,9 @@ func (a *aliasModule) Loader(rtm *rt.Runtime) *rt.Table { func _hlalias() {} // #interface aliases -// list() -> aliases (table) +// list() -> table // Get a table of all aliases, with string keys as the alias and the value as the command. -// @returns table +// --- @returns table 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 3ac7c92..3920e6f 100644 --- a/api.go +++ b/api.go @@ -231,8 +231,9 @@ func hlrun(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) { return c.PushingNext(t.Runtime, rt.IntValue(int64(exitcode)), rt.StringValue(stdoutStr), rt.StringValue(stderrStr)), nil } -// cwd() +// cwd() -> string // Returns the current directory of the shell +// --- @returns string func hlcwd(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) { cwd, _ := os.Getwd() @@ -444,12 +445,12 @@ func hlgoro(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) { return c.Next(), nil } -// timeout(cb, time) -// Runs the `cb` function after `time` in milliseconds -// Returns a `timer` object (see `doc timers`). +// timeout(cb, time) -> @Timer +// Runs the `cb` function after `time` in milliseconds. +// This creates a timer that starts immediately. // --- @param cb function // --- @param time number -// --- @returns table +// --- @returns Timer func hltimeout(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) { if err := c.CheckNArgs(2); err != nil { return nil, err @@ -470,12 +471,12 @@ func hltimeout(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) { return c.PushingNext1(t.Runtime, rt.UserDataValue(timer.ud)), nil } -// interval(cb, time) +// interval(cb, time) -> @Timer // Runs the `cb` function every `time` milliseconds. -// Returns a `timer` object (see `doc timers`). +// This creates a timer that starts immediately. // --- @param cb function // --- @param time number -// --- @return table +// --- @return Timer func hlinterval(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) { if err := c.CheckNArgs(2); err != nil { return nil, err @@ -536,9 +537,11 @@ func hlprependPath(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) { return c.Next(), nil } -// which(name) -// Checks if `name` is a valid command +// 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. // --- @param name string +// --- @returns string func hlwhich(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) { if err := c.Check1Arg(); err != nil { return nil, err @@ -548,7 +551,10 @@ func hlwhich(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) { return nil, err } - cmd := aliases.Resolve(name) + // itll return either the original command or what was passed + // if name isnt empty its not an issue + alias := aliases.Resolve(name) + cmd := strings.Split(alias, " ")[0] // check for commander if commands[cmd] != nil { diff --git a/cmd/docgen/docgen.go b/cmd/docgen/docgen.go index cf70840..faa7845 100644 --- a/cmd/docgen/docgen.go +++ b/cmd/docgen/docgen.go @@ -7,6 +7,7 @@ import ( "go/doc" "go/parser" "go/token" + "regexp" "strings" "os" "sync" @@ -31,6 +32,7 @@ type emmyPiece struct { } type module struct { + Types []docPiece Docs []docPiece Fields []docPiece Properties []docPiece @@ -38,6 +40,7 @@ type module struct { Description string ParentModule string HasInterfaces bool + HasTypes bool } type docPiece struct { @@ -49,6 +52,7 @@ type docPiece struct { GoFuncName string IsInterface bool IsMember bool + IsType bool Fields []docPiece Properties []docPiece } @@ -61,6 +65,7 @@ type tag struct { var docs = make(map[string]module) var interfaceDocs = make(map[string]module) var emmyDocs = make(map[string][]emmyPiece) +var typeTable = make(map[string][]string) // [0] = parentMod, [1] = interfaces var prefix = map[string]string{ "main": "hl", "hilbish": "hl", @@ -119,6 +124,71 @@ func docPieceTag(tagName string, tags map[string][]tag) []docPiece { return dps } +func setupDocType(mod string, typ *doc.Type) *docPiece { + docs := strings.TrimSpace(typ.Doc) + inInterface := strings.HasPrefix(docs, "#interface") + if !inInterface { + return nil + } + + tags, doc := getTagsAndDocs(docs) + + var interfaces string + typeName := strings.ToUpper(string(typ.Name[0])) + typ.Name[1:] + typeDoc := []string{} + + if inInterface { + interfaces = tags["interface"][0].id + } + + fields := docPieceTag("field", tags) + properties := docPieceTag("property", tags) + + for _, d := range doc { + if strings.HasPrefix(d, "---") { + // TODO: document types in lua + /* + emmyLine := strings.TrimSpace(strings.TrimPrefix(d, "---")) + emmyLinePieces := strings.Split(emmyLine, " ") + emmyType := emmyLinePieces[0] + if emmyType == "@param" { + em.Params = append(em.Params, emmyLinePieces[1]) + } + if emmyType == "@vararg" { + em.Params = append(em.Params, "...") // add vararg + } + em.Annotations = append(em.Annotations, d) + */ + } else { + typeDoc = append(typeDoc, d) + } + } + + var isMember bool + if tags["member"] != nil { + isMember = true + } + var parentMod string + if inInterface { + parentMod = mod + } + dps := &docPiece{ + Doc: typeDoc, + FuncName: typeName, + Interfacing: interfaces, + IsInterface: inInterface, + IsMember: isMember, + IsType: true, + ParentModule: parentMod, + Fields: fields, + Properties: properties, + } + + typeTable[strings.ToLower(typeName)] = []string{parentMod, interfaces} + + return dps +} + func setupDoc(mod string, fun *doc.Func) *docPiece { docs := strings.TrimSpace(fun.Doc) inInterface := strings.HasPrefix(docs, "#interface") @@ -220,6 +290,7 @@ func main() { for l, f := range pkgs { p := doc.New(f, "./", doc.AllDecls) pieces := []docPiece{} + typePieces := []docPiece{} mod := l if mod == "main" { mod = "hilbish" @@ -237,6 +308,14 @@ func main() { } } for _, t := range p.Types { + typePiece := setupDocType(mod, t) + if typePiece != nil { + typePieces = append(typePieces, *typePiece) + if typePiece.IsInterface { + hasInterfaces = true + } + } + for _, m := range t.Methods { piece := setupDoc(mod, m) if piece == nil { @@ -254,6 +333,7 @@ func main() { shortDesc := descParts[0] desc := descParts[1:] filteredPieces := []docPiece{} + filteredTypePieces := []docPiece{} for _, piece := range pieces { if !piece.IsInterface { filteredPieces = append(filteredPieces, piece) @@ -276,10 +356,28 @@ func main() { interfaceModules[modname].Properties = piece.Properties continue } + interfaceModules[modname].Docs = append(interfaceModules[modname].Docs, piece) } + for _, piece := range typePieces { + if !piece.IsInterface { + filteredTypePieces = append(filteredTypePieces, piece) + continue + } + + modname := piece.ParentModule + "." + piece.Interfacing + if interfaceModules[modname] == nil { + interfaceModules[modname] = &module{ + ParentModule: piece.ParentModule, + } + } + + interfaceModules[modname].Types = append(interfaceModules[modname].Types, piece) + } + docs[mod] = module{ + Types: filteredTypePieces, Docs: filteredPieces, ShortDescription: shortDesc, Description: strings.Join(desc, "\n"), @@ -335,17 +433,71 @@ func main() { } f.WriteString("\n") } + if len(modu.Docs) != 0 { + typeTag, _ := regexp.Compile(`@\w+`) f.WriteString("## Functions\n") + for _, dps := range modu.Docs { + if dps.IsMember { + continue + } + htmlSig := typeTag.ReplaceAllStringFunc(strings.Replace(dps.FuncSig, "<", `\<`, -1), func(typ string) string { + typName := typ[1:] + typLookup := typeTable[strings.ToLower(typName)] + linkedTyp := fmt.Sprintf("/Hilbish/docs/api/%s/%s/#%s", typLookup[0], typLookup[0] + "." + typLookup[1], strings.ToLower(typName)) + return fmt.Sprintf(`%s`, linkedTyp, typName) + }) + f.WriteString(fmt.Sprintf("### %s\n", htmlSig)) + for _, doc := range dps.Doc { + if !strings.HasPrefix(doc, "---") { + f.WriteString(doc + "\n") + } + } + f.WriteString("\n") + } } - for _, dps := range modu.Docs { - f.WriteString(fmt.Sprintf("### %s\n", dps.FuncSig)) - for _, doc := range dps.Doc { - if !strings.HasPrefix(doc, "---") { - f.WriteString(doc + "\n") + + if len(modu.Types) != 0 { + f.WriteString("## Types\n") + for _, dps := range modu.Types { + f.WriteString(fmt.Sprintf("## %s\n", dps.FuncName)) + for _, doc := range dps.Doc { + if !strings.HasPrefix(doc, "---") { + f.WriteString(doc + "\n") + } + } + 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("\n") + typeTag, _ := regexp.Compile(`@\w+`) + + f.WriteString("### Methods\n") + for _, dps := range modu.Docs { + if !dps.IsMember { + continue + } + htmlSig := typeTag.ReplaceAllStringFunc(strings.Replace(dps.FuncSig, "<", `\<`, -1), func(typ string) string { + // todo: get type from global table to link to + // other pages (hilbish page can link to hilbish.jobs#Job) + typName := typ[1:] + linkedTyp := strings.ToLower(typName) // TODO: link + return fmt.Sprintf(`%s`, linkedTyp, typName) + }) + f.WriteString(fmt.Sprintf("#### %s\n", htmlSig)) + for _, doc := range dps.Doc { + if !strings.HasPrefix(doc, "---") { + f.WriteString(doc + "\n") + } + } + f.WriteString("\n") } } - f.WriteString("\n") } }(mod, docPath, v) diff --git a/docs/api/hilbish/_index.md b/docs/api/hilbish/_index.md index 1773892..52bd404 100644 --- a/docs/api/hilbish/_index.md +++ b/docs/api/hilbish/_index.md @@ -35,7 +35,7 @@ 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() +### cwd() -> string Returns the current directory of the shell ### exec(cmd) @@ -60,9 +60,9 @@ 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) +### interval(cb, time) -> Timer Runs the `cb` function every `time` milliseconds. -Returns a `timer` object (see `doc timers`). +This creates a timer that starts immediately. ### multiprompt(str) Changes the continued line prompt to `str` @@ -95,10 +95,11 @@ 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`). +### timeout(cb, time) -> Timer +Runs the `cb` function after `time` in milliseconds. +This creates a timer that starts immediately. -### which(name) -Checks if `name` is a valid command +### 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. diff --git a/docs/api/hilbish/hilbish.aliases.md b/docs/api/hilbish/hilbish.aliases.md index 9b90e5c..bae5bfc 100644 --- a/docs/api/hilbish/hilbish.aliases.md +++ b/docs/api/hilbish/hilbish.aliases.md @@ -17,9 +17,8 @@ This is an alias (ha) for the `hilbish.alias` function. ### delete(name) Removes an alias. -### list() -> aliases (table) +### list() -> table\ Get a table of all aliases, with string keys as the alias and the value as the command. -@returns table ### resolve(alias) -> command (string) Tries to resolve an alias to its command. diff --git a/docs/api/hilbish/hilbish.jobs.md b/docs/api/hilbish/hilbish.jobs.md index d8ec989..e41be2c 100644 --- a/docs/api/hilbish/hilbish.jobs.md +++ b/docs/api/hilbish/hilbish.jobs.md @@ -14,7 +14,26 @@ Manage interactive jobs in Hilbish via Lua. Jobs are the name of background tasks/commands. A job can be started via interactive usage or with the functions defined below for use in external runners. -## Object properties +## Functions +### add(cmdstr, args, execPath) +Adds a new job to the job table. Note that this does not immediately run it. + +### all() -> table\<Job> +Returns a table of all job objects. + +### disown(id) +Disowns a job. This deletes it from the job table. + +### get(id) -> Job +Get a job object via its ID. + +### last() -> Job +Returns the last added job from the table. + +## Types +## 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 @@ -23,32 +42,17 @@ interactive usage or with the functions defined below for use in external runner - `stdout`: The standard output of the job. This just means the normal logs of the process. - `stderr`: The standard error stream of the process. This (usually) includes error messages of the job. -## Functions -### background() +### Methods +#### background() Puts a job in the background. This acts the same as initially running a job. -### foreground() +#### foreground() Puts a job in the foreground. This will cause it to run like it was executed normally and wait for it to complete. -### start() +#### start() Starts running the job. -### stop() +#### stop() Stops the job from running. -### add(cmdstr, args, execPath) -Adds a new job to the job table. Note that this does not immediately run it. - -### all() -> jobs (table) -Returns a table of all job objects. - -### disown(id) -Disowns a job. This deletes it from the job table. - -### get(id) -> job (Job/Table) -Get a job object via its ID. - -### last() -> job (Job/Table) -Returns the last added job from the table. - diff --git a/docs/api/hilbish/hilbish.timers.md b/docs/api/hilbish/hilbish.timers.md index 0261a9d..e899d1d 100644 --- a/docs/api/hilbish/hilbish.timers.md +++ b/docs/api/hilbish/hilbish.timers.md @@ -8,30 +8,52 @@ menu: --- ## Introduction -The timers interface si one to easily set timeouts and intervals -to run functions after a certain time or repeatedly without using -odd tricks. + +If you ever want to run a piece of code on a timed interval, or want to wait +a few seconds, you don't have to rely on timing tricks, as Hilbish has a +timer API to set intervals and timeouts. + +These are the simple functions `hilbish.interval` and `hilbish.timeout` (doc +accessible with `doc hilbish`). But if you want slightly more control over +them, there is the `hilbish.timers` interface. It allows you to get +a timer via ID and control them. + +All functions documented with the `Timer` type refer to a Timer object. + +An example of usage: +``` +local t = hilbish.timers.create(hilbish.timers.TIMEOUT, 5000, function() + print 'hello!' +end) + +t:start() +print(t.running) // true +``` ## Interface fields - `INTERVAL`: Constant for an interval timer type - `TIMEOUT`: Constant for a timeout timer type -## Object properties +## Functions +### create(type, time, callback) -> Timer +Creates a timer that runs based on the specified `time` in milliseconds. +The `type` can either be `hilbish.timers.INTERVAL` or `hilbish.timers.TIMEOUT` + +### get(id) -> Timer +Retrieves a timer via its ID. + +## Types +## 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 -## Functions -### start() +### Methods +#### start() Starts a timer. -### stop() +#### stop() Stops a timer. -### create(type, time, callback) -Creates a timer that runs based on the specified `time` in milliseconds. -The `type` can either be `hilbish.timers.INTERVAL` or `hilbish.timers.TIMEOUT` - -### get(id) -> timer (Timer/Table) -Retrieves a timer via its ID. - diff --git a/docs/api/index.md b/docs/api/index.md deleted file mode 100644 index 4effa19..0000000 --- a/docs/api/index.md +++ /dev/null @@ -1 +0,0 @@ -hello! diff --git a/docs/hooks/command.md b/docs/hooks/command.md index f97f7e3..cd1ae3c 100644 --- a/docs/hooks/command.md +++ b/docs/hooks/command.md @@ -3,5 +3,5 @@ + `command.not-found` -> cmdStr > Thrown when a command is not found. -+ `command.no-perm` -> cmdStr > Thrown when Hilbish attempts to execute a file but -has no permission. ++ `command.not-executable` -> cmdStr > Thrown when Hilbish attempts to run a file +that is not executable. diff --git a/docs/timers.md b/docs/timers.md index 0f89718..1b9c602 100644 --- a/docs/timers.md +++ b/docs/timers.md @@ -1,38 +1 @@ -If you ever want to run a piece of code on a timed interval, or want to wait -a few seconds, you don't have to rely on timing tricks, as Hilbish has a -timer API to set intervals and timeouts. - -These are the simple functions `hilbish.interval` and `hilbish.timeout` (doc -accessible with `doc hilbish`). But if you want slightly more control over -them, there is the `hilbish.timers` interface. It allows you to get -a timer via ID. - -# Timer Interface -## Functions -- `get(id)` -> timer: get a timer via its id -- `create(type, ms, callback)` -> timer: creates a timer, adding it to the timer pool. -`type` is the type of timer it will be. 0 is an interval, 1 is a timeout. -`ms` is the time it will run for in seconds. callback is the function called -when the timer is triggered. - -# Timer Object -All those previously mentioned functions return a `timer` object, to which -you can stop and start a timer again. - -An example of usage: -local t = hilbish.timers.create(1, 5000, function() - print 'hello!' -end) - -t:stop() -print(t.running, t.duration, t.type) -t:start() - -## Properties -- `duration`: amount of time the timer runs for in milliseconds -- `running`: whether the timer is running or not -- `type`: the type of timer (0 is interval, 1 is timeout) - -## Functions -- `stop()`: stops the timer. returns an error if it's already stopped -- `start()`: starts the timer. returns an error if it's already started +This has been moved to the `hilbish.timers` API doc (accessible by `doc api hilbish.timers`) diff --git a/emmyLuaDocs/hilbish.lua b/emmyLuaDocs/hilbish.lua index da5bf1c..24588bd 100644 --- a/emmyLuaDocs/hilbish.lua +++ b/emmyLuaDocs/hilbish.lua @@ -63,6 +63,7 @@ function hilbish.appendPath(dir) end function hilbish.complete(scope, cb) end --- Returns the current directory of the shell +--- @returns string function hilbish.cwd() end --- Replaces running hilbish with `cmd` @@ -94,10 +95,10 @@ function hilbish.hinter(line, pos) end function hilbish.inputMode(mode) end --- Runs the `cb` function every `time` milliseconds. ---- Returns a `timer` object (see `doc timers`). +--- This creates a timer that starts immediately. --- @param cb function --- @param time number ---- @return table +--- @return Timer function hilbish.interval(cb, time) end --- Changes the continued line prompt to `str` @@ -141,15 +142,17 @@ function hilbish.run(cmd, returnOut) end --- @param mode string|function function hilbish.runnerMode(mode) end ---- Runs the `cb` function after `time` in milliseconds ---- Returns a `timer` object (see `doc timers`). +--- Runs the `cb` function after `time` in milliseconds. +--- This creates a timer that starts immediately. --- @param cb function --- @param time number ---- @returns table +--- @returns Timer function hilbish.timeout(cb, time) end ---- Checks if `name` is a valid command +--- Checks if `name` is a valid command. +--- Will return the path of the binary, or a basename if it's a commander. --- @param name string +--- @returns string function hilbish.which(name) end --- Puts a job in the background. This acts the same as initially running a job. @@ -180,7 +183,7 @@ function hilbish.runner.lua(cmd) end function hilbish.jobs:start() end --- Stops the job from running. -function hilbish.jobs.stop() end +function hilbish.jobs:stop() end --- Runs a command in Hilbish's shell script interpreter. --- This is the equivalent of using `source`. diff --git a/gallery/tab.png b/gallery/tab.png new file mode 100644 index 0000000..409d796 Binary files /dev/null and b/gallery/tab.png differ diff --git a/job.go b/job.go index 2b60a80..a933016 100644 --- a/job.go +++ b/job.go @@ -18,6 +18,15 @@ import ( var jobs *jobHandler var jobMetaKey = rt.StringValue("hshjob") +// #interface jobs +// #property cmd The user entered command string for the job. +// #property running Whether the job is running or not. +// #property id The ID of the job in the job table +// #property pid The Process ID +// #property exitCode The last exit code of the job. +// #property stdout The standard output of the job. This just means the normal logs of the process. +// #property stderr The standard error stream of the process. This (usually) includes error messages of the job. +// The Job type describes a Hilbish job. type job struct { cmd string running bool @@ -135,6 +144,7 @@ func luaStartJob(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) { } // #interface jobs +// #member // stop() // Stops the job from running. func luaStopJob(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) { @@ -293,13 +303,6 @@ func (j *jobHandler) stopAll() { } // #interface jobs -// #property cmd The user entered command string for the job. -// #property running Whether the job is running or not. -// #property id The ID of the job in the job table -// #property pid The Process ID -// #property exitCode The last exit code of the job. -// #property stdout The standard output of the job. This just means the normal logs of the process. -// #property stderr The standard error stream of the process. This (usually) includes error messages of the job. // background job management /* Manage interactive jobs in Hilbish via Lua. @@ -384,7 +387,7 @@ func jobUserData(j *job) *rt.UserData { } // #interface jobs -// get(id) -> job (Job/Table) +// get(id) -> @Job // Get a job object via its ID. // --- @param id number // --- @returns Job @@ -444,7 +447,7 @@ func (j *jobHandler) luaAddJob(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) { } // #interface jobs -// all() -> jobs (table) +// all() -> table<@Job> // Returns a table of all job objects. // --- @returns table func (j *jobHandler) luaAllJobs(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) { @@ -481,7 +484,7 @@ func (j *jobHandler) luaDisownJob(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) { } // #interface jobs -// last() -> job (Job/Table) +// last() -> @Job // Returns the last added job from the table. // --- @returns Job func (j *jobHandler) luaLastJob(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) { diff --git a/nature/commands/cd.lua b/nature/commands/cd.lua index 8f68271..7cfe4a2 100644 --- a/nature/commands/cd.lua +++ b/nature/commands/cd.lua @@ -8,28 +8,21 @@ commander.register('cd', function (args, sinks) if #args > 1 then sinks.out:writeln("cd: too many arguments") return 1 - elseif #args > 0 then - local path = args[1]:gsub('$%$','\0'):gsub('${([%w_]+)}', os.getenv) - :gsub('$([%w_]+)', os.getenv):gsub('%z','$'):gsub('^%s*(.-)%s*$', '%1') - - if path == '-' then - path = dirs.old - sinks.out:writeln(path) - end - dirs.setOld(hilbish.cwd()) - dirs.push(path) - - local ok, err = pcall(function() fs.cd(path) end) - if not ok then - sinks.out:writeln(err) - return 1 - end - bait.throw('cd', path) - - return end - fs.cd(hilbish.home) - bait.throw('cd', hilbish.home) - dirs.push(hilbish.home) + local path = args[1] and args[1] or hilbish.home + if path == '-' then + path = dirs.old + sinks.out:writeln(path) + end + + dirs.setOld(hilbish.cwd()) + dirs.push(path) + + local ok, err = pcall(function() fs.cd(path) end) + if not ok then + sinks.out:writeln(err) + return 1 + end + bait.throw('cd', path) end) diff --git a/nature/commands/doc.lua b/nature/commands/doc.lua index 621791d..78b96eb 100644 --- a/nature/commands/doc.lua +++ b/nature/commands/doc.lua @@ -4,12 +4,27 @@ local lunacolors = require 'lunacolors' commander.register('doc', function(args, sinks) local moddocPath = hilbish.dataDir .. '/docs/' + local stat = fs.stat '.git/refs/heads/extended-job-api' + if stat then + -- hilbish git + moddocPath = './docs/' + end local apidocHeader = [[ # %s {grayBg} {white}{italic}%s {reset} ]] + local modules = table.map(fs.readdir(moddocPath), function(f) + return lunacolors.underline(lunacolors.blue(string.gsub(f, '.md', ''))) + end) + local doc = [[ +Welcome to Hilbish's documentation viewer! Here you can find +documentation for builtin functions and other things related +to Hilbish. + +Usage: doc
[subdoc] +Available sections: ]] .. table.concat(modules, ', ') if #args > 0 then local mod = args[1] @@ -24,6 +39,9 @@ commander.register('doc', function(args, sinks) subdocName = '_index' end f = io.open(moddocPath .. subdocName .. '.md', 'rb') + if not f then + f = io.open(moddocPath .. subdocName:match '%w+' .. '/' .. subdocName .. '.md', 'rb') + end if not f then moddocPath = moddocPath .. subdocName .. '/' subdocName = args[3] or '_index' @@ -31,11 +49,11 @@ commander.register('doc', function(args, sinks) end if not f then sinks.out:writeln('No documentation found for ' .. mod .. '.') - return + return 1 end end funcdocs = f:read '*a':gsub('-([%d]+)', '%1') - local moddocs = table.filter(fs.readdir(moddocPath), function(f) return f ~= '_index.md' end) + local moddocs = table.filter(fs.readdir(moddocPath), function(f) return f ~= '_index.md' or f ~= 'index.md' end) local subdocs = table.map(moddocs, function(fname) return lunacolors.underline(lunacolors.blue(string.gsub(fname, '.md', ''))) end) @@ -63,34 +81,20 @@ commander.register('doc', function(args, sinks) if mod == 'api' then funcdocs = string.format(apidocHeader, vals.title, vals.description or 'no description.') .. funcdocs end - local backtickOccurence = 0 - local formattedFuncs = lunacolors.format(funcdocs:sub(1, #funcdocs - 1):gsub('`', function() - backtickOccurence = backtickOccurence + 1 - if backtickOccurence % 2 == 0 then - return '{reset}' - else - return '{underline}{green}' - end - end):gsub('#+.-\n', function(t) - return '{bold}{magenta}' .. t .. '{reset}' - end)) - sinks.out:writeln(formattedFuncs) + doc = funcdocs:sub(1, #funcdocs - 1) f:close() - - return end - local modules = table.map(fs.readdir(moddocPath), function(f) - return lunacolors.underline(lunacolors.blue(string.gsub(f, '.md', ''))) - end) - sinks.out:writeln [[ -Welcome to Hilbish's doc tool! Here you can find documentation for builtin -functions and other things. - -Usage: doc
[subdoc] -A section is a module or a literal section and a subdoc is a subsection for it. - -Available sections: ]] - - sinks.out:writeln(table.concat(modules, ', ')) + local backtickOccurence = 0 + sinks.out:writeln(lunacolors.format(doc:gsub('`', function() + backtickOccurence = backtickOccurence + 1 + if backtickOccurence % 2 == 0 then + return '{reset}' + else + return '{underline}{green}' + end + end):gsub('#+.-\n', function(t) + local signature = t:gsub('<.->(.-)', '{underline}%1'):gsub('\\', '<') + return '{bold}{yellow}' .. signature .. '{reset}' + end))) end) diff --git a/nature/init.lua b/nature/init.lua index ecd1054..d1f919c 100644 --- a/nature/init.lua +++ b/nature/init.lua @@ -67,7 +67,7 @@ do end bait.catch('error', function(event, handler, err) - bait.release(event, handler) + print(string.format('Encountered an error in %s handler\n%s', event, err:sub(8))) end) bait.catch('command.not-found', function(cmd) diff --git a/nature/runner.lua b/nature/runner.lua index 9b62ad1..235ab77 100644 --- a/nature/runner.lua +++ b/nature/runner.lua @@ -75,6 +75,12 @@ function hilbish.runner.setCurrent(name) hilbish.runner.setMode(r.run) end +--- Returns the current runner by name. +--- @returns string +function hilbish.runner.getCurrent() + return currentRunner +end + hilbish.runner.add('hybrid', function(input) local cmdStr = hilbish.aliases.resolve(input) diff --git a/timer.go b/timer.go index be8f270..d2568b1 100644 --- a/timer.go +++ b/timer.go @@ -15,6 +15,11 @@ const ( timerTimeout ) +// #interface timers +// #property type What type of timer it is +// #property running If the timer is running +// #property duration The duration in milliseconds that the timer will run +// The Job type describes a Hilbish timer. type timer struct{ id int typ timerType diff --git a/timerhandler.go b/timerhandler.go index 3a2ecbb..0cb4197 100644 --- a/timerhandler.go +++ b/timerhandler.go @@ -62,7 +62,7 @@ func (th *timersModule) get(id int) *timer { } // #interface timers -// create(type, time, callback) +// create(type, time, callback) -> @Timer // Creates a timer that runs based on the specified `time` in milliseconds. // The `type` can either be `hilbish.timers.INTERVAL` or `hilbish.timers.TIMEOUT` // --- @param type number @@ -91,7 +91,7 @@ func (th *timersModule) luaCreate(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) { } // #interface timers -// get(id) -> timer (Timer/Table) +// get(id) -> @Timer // Retrieves a timer via its ID. // --- @param id number // --- @returns Timer @@ -115,13 +115,30 @@ func (th *timersModule) luaGet(thr *rt.Thread, c *rt.GoCont) (rt.Cont, error) { // #interface timers // #field INTERVAL Constant for an interval timer type // #field TIMEOUT Constant for a timeout timer type -// #property type What type of timer it is -// #property running If the timer is running -// #property duration The duration in milliseconds that the timer will run // timeout and interval API -// The timers interface si one to easily set timeouts and intervals -// to run functions after a certain time or repeatedly without using -// odd tricks. +/* +If you ever want to run a piece of code on a timed interval, or want to wait +a few seconds, you don't have to rely on timing tricks, as Hilbish has a +timer API to set intervals and timeouts. + +These are the simple functions `hilbish.interval` and `hilbish.timeout` (doc +accessible with `doc hilbish`). But if you want slightly more control over +them, there is the `hilbish.timers` interface. It allows you to get +a timer via ID and control them. + +## Timer Object +All functions documented with the `Timer` type refer to a Timer object. + +An example of usage: +``` +local t = hilbish.timers.create(hilbish.timers.TIMEOUT, 5000, function() + print 'hello!' +end) + +t:start() +print(t.running) // true +``` +*/ func (th *timersModule) loader(rtm *rt.Runtime) *rt.Table { timerMethods := rt.NewTable() timerFuncs := map[string]util.LuaExport{ diff --git a/vars.go b/vars.go index 810c1ee..41c7a02 100644 --- a/vars.go +++ b/vars.go @@ -11,7 +11,7 @@ var ( // Version info var ( - ver = "v2.0.0" + ver = "v2.1.0" releaseName = "Hibiscus" gitCommit string gitBranch string diff --git a/website/.hugo_build.lock b/website/.hugo_build.lock deleted file mode 100644 index e69de29..0000000 diff --git a/website/config.toml b/website/config.toml index ff6b801..31f42d5 100644 --- a/website/config.toml +++ b/website/config.toml @@ -20,6 +20,16 @@ enableGitInfo = true name = 'Docs' pageref = '/docs' weight = 3 - +[[menu.nav]] + identifier = 'blog' + name = 'Blog' + pageref = '/blog' + weight = 4 + [markup.goldmark.renderer] unsafe = true + +[author] + [author.sammyette] + name = 'sammyette' + picture = 'https://avatars1.githubusercontent.com/u/38820196?s=460&u=b9f4efb2375bae6cb30656d790c6e0a2939327c0&v=4' diff --git a/website/content/blog/v2.0-release.md b/website/content/blog/v2.0-release.md new file mode 100644 index 0000000..23b8f6f --- /dev/null +++ b/website/content/blog/v2.0-release.md @@ -0,0 +1,114 @@ +--- +title: "Hilbish v2.0 Release" +date: 2022-12-29T01:55:21+00:00 +--- + +Hilbish v2.0 has been released! +Well actually, it was released a week ago, but I only wrote this +Hilbish blog *after* that. + +This is a **big** release, coming 9 months after the previous v1.2.0 and +featuring over 40+ bug fixes and tons of new features and enhancements, so +let's see what is in this release. + +# Documentation +When querying about the problems people have with Hilbish, one of the +issues was its poor documentation. Hilbish had plain text, autogenerated +documentation which only covered the module functions (bait, hilbish, +commander, etc.) and did not include the interfaces (`hilbish.timers`, +`hilbish.jobs` and all that). + +I have tried to improve this by working on documenting all the +interfaces (except for some functions of `hilbish.runner`, that's hard to do) +and made the documentation markdown for use on this website. This means +that users can look at documentation here or with the `doc` command. + +Hopefully this addresses documentation complaints, and if not, please open an issue. + +# Main Bug Fixes +As this is a piece of software with no unit testing that is maintained by me alone, +there is gonna be either some bug or something that I overlooked when +making a change. I make a lot of mistakes. There's also the other fact that +sometimes there's just bugs for any other reasosn. Good thing I fixed +more than 40 of those bugs in this release! + +## Readline Bug Fixes +The pure Go readline library is good in some ways and bad in others. +A good portion of the bug fixes are for the readline library, and also +related to text input with east asian characters and the like (Korean, Japanese, +etc.) + +A few of the fixes (and additions) include: + +- Fixing various crashes, including when there is a "stray" newline at the end of text +- Grid completion menu causing spam and duplicate text when there are items longer than +the terminal and/or contain Japanese or other characters. +- Cursor positioning with CJK characters +- Adding new keybinds and fixing others + +## Other fixes +There are a lot more fixes, even more than the ones listed here, but these are the main ones: + - Don't put alias expanded command in history (I've fixed this 5 times now....) + - Handle stdin being nonblocking + - Completion related fixes, like showing the full name, completing files with spaces + +# Breaking changes +This release is a major version bump not only because there are tons of fixes, but because +there are breaking changes. This means that there are some changes done which would +cause errors with an old user config (breaking). + +## Lua 5.4 +The most important is the use of a new Lua VM library. Previously, Hilbish +used gopher-lua, which implements Lua 5.1. This has been changed to +[golua](https://github.com/arnodel/golua/), which implements Lua 5.4. + +Moving from 5.1 to 5.4 does have breaking changes even if it doesn't seem like it, +and since these are different Lua implementations, there may be some differences there too. + +## Userdata +Previously, objects such as jobs or timers were represented by tables. +This has been changed to userdata to make more sense. + +## Other changes +Runner functions are now required to return a table. +It can (at the moment) have 4 variables: + - `input` (user input) + - `exitCode` (exit code) + - `error` (error message) + - `continue` (whether to prompt for more input) +User input has been added to the return to account for runners wanting to +prompt for continued input, and to add it properly to history. `continue` +got added so that it would be easier for runners to get continued input +without having to actually handle it at all. + +The MacOS config paths now match Linux, since it makes more sense for +a program like Hilbish. + +The Hilbish greeting is now an *opt*, and is printed by default. + +# Feature Additions +Besides fixes and changes, this release also includes a good portion of +new features! Users can now add handlers for syntax highlighting and +inline hinting. + +Some new hooks have been added, like `hilbish.cancel` and `hilbish.init`. +You can look at all the hooks via the `doc hooks` command + +Job management functions have also been added. You can now put jobs in the +foreground/background and disown them via the expected commands and also +via the Lua API. + +The `hilbish.timers` API interface was also added in this release! + +# Closing Off +Hilbish has gone from something small and simple for myself to a slightly +advanced shell with a decent amount of features, and a few users. It +still hasn't reached levels of other alt shells in regards to literally +everything, but the goal is to get there! + +If you want to check the FULL changelog, you can [do so here.](https://github.com/Rosettea/Hilbish/releases/tag/v2.0.0) +This v2.0 release marks an advancement in Hilbish (and also how long +one of my projects hasn't died) and I hope it can advance even further. + +Thanks for reading, and I'll be back for the v2.1 release notes, or maybe +something else in between. diff --git a/website/content/blog/welcome.md b/website/content/blog/welcome.md new file mode 100644 index 0000000..16a878d --- /dev/null +++ b/website/content/blog/welcome.md @@ -0,0 +1,6 @@ +--- +title: "Welcome to the Hilbish blog" +--- + +Hello! Welcome to the Hilbish blog. This will mainly contain release +announcements and some other things relating to Hilbish (development). diff --git a/website/themes/hsh/layouts/_default/_markup/render-heading.html b/website/themes/hsh/layouts/_default/_markup/render-heading.html index 6ea5346..da71fe1 100644 --- a/website/themes/hsh/layouts/_default/_markup/render-heading.html +++ b/website/themes/hsh/layouts/_default/_markup/render-heading.html @@ -1,6 +1,11 @@ - + + {{ .Text | safeHTML }} + + + + {{ if eq .Text ""}} -
+
{{ end }} diff --git a/website/themes/hsh/layouts/_default/_markup/render-link.html b/website/themes/hsh/layouts/_default/_markup/render-link.html index 9c2a95e..b0d800e 100644 --- a/website/themes/hsh/layouts/_default/_markup/render-link.html +++ b/website/themes/hsh/layouts/_default/_markup/render-link.html @@ -1,4 +1 @@ - - {{ .Text | safeHTML }} - - +{{ .Text | safeHTML }} diff --git a/website/themes/hsh/layouts/_default/list.html b/website/themes/hsh/layouts/_default/list.html index e69de29..bbb9e8a 100644 --- a/website/themes/hsh/layouts/_default/list.html +++ b/website/themes/hsh/layouts/_default/list.html @@ -0,0 +1,21 @@ +{{ define "main" }} +
+
+ {{ range where .Site.RegularPages "Section" "in" "blog" }} +
+
+
+
{{ .Title }}
+
+ {{- if isset .Params "date" -}} + + {{- end -}} +
+

{{if .Description}}{{ .Description }}{{ else }}{{ .Summary }}{{ end }}

+
+
+
+ {{- end }} +
+
+{{ end }} diff --git a/website/themes/hsh/layouts/_default/single.html b/website/themes/hsh/layouts/_default/single.html index 0ac0e37..bd7e18c 100644 --- a/website/themes/hsh/layouts/_default/single.html +++ b/website/themes/hsh/layouts/_default/single.html @@ -2,7 +2,16 @@

{{ .Title }}

- {{.Content}} + + + by {{ .Site.Author.sammyette.name }} + {{- if isset .Params "date" -}} + + {{- end -}} + +
+ {{.Content}} +
{{ end }} diff --git a/website/themes/hsh/layouts/partials/head.html b/website/themes/hsh/layouts/partials/head.html index 3556074..fca4558 100644 --- a/website/themes/hsh/layouts/partials/head.html +++ b/website/themes/hsh/layouts/partials/head.html @@ -1,7 +1,7 @@ {{ $title := print .Title " — " .Site.Title }} - {{ if .IsHome }}{{ $title = .Site.Title }}{{ end }} - {{ $title }} + {{ if .IsHome }}{{ $title = .Site.Title }}{{ end }} + {{ $title }} @@ -23,4 +23,16 @@ + +