forked from sloum/bombadillo
Replace calls to `stty` with syscalls
- Move termios-related functionality to its own package - Reimplement stty calls using ioctl calls - Add per-platform constants for linux and non-linux because the ioctl enums are different. The enums in Darwin seem to come from BSD and so I'm assuming they might also work for other operating systems. If not, we'll need to add other build-constrained const files. This code has been tested on Darwin and will be tested on Linux before merging.
This commit is contained in:
parent
36ae4a228f
commit
6d90e6b4c0
20
client.go
20
client.go
|
@ -4,7 +4,6 @@ import (
|
|||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"regexp"
|
||||
"strconv"
|
||||
|
@ -19,6 +18,7 @@ import (
|
|||
"tildegit.org/sloum/bombadillo/http"
|
||||
"tildegit.org/sloum/bombadillo/local"
|
||||
"tildegit.org/sloum/bombadillo/telnet"
|
||||
"tildegit.org/sloum/bombadillo/termios"
|
||||
)
|
||||
|
||||
//------------------------------------------------\\
|
||||
|
@ -43,14 +43,7 @@ type client struct {
|
|||
//--------------------------------------------------\\
|
||||
|
||||
func (c *client) GetSizeOnce() {
|
||||
cmd := exec.Command("stty", "size")
|
||||
cmd.Stdin = os.Stdin
|
||||
out, err := cmd.Output()
|
||||
if err != nil {
|
||||
cui.Exit(5, "Fatal error: Unable to retrieve terminal size")
|
||||
}
|
||||
var h, w int
|
||||
_, _ = fmt.Sscan(string(out), &h, &w)
|
||||
var w, h = termios.GetWindowSize()
|
||||
c.Height = h
|
||||
c.Width = w
|
||||
}
|
||||
|
@ -61,14 +54,7 @@ func (c *client) GetSize() {
|
|||
c.Draw()
|
||||
|
||||
for {
|
||||
cmd := exec.Command("stty", "size")
|
||||
cmd.Stdin = os.Stdin
|
||||
out, err := cmd.Output()
|
||||
if err != nil {
|
||||
cui.Exit(5, "Fatal error: Unable to retrieve terminal size")
|
||||
}
|
||||
var h, w int
|
||||
_, _ = fmt.Sscan(string(out), &h, &w)
|
||||
var w, h = termios.GetWindowSize()
|
||||
if h != c.Height || w != c.Width {
|
||||
c.Height = h
|
||||
c.Width = w
|
||||
|
|
37
cui/cui.go
37
cui/cui.go
|
@ -5,6 +5,8 @@ import (
|
|||
"fmt"
|
||||
"os"
|
||||
"os/exec"
|
||||
|
||||
"tildegit.org/sloum/bombadillo/termios"
|
||||
)
|
||||
|
||||
var Shapes = map[string]string{
|
||||
|
@ -55,16 +57,17 @@ func Exit(exitCode int, msg string) {
|
|||
|
||||
// InitTerm sets the terminal modes appropriate for Bombadillo
|
||||
func InitTerm() {
|
||||
SetCharMode()
|
||||
Tput("smcup") // use alternate screen
|
||||
Tput("rmam") // turn off line wrapping
|
||||
termios.SetCharMode()
|
||||
Tput("smcup") // use alternate screen
|
||||
Tput("rmam") // turn off line wrapping
|
||||
fmt.Print("\033[?25l") // hide cursor
|
||||
}
|
||||
|
||||
// CleanupTerm reverts changs to terminal mode made by InitTerm
|
||||
func CleanupTerm() {
|
||||
moveCursorToward("down", 500)
|
||||
moveCursorToward("right", 500)
|
||||
SetLineMode()
|
||||
termios.SetLineMode()
|
||||
|
||||
fmt.Print("\n")
|
||||
fmt.Print("\033[?25h") // reenables cursor blinking
|
||||
|
@ -98,7 +101,7 @@ func Getch() rune {
|
|||
}
|
||||
|
||||
func GetLine(prefix string) (string, error) {
|
||||
SetLineMode()
|
||||
termios.SetLineMode()
|
||||
|
||||
reader := bufio.NewReader(os.Stdin)
|
||||
fmt.Print(prefix)
|
||||
|
@ -107,32 +110,10 @@ func GetLine(prefix string) (string, error) {
|
|||
return "", err
|
||||
}
|
||||
|
||||
SetCharMode()
|
||||
termios.SetCharMode()
|
||||
return text[:len(text)-1], nil
|
||||
}
|
||||
|
||||
func SetCharMode() {
|
||||
cmd := exec.Command("stty", "cbreak", "-echo")
|
||||
cmd.Stdin = os.Stdin
|
||||
cmd.Stdout = os.Stdout
|
||||
err := cmd.Run()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
fmt.Print("\033[?25l")
|
||||
}
|
||||
|
||||
func SetLineMode() {
|
||||
cmd := exec.Command("stty", "-cbreak", "echo")
|
||||
cmd.Stdin = os.Stdin
|
||||
cmd.Stdout = os.Stdout
|
||||
err := cmd.Run()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
func Tput(opt string) {
|
||||
cmd := exec.Command("tput", opt)
|
||||
cmd.Stdin = os.Stdin
|
||||
|
|
|
@ -0,0 +1,10 @@
|
|||
// +build linux
|
||||
|
||||
package termios
|
||||
|
||||
import "syscall"
|
||||
|
||||
const (
|
||||
getTermiosIoctl = syscall.TCGETS
|
||||
setTermiosIoctl = syscall.TCSETS
|
||||
)
|
|
@ -0,0 +1,10 @@
|
|||
// +build !linux
|
||||
|
||||
package termios
|
||||
|
||||
import "syscall"
|
||||
|
||||
const (
|
||||
getTermiosIoctl = syscall.TIOCGETA
|
||||
setTermiosIoctl = syscall.TIOCSETAF
|
||||
)
|
|
@ -0,0 +1,60 @@
|
|||
package termios
|
||||
|
||||
import (
|
||||
"os"
|
||||
"runtime"
|
||||
"syscall"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
type winsize struct {
|
||||
Row uint16
|
||||
Col uint16
|
||||
Xpixel uint16
|
||||
Ypixel uint16
|
||||
}
|
||||
|
||||
var fd = os.Stdin.Fd()
|
||||
|
||||
func ioctl(fd, request, argp uintptr) error {
|
||||
if _, _, e := syscall.Syscall(syscall.SYS_IOCTL, fd, request, argp); e != 0 {
|
||||
return e
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func GetWindowSize() (int, int) {
|
||||
var value winsize
|
||||
ioctl(fd, syscall.TIOCGWINSZ, uintptr(unsafe.Pointer(&value)))
|
||||
return int(value.Col), int(value.Row)
|
||||
}
|
||||
|
||||
func getTermios() syscall.Termios {
|
||||
var value syscall.Termios
|
||||
err := ioctl(fd, getTermiosIoctl, uintptr(unsafe.Pointer(&value)))
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return value
|
||||
}
|
||||
|
||||
func setTermios(termios syscall.Termios) {
|
||||
err := ioctl(fd, setTermiosIoctl, uintptr(unsafe.Pointer(&termios)))
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
runtime.KeepAlive(termios)
|
||||
}
|
||||
|
||||
func SetCharMode() {
|
||||
t := getTermios()
|
||||
t.Lflag = t.Lflag ^ syscall.ICANON
|
||||
t.Lflag = t.Lflag ^ syscall.ECHO
|
||||
setTermios(t)
|
||||
}
|
||||
|
||||
func SetLineMode() {
|
||||
var t = getTermios()
|
||||
t.Lflag = t.Lflag | (syscall.ICANON | syscall.ECHO)
|
||||
setTermios(t)
|
||||
}
|
Loading…
Reference in New Issue