diff --git a/go-tty-fork20200922/.travis.yml b/go-tty-fork20200922/.travis.yml deleted file mode 100644 index 63b9f70..0000000 --- a/go-tty-fork20200922/.travis.yml +++ /dev/null @@ -1,4 +0,0 @@ -language: go -sudo: false -go: - - tip diff --git a/go-tty-fork20200922/LICENSE b/go-tty-fork20200922/LICENSE deleted file mode 100644 index e364750..0000000 --- a/go-tty-fork20200922/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -The MIT License (MIT) - -Copyright (c) 2018 Yasuhiro Matsumoto - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. diff --git a/go-tty-fork20200922/README.md b/go-tty-fork20200922/README.md deleted file mode 100644 index 6712eb4..0000000 --- a/go-tty-fork20200922/README.md +++ /dev/null @@ -1,49 +0,0 @@ -# go-tty - -Simple tty utility - -## Usage - -```go -tty, err := tty.Open() -if err != nil { - log.Fatal(err) -} -defer tty.Close() - -for { - r, err := tty.ReadRune() - if err != nil { - log.Fatal(err) - } - // handle key event -} -``` - -if you are on windows and want to display ANSI colors, use go-colorable. - -```go -tty, err := tty.Open() -if err != nil { - log.Fatal(err) -} -defer tty.Close() - -out := colorable.NewColorable(tty.Output()) - -fmt.Fprintln(out, "\x1b[2J") -``` - -## Installation - -``` -$ go get github.com/mattn/go-tty -``` - -## License - -MIT - -## Author - -Yasuhiro Matsumoto (a.k.a mattn) diff --git a/go-tty-fork20200922/_example/password.go b/go-tty-fork20200922/_example/password.go deleted file mode 100644 index 55edeea..0000000 --- a/go-tty-fork20200922/_example/password.go +++ /dev/null @@ -1,29 +0,0 @@ -// +build ignore - -package main - -import ( - "encoding/base64" - "fmt" - - "github.com/mattn/go-tty" -) - -func main() { - tty, err := tty.Open() - defer tty.Close() - - fmt.Print("Username: ") - username, err := tty.ReadString() - if err != nil { - println("canceled") - return - } - fmt.Print("Password: ") - password, err := tty.ReadPassword() - if err != nil { - println("canceled") - return - } - fmt.Println(base64.StdEncoding.EncodeToString([]byte(username + ":" + password))) -} diff --git a/go-tty-fork20200922/_example/readline.go b/go-tty-fork20200922/_example/readline.go deleted file mode 100644 index 28d0815..0000000 --- a/go-tty-fork20200922/_example/readline.go +++ /dev/null @@ -1,24 +0,0 @@ -// +build ignore - -package main - -import ( - "log" - - "github.com/mattn/go-tty" - "github.com/mattn/go-tty/ttyutil" -) - -func main() { - t, err := tty.Open() - if err != nil { - log.Fatal(err) - } - defer t.Close() - - s, err := ttyutil.ReadLine(t) - if err != nil { - log.Fatal(err) - } - println(s) -} diff --git a/go-tty-fork20200922/_example/simple.go b/go-tty-fork20200922/_example/simple.go deleted file mode 100644 index b242354..0000000 --- a/go-tty-fork20200922/_example/simple.go +++ /dev/null @@ -1,45 +0,0 @@ -// +build ignore - -package main - -import ( - "fmt" - "log" - - "github.com/mattn/go-tty" -) - -func main() { - t, err := tty.Open() - if err != nil { - log.Fatal(err) - } - defer t.Close() - - go func() { - for ws := range t.SIGWINCH() { - fmt.Println("Resized", ws.W, ws.H) - } - }() - - clean,err := t.Raw() - if err != nil { - log.Fatal(err) - } - defer clean() - - fmt.Println("Hit any key") - for { - r, err := t.ReadRune() - if err != nil { - log.Fatal(err) - } - if r == 0 { - continue - } - fmt.Printf("0x%X: %c\n", r, r) - if !t.Buffered() { - break - } - } -} diff --git a/go-tty-fork20200922/go.mod b/go-tty-fork20200922/go.mod deleted file mode 100644 index e8b512e..0000000 --- a/go-tty-fork20200922/go.mod +++ /dev/null @@ -1,11 +0,0 @@ -module github.com/mattn/go-tty - -go 1.14 - -require ( - github.com/mattn/go-colorable v0.1.4 - github.com/mattn/go-isatty v0.0.10 - github.com/mattn/go-runewidth v0.0.7 - golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e - golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e -) diff --git a/go-tty-fork20200922/go.sum b/go-tty-fork20200922/go.sum deleted file mode 100644 index 1d5a1d4..0000000 --- a/go-tty-fork20200922/go.sum +++ /dev/null @@ -1,15 +0,0 @@ -github.com/mattn/go-colorable v0.1.4 h1:snbPLB8fVfU9iwbbo30TPtbLRzwWu6aJS6Xh4eaaviA= -github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= -github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= -github.com/mattn/go-isatty v0.0.10 h1:qxFzApOv4WsAL965uUPIsXzAKCZxN2p9UqdhFS4ZW10= -github.com/mattn/go-isatty v0.0.10/go.mod h1:qgIWMr58cqv1PHHyhnkY9lrL7etaEgOFcMEpPG5Rm84= -github.com/mattn/go-runewidth v0.0.6 h1:V2iyH+aX9C5fsYCpK60U8BYIvmhqxuOL3JZcqc1NB7k= -github.com/mattn/go-runewidth v0.0.6/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI= -github.com/mattn/go-runewidth v0.0.7 h1:Ei8KR0497xHyKJPAv59M1dkC+rOZCMBJ+t3fZ+twI54= -github.com/mattn/go-runewidth v0.0.7/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI= -golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e h1:vcxGaoTs7kV8m5Np9uUNQin4BrLOthgV7252N8V+FwY= -golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20191008105621-543471e840be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e h1:N7DeIrjYszNmSW409R3frPPwglRwMkXSBzwVbkOjLLA= -golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= diff --git a/go-tty-fork20200922/ls-files b/go-tty-fork20200922/ls-files deleted file mode 100644 index 69fa2fb..0000000 --- a/go-tty-fork20200922/ls-files +++ /dev/null @@ -1,16 +0,0 @@ -.travis.yml -LICENSE -README.md -_example/password.go -_example/readline.go -_example/simple.go -go.mod -go.sum -tty.go -tty_bsd.go -tty_linux.go -tty_plan9.go -tty_sys5.go -tty_unix.go -tty_windows.go -ttyutil/readline.go diff --git a/go-tty-fork20200922/tty.go b/go-tty-fork20200922/tty.go deleted file mode 100644 index 13cb206..0000000 --- a/go-tty-fork20200922/tty.go +++ /dev/null @@ -1,128 +0,0 @@ -package tty - -import ( - "os" - "strings" - "unicode" -) - -func Open() (*TTY, error) { - return open("/dev/tty") -} - -func OpenDevice(path string) (*TTY, error) { - return open(path) -} - -func (tty *TTY) Raw() (func() error, error) { - return tty.raw() -} - -func (tty *TTY) MustRaw() func() error { - f, err := tty.raw() - if err != nil { - panic(err.Error()) - } - return f -} - -func (tty *TTY) Buffered() bool { - return tty.buffered() -} - -func (tty *TTY) ReadRune() (rune, error) { - return tty.readRune() -} - -func (tty *TTY) Close() error { - return tty.close() -} - -func (tty *TTY) Size() (int, int, error) { - return tty.size() -} - -func (tty *TTY) SizePixel() (int, int, int, int, error) { - return tty.sizePixel() -} - -func (tty *TTY) Input() *os.File { - return tty.input() -} - -func (tty *TTY) Output() *os.File { - return tty.output() -} - -// Display types. -const ( - displayNone = iota - displayRune - displayMask -) - -func (tty *TTY) readString(displayType int) (string, error) { - rs := []rune{} -loop: - for { - r, err := tty.readRune() - if err != nil { - return "", err - } - switch r { - case 13: - break loop - case 8, 127: - if len(rs) > 0 { - rs = rs[:len(rs)-1] - if displayType != displayNone { - tty.Output().WriteString("\b \b") - } - } - default: - if unicode.IsPrint(r) { - rs = append(rs, r) - switch displayType { - case displayRune: - tty.Output().WriteString(string(r)) - case displayMask: - tty.Output().WriteString("*") - } - } - } - } - return string(rs), nil -} - -func (tty *TTY) ReadString() (string, error) { - defer tty.Output().WriteString("\n") - return tty.readString(displayRune) -} - -func (tty *TTY) ReadPassword() (string, error) { - defer tty.Output().WriteString("\n") - return tty.readString(displayMask) -} - -func (tty *TTY) ReadPasswordNoEcho() (string, error) { - defer tty.Output().WriteString("\n") - return tty.readString(displayNone) -} - -func (tty *TTY) ReadPasswordClear() (string, error) { - s, err := tty.readString(displayMask) - tty.Output().WriteString( - strings.Repeat("\b", len(s)) + - strings.Repeat(" ", len(s)) + - strings.Repeat("\b", len(s))) - return s, err -} - -type WINSIZE struct { - W int - H int -} - -func (tty *TTY) SIGWINCH() <-chan WINSIZE { - return tty.sigwinch() -} diff --git a/go-tty-fork20200922/tty_bsd.go b/go-tty-fork20200922/tty_bsd.go deleted file mode 100644 index e0a51fc..0000000 --- a/go-tty-fork20200922/tty_bsd.go +++ /dev/null @@ -1,12 +0,0 @@ -// +build darwin dragonfly freebsd netbsd openbsd - -package tty - -import ( - "syscall" -) - -const ( - ioctlReadTermios = syscall.TIOCGETA - ioctlWriteTermios = syscall.TIOCSETA -) diff --git a/go-tty-fork20200922/tty_linux.go b/go-tty-fork20200922/tty_linux.go deleted file mode 100644 index 1b9e8ce..0000000 --- a/go-tty-fork20200922/tty_linux.go +++ /dev/null @@ -1,8 +0,0 @@ -// +build linux - -package tty - -const ( - ioctlReadTermios = 0x5401 // syscall.TCGETS - ioctlWriteTermios = 0x5402 // syscall.TCSETS -) diff --git a/go-tty-fork20200922/tty_plan9.go b/go-tty-fork20200922/tty_plan9.go deleted file mode 100644 index 7828953..0000000 --- a/go-tty-fork20200922/tty_plan9.go +++ /dev/null @@ -1,69 +0,0 @@ -package tty - -import ( - "bufio" - "errors" - "os" - "syscall" -) - -type TTY struct { - in *os.File - bin *bufio.Reader - out *os.File -} - -func open(path string) (*TTY, error) { - tty := new(TTY) - - in, err := os.Open("/dev/cons") - if err != nil { - return nil, err - } - tty.in = in - tty.bin = bufio.NewReader(in) - - out, err := os.OpenFile("/dev/cons", syscall.O_WRONLY, 0) - if err != nil { - return nil, err - } - tty.out = out - - return tty, nil -} - -func (tty *TTY) buffered() bool { - return tty.bin.Buffered() > 0 -} - -func (tty *TTY) readRune() (rune, error) { - r, _, err := tty.bin.ReadRune() - return r, err -} - -func (tty *TTY) close() (err error) { - if err2 := tty.in.Close(); err2 != nil { - err = err2 - } - if err2 := tty.out.Close(); err2 != nil { - err = err2 - } - return -} - -func (tty *TTY) size() (int, int, error) { - return 80, 24, nil -} - -func (tty *TTY) sizePixel() (int, int, int, int, error) { - x, y, _ := tty.size() - return x, y, -1, -1, errors.New("no implemented method for querying size in pixels on Plan 9") -} - -func (tty *TTY) input() *os.File { - return tty.in -} - -func (tty *TTY) output() *os.File { - return tty.out -} diff --git a/go-tty-fork20200922/tty_sys5.go b/go-tty-fork20200922/tty_sys5.go deleted file mode 100644 index 7dc30ed..0000000 --- a/go-tty-fork20200922/tty_sys5.go +++ /dev/null @@ -1,12 +0,0 @@ -// +build solaris - -package tty - -import ( - "golang.org/x/sys/unix" -) - -const ( - ioctlReadTermios = unix.TCGETA - ioctlWriteTermios = unix.TCSETA -) diff --git a/go-tty-fork20200922/tty_unix.go b/go-tty-fork20200922/tty_unix.go deleted file mode 100644 index 3cb9450..0000000 --- a/go-tty-fork20200922/tty_unix.go +++ /dev/null @@ -1,142 +0,0 @@ -// +build !windows -// +build !plan9 - -package tty - -import ( - "bufio" - "os" - "os/signal" - "syscall" - "unsafe" - - "golang.org/x/sys/unix" -) - -type TTY struct { - in *os.File - bin *bufio.Reader - out *os.File - termios syscall.Termios - ss chan os.Signal -} - -func open(path string) (*TTY, error) { - tty := new(TTY) - - in, err := os.Open(path) - if err != nil { - return nil, err - } - tty.in = in - tty.bin = bufio.NewReader(in) - - out, err := os.OpenFile(path, syscall.O_WRONLY, 0) - if err != nil { - return nil, err - } - tty.out = out - - if _, _, err := syscall.Syscall(syscall.SYS_IOCTL, uintptr(tty.in.Fd()), ioctlReadTermios, uintptr(unsafe.Pointer(&tty.termios))); err != 0 { - return nil, err - } - newios := tty.termios - newios.Iflag &^= syscall.ISTRIP | syscall.INLCR | syscall.ICRNL | syscall.IGNCR | syscall.IXOFF - newios.Lflag &^= syscall.ECHO | syscall.ICANON /*| syscall.ISIG*/ - if _, _, err := syscall.Syscall(syscall.SYS_IOCTL, uintptr(tty.in.Fd()), ioctlWriteTermios, uintptr(unsafe.Pointer(&newios))); err != 0 { - return nil, err - } - - tty.ss = make(chan os.Signal, 1) - - return tty, nil -} - -func (tty *TTY) buffered() bool { - return tty.bin.Buffered() > 0 -} - -func (tty *TTY) readRune() (rune, error) { - r, _, err := tty.bin.ReadRune() - return r, err -} - -func (tty *TTY) close() error { - signal.Stop(tty.ss) - close(tty.ss) - _, _, err := syscall.Syscall(syscall.SYS_IOCTL, uintptr(tty.in.Fd()), ioctlWriteTermios, uintptr(unsafe.Pointer(&tty.termios))) - return err -} - -func (tty *TTY) size() (int, int, error) { - x, y, _, _, err := tty.sizePixel() - return x, y, err -} - -func (tty *TTY) sizePixel() (int, int, int, int, error) { - var dim [4]uint16 - if _, _, err := syscall.Syscall(syscall.SYS_IOCTL, uintptr(tty.out.Fd()), uintptr(syscall.TIOCGWINSZ), uintptr(unsafe.Pointer(&dim))); err != 0 { - return -1, -1, -1, -1, err - } - return int(dim[1]), int(dim[0]), int(dim[2]), int(dim[3]), nil -} - -func (tty *TTY) input() *os.File { - return tty.in -} - -func (tty *TTY) output() *os.File { - return tty.out -} - -func (tty *TTY) raw() (func() error, error) { - termios, err := unix.IoctlGetTermios(int(tty.in.Fd()), ioctlReadTermios) - if err != nil { - return nil, err - } - backup := *termios - - termios.Iflag &^= unix.IGNBRK | unix.BRKINT | unix.PARMRK | unix.ISTRIP | unix.INLCR | unix.IGNCR | unix.ICRNL | unix.IXON - termios.Oflag &^= unix.OPOST - termios.Lflag &^= unix.ECHO | unix.ECHONL | unix.ICANON | unix.ISIG | unix.IEXTEN - termios.Cflag &^= unix.CSIZE | unix.PARENB - termios.Cflag |= unix.CS8 - termios.Cc[unix.VMIN] = 1 - termios.Cc[unix.VTIME] = 0 - if err := unix.IoctlSetTermios(int(tty.in.Fd()), ioctlWriteTermios, termios); err != nil { - return nil, err - } - - return func() error { - if err := unix.IoctlSetTermios(int(tty.in.Fd()), ioctlWriteTermios, &backup); err != nil { - return err - } - return nil - }, nil -} - -func (tty *TTY) sigwinch() <-chan WINSIZE { - signal.Notify(tty.ss, syscall.SIGWINCH) - - ws := make(chan WINSIZE) - go func() { - defer close(ws) - for sig := range tty.ss { - if sig != syscall.SIGWINCH { - continue - } - - w, h, err := tty.size() - if err != nil { - continue - } - // send but do not block for it - select { - case ws <- WINSIZE{W: w, H: h}: - default: - } - - } - }() - return ws -} diff --git a/go-tty-fork20200922/tty_windows.go b/go-tty-fork20200922/tty_windows.go deleted file mode 100644 index 1b89f7e..0000000 --- a/go-tty-fork20200922/tty_windows.go +++ /dev/null @@ -1,394 +0,0 @@ -// +build windows - -package tty - -import ( - "context" - "errors" - "os" - "syscall" - "unsafe" - - "github.com/mattn/go-isatty" -) - -const ( - rightAltPressed = 1 - leftAltPressed = 2 - rightCtrlPressed = 4 - leftCtrlPressed = 8 - shiftPressed = 0x0010 - ctrlPressed = rightCtrlPressed | leftCtrlPressed - altPressed = rightAltPressed | leftAltPressed -) - -const ( - enableProcessedInput = 0x1 - enableLineInput = 0x2 - enableEchoInput = 0x4 - enableWindowInput = 0x8 - enableMouseInput = 0x10 - enableInsertMode = 0x20 - enableQuickEditMode = 0x40 - enableExtendedFlag = 0x80 - - enableProcessedOutput = 1 - enableWrapAtEolOutput = 2 - - keyEvent = 0x1 - mouseEvent = 0x2 - windowBufferSizeEvent = 0x4 -) - -var kernel32 = syscall.NewLazyDLL("kernel32.dll") - -var ( - procAllocConsole = kernel32.NewProc("AllocConsole") - procSetStdHandle = kernel32.NewProc("SetStdHandle") - procGetStdHandle = kernel32.NewProc("GetStdHandle") - procSetConsoleScreenBufferSize = kernel32.NewProc("SetConsoleScreenBufferSize") - procCreateConsoleScreenBuffer = kernel32.NewProc("CreateConsoleScreenBuffer") - procGetConsoleScreenBufferInfo = kernel32.NewProc("GetConsoleScreenBufferInfo") - procWriteConsoleOutputCharacter = kernel32.NewProc("WriteConsoleOutputCharacterW") - procWriteConsoleOutputAttribute = kernel32.NewProc("WriteConsoleOutputAttribute") - procGetConsoleCursorInfo = kernel32.NewProc("GetConsoleCursorInfo") - procSetConsoleCursorInfo = kernel32.NewProc("SetConsoleCursorInfo") - procSetConsoleCursorPosition = kernel32.NewProc("SetConsoleCursorPosition") - procReadConsoleInput = kernel32.NewProc("ReadConsoleInputW") - procGetConsoleMode = kernel32.NewProc("GetConsoleMode") - procSetConsoleMode = kernel32.NewProc("SetConsoleMode") - procFillConsoleOutputCharacter = kernel32.NewProc("FillConsoleOutputCharacterW") - procFillConsoleOutputAttribute = kernel32.NewProc("FillConsoleOutputAttribute") - procScrollConsoleScreenBuffer = kernel32.NewProc("ScrollConsoleScreenBufferW") -) - -type wchar uint16 -type short int16 -type dword uint32 -type word uint16 - -type coord struct { - x short - y short -} - -type smallRect struct { - left short - top short - right short - bottom short -} - -type consoleScreenBufferInfo struct { - size coord - cursorPosition coord - attributes word - window smallRect - maximumWindowSize coord -} - -type consoleCursorInfo struct { - size dword - visible int32 -} - -type inputRecord struct { - eventType word - _ [2]byte - event [16]byte -} - -type keyEventRecord struct { - keyDown int32 - repeatCount word - virtualKeyCode word - virtualScanCode word - unicodeChar wchar - controlKeyState dword -} - -type windowBufferSizeRecord struct { - size coord -} - -type mouseEventRecord struct { - mousePos coord - buttonState dword - controlKeyState dword - eventFlags dword -} - -type charInfo struct { - unicodeChar wchar - attributes word -} - -type TTY struct { - in *os.File - out *os.File - st uint32 - rs []rune - ws chan WINSIZE - sigwinchCtx context.Context - sigwinchCtxCancel context.CancelFunc - readNextKeyUp bool -} - -func readConsoleInput(fd uintptr, record *inputRecord) (err error) { - var w uint32 - r1, _, err := procReadConsoleInput.Call(fd, uintptr(unsafe.Pointer(record)), 1, uintptr(unsafe.Pointer(&w))) - if r1 == 0 { - return err - } - return nil -} - -func open(path string) (*TTY, error) { - tty := new(TTY) - if false && isatty.IsTerminal(os.Stdin.Fd()) { - tty.in = os.Stdin - } else { - in, err := syscall.Open("CONIN$", syscall.O_RDWR, 0) - if err != nil { - return nil, err - } - - tty.in = os.NewFile(uintptr(in), "/dev/tty") - } - - if isatty.IsTerminal(os.Stdout.Fd()) { - tty.out = os.Stdout - } else { - procAllocConsole.Call() - out, err := syscall.Open("CONOUT$", syscall.O_RDWR, 0) - if err != nil { - return nil, err - } - - tty.out = os.NewFile(uintptr(out), "/dev/tty") - } - - h := tty.in.Fd() - var st uint32 - r1, _, err := procGetConsoleMode.Call(h, uintptr(unsafe.Pointer(&st))) - if r1 == 0 { - return nil, err - } - tty.st = st - - st &^= enableEchoInput - st &^= enableInsertMode - st &^= enableLineInput - st &^= enableMouseInput - st &^= enableWindowInput - st &^= enableExtendedFlag - st &^= enableQuickEditMode - - // ignore error - procSetConsoleMode.Call(h, uintptr(st)) - - tty.ws = make(chan WINSIZE) - tty.sigwinchCtx, tty.sigwinchCtxCancel = context.WithCancel(context.Background()) - - return tty, nil -} - -func (tty *TTY) buffered() bool { - return len(tty.rs) > 0 -} - -func (tty *TTY) readRune() (rune, error) { - if len(tty.rs) > 0 { - r := tty.rs[0] - tty.rs = tty.rs[1:] - return r, nil - } - var ir inputRecord - err := readConsoleInput(tty.in.Fd(), &ir) - if err != nil { - return 0, err - } - - switch ir.eventType { - case windowBufferSizeEvent: - wr := (*windowBufferSizeRecord)(unsafe.Pointer(&ir.event)) - ws := WINSIZE{ - W: int(wr.size.x), - H: int(wr.size.y), - } - - if err := tty.sigwinchCtx.Err(); err != nil { - // closing - // the following select might panic without this guard close - return 0, err - } - - select { - case tty.ws <- ws: - case <-tty.sigwinchCtx.Done(): - return 0, tty.sigwinchCtx.Err() - default: - return 0, nil // no one is currently trying to read - } - case keyEvent: - kr := (*keyEventRecord)(unsafe.Pointer(&ir.event)) - if kr.keyDown == 0 { - if kr.unicodeChar != 0 && tty.readNextKeyUp { - tty.readNextKeyUp = false - return rune(kr.unicodeChar), nil - } - } else { - if kr.controlKeyState&altPressed != 0 && kr.unicodeChar > 0 { - tty.rs = []rune{rune(kr.unicodeChar)} - return rune(0x1b), nil - } - if kr.unicodeChar > 0 { - if kr.controlKeyState&shiftPressed != 0 { - switch kr.unicodeChar { - case 0x09: - tty.rs = []rune{0x5b, 0x5a} - return rune(0x1b), nil - } - } - return rune(kr.unicodeChar), nil - } - vk := kr.virtualKeyCode - if kr.controlKeyState&ctrlPressed != 0 { - switch vk { - case 0x21: // ctrl-page-up - tty.rs = []rune{0x5b, 0x35, 0x3B, 0x35, 0x7e} - return rune(0x1b), nil - case 0x22: // ctrl-page-down - tty.rs = []rune{0x5b, 0x36, 0x3B, 0x35, 0x7e} - return rune(0x1b), nil - case 0x23: // ctrl-end - tty.rs = []rune{0x5b, 0x31, 0x3B, 0x35, 0x46} - return rune(0x1b), nil - case 0x24: // ctrl-home - tty.rs = []rune{0x5b, 0x31, 0x3B, 0x35, 0x48} - return rune(0x1b), nil - case 0x25: // ctrl-left - tty.rs = []rune{0x5b, 0x31, 0x3B, 0x35, 0x44} - return rune(0x1b), nil - case 0x26: // ctrl-up - tty.rs = []rune{0x5b, 0x31, 0x3B, 0x35, 0x41} - return rune(0x1b), nil - case 0x27: // ctrl-right - tty.rs = []rune{0x5b, 0x31, 0x3B, 0x35, 0x43} - return rune(0x1b), nil - case 0x28: // ctrl-down - tty.rs = []rune{0x5b, 0x31, 0x3B, 0x35, 0x42} - return rune(0x1b), nil - case 0x2e: // ctrl-delete - tty.rs = []rune{0x5b, 0x33, 0x3B, 0x35, 0x7e} - return rune(0x1b), nil - } - } - switch vk { - case 0x12: // menu - if kr.controlKeyState&leftAltPressed != 0 { - tty.readNextKeyUp = true - } - return 0, nil - case 0x21: // page-up - tty.rs = []rune{0x5b, 0x35, 0x7e} - return rune(0x1b), nil - case 0x22: // page-down - tty.rs = []rune{0x5b, 0x36, 0x7e} - return rune(0x1b), nil - case 0x23: // end - tty.rs = []rune{0x5b, 0x46} - return rune(0x1b), nil - case 0x24: // home - tty.rs = []rune{0x5b, 0x48} - return rune(0x1b), nil - case 0x25: // left - tty.rs = []rune{0x5b, 0x44} - return rune(0x1b), nil - case 0x26: // up - tty.rs = []rune{0x5b, 0x41} - return rune(0x1b), nil - case 0x27: // right - tty.rs = []rune{0x5b, 0x43} - return rune(0x1b), nil - case 0x28: // down - tty.rs = []rune{0x5b, 0x42} - return rune(0x1b), nil - case 0x2e: // delete - tty.rs = []rune{0x5b, 0x33, 0x7e} - return rune(0x1b), nil - case 0x70, 0x71, 0x72, 0x73: // F1,F2,F3,F4 - tty.rs = []rune{0x5b, 0x4f, rune(vk) - 0x20} - return rune(0x1b), nil - case 0x074, 0x75, 0x76, 0x77: // F5,F6,F7,F8 - tty.rs = []rune{0x5b, 0x31, rune(vk) - 0x3f, 0x7e} - return rune(0x1b), nil - case 0x78, 0x79: // F9,F10 - tty.rs = []rune{0x5b, 0x32, rune(vk) - 0x48, 0x7e} - return rune(0x1b), nil - case 0x7a, 0x7b: // F11,F12 - tty.rs = []rune{0x5b, 0x32, rune(vk) - 0x47, 0x7e} - return rune(0x1b), nil - } - return 0, nil - } - } - return 0, nil -} - -func (tty *TTY) close() error { - procSetConsoleMode.Call(tty.in.Fd(), uintptr(tty.st)) - tty.sigwinchCtxCancel() - close(tty.ws) - return nil -} - -func (tty *TTY) size() (int, int, error) { - var csbi consoleScreenBufferInfo - r1, _, err := procGetConsoleScreenBufferInfo.Call(tty.out.Fd(), uintptr(unsafe.Pointer(&csbi))) - if r1 == 0 { - return 0, 0, err - } - return int(csbi.window.right - csbi.window.left + 1), int(csbi.window.bottom - csbi.window.top + 1), nil -} - -func (tty *TTY) sizePixel() (int, int, int, int, error) { - x, y, err := tty.size() - if err != nil { - x = -1 - y = -1 - } - return x, y, -1, -1, errors.New("no implemented method for querying size in pixels on Windows") -} - -func (tty *TTY) input() *os.File { - return tty.in -} - -func (tty *TTY) output() *os.File { - return tty.out -} - -func (tty *TTY) raw() (func() error, error) { - var st uint32 - r1, _, err := procGetConsoleMode.Call(tty.in.Fd(), uintptr(unsafe.Pointer(&st))) - if r1 == 0 { - return nil, err - } - mode := st &^ (enableEchoInput | enableProcessedInput | enableLineInput | enableProcessedOutput) - r1, _, err = procSetConsoleMode.Call(tty.in.Fd(), uintptr(mode)) - if r1 == 0 { - return nil, err - } - return func() error { - r1, _, err := procSetConsoleMode.Call(tty.in.Fd(), uintptr(st)) - if r1 == 0 { - return err - } - return nil - }, nil -} - -func (tty *TTY) sigwinch() <-chan WINSIZE { - return tty.ws -} diff --git a/go-tty-fork20200922/ttyutil/readline.go b/go-tty-fork20200922/ttyutil/readline.go deleted file mode 100644 index 5efa7ac..0000000 --- a/go-tty-fork20200922/ttyutil/readline.go +++ /dev/null @@ -1,210 +0,0 @@ -package ttyutil - -import ( - "bytes" - "fmt" - "io" - "os" - "os/signal" - - "github.com/mattn/go-colorable" - "github.com/mattn/go-runewidth" - "github.com/mattn/go-tty" -) - -type ctx struct { - w io.Writer - input []rune - last []rune - prompt string - cursor_x int - old_row int - old_crow int - size int -} - -func (c *ctx) redraw(dirty bool, passwordChar rune) error { - var buf bytes.Buffer - - buf.WriteString("\x1b[5>h") - - buf.WriteString("\x1b[1G") - if dirty { - buf.WriteString("\x1b[0K") - } - for i := 0; i < c.old_row-c.old_crow; i++ { - buf.WriteString("\x1b[B") - } - for i := 0; i < c.old_row; i++ { - if dirty { - buf.WriteString("\x1b[2K") - } - buf.WriteString("\x1b[A") - } - - var rs []rune - if passwordChar != 0 { - for i := 0; i < len(c.input); i++ { - rs = append(rs, passwordChar) - } - } else { - rs = c.input - } - - ccol, crow, col, row := -1, 0, 0, 0 - plen := len([]rune(c.prompt)) - for i, r := range []rune(c.prompt + string(rs)) { - if i == plen+c.cursor_x { - ccol = col - crow = row - } - rw := runewidth.RuneWidth(r) - if col+rw > c.size { - col = 0 - row++ - if dirty { - buf.WriteString("\n\r\x1b[0K") - } - } - if dirty { - buf.WriteString(string(r)) - } - col += rw - } - if dirty { - buf.WriteString("\x1b[1G") - for i := 0; i < row; i++ { - buf.WriteString("\x1b[A") - } - } - if ccol == -1 { - ccol = col - crow = row - } - for i := 0; i < crow; i++ { - buf.WriteString("\x1b[B") - } - buf.WriteString(fmt.Sprintf("\x1b[%dG", ccol+1)) - - buf.WriteString("\x1b[5>l") - io.Copy(c.w, &buf) - - c.old_row = row - c.old_crow = crow - - return nil -} - -func ReadLine(tty *tty.TTY) (string, error) { - c := new(ctx) - c.w = colorable.NewColorableStdout() - quit := false - sc := make(chan os.Signal, 1) - signal.Notify(sc, os.Interrupt) - go func() { - <-sc - c.input = nil - quit = true - }() - c.size = 80 - - dirty := true -loop: - for !quit { - err := c.redraw(dirty, 0) - if err != nil { - return "", err - } - dirty = false - - r, err := tty.ReadRune() - if err != nil { - break - } - switch r { - case 0: - case 1: // CTRL-A - c.cursor_x = 0 - case 2: // CTRL-B - if c.cursor_x > 0 { - c.cursor_x-- - } - case 3: // BREAK - return "", nil - case 4: // CTRL-D - if len(c.input) > 0 { - continue - } - return "", io.EOF - case 5: // CTRL-E - c.cursor_x = len(c.input) - case 6: // CTRL-F - if c.cursor_x < len(c.input) { - c.cursor_x++ - } - case 8, 0x7F: // BS - if c.cursor_x > 0 { - c.input = append(c.input[0:c.cursor_x-1], c.input[c.cursor_x:len(c.input)]...) - c.cursor_x-- - dirty = true - } - case 27: - if !tty.Buffered() { - return "", io.EOF - } - r, err = tty.ReadRune() - if err == nil && r == 0x5b { - r, err = tty.ReadRune() - if err != nil { - panic(err) - } - switch r { - case 'C': - if c.cursor_x < len(c.input) { - c.cursor_x++ - } - case 'D': - if c.cursor_x > 0 { - c.cursor_x-- - } - } - } - case 10: // LF - break loop - case 11: // CTRL-K - c.input = c.input[:c.cursor_x] - dirty = true - case 12: // CTRL-L - dirty = true - case 13: // CR - break loop - case 21: // CTRL-U - c.input = c.input[c.cursor_x:] - c.cursor_x = 0 - dirty = true - case 23: // CTRL-W - for i := len(c.input) - 1; i >= 0; i-- { - if i == 0 || c.input[i] == ' ' || c.input[i] == '\t' { - c.input = append(c.input[:i], c.input[c.cursor_x:]...) - c.cursor_x = i - dirty = true - break - } - } - default: - tmp := []rune{} - tmp = append(tmp, c.input[0:c.cursor_x]...) - tmp = append(tmp, r) - c.input = append(tmp, c.input[c.cursor_x:len(c.input)]...) - c.cursor_x++ - dirty = true - } - } - os.Stdout.WriteString("\n") - - if c.input == nil { - return "", io.EOF - } - - return string(c.input), nil -} diff --git a/go.mod b/go.mod index e3b5789..22c98d3 100644 --- a/go.mod +++ b/go.mod @@ -8,6 +8,7 @@ require ( github.com/mattn/go-runewidth v0.0.9 github.com/mattn/go-tty v0.0.3 golang.org/x/sys v0.0.0-20200922070232-aee5d888a860 // indirect + golang.org/x/text v0.3.3 ) -replace github.com/mattn/go-tty v0.0.3 => ./go-tty-fork20200922 +replace github.com/mattn/go-tty v0.0.3 => github.com/zetamatta/go-tty v0.0.4-0.20200922103638-e1c25758b0f4 diff --git a/go.sum b/go.sum index 564889f..a84391a 100644 --- a/go.sum +++ b/go.sum @@ -12,6 +12,8 @@ github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Ky github.com/mattn/go-runewidth v0.0.7/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI= github.com/mattn/go-runewidth v0.0.9 h1:Lm995f3rfxdpd6TSmuVCHVb/QhupuXlYr8sCI/QdE+0= github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI= +github.com/zetamatta/go-tty v0.0.4-0.20200922103638-e1c25758b0f4 h1:itqCHmKX2SltgMjtVYdYRUA4J8N9xMgprib3y+lMGJQ= +github.com/zetamatta/go-tty v0.0.4-0.20200922103638-e1c25758b0f4/go.mod h1:+0QBZrHExAnq8s9KMEZErKk7qTDOyCmOmXxHBLO8M2o= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20191008105621-543471e840be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -21,3 +23,6 @@ golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200922070232-aee5d888a860 h1:YEu4SMq7D0cmT7CBbXfcH0NZeuChAXwsHe/9XueUO6o= golang.org/x/sys v0.0.0-20200922070232-aee5d888a860/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/text v0.3.3 h1:cokOdA+Jmi5PJGXLlLllQSgYigAEfHXJAERHVMaCc2k= +golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=