Skip to content

Commit

Permalink
add driver for setting up tty file descriptors, allowing use with SSH…
Browse files Browse the repository at this point in the history
… servers

Signed-off-by: Jeff Lindsay <progrium@gmail.com>
  • Loading branch information
progrium committed Sep 5, 2018
1 parent de7e78e commit 646fb36
Show file tree
Hide file tree
Showing 6 changed files with 88 additions and 33 deletions.
59 changes: 59 additions & 0 deletions driver.go
@@ -0,0 +1,59 @@
package tcell

import (
"errors"
"os"
"os/signal"
"syscall"
)

// ErrWinSizeUnused is for TermDrivers to signal to use the default platform
// window size lookup method
var ErrWinSizeUnused = errors.New("driver does not provide WinSize")

// TermDriver allows you to customize the TTY used by Screen,
// most notably to support a PTY pair that can be used with SSH servers.
type TermDriver interface {
// Init sets up two file TTY/PTY file descriptors, which may be the same
// in some cases. It also takes a chan that is used to notify the Screen
// refresh the window size.
Init(winch chan os.Signal) (in *os.File, out *os.File, err error)

// Fini is called before the cleanup of Screen's Fini. It's typically used
// to unsubscribe window change signals.
Fini()

// WinSize returns the current window width and height. It can also return
// ErrWinSizeUnused to tell Screen to use platform syscalls to get the
// window size from the out file descriptor.
WinSize() (width int, height int, err error)
}

// defaultTermDriver is what's used when you don't specify a custom TermDriver
type defaultTermDriver struct {
winch chan os.Signal
out *os.File
}

func (d *defaultTermDriver) Init(winch chan os.Signal) (in *os.File, out *os.File, err error) {
in, err = os.OpenFile("/dev/tty", os.O_RDONLY, 0)
if err != nil {
return
}
out, err = os.OpenFile("/dev/tty", os.O_WRONLY, 0)
if err != nil {
return
}
signal.Notify(winch, syscall.SIGWINCH)
d.winch = winch
d.out = out
return
}

func (d *defaultTermDriver) Fini() {
signal.Stop(d.winch)
}

func (d *defaultTermDriver) WinSize() (int, int, error) {
return 0, 0, ErrWinSizeUnused
}
9 changes: 9 additions & 0 deletions tscreen.go
Expand Up @@ -42,6 +42,7 @@ func NewTerminfoScreen() (Screen, error) {
return nil, e
}
t := &tScreen{ti: ti}
t.driver = &defaultTermDriver{}

t.keyexist = make(map[Key]bool)
t.keycodes = make(map[string]*tKeyCode)
Expand All @@ -68,6 +69,7 @@ type tKeyCode struct {
// tScreen represents a screen backed by a terminfo implementation.
type tScreen struct {
ti *terminfo.Terminfo
driver TermDriver
h int
w int
fini bool
Expand Down Expand Up @@ -1386,3 +1388,10 @@ func (t *tScreen) HasKey(k Key) bool {
}

func (t *tScreen) Resize(int, int, int, int) {}

// SetDriver is used to replace the default TermDriver.
// When using this package, you'll want to make an interface
// and type assert your Screen to get this method.
func (t *tScreen) SetDriver(driver TermDriver) {
t.driver = driver
}
15 changes: 5 additions & 10 deletions tscreen_bsd.go
Expand Up @@ -17,8 +17,6 @@
package tcell

import (
"os"
"os/signal"
"syscall"
"unsafe"
)
Expand All @@ -33,10 +31,7 @@ func (t *tScreen) termioInit() error {
var ioc uintptr
t.tiosp = &termiosPrivate{}

if t.in, e = os.OpenFile("/dev/tty", os.O_RDONLY, 0); e != nil {
goto failed
}
if t.out, e = os.OpenFile("/dev/tty", os.O_WRONLY, 0); e != nil {
if t.in, t.out, e = t.driver.Init(t.sigwinch); e != nil {
goto failed
}

Expand Down Expand Up @@ -69,8 +64,6 @@ func (t *tScreen) termioInit() error {
goto failed
}

signal.Notify(t.sigwinch, syscall.SIGWINCH)

if w, h, e := t.getWinSize(); e == nil && w != 0 && h != 0 {
t.cells.Resize(w, h)
}
Expand All @@ -89,7 +82,7 @@ failed:

func (t *tScreen) termioFini() {

signal.Stop(t.sigwinch)
t.driver.Fini()

<-t.indoneq

Expand All @@ -106,7 +99,9 @@ func (t *tScreen) termioFini() {
}

func (t *tScreen) getWinSize() (int, int, error) {

if w, h, err := t.driver.WinSize(); err != ErrWinSizeUnused {
return w, h, err
}
fd := uintptr(t.out.Fd())
dim := [4]uint16{}
dimp := uintptr(unsafe.Pointer(&dim))
Expand Down
15 changes: 5 additions & 10 deletions tscreen_darwin.go
Expand Up @@ -32,8 +32,6 @@ package tcell
// a long time (probably forever) so holding one's breath is contraindicated.

import (
"os"
"os/signal"
"syscall"
"unsafe"
)
Expand All @@ -48,10 +46,7 @@ func (t *tScreen) termioInit() error {
var ioc uintptr
t.tiosp = &termiosPrivate{}

if t.in, e = os.OpenFile("/dev/tty", os.O_RDONLY, 0); e != nil {
goto failed
}
if t.out, e = os.OpenFile("/dev/tty", os.O_WRONLY, 0); e != nil {
if t.in, t.out, e = t.driver.Init(t.sigwinch); e != nil {
goto failed
}

Expand Down Expand Up @@ -84,8 +79,6 @@ func (t *tScreen) termioInit() error {
goto failed
}

signal.Notify(t.sigwinch, syscall.SIGWINCH)

if w, h, e := t.getWinSize(); e == nil && w != 0 && h != 0 {
t.cells.Resize(w, h)
}
Expand All @@ -104,7 +97,7 @@ failed:

func (t *tScreen) termioFini() {

signal.Stop(t.sigwinch)
t.driver.Fini()

<-t.indoneq

Expand All @@ -127,7 +120,9 @@ func (t *tScreen) termioFini() {
}

func (t *tScreen) getWinSize() (int, int, error) {

if w, h, err := t.driver.WinSize(); err != ErrWinSizeUnused {
return w, h, err
}
fd := uintptr(t.out.Fd())
dim := [4]uint16{}
dimp := uintptr(unsafe.Pointer(&dim))
Expand Down
12 changes: 5 additions & 7 deletions tscreen_linux.go
Expand Up @@ -17,7 +17,6 @@
package tcell

import (
"os"
"os/signal"
"syscall"
"unsafe"
Expand All @@ -33,10 +32,7 @@ func (t *tScreen) termioInit() error {
var ioc uintptr
t.tiosp = &termiosPrivate{}

if t.in, e = os.OpenFile("/dev/tty", os.O_RDONLY, 0); e != nil {
goto failed
}
if t.out, e = os.OpenFile("/dev/tty", os.O_WRONLY, 0); e != nil {
if t.in, t.out, e = t.driver.Init(t.sigwinch); e != nil {
goto failed
}

Expand Down Expand Up @@ -98,7 +94,7 @@ failed:

func (t *tScreen) termioFini() {

signal.Stop(t.sigwinch)
t.driver.Fini()

<-t.indoneq

Expand All @@ -116,7 +112,9 @@ func (t *tScreen) termioFini() {
}

func (t *tScreen) getWinSize() (int, int, error) {

if w, h, err := t.driver.WinSize(); err != ErrWinSizeUnused {
return w, h, err
}
fd := uintptr(t.out.Fd())
dim := [4]uint16{}
dimp := uintptr(unsafe.Pointer(&dim))
Expand Down
11 changes: 5 additions & 6 deletions tscreen_posix.go
Expand Up @@ -17,7 +17,6 @@
package tcell

import (
"os"
"os/signal"
"syscall"
)
Expand Down Expand Up @@ -128,10 +127,7 @@ func (t *tScreen) termioInit() error {
var newtios C.struct_termios
var fd C.int

if t.in, e = os.OpenFile("/dev/tty", os.O_RDONLY, 0); e != nil {
goto failed
}
if t.out, e = os.OpenFile("/dev/tty", os.O_WRONLY, 0); e != nil {
if t.in, t.out, e = t.driver.Init(t.sigwinch); e != nil {
goto failed
}

Expand Down Expand Up @@ -183,7 +179,7 @@ failed:

func (t *tScreen) termioFini() {

signal.Stop(t.sigwinch)
t.driver.Fini()

<-t.indoneq

Expand All @@ -198,6 +194,9 @@ func (t *tScreen) termioFini() {
}

func (t *tScreen) getWinSize() (int, int, error) {
if w, h, err := t.driver.WinSize(); err != ErrWinSizeUnused {
return w, h, err
}
var cx, cy C.int
if r, e := C.getwinsize(C.int(t.out.Fd()), &cx, &cy); r != 0 {
return 0, 0, e
Expand Down

0 comments on commit 646fb36

Please sign in to comment.