mirror of https://github.com/Hilbis/Hilbish
feat: add sink for commanders to write output/read input (#232)
to write output, you would usually just use the print builtin since commanders are just lua custom commands but this does not consider the fact of pipes or other shell operators being used to redirect or whatever. this adds readable/writable "sinks" which is a type for input or output and is currently only used for commanders but can be used for other hilbish things in the futuremultiline
parent
088e326bd1
commit
2f6ab5fd92
|
@ -4,9 +4,11 @@
|
||||||
### Added
|
### Added
|
||||||
- Documented custom userdata types (Job and Timer Objects)
|
- Documented custom userdata types (Job and Timer Objects)
|
||||||
- Coming with fix is also adding the return types for some functions that were missing it
|
- Coming with fix is also adding the return types for some functions that were missing it
|
||||||
|
- Added a dedicated input and dedicated outputs for commanders.
|
||||||
|
|
||||||
### Fixed
|
### Fixed
|
||||||
- `hilbish.which` not working correctly with aliases
|
- `hilbish.which` not working correctly with aliases
|
||||||
|
- Commanders not being able to pipe with commands or any related operator.
|
||||||
|
|
||||||
## [2.0.1] - 2022-12-28
|
## [2.0.1] - 2022-12-28
|
||||||
### Fixed
|
### Fixed
|
||||||
|
|
|
@ -414,7 +414,14 @@ func main() {
|
||||||
|
|
||||||
f, _ := os.Create(docPath)
|
f, _ := os.Create(docPath)
|
||||||
f.WriteString(fmt.Sprintf(header, modOrIface, modname, modu.ShortDescription))
|
f.WriteString(fmt.Sprintf(header, modOrIface, modname, modu.ShortDescription))
|
||||||
f.WriteString(fmt.Sprintf("## Introduction\n%s\n\n", modu.Description))
|
typeTag, _ := regexp.Compile(`@\w+`)
|
||||||
|
modDescription := typeTag.ReplaceAllStringFunc(strings.Replace(modu.Description, "<", `\<`, -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("## Introduction\n%s\n\n", modDescription))
|
||||||
if len(modu.Fields) != 0 {
|
if len(modu.Fields) != 0 {
|
||||||
f.WriteString("## Interface fields\n")
|
f.WriteString("## Interface fields\n")
|
||||||
for _, dps := range modu.Fields {
|
for _, dps := range modu.Fields {
|
||||||
|
@ -435,7 +442,6 @@ func main() {
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(modu.Docs) != 0 {
|
if len(modu.Docs) != 0 {
|
||||||
typeTag, _ := regexp.Compile(`@\w+`)
|
|
||||||
f.WriteString("## Functions\n")
|
f.WriteString("## Functions\n")
|
||||||
for _, dps := range modu.Docs {
|
for _, dps := range modu.Docs {
|
||||||
if dps.IsMember {
|
if dps.IsMember {
|
||||||
|
@ -475,8 +481,6 @@ func main() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
f.WriteString("\n")
|
f.WriteString("\n")
|
||||||
typeTag, _ := regexp.Compile(`@\w+`)
|
|
||||||
|
|
||||||
f.WriteString("### Methods\n")
|
f.WriteString("### Methods\n")
|
||||||
for _, dps := range modu.Docs {
|
for _, dps := range modu.Docs {
|
||||||
if !dps.IsMember {
|
if !dps.IsMember {
|
||||||
|
|
|
@ -8,7 +8,41 @@ menu:
|
||||||
---
|
---
|
||||||
|
|
||||||
## Introduction
|
## Introduction
|
||||||
|
|
||||||
Commander is a library for writing custom commands in Lua.
|
Commander is a library for writing custom commands in Lua.
|
||||||
|
In order to make it easier to write commands for Hilbish,
|
||||||
|
not require separate scripts and to be able to use in a config,
|
||||||
|
the Commander library exists. This is like a very simple wrapper
|
||||||
|
that works with Hilbish for writing commands. Example:
|
||||||
|
|
||||||
|
```lua
|
||||||
|
local commander = require 'commander'
|
||||||
|
|
||||||
|
commander.register('hello', function(args, sinks)
|
||||||
|
sinks.out:writeln 'Hello world!'
|
||||||
|
end)
|
||||||
|
```
|
||||||
|
|
||||||
|
In this example, a command with the name of `hello` is created
|
||||||
|
that will print `Hello world!` to output. One question you may
|
||||||
|
have is: What is the `sinks` parameter?
|
||||||
|
|
||||||
|
A sink is a writable/readable pipe, or you can imagine a Lua
|
||||||
|
file. It's used in this case to write to the proper output,
|
||||||
|
incase a user either pipes to another command or redirects somewhere else.
|
||||||
|
|
||||||
|
So, the `sinks` parameter is a table containing 3 sinks:
|
||||||
|
`in`, `out`, and `err`.
|
||||||
|
- `in` is the standard input. You can read from this sink
|
||||||
|
to get user input. (**This is currently unimplemented.**)
|
||||||
|
- `out` is standard output. This is usually where text meant for
|
||||||
|
output should go.
|
||||||
|
- `err` is standard error. This sink is for writing errors, as the
|
||||||
|
name would suggest.
|
||||||
|
|
||||||
|
A sink has 2 methods:
|
||||||
|
- `write(str)` will write to the sink.
|
||||||
|
- `writeln(str)` will write to the sink with a newline at the end.
|
||||||
|
|
||||||
## Functions
|
## Functions
|
||||||
### deregister(name)
|
### deregister(name)
|
||||||
|
|
13
exec.go
13
exec.go
|
@ -323,8 +323,18 @@ func execHandle(bg bool) interp.ExecHandlerFunc {
|
||||||
luacmdArgs.Set(rt.IntValue(int64(i + 1)), rt.StringValue(str))
|
luacmdArgs.Set(rt.IntValue(int64(i + 1)), rt.StringValue(str))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
hc := interp.HandlerCtx(ctx)
|
||||||
if commands[args[0]] != nil {
|
if commands[args[0]] != nil {
|
||||||
luaexitcode, err := rt.Call1(l.MainThread(), rt.FunctionValue(commands[args[0]]), rt.TableValue(luacmdArgs))
|
stdin := newSinkInput(hc.Stdin)
|
||||||
|
stdout := newSinkOutput(hc.Stdout)
|
||||||
|
stderr := newSinkOutput(hc.Stderr)
|
||||||
|
|
||||||
|
sinks := rt.NewTable()
|
||||||
|
sinks.Set(rt.StringValue("in"), rt.UserDataValue(stdin.ud))
|
||||||
|
sinks.Set(rt.StringValue("out"), rt.UserDataValue(stdout.ud))
|
||||||
|
sinks.Set(rt.StringValue("err"), rt.UserDataValue(stderr.ud))
|
||||||
|
|
||||||
|
luaexitcode, err := rt.Call1(l.MainThread(), rt.FunctionValue(commands[args[0]]), rt.TableValue(luacmdArgs), rt.TableValue(sinks))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Fprintln(os.Stderr, "Error in command:\n" + err.Error())
|
fmt.Fprintln(os.Stderr, "Error in command:\n" + err.Error())
|
||||||
return interp.NewExitStatus(1)
|
return interp.NewExitStatus(1)
|
||||||
|
@ -364,7 +374,6 @@ func execHandle(bg bool) interp.ExecHandlerFunc {
|
||||||
killTimeout := 2 * time.Second
|
killTimeout := 2 * time.Second
|
||||||
// from here is basically copy-paste of the default exec handler from
|
// from here is basically copy-paste of the default exec handler from
|
||||||
// sh/interp but with our job handling
|
// sh/interp but with our job handling
|
||||||
hc := interp.HandlerCtx(ctx)
|
|
||||||
path, err := interp.LookPathDir(hc.Dir, hc.Env, args[0])
|
path, err := interp.LookPathDir(hc.Dir, hc.Env, args[0])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Fprintln(hc.Stderr, err)
|
fmt.Fprintln(hc.Stderr, err)
|
||||||
|
|
|
@ -1,5 +1,40 @@
|
||||||
// library for custom commands
|
// library for custom commands
|
||||||
// Commander is a library for writing custom commands in Lua.
|
/*
|
||||||
|
Commander is a library for writing custom commands in Lua.
|
||||||
|
In order to make it easier to write commands for Hilbish,
|
||||||
|
not require separate scripts and to be able to use in a config,
|
||||||
|
the Commander library exists. This is like a very simple wrapper
|
||||||
|
that works with Hilbish for writing commands. Example:
|
||||||
|
|
||||||
|
```lua
|
||||||
|
local commander = require 'commander'
|
||||||
|
|
||||||
|
commander.register('hello', function(args, sinks)
|
||||||
|
sinks.out:writeln 'Hello world!'
|
||||||
|
end)
|
||||||
|
```
|
||||||
|
|
||||||
|
In this example, a command with the name of `hello` is created
|
||||||
|
that will print `Hello world!` to output. One question you may
|
||||||
|
have is: What is the `sinks` parameter?
|
||||||
|
|
||||||
|
A sink is a writable/readable pipe, or you can imagine a Lua
|
||||||
|
file. It's used in this case to write to the proper output,
|
||||||
|
incase a user either pipes to another command or redirects somewhere else.
|
||||||
|
|
||||||
|
So, the `sinks` parameter is a table containing 3 sinks:
|
||||||
|
`in`, `out`, and `err`.
|
||||||
|
- `in` is the standard input. You can read from this sink
|
||||||
|
to get user input. (**This is currently unimplemented.**)
|
||||||
|
- `out` is standard output. This is usually where text meant for
|
||||||
|
output should go.
|
||||||
|
- `err` is standard error. This sink is for writing errors, as the
|
||||||
|
name would suggest.
|
||||||
|
|
||||||
|
A sink has 2 methods:
|
||||||
|
- `write(str)` will write to the sink.
|
||||||
|
- `writeln(str)` will write to the sink with a newline at the end.
|
||||||
|
*/
|
||||||
package commander
|
package commander
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
|
1
lua.go
1
lua.go
|
@ -23,6 +23,7 @@ func luaInit() {
|
||||||
MessageHandler: debuglib.Traceback,
|
MessageHandler: debuglib.Traceback,
|
||||||
})
|
})
|
||||||
lib.LoadAll(l)
|
lib.LoadAll(l)
|
||||||
|
setupSinkType(l)
|
||||||
|
|
||||||
lib.LoadLibs(l, hilbishLoader)
|
lib.LoadLibs(l, hilbishLoader)
|
||||||
// yes this is stupid, i know
|
// yes this is stupid, i know
|
||||||
|
|
|
@ -1,15 +1,15 @@
|
||||||
local commander = require 'commander'
|
local commander = require 'commander'
|
||||||
|
|
||||||
commander.register('bg', function()
|
commander.register('bg', function(_, sinks)
|
||||||
local job = hilbish.jobs.last()
|
local job = hilbish.jobs.last()
|
||||||
if not job then
|
if not job then
|
||||||
print 'bg: no last job'
|
sinks.out:writeln 'bg: no last job'
|
||||||
return 1
|
return 1
|
||||||
end
|
end
|
||||||
|
|
||||||
local err = job.background()
|
local err = job.background()
|
||||||
if err then
|
if err then
|
||||||
print('bg: ' .. err)
|
sinks.out:writeln('bg: ' .. err)
|
||||||
return 2
|
return 2
|
||||||
end
|
end
|
||||||
end)
|
end)
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
local commander = require 'commander'
|
local commander = require 'commander'
|
||||||
local fs = require 'fs'
|
local fs = require 'fs'
|
||||||
|
|
||||||
commander.register('cat', function(args)
|
commander.register('cat', function(args, sinks)
|
||||||
local exit = 0
|
local exit = 0
|
||||||
|
|
||||||
if #args == 0 then
|
if #args == 0 then
|
||||||
print [[
|
sinks.out:writeln [[
|
||||||
usage: cat [file]...]]
|
usage: cat [file]...]]
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -13,11 +13,11 @@ usage: cat [file]...]]
|
||||||
local f = io.open(fName)
|
local f = io.open(fName)
|
||||||
if f == nil then
|
if f == nil then
|
||||||
exit = 1
|
exit = 1
|
||||||
print(string.format('cat: %s: no such file or directory', fName))
|
sinks.out:writeln(string.format('cat: %s: no such file or directory', fName))
|
||||||
goto continue
|
goto continue
|
||||||
end
|
end
|
||||||
|
|
||||||
io.write(f:read '*a')
|
sinks.out:writeln(f:read '*a')
|
||||||
::continue::
|
::continue::
|
||||||
end
|
end
|
||||||
io.flush()
|
io.flush()
|
||||||
|
|
|
@ -4,16 +4,16 @@ local fs = require 'fs'
|
||||||
local dirs = require 'nature.dirs'
|
local dirs = require 'nature.dirs'
|
||||||
|
|
||||||
dirs.old = hilbish.cwd()
|
dirs.old = hilbish.cwd()
|
||||||
commander.register('cd', function (args)
|
commander.register('cd', function (args, sinks)
|
||||||
if #args > 1 then
|
if #args > 1 then
|
||||||
print("cd: too many arguments")
|
sinks.out:writeln("cd: too many arguments")
|
||||||
return 1
|
return 1
|
||||||
end
|
end
|
||||||
|
|
||||||
local path = args[1] and args[1] or hilbish.home
|
local path = args[1] and args[1] or hilbish.home
|
||||||
if path == '-' then
|
if path == '-' then
|
||||||
path = dirs.old
|
path = dirs.old
|
||||||
print(path)
|
sinks.out:writeln(path)
|
||||||
end
|
end
|
||||||
|
|
||||||
dirs.setOld(hilbish.cwd())
|
dirs.setOld(hilbish.cwd())
|
||||||
|
@ -21,7 +21,7 @@ commander.register('cd', function (args)
|
||||||
|
|
||||||
local ok, err = pcall(function() fs.cd(path) end)
|
local ok, err = pcall(function() fs.cd(path) end)
|
||||||
if not ok then
|
if not ok then
|
||||||
print(err)
|
sinks.out:writeln(err)
|
||||||
return 1
|
return 1
|
||||||
end
|
end
|
||||||
bait.throw('cd', path)
|
bait.throw('cd', path)
|
||||||
|
|
|
@ -3,9 +3,9 @@ local fs = require 'fs'
|
||||||
local lunacolors = require 'lunacolors'
|
local lunacolors = require 'lunacolors'
|
||||||
local dirs = require 'nature.dirs'
|
local dirs = require 'nature.dirs'
|
||||||
|
|
||||||
commander.register('cdr', function(args)
|
commander.register('cdr', function(args, sinks)
|
||||||
if not args[1] then
|
if not args[1] then
|
||||||
print(lunacolors.format [[
|
sinks.out:writeln(lunacolors.format [[
|
||||||
cdr: change directory to one which has been recently visied
|
cdr: change directory to one which has been recently visied
|
||||||
|
|
||||||
usage: cdr <index>
|
usage: cdr <index>
|
||||||
|
@ -17,21 +17,21 @@ to get a list of recent directories, use {green}{underline}cdr list{reset}]])
|
||||||
if args[1] == 'list' then
|
if args[1] == 'list' then
|
||||||
local recentDirs = dirs.recentDirs
|
local recentDirs = dirs.recentDirs
|
||||||
if #recentDirs == 0 then
|
if #recentDirs == 0 then
|
||||||
print 'No directories have been visited.'
|
sinks.out:writeln 'No directories have been visited.'
|
||||||
return 1
|
return 1
|
||||||
end
|
end
|
||||||
print(table.concat(recentDirs, '\n'))
|
sinks.out:writeln(table.concat(recentDirs, '\n'))
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
local index = tonumber(args[1])
|
local index = tonumber(args[1])
|
||||||
if not index then
|
if not index then
|
||||||
print(string.format('Received %s as index, which isn\'t a number.', index))
|
sinks.out:writeln(string.format('Received %s as index, which isn\'t a number.', index))
|
||||||
return 1
|
return 1
|
||||||
end
|
end
|
||||||
|
|
||||||
if not dirs.recent(index) then
|
if not dirs.recent(index) then
|
||||||
print(string.format('No recent directory found at index %s.', index))
|
sinks.out:writeln(string.format('No recent directory found at index %s.', index))
|
||||||
return 1
|
return 1
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
local commander = require 'commander'
|
local commander = require 'commander'
|
||||||
|
|
||||||
commander.register('disown', function(args)
|
commander.register('disown', function(args, sinks)
|
||||||
if #hilbish.jobs.all() == 0 then
|
if #hilbish.jobs.all() == 0 then
|
||||||
print 'disown: no current job'
|
sinks.out:writeln 'disown: no current job'
|
||||||
return 1
|
return 1
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -10,7 +10,7 @@ commander.register('disown', function(args)
|
||||||
if #args < 0 then
|
if #args < 0 then
|
||||||
id = tonumber(args[1])
|
id = tonumber(args[1])
|
||||||
if not id then
|
if not id then
|
||||||
print 'disown: invalid id for job'
|
sinks.out:writeln 'disown: invalid id for job'
|
||||||
return 1
|
return 1
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
|
@ -19,7 +19,7 @@ commander.register('disown', function(args)
|
||||||
|
|
||||||
local ok = pcall(hilbish.jobs.disown, id)
|
local ok = pcall(hilbish.jobs.disown, id)
|
||||||
if not ok then
|
if not ok then
|
||||||
print 'disown: job does not exist'
|
sinks.out:writeln 'disown: job does not exist'
|
||||||
return 2
|
return 2
|
||||||
end
|
end
|
||||||
end)
|
end)
|
||||||
|
|
|
@ -2,7 +2,7 @@ local commander = require 'commander'
|
||||||
local fs = require 'fs'
|
local fs = require 'fs'
|
||||||
local lunacolors = require 'lunacolors'
|
local lunacolors = require 'lunacolors'
|
||||||
|
|
||||||
commander.register('doc', function(args)
|
commander.register('doc', function(args, sinks)
|
||||||
local moddocPath = hilbish.dataDir .. '/docs/'
|
local moddocPath = hilbish.dataDir .. '/docs/'
|
||||||
local stat = fs.stat '.git/refs/heads/extended-job-api'
|
local stat = fs.stat '.git/refs/heads/extended-job-api'
|
||||||
if stat then
|
if stat then
|
||||||
|
@ -48,7 +48,7 @@ Available sections: ]] .. table.concat(modules, ', ')
|
||||||
f = io.open(moddocPath .. subdocName .. '.md', 'rb')
|
f = io.open(moddocPath .. subdocName .. '.md', 'rb')
|
||||||
end
|
end
|
||||||
if not f then
|
if not f then
|
||||||
print('No documentation found for ' .. mod .. '.')
|
sinks.out:writeln('No documentation found for ' .. mod .. '.')
|
||||||
return 1
|
return 1
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -86,7 +86,7 @@ Available sections: ]] .. table.concat(modules, ', ')
|
||||||
end
|
end
|
||||||
|
|
||||||
local backtickOccurence = 0
|
local backtickOccurence = 0
|
||||||
print(lunacolors.format(doc:gsub('`', function()
|
sinks.out:writeln(lunacolors.format(doc:gsub('`', function()
|
||||||
backtickOccurence = backtickOccurence + 1
|
backtickOccurence = backtickOccurence + 1
|
||||||
if backtickOccurence % 2 == 0 then
|
if backtickOccurence % 2 == 0 then
|
||||||
return '{reset}'
|
return '{reset}'
|
||||||
|
|
|
@ -1,15 +1,15 @@
|
||||||
local commander = require 'commander'
|
local commander = require 'commander'
|
||||||
|
|
||||||
commander.register('fg', function()
|
commander.register('fg', function(_, sinks)
|
||||||
local job = hilbish.jobs.last()
|
local job = hilbish.jobs.last()
|
||||||
if not job then
|
if not job then
|
||||||
print 'fg: no last job'
|
sinks.out:writeln 'fg: no last job'
|
||||||
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
|
||||||
print('fg: ' .. err)
|
sinks.out:writeln('fg: ' .. err)
|
||||||
return 2
|
return 2
|
||||||
end
|
end
|
||||||
end)
|
end)
|
||||||
|
|
|
@ -0,0 +1,121 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
|
||||||
|
"hilbish/util"
|
||||||
|
|
||||||
|
rt "github.com/arnodel/golua/runtime"
|
||||||
|
)
|
||||||
|
|
||||||
|
var sinkMetaKey = rt.StringValue("hshsink")
|
||||||
|
|
||||||
|
// a sink is a structure that has input and/or output
|
||||||
|
// it is like a lua file when used in popen, but specific to hilbish
|
||||||
|
type sink struct{
|
||||||
|
writer io.Writer
|
||||||
|
reader io.Reader
|
||||||
|
ud *rt.UserData
|
||||||
|
}
|
||||||
|
|
||||||
|
func setupSinkType(rtm *rt.Runtime) {
|
||||||
|
sinkMeta := rt.NewTable()
|
||||||
|
|
||||||
|
sinkMethods := rt.NewTable()
|
||||||
|
sinkFuncs := map[string]util.LuaExport{
|
||||||
|
"write": {luaSinkWrite, 2, false},
|
||||||
|
"writeln": {luaSinkWriteln, 2, false},
|
||||||
|
}
|
||||||
|
util.SetExports(l, sinkMethods, sinkFuncs)
|
||||||
|
|
||||||
|
sinkIndex := func(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
|
||||||
|
arg := c.Arg(1)
|
||||||
|
val := sinkMethods.Get(arg)
|
||||||
|
|
||||||
|
return c.PushingNext1(t.Runtime, val), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
sinkMeta.Set(rt.StringValue("__index"), rt.FunctionValue(rt.NewGoFunction(sinkIndex, "__index", 2, false)))
|
||||||
|
l.SetRegistry(sinkMetaKey, rt.TableValue(sinkMeta))
|
||||||
|
}
|
||||||
|
|
||||||
|
func luaSinkWrite(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
|
||||||
|
if err := c.CheckNArgs(2); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
s, err := sinkArg(c, 0)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
data, err := c.StringArg(1)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
s.writer.Write([]byte(data))
|
||||||
|
|
||||||
|
return c.Next(), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func luaSinkWriteln(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
|
||||||
|
if err := c.CheckNArgs(2); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
s, err := sinkArg(c, 0)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
data, err := c.StringArg(1)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
s.writer.Write([]byte(data + "\n"))
|
||||||
|
|
||||||
|
return c.Next(), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func newSinkInput(r io.Reader) *sink {
|
||||||
|
s := &sink{
|
||||||
|
reader: r,
|
||||||
|
}
|
||||||
|
s.ud = sinkUserData(s)
|
||||||
|
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
|
||||||
|
func newSinkOutput(w io.Writer) *sink {
|
||||||
|
s := &sink{
|
||||||
|
writer: w,
|
||||||
|
}
|
||||||
|
s.ud = sinkUserData(s)
|
||||||
|
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
|
||||||
|
func sinkArg(c *rt.GoCont, arg int) (*sink, error) {
|
||||||
|
s, ok := valueToSink(c.Arg(arg))
|
||||||
|
if !ok {
|
||||||
|
return nil, fmt.Errorf("#%d must be a sink", arg + 1)
|
||||||
|
}
|
||||||
|
|
||||||
|
return s, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func valueToSink(val rt.Value) (*sink, bool) {
|
||||||
|
u, ok := val.TryUserData()
|
||||||
|
if !ok {
|
||||||
|
return nil, false
|
||||||
|
}
|
||||||
|
|
||||||
|
s, ok := u.Value().(*sink)
|
||||||
|
return s, ok
|
||||||
|
}
|
||||||
|
|
||||||
|
func sinkUserData(s *sink) *rt.UserData {
|
||||||
|
sinkMeta := l.Registry(sinkMetaKey)
|
||||||
|
return rt.NewUserData(s, sinkMeta.AsTable())
|
||||||
|
}
|
Loading…
Reference in New Issue