mirror of https://github.com/chzyer/readline.git
finish windows support
This commit is contained in:
parent
6eb29567f6
commit
bb60b8a58f
|
@ -1,9 +1,10 @@
|
||||||
language: go
|
language: go
|
||||||
go:
|
go:
|
||||||
- 1.4
|
|
||||||
- 1.5
|
- 1.5
|
||||||
before_install:
|
before_install:
|
||||||
- go get golang.org/x/crypto/ssh/terminal
|
- go get golang.org/x/crypto/ssh/terminal
|
||||||
script:
|
script:
|
||||||
- go install github.com/chzyer/readline/example
|
- GOOS=windows go install github.com/chzyer/readline/example
|
||||||
|
- GOOS=linux go install github.com/chzyer/readline/example
|
||||||
|
- GOOS=darwin go install github.com/chzyer/readline/example
|
||||||
- go test -v
|
- go test -v
|
||||||
|
|
|
@ -12,9 +12,41 @@ import (
|
||||||
"unsafe"
|
"unsafe"
|
||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
const (
|
||||||
Stdout = NewANSIWriter(Stdout)
|
_ = uint16(0)
|
||||||
Stderr = NewANSIWriter(Stderr)
|
COLOR_FBLUE = 0x0001
|
||||||
|
COLOR_FGREEN = 0x0002
|
||||||
|
COLOR_FRED = 0x0004
|
||||||
|
COLOR_FINTENSITY = 0x0008
|
||||||
|
|
||||||
|
COLOR_BBLUE = 0x0010
|
||||||
|
COLOR_BGREEN = 0x0020
|
||||||
|
COLOR_BRED = 0x0040
|
||||||
|
COLOR_BINTENSITY = 0x0080
|
||||||
|
|
||||||
|
COMMON_LVB_UNDERSCORE = 0x8000
|
||||||
|
)
|
||||||
|
|
||||||
|
var ColorTableFg = []word{
|
||||||
|
0, // 30: Black
|
||||||
|
COLOR_FRED, // 31: Red
|
||||||
|
COLOR_FGREEN, // 32: Green
|
||||||
|
COLOR_FRED | COLOR_FGREEN, // 33: Yellow
|
||||||
|
COLOR_FBLUE, // 34: Blue
|
||||||
|
COLOR_FRED | COLOR_FBLUE, // 35: Magenta
|
||||||
|
COLOR_FGREEN | COLOR_FBLUE, // 36: Cyan
|
||||||
|
COLOR_FRED | COLOR_FBLUE | COLOR_FGREEN, // 37: White
|
||||||
|
}
|
||||||
|
|
||||||
|
var ColorTableBg = []word{
|
||||||
|
0, // 40: Black
|
||||||
|
COLOR_BRED, // 41: Red
|
||||||
|
COLOR_BGREEN, // 42: Green
|
||||||
|
COLOR_BRED | COLOR_BGREEN, // 43: Yellow
|
||||||
|
COLOR_BBLUE, // 44: Blue
|
||||||
|
COLOR_BRED | COLOR_BBLUE, // 45: Magenta
|
||||||
|
COLOR_BGREEN | COLOR_BBLUE, // 46: Cyan
|
||||||
|
COLOR_BRED | COLOR_BBLUE | COLOR_BGREEN, // 47: White
|
||||||
}
|
}
|
||||||
|
|
||||||
type ANSIWriter struct {
|
type ANSIWriter struct {
|
||||||
|
@ -140,11 +172,13 @@ func (a *ANSIWriter) ioloopEscSeq(w *bufio.Writer, r rune, argptr *[]string) boo
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
if c >= 30 && c < 40 {
|
if c >= 30 && c < 40 {
|
||||||
|
color ^= COLOR_FINTENSITY
|
||||||
color |= ColorTableFg[c-30]
|
color |= ColorTableFg[c-30]
|
||||||
} else if c >= 40 && c < 50 {
|
} else if c >= 40 && c < 50 {
|
||||||
|
color ^= COLOR_BINTENSITY
|
||||||
color |= ColorTableBg[c-40]
|
color |= ColorTableBg[c-40]
|
||||||
} else if c == 4 {
|
} else if c == 4 {
|
||||||
color |= COMMON_LVB_UNDERSCORE
|
color |= COMMON_LVB_UNDERSCORE | ColorTableFg[7]
|
||||||
} else { // unknown code treat as reset
|
} else { // unknown code treat as reset
|
||||||
color = ColorTableFg[7]
|
color = ColorTableFg[7]
|
||||||
}
|
}
|
||||||
|
@ -225,40 +259,3 @@ func eraseLine() error {
|
||||||
uintptr(unsafe.Pointer(&written)),
|
uintptr(unsafe.Pointer(&written)),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
const (
|
|
||||||
_ = uint16(0)
|
|
||||||
COLOR_FBLUE = 0x0001
|
|
||||||
COLOR_FGREEN = 0x0002
|
|
||||||
COLOR_FRED = 0x0004
|
|
||||||
COLOR_FINTENSITY = 0x0008
|
|
||||||
|
|
||||||
COLOR_BBLUE = 0x0010
|
|
||||||
COLOR_BGREEN = 0x0020
|
|
||||||
COLOR_BRED = 0x0040
|
|
||||||
COLOR_BINTENSITY = 0x0080
|
|
||||||
|
|
||||||
COMMON_LVB_UNDERSCORE = 0x8000
|
|
||||||
)
|
|
||||||
|
|
||||||
var ColorTableFg = []word{
|
|
||||||
0, // 30: Black
|
|
||||||
COLOR_FRED, // 31: Red
|
|
||||||
COLOR_FGREEN, // 32: Green
|
|
||||||
COLOR_FRED | COLOR_FGREEN, // 33: Yellow
|
|
||||||
COLOR_FBLUE, // 34: Blue
|
|
||||||
COLOR_FRED | COLOR_FBLUE, // 35: Magenta
|
|
||||||
COLOR_FGREEN | COLOR_FBLUE, // 36: Cyan
|
|
||||||
COLOR_FRED | COLOR_FBLUE | COLOR_FGREEN, // 37: White
|
|
||||||
}
|
|
||||||
|
|
||||||
var ColorTableBg = []word{
|
|
||||||
0, // 40: Black
|
|
||||||
COLOR_BRED, // 41: Red
|
|
||||||
COLOR_BGREEN, // 42: Green
|
|
||||||
COLOR_BRED | COLOR_BGREEN, // 43: Yellow
|
|
||||||
COLOR_BBLUE, // 44: Blue
|
|
||||||
COLOR_BRED | COLOR_BBLUE, // 45: Magenta
|
|
||||||
COLOR_BGREEN | COLOR_BBLUE, // 46: Cyan
|
|
||||||
COLOR_BRED | COLOR_BBLUE | COLOR_BGREEN, // 47: White
|
|
||||||
}
|
|
2
char.go
2
char.go
|
@ -26,7 +26,7 @@ const (
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
MetaPrev = -iota - 1
|
MetaPrev rune = -iota - 1
|
||||||
MetaNext
|
MetaNext
|
||||||
MetaDelete
|
MetaDelete
|
||||||
MetaBackspace
|
MetaBackspace
|
||||||
|
|
|
@ -7,6 +7,8 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"gopkg.in/logex.v1"
|
||||||
|
|
||||||
"github.com/chzyer/readline"
|
"github.com/chzyer/readline"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -39,6 +41,7 @@ func main() {
|
||||||
HistoryFile: "/tmp/readline.tmp",
|
HistoryFile: "/tmp/readline.tmp",
|
||||||
AutoComplete: completer,
|
AutoComplete: completer,
|
||||||
})
|
})
|
||||||
|
logex.SetStd(logex.NewLoggerEx(l.Stderr()))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,122 @@
|
||||||
|
// +build windows
|
||||||
|
|
||||||
|
package readline
|
||||||
|
|
||||||
|
import "unsafe"
|
||||||
|
|
||||||
|
const (
|
||||||
|
VK_CANCEL = 0x03
|
||||||
|
VK_BACK = 0x08
|
||||||
|
VK_TAB = 0x09
|
||||||
|
VK_RETURN = 0x0D
|
||||||
|
VK_SHIFT = 0x10
|
||||||
|
VK_CONTROL = 0x11
|
||||||
|
VK_MENU = 0x12
|
||||||
|
VK_ESCAPE = 0x1B
|
||||||
|
VK_LEFT = 0x25
|
||||||
|
VK_UP = 0x26
|
||||||
|
VK_RIGHT = 0x27
|
||||||
|
VK_DOWN = 0x28
|
||||||
|
VK_DELETE = 0x2E
|
||||||
|
VK_LSHIFT = 0xA0
|
||||||
|
VK_RSHIFT = 0xA1
|
||||||
|
VK_LCONTROL = 0xA2
|
||||||
|
VK_RCONTROL = 0xA3
|
||||||
|
)
|
||||||
|
|
||||||
|
type RawReader struct {
|
||||||
|
ctrlKey bool
|
||||||
|
altKey bool
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewRawReader() *RawReader {
|
||||||
|
r := new(RawReader)
|
||||||
|
return r
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *RawReader) Read(buf []byte) (int, error) {
|
||||||
|
ir := new(_INPUT_RECORD)
|
||||||
|
var read int
|
||||||
|
var err error
|
||||||
|
next:
|
||||||
|
err = kernel.ReadConsoleInputW(stdin,
|
||||||
|
uintptr(unsafe.Pointer(ir)),
|
||||||
|
1,
|
||||||
|
uintptr(unsafe.Pointer(&read)),
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
if ir.EventType != EVENT_KEY {
|
||||||
|
goto next
|
||||||
|
}
|
||||||
|
ker := (*_KEY_EVENT_RECORD)(unsafe.Pointer(&ir.Event[0]))
|
||||||
|
if ker.bKeyDown == 0 { // keyup
|
||||||
|
if r.ctrlKey || r.altKey {
|
||||||
|
switch ker.wVirtualKeyCode {
|
||||||
|
case VK_RCONTROL, VK_LCONTROL:
|
||||||
|
r.ctrlKey = false
|
||||||
|
case VK_MENU: //alt
|
||||||
|
r.altKey = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
goto next
|
||||||
|
}
|
||||||
|
|
||||||
|
if ker.unicodeChar == 0 {
|
||||||
|
var target rune
|
||||||
|
switch ker.wVirtualKeyCode {
|
||||||
|
case VK_RCONTROL, VK_LCONTROL:
|
||||||
|
r.ctrlKey = true
|
||||||
|
case VK_MENU: //alt
|
||||||
|
r.altKey = true
|
||||||
|
case VK_LEFT:
|
||||||
|
target = CharBackward
|
||||||
|
case VK_RIGHT:
|
||||||
|
target = CharForward
|
||||||
|
case VK_UP:
|
||||||
|
target = CharPrev
|
||||||
|
case VK_DOWN:
|
||||||
|
target = CharNext
|
||||||
|
}
|
||||||
|
if target != 0 {
|
||||||
|
return r.write(buf, target)
|
||||||
|
}
|
||||||
|
goto next
|
||||||
|
}
|
||||||
|
char := rune(ker.unicodeChar)
|
||||||
|
if r.ctrlKey {
|
||||||
|
switch char {
|
||||||
|
case 'A':
|
||||||
|
char = CharLineStart
|
||||||
|
case 'E':
|
||||||
|
char = CharLineEnd
|
||||||
|
case 'R':
|
||||||
|
char = CharBckSearch
|
||||||
|
case 'S':
|
||||||
|
char = CharFwdSearch
|
||||||
|
}
|
||||||
|
} else if r.altKey {
|
||||||
|
switch char {
|
||||||
|
case VK_BACK:
|
||||||
|
char = CharBackspace
|
||||||
|
}
|
||||||
|
return r.writeEsc(buf, char)
|
||||||
|
}
|
||||||
|
return r.write(buf, char)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *RawReader) writeEsc(b []byte, char rune) (int, error) {
|
||||||
|
b[0] = '\033'
|
||||||
|
n := copy(b[1:], []byte(string(char)))
|
||||||
|
return n + 1, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *RawReader) write(b []byte, char rune) (int, error) {
|
||||||
|
n := copy(b, []byte(string(char)))
|
||||||
|
return n, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *RawReader) Close() error {
|
||||||
|
return nil
|
||||||
|
}
|
1
std.go
1
std.go
|
@ -6,6 +6,7 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
Stdin io.ReadCloser = os.Stdin
|
||||||
Stdout io.WriteCloser = os.Stdout
|
Stdout io.WriteCloser = os.Stdout
|
||||||
Stderr io.WriteCloser = os.Stderr
|
Stderr io.WriteCloser = os.Stderr
|
||||||
)
|
)
|
||||||
|
|
|
@ -0,0 +1,9 @@
|
||||||
|
// +build windows
|
||||||
|
|
||||||
|
package readline
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
Stdin = NewRawReader()
|
||||||
|
Stdout = NewANSIWriter(Stdout)
|
||||||
|
Stderr = NewANSIWriter(Stderr)
|
||||||
|
}
|
|
@ -3,7 +3,6 @@ package readline
|
||||||
import (
|
import (
|
||||||
"bufio"
|
"bufio"
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
|
||||||
"sync"
|
"sync"
|
||||||
"sync/atomic"
|
"sync/atomic"
|
||||||
|
|
||||||
|
@ -81,7 +80,7 @@ func (t *Terminal) ioloop() {
|
||||||
expectNextChar bool
|
expectNextChar bool
|
||||||
)
|
)
|
||||||
|
|
||||||
buf := bufio.NewReader(os.Stdin)
|
buf := bufio.NewReader(Stdin)
|
||||||
for {
|
for {
|
||||||
if !expectNextChar {
|
if !expectNextChar {
|
||||||
atomic.StoreInt64(&t.isReading, 0)
|
atomic.StoreInt64(&t.isReading, 0)
|
||||||
|
|
|
@ -11,14 +11,16 @@ import (
|
||||||
var (
|
var (
|
||||||
kernel = NewKernel()
|
kernel = NewKernel()
|
||||||
stdout = uintptr(syscall.Stdout)
|
stdout = uintptr(syscall.Stdout)
|
||||||
|
stdin = uintptr(syscall.Stdin)
|
||||||
)
|
)
|
||||||
|
|
||||||
type Kernel struct {
|
type Kernel struct {
|
||||||
SetConsoleCursorPosition,
|
SetConsoleCursorPosition,
|
||||||
SetConsoleTextAttribute,
|
SetConsoleTextAttribute,
|
||||||
GetConsoleScreenBufferInfo,
|
|
||||||
FillConsoleOutputCharacterW,
|
FillConsoleOutputCharacterW,
|
||||||
FillConsoleOutputAttribute,
|
FillConsoleOutputAttribute,
|
||||||
|
ReadConsoleInputW,
|
||||||
|
GetConsoleScreenBufferInfo,
|
||||||
GetConsoleCursorInfo,
|
GetConsoleCursorInfo,
|
||||||
GetStdHandle CallFunc
|
GetStdHandle CallFunc
|
||||||
}
|
}
|
||||||
|
@ -26,6 +28,7 @@ type Kernel struct {
|
||||||
type short int16
|
type short int16
|
||||||
type word uint16
|
type word uint16
|
||||||
type dword uint32
|
type dword uint32
|
||||||
|
type wchar uint16
|
||||||
|
|
||||||
type _COORD struct {
|
type _COORD struct {
|
||||||
x short
|
x short
|
||||||
|
@ -36,6 +39,34 @@ func (c *_COORD) ptr() uintptr {
|
||||||
return uintptr(*(*int32)(unsafe.Pointer(c)))
|
return uintptr(*(*int32)(unsafe.Pointer(c)))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const (
|
||||||
|
EVENT_KEY = 0x0001
|
||||||
|
EVENT_MOUSE = 0x0002
|
||||||
|
EVENT_WINDOW_BUFFER_SIZE = 0x0004
|
||||||
|
EVENT_MENU = 0x0008
|
||||||
|
EVENT_FOCUS = 0x0010
|
||||||
|
)
|
||||||
|
|
||||||
|
type _KEY_EVENT_RECORD struct {
|
||||||
|
bKeyDown int32
|
||||||
|
wRepeatCount word
|
||||||
|
wVirtualKeyCode word
|
||||||
|
wVirtualScanCode word
|
||||||
|
unicodeChar wchar
|
||||||
|
dwControlKeyState dword
|
||||||
|
}
|
||||||
|
|
||||||
|
// KEY_EVENT_RECORD KeyEvent;
|
||||||
|
// MOUSE_EVENT_RECORD MouseEvent;
|
||||||
|
// WINDOW_BUFFER_SIZE_RECORD WindowBufferSizeEvent;
|
||||||
|
// MENU_EVENT_RECORD MenuEvent;
|
||||||
|
// FOCUS_EVENT_RECORD FocusEvent;
|
||||||
|
type _INPUT_RECORD struct {
|
||||||
|
EventType word
|
||||||
|
Padding uint16
|
||||||
|
Event [16]byte
|
||||||
|
}
|
||||||
|
|
||||||
type _CONSOLE_SCREEN_BUFFER_INFO struct {
|
type _CONSOLE_SCREEN_BUFFER_INFO struct {
|
||||||
dwSize _COORD
|
dwSize _COORD
|
||||||
dwCursorPosition _COORD
|
dwCursorPosition _COORD
|
||||||
|
|
Loading…
Reference in New Issue