chore: merge from master

pull/240/head
sammyette 2023-03-25 17:45:45 -04:00
commit 7531bbfd14
Signed by: sammyette
GPG Key ID: 904FC49417B44DCD
7 changed files with 137 additions and 7 deletions

View File

@ -1,5 +1,15 @@
# 🎀 Changelog # 🎀 Changelog
## Unreleased
### Added
- Made a few additions to the sink type:
- `read()` method for retrieving input (so now the `in` sink of commanders is useful)
- `flush()` and `autoFlush()` related to flushing outputs
- `pipe` property to check if a sink with input is a pipe (like stdin)
### Fixed
- Replaced `sed` in-place editing with `grep` and `mv` for compatibility with BSD utils
## [2.1.0] - 2022-02-10 ## [2.1.0] - 2022-02-10
### Added ### Added
- Documented custom userdata types (Job and Timer Objects) - Documented custom userdata types (Job and Timer Objects)

View File

@ -34,4 +34,4 @@ tasks:
- rm -vrf - rm -vrf
"{{.DESTDIR}}{{.BINDIR}}/hilbish" "{{.DESTDIR}}{{.BINDIR}}/hilbish"
"{{.DESTDIR}}{{.LIBDIR}}" "{{.DESTDIR}}{{.LIBDIR}}"
- sed -i '/hilbish/d' /etc/shells - grep -v 'hilbish' /etc/shells > /tmp/shells.hilbish_uninstall && mv /tmp/shells.hilbish_uninstall /etc/shells

View File

@ -109,6 +109,16 @@ A sink is a structure that has input and/or output to/from
a desination. a desination.
### Methods ### Methods
#### autoFlush(auto)
Sets/toggles the option of automatically flushing output.
A call with no argument will toggle the value.
#### flush()
Flush writes all buffered input to the sink.
#### read() -> string
Reads input from the sink.
#### write(str) #### write(str)
Writes data to a sink. Writes data to a sink.

View File

@ -180,6 +180,18 @@ function hilbish.jobs:foreground() end
--- @param cmd string --- @param cmd string
function hilbish.runner.lua(cmd) end function hilbish.runner.lua(cmd) end
--- Sets/toggles the option of automatically flushing output.
--- A call with no argument will toggle the value.
--- @param auto boolean|nil
function hilbish:autoFlush(auto) end
--- Flush writes all buffered input to the sink.
function hilbish:flush() end
--- Reads input from the sink.
--- @returns string
function hilbish:read() end
--- Writes data to a sink. --- Writes data to a sink.
function hilbish:write(str) end function hilbish:write(str) end

View File

@ -7,7 +7,7 @@ commander.register('bg', function(_, sinks)
return 1 return 1
end end
local err = job.background() local err = job:background()
if err then if err then
sinks.out:writeln('bg: ' .. err) sinks.out:writeln('bg: ' .. err)
return 2 return 2

View File

@ -7,7 +7,7 @@ commander.register('fg', function(_, sinks)
return 1 return 1
end end
local err = job.foreground() -- waits for job; blocks local err = job:foreground() -- waits for job; blocks
if err then if err then
sinks.out:writeln('fg: ' .. err) sinks.out:writeln('fg: ' .. err)
return 2 return 2

106
sink.go
View File

@ -1,8 +1,10 @@
package main package main
import ( import (
"bufio"
"fmt" "fmt"
"io" "io"
"os"
"hilbish/util" "hilbish/util"
@ -15,9 +17,11 @@ var sinkMetaKey = rt.StringValue("hshsink")
// A sink is a structure that has input and/or output to/from // A sink is a structure that has input and/or output to/from
// a desination. // a desination.
type sink struct{ type sink struct{
writer io.Writer writer *bufio.Writer
reader io.Reader reader *bufio.Reader
file *os.File
ud *rt.UserData ud *rt.UserData
autoFlush bool
} }
func setupSinkType(rtm *rt.Runtime) { func setupSinkType(rtm *rt.Runtime) {
@ -25,15 +29,35 @@ func setupSinkType(rtm *rt.Runtime) {
sinkMethods := rt.NewTable() sinkMethods := rt.NewTable()
sinkFuncs := map[string]util.LuaExport{ sinkFuncs := map[string]util.LuaExport{
"flush": {luaSinkFlush, 1, false},
"read": {luaSinkRead, 1, false},
"autoFlush": {luaSinkAutoFlush, 2, false},
"write": {luaSinkWrite, 2, false}, "write": {luaSinkWrite, 2, false},
"writeln": {luaSinkWriteln, 2, false}, "writeln": {luaSinkWriteln, 2, false},
} }
util.SetExports(l, sinkMethods, sinkFuncs) util.SetExports(l, sinkMethods, sinkFuncs)
sinkIndex := func(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) { sinkIndex := func(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
s, _ := sinkArg(c, 0)
arg := c.Arg(1) arg := c.Arg(1)
val := sinkMethods.Get(arg) val := sinkMethods.Get(arg)
if val != rt.NilValue {
return c.PushingNext1(t.Runtime, val), nil
}
keyStr, _ := arg.TryString()
switch keyStr {
case "pipe":
val = rt.BoolValue(false)
if s.file != nil {
fileInfo, _ := s.file.Stat();
val = rt.BoolValue(fileInfo.Mode() & os.ModeCharDevice == 0)
}
}
return c.PushingNext1(t.Runtime, val), nil return c.PushingNext1(t.Runtime, val), nil
} }
@ -41,6 +65,25 @@ func setupSinkType(rtm *rt.Runtime) {
l.SetRegistry(sinkMetaKey, rt.TableValue(sinkMeta)) l.SetRegistry(sinkMetaKey, rt.TableValue(sinkMeta))
} }
// #member
// read() -> string
// --- @returns string
// Reads input from the sink.
func luaSinkRead(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
if err := c.Check1Arg(); err != nil {
return nil, err
}
s, err := sinkArg(c, 0)
if err != nil {
return nil, err
}
str, _ := s.reader.ReadString('\n')
return c.PushingNext1(t.Runtime, rt.StringValue(str)), nil
}
// #member // #member
// write(str) // write(str)
// Writes data to a sink. // Writes data to a sink.
@ -59,6 +102,9 @@ func luaSinkWrite(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
} }
s.writer.Write([]byte(data)) s.writer.Write([]byte(data))
if s.autoFlush {
s.writer.Flush()
}
return c.Next(), nil return c.Next(), nil
} }
@ -81,22 +127,74 @@ func luaSinkWriteln(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
} }
s.writer.Write([]byte(data + "\n")) s.writer.Write([]byte(data + "\n"))
if s.autoFlush {
s.writer.Flush()
}
return c.Next(), nil
}
// #member
// flush()
// Flush writes all buffered input to the sink.
func luaSinkFlush(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
if err := c.Check1Arg(); err != nil {
return nil, err
}
s, err := sinkArg(c, 0)
if err != nil {
return nil, err
}
s.writer.Flush()
return c.Next(), nil
}
// #member
// autoFlush(auto)
// Sets/toggles the option of automatically flushing output.
// A call with no argument will toggle the value.
// --- @param auto boolean|nil
func luaSinkAutoFlush(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
s, err := sinkArg(c, 0)
if err != nil {
return nil, err
}
v := c.Arg(1)
if v.Type() != rt.BoolType && v.Type() != rt.NilType {
return nil, fmt.Errorf("#1 must be a boolean")
}
value := !s.autoFlush
if v.Type() == rt.BoolType {
value = v.AsBool()
}
s.autoFlush = value
return c.Next(), nil return c.Next(), nil
} }
func newSinkInput(r io.Reader) *sink { func newSinkInput(r io.Reader) *sink {
s := &sink{ s := &sink{
reader: r, reader: bufio.NewReader(r),
} }
s.ud = sinkUserData(s) s.ud = sinkUserData(s)
if f, ok := r.(*os.File); ok {
s.file = f
}
return s return s
} }
func newSinkOutput(w io.Writer) *sink { func newSinkOutput(w io.Writer) *sink {
s := &sink{ s := &sink{
writer: w, writer: bufio.NewWriter(w),
autoFlush: true,
} }
s.ud = sinkUserData(s) s.ud = sinkUserData(s)