diff --git a/CHANGELOG.md b/CHANGELOG.md index 161fde2..cebe18e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,15 @@ # 🎀 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 ### Added - Documented custom userdata types (Job and Timer Objects) diff --git a/Taskfile.yaml b/Taskfile.yaml index 6bf17e0..5c5caae 100644 --- a/Taskfile.yaml +++ b/Taskfile.yaml @@ -34,4 +34,4 @@ tasks: - rm -vrf "{{.DESTDIR}}{{.BINDIR}}/hilbish" "{{.DESTDIR}}{{.LIBDIR}}" - - sed -i '/hilbish/d' /etc/shells + - grep -v 'hilbish' /etc/shells > /tmp/shells.hilbish_uninstall && mv /tmp/shells.hilbish_uninstall /etc/shells diff --git a/docs/api/hilbish/_index.md b/docs/api/hilbish/_index.md index 81ca993..d2d13c8 100644 --- a/docs/api/hilbish/_index.md +++ b/docs/api/hilbish/_index.md @@ -109,6 +109,16 @@ A sink is a structure that has input and/or output to/from a desination. ### 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) Writes data to a sink. diff --git a/emmyLuaDocs/hilbish.lua b/emmyLuaDocs/hilbish.lua index 8b20583..8d46276 100644 --- a/emmyLuaDocs/hilbish.lua +++ b/emmyLuaDocs/hilbish.lua @@ -180,6 +180,18 @@ function hilbish.jobs:foreground() end --- @param cmd string 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. function hilbish:write(str) end diff --git a/nature/commands/bg.lua b/nature/commands/bg.lua index a7f486a..fbb3543 100644 --- a/nature/commands/bg.lua +++ b/nature/commands/bg.lua @@ -7,7 +7,7 @@ commander.register('bg', function(_, sinks) return 1 end - local err = job.background() + local err = job:background() if err then sinks.out:writeln('bg: ' .. err) return 2 diff --git a/nature/commands/fg.lua b/nature/commands/fg.lua index 64b145f..c5b6738 100644 --- a/nature/commands/fg.lua +++ b/nature/commands/fg.lua @@ -7,7 +7,7 @@ commander.register('fg', function(_, sinks) return 1 end - local err = job.foreground() -- waits for job; blocks + local err = job:foreground() -- waits for job; blocks if err then sinks.out:writeln('fg: ' .. err) return 2 diff --git a/sink.go b/sink.go index 9a98856..2ecc19d 100644 --- a/sink.go +++ b/sink.go @@ -1,8 +1,10 @@ package main import ( + "bufio" "fmt" "io" + "os" "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 desination. type sink struct{ - writer io.Writer - reader io.Reader + writer *bufio.Writer + reader *bufio.Reader + file *os.File ud *rt.UserData + autoFlush bool } func setupSinkType(rtm *rt.Runtime) { @@ -25,15 +29,35 @@ func setupSinkType(rtm *rt.Runtime) { sinkMethods := rt.NewTable() sinkFuncs := map[string]util.LuaExport{ + "flush": {luaSinkFlush, 1, false}, + "read": {luaSinkRead, 1, false}, + "autoFlush": {luaSinkAutoFlush, 2, false}, "write": {luaSinkWrite, 2, false}, "writeln": {luaSinkWriteln, 2, false}, } util.SetExports(l, sinkMethods, sinkFuncs) sinkIndex := func(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) { + s, _ := sinkArg(c, 0) + arg := c.Arg(1) 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 } @@ -41,6 +65,25 @@ func setupSinkType(rtm *rt.Runtime) { 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 // write(str) // 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)) + if s.autoFlush { + s.writer.Flush() + } 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")) + 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 } func newSinkInput(r io.Reader) *sink { s := &sink{ - reader: r, + reader: bufio.NewReader(r), } s.ud = sinkUserData(s) + if f, ok := r.(*os.File); ok { + s.file = f + } + return s } func newSinkOutput(w io.Writer) *sink { s := &sink{ - writer: w, + writer: bufio.NewWriter(w), + autoFlush: true, } s.ud = sinkUserData(s)