chore: merge from master

commander-stdout
sammyette 2023-01-20 18:42:44 -04:00
commit e3dca7a996
Signed by: sammyette
GPG Key ID: 904FC49417B44DCD
32 changed files with 568 additions and 223 deletions

1
.gitignore vendored
View File

@ -6,3 +6,4 @@ docgen
.vim
petals/
.hugo_build.lock

View File

@ -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

View File

@ -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
<div align="center">
<img src="gallery/default.png"><br><br>
<img src="gallery/terminal.png"><br><br>
<img src="gallery/tab.png"><br><br>
<img src="gallery/pillprompt.png">
</div>
# 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

View File

@ -92,9 +92,9 @@ func (a *aliasModule) Loader(rtm *rt.Runtime) *rt.Table {
func _hlalias() {}
// #interface aliases
// list() -> aliases (table)
// list() -> table<string, string>
// Get a table of all aliases, with string keys as the alias and the value as the command.
// @returns table<string, string>
// --- @returns table<string, string>
func (a *aliasModule) luaList(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
aliasesList := rt.NewTable()
for k, v := range a.All() {

28
api.go
View File

@ -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 {

View File

@ -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,11 +433,21 @@ func main() {
}
f.WriteString("\n")
}
if len(modu.Docs) != 0 {
typeTag, _ := regexp.Compile(`@\w+`)
f.WriteString("## Functions\n")
}
for _, dps := range modu.Docs {
f.WriteString(fmt.Sprintf("### %s\n", dps.FuncSig))
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(`<a href="%s" style="text-decoration: none;">%s</a>`, linkedTyp, typName)
})
f.WriteString(fmt.Sprintf("### %s\n", htmlSig))
for _, doc := range dps.Doc {
if !strings.HasPrefix(doc, "---") {
f.WriteString(doc + "\n")
@ -347,6 +455,50 @@ func main() {
}
f.WriteString("\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(`<a href="#%s" style="text-decoration: none;">%s</a>`, 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")
}
}
}
}(mod, docPath, v)
go func(md, modname string, modu module) {

View File

@ -35,7 +35,7 @@ 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()
### 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) -> <a href="/Hilbish/docs/api/hilbish/hilbish.timers/#timer" style="text-decoration: none;">Timer</a>
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) -> <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.
### 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.

View File

@ -17,9 +17,8 @@ This is an alias (ha) for the `hilbish.alias` function.
### delete(name)
Removes an alias.
### list() -> aliases (table)
### list() -> table\<string, string>
Get a table of all aliases, with string keys as the alias and the value as the command.
@returns table<string, string>
### resolve(alias) -> command (string)
Tries to resolve an alias to its command.

View File

@ -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\<<a href="/Hilbish/docs/api/hilbish/hilbish.jobs/#job" style="text-decoration: none;">Job</a>>
Returns a table of all job objects.
### disown(id)
Disowns a job. This deletes it from the job table.
### get(id) -> <a href="/Hilbish/docs/api/hilbish/hilbish.jobs/#job" style="text-decoration: none;">Job</a>
Get a job object via its ID.
### last() -> <a href="/Hilbish/docs/api/hilbish/hilbish.jobs/#job" style="text-decoration: none;">Job</a>
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<Job/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.

View File

@ -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) -> <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`
### get(id) -> <a href="/Hilbish/docs/api/hilbish/hilbish.timers/#timer" style="text-decoration: none;">Timer</a>
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.

View File

@ -1 +0,0 @@
hello!

View File

@ -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.

View File

@ -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`)

View File

@ -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`.

BIN
gallery/tab.png 100644

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

23
job.go
View File

@ -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<Job/Table>)
// all() -> table<@Job>
// Returns a table of all job objects.
// --- @returns table<Job>
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) {

View File

@ -8,14 +8,14 @@ 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')
end
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)
@ -25,11 +25,4 @@ commander.register('cd', function (args, sinks)
return 1
end
bait.throw('cd', path)
return
end
fs.cd(hilbish.home)
bait.throw('cd', hilbish.home)
dirs.push(hilbish.home)
end)

View File

@ -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 <section> [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,8 +81,12 @@ commander.register('doc', function(args, sinks)
if mod == 'api' then
funcdocs = string.format(apidocHeader, vals.title, vals.description or 'no description.') .. funcdocs
end
doc = funcdocs:sub(1, #funcdocs - 1)
f:close()
end
local backtickOccurence = 0
local formattedFuncs = lunacolors.format(funcdocs:sub(1, #funcdocs - 1):gsub('`', function()
sinks.out:writeln(lunacolors.format(doc:gsub('`', function()
backtickOccurence = backtickOccurence + 1
if backtickOccurence % 2 == 0 then
return '{reset}'
@ -72,25 +94,7 @@ commander.register('doc', function(args, sinks)
return '{underline}{green}'
end
end):gsub('#+.-\n', function(t)
return '{bold}{magenta}' .. t .. '{reset}'
end))
sinks.out:writeln(formattedFuncs)
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 <section> [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 signature = t:gsub('<.->(.-)</.->', '{underline}%1'):gsub('\\', '<')
return '{bold}{yellow}' .. signature .. '{reset}'
end)))
end)

View File

@ -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)

View File

@ -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)

View File

@ -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

View File

@ -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{

View File

@ -11,7 +11,7 @@ var (
// Version info
var (
ver = "v2.0.0"
ver = "v2.1.0"
releaseName = "Hibiscus"
gitCommit string
gitBranch string

View File

@ -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'

View File

@ -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.

View File

@ -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).

View File

@ -1,6 +1,11 @@
<h{{ (add .Level 1) }} id="{{ .Anchor | safeURL }}">
<h{{ (add .Level 1) }} id="{{ .Anchor | safeURL }}" class="heading">
{{ .Text | safeHTML }}
<a href="#{{ .Anchor | safeURL }}" class='heading-link'>
<i class="fas fa-paperclip"></i>
</a>
</h{{ (add .Level 1) }}>
{{ if eq .Text ""}}
<hr>
{{ end }}

View File

@ -1,4 +1 @@
<a href="{{ .Destination | safeURL }}"{{ with .Title}} title="{{ . }}"{{ end }}{{ if eq (substr .Destination 0 4) "http" }} target="_blank" rel="noopener"{{ end }}>
{{ .Text | safeHTML }}
</a>
<a href="{{ .Destination | safeURL }}"{{ with .Title}} title="{{ . }}"{{ end }}{{ if eq (substr .Destination 0 4) "http" }} target="_blank" rel="noopener"{{ end }}>{{ .Text | safeHTML }}</a>

View File

@ -0,0 +1,21 @@
{{ define "main" }}
<main>
<div class="row row-cols-1 row-cols-md-1 g-4">
{{ range where .Site.RegularPages "Section" "in" "blog" }}
<div class="col d-flex justify-content-center">
<div class="card" style="width: 56rem;">
<div class="card-body">
<a href="{{ .Permalink }}"><h5 class="card-title">{{ .Title }}</h5></a>
<h6 class='card-subtitle text-muted mb-2'>
{{- if isset .Params "date" -}}
<time>{{ .Date.Format "January 2, 2006" }}</time>
{{- end -}}
</h6>
<p class="card-text">{{if .Description}}{{ .Description }}{{ else }}{{ .Summary }}{{ end }}</p>
</div>
</div>
</div>
{{- end }}
</div>
</main>
{{ end }}

View File

@ -2,7 +2,16 @@
<main>
<div class="container mt-2">
<h1>{{ .Title }}</h1>
<img src='{{ .Site.Author.sammyette.picture }}' width=48 style='border-radius: 100%'>
<em class='text-muted'>
by <strong>{{ .Site.Author.sammyette.name }}</strong>
{{- if isset .Params "date" -}}
<time> // {{ .Date.Format "January 2, 2006" }}</time>
{{- end -}}
</em>
<div class='my-4'>
{{.Content}}
</div>
</div>
</main>
{{ end }}

View File

@ -23,4 +23,16 @@
<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" />
<style>
.heading > .heading-link {
opacity: 0
}
.heading:hover > .heading-link {
visibility: visible;
opacity: 1;
transition: all .1s ease-in;
}
</style>
</head>