diff --git a/README.md b/README.md index d398406..86b03ed 100644 --- a/README.md +++ b/README.md @@ -19,6 +19,7 @@ You can read the source code in [example/main.go](https://github.com/chzyer/read # Todo +* Add support for windows * Vim mode * More funny examples diff --git a/terminal.go b/terminal.go index 2dd6bbf..23bb3a1 100644 --- a/terminal.go +++ b/terminal.go @@ -6,7 +6,6 @@ import ( "os" "sync" "sync/atomic" - "syscall" "golang.org/x/crypto/ssh/terminal" ) @@ -26,7 +25,7 @@ func NewTerminal(cfg *Config) (*Terminal, error) { if err := cfg.Init(); err != nil { return nil, err } - state, err := MakeRaw(syscall.Stdin) + state, err := MakeRaw(StdinFd) if err != nil { return nil, err } @@ -131,5 +130,5 @@ func (t *Terminal) Close() error { } t.stopChan <- struct{}{} t.wg.Wait() - return Restore(syscall.Stdin, t.state) + return Restore(StdinFd, t.state) } diff --git a/utils.go b/utils.go index 220b711..199ec5c 100644 --- a/utils.go +++ b/utils.go @@ -1,9 +1,7 @@ package readline import ( - "syscall" "unicode" - "unsafe" "golang.org/x/crypto/ssh/terminal" ) @@ -67,28 +65,6 @@ func escapeKey(r rune) rune { return r } -type winsize struct { - Row uint16 - Col uint16 - Xpixel uint16 - Ypixel uint16 -} - -// get width of the terminal -// we can cache it here and refresh after received signal -func getWidth() int { - ws := &winsize{} - retCode, _, errno := syscall.Syscall(syscall.SYS_IOCTL, - uintptr(syscall.Stdin), - uintptr(syscall.TIOCGWINSZ), - uintptr(unsafe.Pointer(ws))) - - if int(retCode) == -1 { - panic(errno) - } - return int(ws.Col) -} - func RunesEqual(a, b []rune) bool { if len(a) != len(b) { return false diff --git a/utils_unix.go b/utils_unix.go new file mode 100644 index 0000000..d022da8 --- /dev/null +++ b/utils_unix.go @@ -0,0 +1,33 @@ +// +build darwin dragonfly freebsd linux,!appengine netbsd openbsd + +package readline + +import ( + "syscall" + "unsafe" +) + +var ( + StdinFd = syscall.Stdin +) + +type winsize struct { + Row uint16 + Col uint16 + Xpixel uint16 + Ypixel uint16 +} + +// get width of the terminal +func getWidth() int { + ws := &winsize{} + retCode, _, errno := syscall.Syscall(syscall.SYS_IOCTL, + uintptr(StdinFd), + uintptr(syscall.TIOCGWINSZ), + uintptr(unsafe.Pointer(ws))) + + if int(retCode) == -1 { + panic(errno) + } + return int(ws.Col) +} diff --git a/utils_windows.go b/utils_windows.go new file mode 100644 index 0000000..3905492 --- /dev/null +++ b/utils_windows.go @@ -0,0 +1,67 @@ +// +build windows + +package readline + +import ( + "syscall" + "unsafe" +) + +type ( + short int16 + word uint16 + + small_rect struct { + left short + top short + right short + bottom short + } + + coord struct { + x short + y short + } + + console_screen_buffer_info struct { + size coord + cursor_position coord + attributes word + window small_rect + maximum_window_size coord + } +) + +var ( + StdinFd = 0 + kernel32 = syscall.NewLazyDLL("kernel32.dll") + tmp_info console_screen_buffer_info + + proc_get_console_screen_buffer_info = kernel32.NewProc("GetConsoleScreenBufferInfo") +) + +func get_console_screen_buffer_info(h syscall.Handle, info *console_screen_buffer_info) (err error) { + r0, _, e1 := syscall.Syscall(proc_get_console_screen_buffer_info.Addr(), + 2, uintptr(h), uintptr(unsafe.Pointer(info)), 0) + if int(r0) == 0 { + if e1 != 0 { + err = error(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func get_term_size(out syscall.Handle) coord { + err := get_console_screen_buffer_info(out, &tmp_info) + if err != nil { + panic(err) + } + return tmp_info.size +} + +// get width of the terminal +func getWidth() int { + return int(get_term_size(syscall.Stdin).x) +}