Files
asciinema/terminal/terminal.go

94 lines
1.7 KiB
Go
Raw Normal View History

2014-08-03 19:50:39 +02:00
package terminal
2014-08-03 20:25:14 +02:00
import (
"io"
"os"
"os/exec"
"os/signal"
"syscall"
"code.google.com/p/go.crypto/ssh/terminal"
"github.com/asciinema/asciinema-cli/ptyx"
2014-08-09 21:49:10 +02:00
"github.com/asciinema/asciinema-cli/util"
2014-08-03 20:25:14 +02:00
"github.com/kr/pty"
)
2014-08-03 19:50:39 +02:00
type Terminal interface {
Size() (int, int, error)
Record(string, io.Writer) error
}
2014-08-03 20:25:14 +02:00
type Pty struct {
Stdin *os.File
Stdout *os.File
}
func New() *Pty {
return &Pty{Stdin: os.Stdin, Stdout: os.Stdout}
}
func (p *Pty) Size() (int, int, error) {
return pty.Getsize(p.Stdout)
}
func (p *Pty) Record(command string, stdoutCopy io.Writer) error {
2014-08-09 21:49:10 +02:00
// start command in pty
2014-08-03 20:25:14 +02:00
cmd := exec.Command("/bin/sh", "-c", command)
cmd.Env = append(os.Environ(), "ASCIINEMA_REC=1")
master, err := pty.Start(cmd)
if err != nil {
return err
}
defer master.Close()
2014-08-09 21:49:10 +02:00
// install WINCH signal handler
2014-08-03 20:25:14 +02:00
signals := make(chan os.Signal, 1)
signal.Notify(signals, syscall.SIGWINCH)
defer signal.Stop(signals)
go func() {
for _ = range signals {
p.resize(master)
}
}()
defer close(signals)
2014-08-09 21:49:10 +02:00
// put stdin into raw mode (if it's a tty)
2014-08-03 20:25:14 +02:00
fd := int(p.Stdin.Fd())
if terminal.IsTerminal(fd) {
oldState, err := terminal.MakeRaw(fd)
if err != nil {
return err
}
defer terminal.Restore(fd, oldState)
}
2014-08-09 21:49:10 +02:00
// do initial resize
2014-08-03 20:25:14 +02:00
p.resize(master)
2014-08-09 21:49:10 +02:00
// start stdin -> master copying
stop := util.Copy(master, p.Stdin)
// copy pty master -> p.stdout & stdoutCopy
2014-08-03 20:25:14 +02:00
stdout := io.MultiWriter(p.Stdout, stdoutCopy)
io.Copy(stdout, master)
2014-08-09 21:49:10 +02:00
// stop stdin -> master copying
stop()
2014-08-03 20:25:14 +02:00
return nil
}
func (p *Pty) resize(f *os.File) {
var rows, cols int
if terminal.IsTerminal(int(p.Stdout.Fd())) {
rows, cols, _ = p.Size()
} else {
rows = 24
cols = 80
}
ptyx.Setsize(f, rows, cols)
}