Add a pretty clumsy fg builtin.

Let's pretend that this fixes #12.
This commit is contained in:
Qi Xiao 2016-02-21 23:45:49 +01:00
parent bda9ec2483
commit f77fd16a6c
4 changed files with 67 additions and 13 deletions

View File

@ -15,6 +15,7 @@ import (
"syscall"
"time"
"github.com/elves/elvish/sys"
"github.com/elves/elvish/util"
)
@ -91,6 +92,8 @@ func init() {
&BuiltinFn{"len", wrapFn(lenFn)},
&BuiltinFn{"count", wrapFn(count)},
&BuiltinFn{"fg", wrapFn(fg)},
&BuiltinFn{"-sleep", wrapFn(_sleep)},
&BuiltinFn{"-stack", wrapFn(_stack)},
&BuiltinFn{"-log", wrapFn(_log)},
@ -103,6 +106,7 @@ var (
ErrInput = errors.New("input error")
ErrStoreNotConnected = errors.New("store not connected")
ErrNoMatchingDir = errors.New("no matching directory")
ErrNotInSameGroup = errors.New("not in the same process group")
)
var (
@ -574,6 +578,49 @@ func count(ec *EvalCtx) {
out <- String(strconv.Itoa(n))
}
func fg(ec *EvalCtx, pids ...int) {
if len(pids) == 0 {
throw(ErrArgs)
}
var thepgid int
for i, pid := range pids {
pgid, err := syscall.Getpgid(pid)
maybeThrow(err)
if i == 0 {
thepgid = pgid
} else if pgid != thepgid {
throw(ErrNotInSameGroup)
}
}
err := sys.Tcsetpgrp(0, thepgid)
maybeThrow(err)
errors := make([]Error, len(pids))
for i, pid := range pids {
err := syscall.Kill(pid, syscall.SIGCONT)
if err != nil {
errors[i] = Error{err}
}
}
for i, pid := range pids {
if errors[i] != OK {
continue
}
var ws syscall.WaitStatus
_, err = syscall.Wait4(pid, &ws, syscall.WUNTRACED, nil)
if err != nil {
errors[i] = Error{err}
} else {
errors[i] = Error{NewExternalCmdExit(ws, pid)}
}
}
throwCompositeError(errors)
}
func _sleep(ec *EvalCtx, t float64) {
time.Sleep(time.Duration(t) * time.Second)
}

View File

@ -77,12 +77,16 @@ func (cp *compiler) pipeline(n *parse.Pipeline) OpFunc {
errors[i] = <-errorChan
}
if !allok(errors) {
if len(errors) == 1 {
throw(errors[0].Inner)
} else {
throw(MultiError{errors})
}
throwCompositeError(errors)
}
}
func throwCompositeError(errors []Error) {
if !allok(errors) {
if len(errors) == 1 {
throw(errors[0].Inner)
} else {
throw(MultiError{errors})
}
}
}

View File

@ -109,8 +109,15 @@ func (f flow) Error() string {
// command was stopped rather than terminated, the Pid field contains the pid
// of the process.
type ExternalCmdExit struct {
WaitStatus syscall.WaitStatus
Pid int
syscall.WaitStatus
Pid int
}
func NewExternalCmdExit(ws syscall.WaitStatus, pid int) error {
if ws.Exited() && ws.ExitStatus() == 0 {
return nil
}
return ExternalCmdExit{ws, pid}
}
func (exit ExternalCmdExit) Error() string {

View File

@ -81,10 +81,6 @@ func (e ExternalCmd) Call(ec *EvalCtx, argVals []Value) {
if err != nil {
throw(fmt.Errorf("wait: %s", err.Error()))
} else {
if ws.Exited() && ws.ExitStatus() == 0 {
// Do nothing
} else {
throw(ExternalCmdExit{ws, pid})
}
maybeThrow(NewExternalCmdExit(ws, pid))
}
}