mirror of https://github.com/Hilbis/Hilbish
Merge f239363a60
into 11323a70aa
commit
da5e01718b
22
api.go
22
api.go
|
@ -48,6 +48,7 @@ var exports = map[string]util.LuaExport{
|
|||
"interval": {hlinterval, 2, false},
|
||||
"read": {hlread, 1, false},
|
||||
"run": {hlrun, 1, true},
|
||||
"suspend": {hlsuspend, 0, false},
|
||||
"timeout": {hltimeout, 2, false},
|
||||
"which": {hlwhich, 1, false},
|
||||
}
|
||||
|
@ -89,6 +90,12 @@ func hilbishLoad(rtm *rt.Runtime) (rt.Value, func()) {
|
|||
if err != nil {
|
||||
return nil, errors.New("hilbish.hinter has to be a function")
|
||||
}
|
||||
} else if k == "suspend" {
|
||||
var err error
|
||||
_, err = c.ClosureArg(2)
|
||||
if err != nil {
|
||||
return nil, errors.New("hilbish.suspend has to be a function")
|
||||
}
|
||||
} else if modVal := mod.Get(rt.StringValue(k)); modVal != rt.NilValue {
|
||||
return nil, errors.New("not allowed to override in hilbish table")
|
||||
}
|
||||
|
@ -218,7 +225,7 @@ func hlrun(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
|
|||
}
|
||||
|
||||
var exitcode uint8
|
||||
stdout, stderr, err := execCommand(cmd, terminalOut)
|
||||
stdout, stderr, err := execCommand(cmd, terminalOut, false)
|
||||
|
||||
if code, ok := interp.IsExitStatus(err); ok {
|
||||
exitcode = code
|
||||
|
@ -753,3 +760,16 @@ func hlhinter(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
|
|||
func hlhighlighter(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
|
||||
return c.Next(), nil
|
||||
}
|
||||
|
||||
// suspend()
|
||||
// Suspends the currently running process. This can (and should be) overwritten if a
|
||||
// a different runner is being used.
|
||||
// --- @param line string
|
||||
func hlsuspend(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
|
||||
if currentHandle != nil || currentHandle.Process != nil {
|
||||
j := jobs.addFromHandler(currentCmd, currentHandle)
|
||||
j.suspend()
|
||||
}
|
||||
|
||||
return c.Next(), nil
|
||||
}
|
||||
|
|
52
exec.go
52
exec.go
|
@ -27,6 +27,8 @@ import (
|
|||
var errNotExec = errors.New("not executable")
|
||||
var errNotFound = errors.New("not found")
|
||||
var runnerMode rt.Value = rt.StringValue("hybrid")
|
||||
var currentHandle *exec.Cmd
|
||||
var currentCmd string
|
||||
|
||||
type execError struct{
|
||||
typ string
|
||||
|
@ -236,7 +238,7 @@ func handleSh(cmdString string) (input string, exitCode uint8, cont bool, runErr
|
|||
}
|
||||
|
||||
func execSh(cmdString string) (string, uint8, bool, error) {
|
||||
_, _, err := execCommand(cmdString, true)
|
||||
_, _, err := execCommand(cmdString, true, true)
|
||||
if err != nil {
|
||||
// If input is incomplete, start multiline prompting
|
||||
if syntax.IsIncomplete(err) {
|
||||
|
@ -257,7 +259,7 @@ func execSh(cmdString string) (string, uint8, bool, error) {
|
|||
}
|
||||
|
||||
// Run command in sh interpreter
|
||||
func execCommand(cmd string, terminalOut bool) (io.Writer, io.Writer, error) {
|
||||
func execCommand(cmd string, terminalOut, interactiveCall bool) (io.Writer, io.Writer, error) {
|
||||
file, err := syntax.NewParser().Parse(strings.NewReader(cmd), "")
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
|
@ -280,16 +282,21 @@ func execCommand(cmd string, terminalOut bool) (io.Writer, io.Writer, error) {
|
|||
var bg bool
|
||||
for _, stmt := range file.Stmts {
|
||||
bg = false
|
||||
printer.Print(buf, stmt.Cmd)
|
||||
|
||||
stmtStr := buf.String()
|
||||
buf.Reset()
|
||||
|
||||
if interactiveCall {
|
||||
currentCmd = stmtStr
|
||||
}
|
||||
|
||||
if stmt.Background {
|
||||
bg = true
|
||||
printer.Print(buf, stmt.Cmd)
|
||||
|
||||
stmtStr := buf.String()
|
||||
buf.Reset()
|
||||
jobs.add(stmtStr, []string{}, "")
|
||||
}
|
||||
|
||||
interp.ExecHandler(execHandle(bg))(runner)
|
||||
interp.ExecHandler(execHandle(bg, interactiveCall))(runner)
|
||||
err = runner.Run(context.TODO(), stmt)
|
||||
if err != nil {
|
||||
return stdout, stderr, err
|
||||
|
@ -299,7 +306,7 @@ func execCommand(cmd string, terminalOut bool) (io.Writer, io.Writer, error) {
|
|||
return stdout, stderr, nil
|
||||
}
|
||||
|
||||
func execHandle(bg bool) interp.ExecHandlerFunc {
|
||||
func execHandle(bg, interactiveCall bool) interp.ExecHandlerFunc {
|
||||
return func(ctx context.Context, args []string) error {
|
||||
_, argstring := splitInput(strings.Join(args, " "))
|
||||
// i dont really like this but it works
|
||||
|
@ -413,6 +420,10 @@ func execHandle(bg bool) interp.ExecHandlerFunc {
|
|||
Stderr: hc.Stderr,
|
||||
}
|
||||
|
||||
if interactiveCall {
|
||||
currentHandle = &cmd
|
||||
}
|
||||
|
||||
var j *job
|
||||
if bg {
|
||||
j = jobs.getLatest()
|
||||
|
@ -422,6 +433,8 @@ func execHandle(bg bool) interp.ExecHandlerFunc {
|
|||
err = cmd.Start()
|
||||
}
|
||||
|
||||
execDone := make(chan struct{}, 1)
|
||||
var suspended bool
|
||||
if err == nil {
|
||||
if done := ctx.Done(); done != nil {
|
||||
go func() {
|
||||
|
@ -443,12 +456,31 @@ func execHandle(bg bool) interp.ExecHandlerFunc {
|
|||
}()
|
||||
}
|
||||
|
||||
err = cmd.Wait()
|
||||
go func() {
|
||||
hooks.On("job.suspend", func(args ...interface{}) {
|
||||
fmt.Println("suspended")
|
||||
val := args[0].(rt.Value)
|
||||
|
||||
_, ok := valueToJob(val)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
|
||||
suspended = true
|
||||
execDone <- struct{}{}
|
||||
})
|
||||
}()
|
||||
go func() {
|
||||
err = cmd.Wait()
|
||||
execDone <- struct{}{}
|
||||
}()
|
||||
|
||||
<-execDone
|
||||
}
|
||||
|
||||
exit := handleExecErr(err)
|
||||
|
||||
if bg {
|
||||
if bg && !suspended {
|
||||
j.exitCode = int(exit)
|
||||
j.finish()
|
||||
}
|
||||
|
|
12
job.go
12
job.go
|
@ -268,6 +268,18 @@ func (j *jobHandler) add(cmd string, args []string, path string) *job {
|
|||
return jb
|
||||
}
|
||||
|
||||
func (j *jobHandler) addFromHandler(cmd string, handler *exec.Cmd) *job {
|
||||
jb := j.add(cmd, handler.Args, handler.Path)
|
||||
if ps := handler.ProcessState; ps != nil {
|
||||
if !ps.Exited() && ps.Pid() != 0 {
|
||||
jb.running = true
|
||||
}
|
||||
}
|
||||
jb.setHandle(handler)
|
||||
|
||||
return jb
|
||||
}
|
||||
|
||||
func (j *jobHandler) getLatest() *job {
|
||||
j.mu.RLock()
|
||||
defer j.mu.RUnlock()
|
||||
|
|
12
job_unix.go
12
job_unix.go
|
@ -8,6 +8,7 @@ import (
|
|||
"syscall"
|
||||
|
||||
"golang.org/x/sys/unix"
|
||||
rt "github.com/arnodel/golua/runtime"
|
||||
)
|
||||
|
||||
func (j *job) foreground() error {
|
||||
|
@ -36,3 +37,14 @@ func (j *job) background() error {
|
|||
proc.Signal(syscall.SIGCONT)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (j *job) suspend() error {
|
||||
proc := j.handle.Process
|
||||
if proc == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
proc.Signal(syscall.SIGSTOP)
|
||||
hooks.Emit("job.suspend", rt.UserDataValue(j.ud))
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -13,3 +13,7 @@ func (j *job) foreground() error {
|
|||
func (j *job) background() error {
|
||||
return errors.New("not supported on windows")
|
||||
}
|
||||
|
||||
func (j *job) suspend() error {
|
||||
return errors.New("not supported on windows")
|
||||
}
|
||||
|
|
|
@ -3,23 +3,32 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"syscall"
|
||||
"os"
|
||||
"os/signal"
|
||||
|
||||
rt "github.com/arnodel/golua/runtime"
|
||||
)
|
||||
|
||||
func handleSignals() {
|
||||
c := make(chan os.Signal)
|
||||
signal.Ignore(syscall.SIGTTOU, syscall.SIGTTIN, syscall.SIGTSTP)
|
||||
signal.Notify(c, os.Interrupt, syscall.SIGTERM, syscall.SIGWINCH, syscall.SIGUSR1, syscall.SIGUSR2, syscall.SIGQUIT)
|
||||
signal.Ignore(syscall.SIGTTOU, syscall.SIGTTIN)
|
||||
signal.Notify(c, os.Interrupt, syscall.SIGTERM, syscall.SIGWINCH, syscall.SIGUSR1, syscall.SIGUSR2, syscall.SIGQUIT, syscall.SIGTSTP)
|
||||
|
||||
for s := range c {
|
||||
switch s {
|
||||
case os.Interrupt: hooks.Emit("signal.sigint")
|
||||
case syscall.SIGTERM: exit(0)
|
||||
case syscall.SIGWINCH: hooks.Emit("signal.resize")
|
||||
case syscall.SIGUSR1: hooks.Emit("signal.sigusr1")
|
||||
case syscall.SIGUSR2: hooks.Emit("signal.sigusr2")
|
||||
case os.Interrupt: hooks.Emit("signal.sigint")
|
||||
case syscall.SIGTERM: exit(0)
|
||||
case syscall.SIGWINCH: hooks.Emit("signal.resize")
|
||||
case syscall.SIGUSR1: hooks.Emit("signal.sigusr1")
|
||||
case syscall.SIGUSR2: hooks.Emit("signal.sigusr2")
|
||||
case syscall.SIGTSTP:
|
||||
suspendHandler := hshMod.Get(rt.StringValue("suspend"))
|
||||
_, err := rt.Call1(l.MainThread(), suspendHandler)
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue