Compare commits

..

No commits in common. "1fd99a78cca2ff3d5f40413621df2b90c62c0eb2" and "8fdde4aa58b176d32e0e92d09bcb4bd1b6cbf978" have entirely different histories.

4 changed files with 25 additions and 89 deletions

View File

@ -23,17 +23,6 @@ is for everything/anything as opposed to just adding a single command completion
[#122](https://github.com/Rosettea/Hilbish/issues/122)
- `fs.abs(path)` to get absolute path.
- Nature module (`doc nature`)
- `hilbish.jobs.add(cmdstr, args, execPath)` to add a job to the job table.
`cmdstr` would be user input, `args` is the args for the command (includes arg0)
and `execPath` is absolute path to command executable
- `job.add` hook is thrown when a job is added. acts as a unique hook for
jobs
- `hilbish.jobs.disown(id)` and `disown` builtin to disown a job. `disown`
without arguments will disown the last job.
- `hilbish.jobs.last()` returns the last added job.
- Job output (stdout/stderr) can now be obtained via the `stdout` and `stderr`
fields on a job object.
- Documentation for jobs is now available via `doc jobs`.
### Changed
- **Breaking Change:** Upgraded to Lua 5.4.
@ -68,8 +57,6 @@ certain color rules.
- Cursor position with CJK characters. ([#145](https://github.com/Rosettea/Hilbish/pull/145))
- Files with same name as parent folder in completions getting cut off [#136](https://github.com/Rosettea/Hilbish/issues/136))
- `hilbish.which` now works with commanders and aliases.
- Background jobs no longer take stdin so they do not interfere with shell
input.
## [1.2.0] - 2022-03-17
### Added

View File

@ -1,5 +1,11 @@
Note: `job` refers to a job object. YOu can check `doc jobs` for more
detail.
Note: A `job` is a table with the following keys:
- cmd: command string
- running: boolean whether the job is running
- id: unique id for the job
- pid: process id for the job
- exitCode: exit code of the job
In ordinary cases you'd prefer to use the id instead of pid. The id is unique to
Hilbish and is how you get jobs with the `hilbish.jobs` interface.
+ `job.start` -> job > Thrown when a new background job starts.

View File

@ -1,40 +0,0 @@
Hilbish has pretty standard job control. It's missing one or two things,
but works well. One thing which is different from other shells
(besides Hilbish) itself is the API for jobs, and of course it's in Lua.
You can add jobs, stop and delete (disown) them and even get output.
# Job Interface
The job interface refers to `hilbish.jobs`.
## Functions
(Note that in the list here, they're called from `hilbish.jobs`, so
a listing of `foo` would mean `hilbish.jobs.foo`)
- `all()` -> {jobs}: Returns a table of all jobs.
- `last()` -> job: Returns the last added job.
- `get(id)` -> job: Get a job by its ID.
- `add(cmdstr, args, execPath)` -> job: Adds a new job to the job table.
Note that this does not run the command; You have to start it manually.
`cmdstr` is the user's input for the job, `args` is a table of arguments
for the command. It includes arg0 (don't set it as entry 0 in the table)
and `execPath` is an absolute path for the command executable.
- `disown(id)`: Removes a job by ID from the job table.
# Job Object
A job object on the Lua side is a table with some functions.
On the under side it represents a job in the job table.
You can still have a job object for a disowned job,
it just won't be *working* anywhere. :^)
## Properties
- `cmd`: command string
- `running`: boolean whether the job is running
- `id`: unique id for the job
- `pid`: process id for the job
- `exitCode`: exit code of the job
In ordinary cases you'd prefer to use the `id` instead of `pid`.
The `id` is unique to Hilbish and is how you get jobs with the
`hilbish.jobs` interface. It may also not describe the job entirely.
## Functions
- `stop()`: Stops the job.
- `start()`: Starts the job.

51
job.go
View File

@ -1,7 +1,6 @@
package main
import (
"bytes"
"errors"
"io"
"os"
@ -28,10 +27,9 @@ type job struct {
// would just be so itll be the same binary command always (path changes)
path string
handle *exec.Cmd
cmdout io.Writer
cmderr io.Writer
stdout *bytes.Buffer
stderr *bytes.Buffer
stdin io.Reader
stdout io.Writer
stderr io.Writer
}
func (j *job) start() error {
@ -40,19 +38,13 @@ func (j *job) start() error {
cmd := exec.Cmd{
Path: j.path,
Args: j.args,
Stdin: j.stdin,
Stdout: j.stdout,
Stderr: j.stderr,
}
j.setHandle(&cmd)
}
// bgProcAttr is defined in execfile_<os>.go, it holds a procattr struct
// in a simple explanation, it makes signals from hilbish (sigint)
// not go to it (child process)
j.handle.SysProcAttr = bgProcAttr
// reset output buffers
j.stdout.Reset()
j.stderr.Reset()
// make cmd write to both standard output and output buffers for lua access
j.handle.Stdout = io.MultiWriter(j.cmdout, j.stdout)
j.handle.Stderr = io.MultiWriter(j.cmderr, j.stderr)
if !j.once {
j.once = true
@ -90,12 +82,9 @@ func (j *job) setHandle(handle *exec.Cmd) {
j.handle = handle
j.args = handle.Args
j.path = handle.Path
if handle.Stdout != nil {
j.cmdout = handle.Stdout
}
if handle.Stderr != nil {
j.cmderr = handle.Stderr
}
j.stdin = handle.Stdin
j.stdout = handle.Stdout
j.stderr = handle.Stderr
}
func (j *job) getProc() *os.Process {
@ -120,8 +109,6 @@ func (j *job) lua() rt.Value {
luaJob.Set(rt.StringValue("id"), rt.IntValue(int64(j.id)))
luaJob.Set(rt.StringValue("pid"), rt.IntValue(int64(j.pid)))
luaJob.Set(rt.StringValue("exitCode"), rt.IntValue(int64(j.exitCode)))
luaJob.Set(rt.StringValue("stdout"), rt.StringValue(string(j.stdout.Bytes())))
luaJob.Set(rt.StringValue("stderr"), rt.StringValue(string(j.stderr.Bytes())))
return rt.TableValue(luaJob)
}
@ -171,10 +158,9 @@ func (j *jobHandler) add(cmd string, args []string, path string) *job {
id: j.latestID,
args: args,
path: path,
cmdout: os.Stdout,
cmderr: os.Stderr,
stdout: &bytes.Buffer{},
stderr: &bytes.Buffer{},
stdin: os.Stdin,
stdout: os.Stdout,
stderr: os.Stderr,
}
j.jobs[j.latestID] = jb
hooks.Em.Emit("job.add", jb.lua())
@ -222,7 +208,7 @@ func (j *jobHandler) loader(rtm *rt.Runtime) *rt.Table {
"all": {j.luaAllJobs, 0, false},
"last": {j.luaLastJob, 0, false},
"get": {j.luaGetJob, 1, false},
"add": {j.luaAddJob, 3, false},
"add": {j.luaAddJob, 2, false},
"disown": {j.luaDisownJob, 1, false},
}
@ -253,7 +239,7 @@ func (j *jobHandler) luaGetJob(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
}
func (j *jobHandler) luaAddJob(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
if err := c.CheckNArgs(3); err != nil {
if err := c.CheckNArgs(2); err != nil {
return nil, err
}
cmd, err := c.StringArg(0)
@ -264,10 +250,6 @@ func (j *jobHandler) luaAddJob(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
if err != nil {
return nil, err
}
execPath, err := c.StringArg(2)
if err != nil {
return nil, err
}
var args []string
util.ForEach(largs, func(k rt.Value, v rt.Value) {
@ -275,8 +257,8 @@ func (j *jobHandler) luaAddJob(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
args = append(args, v.AsString())
}
})
jb := j.add(cmd, args, execPath)
// TODO: change to lookpath for args[0]
jb := j.add(cmd, args, args[0])
return c.PushingNext1(t.Runtime, jb.lua()), nil
}
@ -321,3 +303,4 @@ func (j *jobHandler) luaLastJob(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
return c.PushingNext1(t.Runtime, job.lua()), nil
}