Use syscall consts, check for errors,
Also rename func for non-windows specific names. Signed-off-by: Sachin Joshi <sachin_jayant_joshi@hotmail.com>
This commit is contained in:
parent
c23a02e41a
commit
27c2a55648
5 changed files with 40 additions and 30 deletions
|
@ -30,7 +30,7 @@ func StdStreams() (stdOut io.Writer, stdErr io.Writer, stdIn io.ReadCloser) {
|
||||||
return os.Stdout, os.Stderr, os.Stdin
|
return os.Stdout, os.Stderr, os.Stdin
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetHandleInfo(in interface{}) (uintptr, bool) {
|
func GetFdInfo(in interface{}) (uintptr, bool) {
|
||||||
var inFd uintptr
|
var inFd uintptr
|
||||||
var isTerminalIn bool
|
var isTerminalIn bool
|
||||||
if file, ok := in.(*os.File); ok {
|
if file, ok := in.(*os.File); ok {
|
||||||
|
|
|
@ -107,8 +107,8 @@ func MakeRaw(fd uintptr) (*State, error) {
|
||||||
return state, nil
|
return state, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetHandleInfo returns file descriptor and bool indicating whether the file is a terminal
|
// GetFdInfo returns file descriptor and bool indicating whether the file is a terminal
|
||||||
func GetHandleInfo(in interface{}) (uintptr, bool) {
|
func GetFdInfo(in interface{}) (uintptr, bool) {
|
||||||
return winconsole.GetHandleInfo(in)
|
return winconsole.GetHandleInfo(in)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -83,11 +83,6 @@ const (
|
||||||
|
|
||||||
ANSI_MAX_CMD_LENGTH = 256
|
ANSI_MAX_CMD_LENGTH = 256
|
||||||
|
|
||||||
// https://msdn.microsoft.com/en-us/library/windows/desktop/ms683231(v=vs.85).aspx
|
|
||||||
STD_INPUT_HANDLE = -10
|
|
||||||
STD_OUTPUT_HANDLE = -11
|
|
||||||
STD_ERROR_HANDLE = -12
|
|
||||||
|
|
||||||
MAX_INPUT_BUFFER = 1024
|
MAX_INPUT_BUFFER = 1024
|
||||||
DEFAULT_WIDTH = 80
|
DEFAULT_WIDTH = 80
|
||||||
DEFAULT_HEIGHT = 24
|
DEFAULT_HEIGHT = 24
|
||||||
|
@ -212,7 +207,10 @@ func StdStreams() (stdOut io.Writer, stdErr io.Writer, stdIn io.ReadCloser) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Save current screen buffer info
|
// Save current screen buffer info
|
||||||
handle, _ := syscall.GetStdHandle(STD_OUTPUT_HANDLE)
|
handle, err := syscall.GetStdHandle(syscall.STD_OUTPUT_HANDLE)
|
||||||
|
if nil != err {
|
||||||
|
panic("This should never happen as it is predefined handle.")
|
||||||
|
}
|
||||||
screenBufferInfo, err := GetConsoleScreenBufferInfo(uintptr(handle))
|
screenBufferInfo, err := GetConsoleScreenBufferInfo(uintptr(handle))
|
||||||
if err == nil {
|
if err == nil {
|
||||||
handler.screenBufferInfo = screenBufferInfo
|
handler.screenBufferInfo = screenBufferInfo
|
||||||
|
@ -225,26 +223,36 @@ func StdStreams() (stdOut io.Writer, stdErr io.Writer, stdIn io.ReadCloser) {
|
||||||
wrappedWriter: os.Stdout,
|
wrappedWriter: os.Stdout,
|
||||||
emulator: handler,
|
emulator: handler,
|
||||||
command: make([]byte, 0, ANSI_MAX_CMD_LENGTH),
|
command: make([]byte, 0, ANSI_MAX_CMD_LENGTH),
|
||||||
|
fd: uintptr(handle),
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
stdOut = os.Stdout
|
stdOut = os.Stdout
|
||||||
|
|
||||||
}
|
}
|
||||||
if IsTerminal(os.Stderr.Fd()) {
|
if IsTerminal(os.Stderr.Fd()) {
|
||||||
|
handle, err := syscall.GetStdHandle(syscall.STD_ERROR_HANDLE)
|
||||||
|
if nil != err {
|
||||||
|
panic("This should never happen as it is predefined handle.")
|
||||||
|
}
|
||||||
stdErr = &terminalWriter{
|
stdErr = &terminalWriter{
|
||||||
wrappedWriter: os.Stderr,
|
wrappedWriter: os.Stderr,
|
||||||
emulator: handler,
|
emulator: handler,
|
||||||
command: make([]byte, 0, ANSI_MAX_CMD_LENGTH),
|
command: make([]byte, 0, ANSI_MAX_CMD_LENGTH),
|
||||||
|
fd: uintptr(handle),
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
stdErr = os.Stderr
|
stdErr = os.Stderr
|
||||||
|
|
||||||
}
|
}
|
||||||
if IsTerminal(os.Stdin.Fd()) {
|
if IsTerminal(os.Stdin.Fd()) {
|
||||||
|
handle, err := syscall.GetStdHandle(syscall.STD_INPUT_HANDLE)
|
||||||
|
if nil != err {
|
||||||
|
panic("This should never happen as it is predefined handle.")
|
||||||
|
}
|
||||||
stdIn = &terminalReader{
|
stdIn = &terminalReader{
|
||||||
wrappedReader: os.Stdin,
|
wrappedReader: os.Stdin,
|
||||||
emulator: handler,
|
emulator: handler,
|
||||||
command: make([]byte, 0, ANSI_MAX_CMD_LENGTH),
|
command: make([]byte, 0, ANSI_MAX_CMD_LENGTH),
|
||||||
|
fd: uintptr(handle),
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
stdIn = os.Stdin
|
stdIn = os.Stdin
|
||||||
|
@ -626,7 +634,7 @@ func getWindowsTextAttributeForAnsiValue(originalFlag WORD, defaultValue WORD, a
|
||||||
}
|
}
|
||||||
|
|
||||||
// HandleOutputCommand interpretes the Ansi commands and then makes appropriate Win32 calls
|
// HandleOutputCommand interpretes the Ansi commands and then makes appropriate Win32 calls
|
||||||
func (term *WindowsTerminal) HandleOutputCommand(command []byte) (n int, err error) {
|
func (term *WindowsTerminal) HandleOutputCommand(fd uintptr, command []byte) (n int, err error) {
|
||||||
// console settings changes need to happen in atomic way
|
// console settings changes need to happen in atomic way
|
||||||
term.outMutex.Lock()
|
term.outMutex.Lock()
|
||||||
defer term.outMutex.Unlock()
|
defer term.outMutex.Unlock()
|
||||||
|
@ -636,7 +644,7 @@ func (term *WindowsTerminal) HandleOutputCommand(command []byte) (n int, err err
|
||||||
parsedCommand := parseAnsiCommand(command)
|
parsedCommand := parseAnsiCommand(command)
|
||||||
|
|
||||||
// use appropriate handle
|
// use appropriate handle
|
||||||
handle, _ := syscall.GetStdHandle(STD_OUTPUT_HANDLE)
|
handle := syscall.Handle(fd)
|
||||||
|
|
||||||
switch parsedCommand.Command {
|
switch parsedCommand.Command {
|
||||||
case "m":
|
case "m":
|
||||||
|
@ -891,7 +899,7 @@ func (term *WindowsTerminal) HandleOutputCommand(command []byte) (n int, err err
|
||||||
}
|
}
|
||||||
|
|
||||||
// WriteChars writes the bytes to given writer.
|
// WriteChars writes the bytes to given writer.
|
||||||
func (term *WindowsTerminal) WriteChars(w io.Writer, p []byte) (n int, err error) {
|
func (term *WindowsTerminal) WriteChars(fd uintptr, w io.Writer, p []byte) (n int, err error) {
|
||||||
return w.Write(p)
|
return w.Write(p)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1027,8 +1035,8 @@ func mapKeystokeToTerminalString(keyEvent *KEY_EVENT_RECORD, escapeSequence []by
|
||||||
|
|
||||||
// getAvailableInputEvents polls the console for availble events
|
// getAvailableInputEvents polls the console for availble events
|
||||||
// The function does not return until at least one input record has been read.
|
// The function does not return until at least one input record has been read.
|
||||||
func getAvailableInputEvents() (inputEvents []INPUT_RECORD, err error) {
|
func getAvailableInputEvents(fd uintptr) (inputEvents []INPUT_RECORD, err error) {
|
||||||
handle, _ := syscall.GetStdHandle(STD_INPUT_HANDLE)
|
handle := syscall.Handle(fd)
|
||||||
if nil != err {
|
if nil != err {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -1064,7 +1072,7 @@ func getTranslatedKeyCodes(inputEvents []INPUT_RECORD, escapeSequence []byte) st
|
||||||
}
|
}
|
||||||
|
|
||||||
// ReadChars reads the characters from the given reader
|
// ReadChars reads the characters from the given reader
|
||||||
func (term *WindowsTerminal) ReadChars(w io.Reader, p []byte) (n int, err error) {
|
func (term *WindowsTerminal) ReadChars(fd uintptr, w io.Reader, p []byte) (n int, err error) {
|
||||||
n = 0
|
n = 0
|
||||||
for n < len(p) {
|
for n < len(p) {
|
||||||
select {
|
select {
|
||||||
|
@ -1076,7 +1084,7 @@ func (term *WindowsTerminal) ReadChars(w io.Reader, p []byte) (n int, err error)
|
||||||
if n > 0 {
|
if n > 0 {
|
||||||
return n, nil
|
return n, nil
|
||||||
}
|
}
|
||||||
inputEvents, _ := getAvailableInputEvents()
|
inputEvents, _ := getAvailableInputEvents(fd)
|
||||||
if inputEvents != nil {
|
if inputEvents != nil {
|
||||||
if len(inputEvents) == 0 && nil != err {
|
if len(inputEvents) == 0 && nil != err {
|
||||||
return n, err
|
return n, err
|
||||||
|
@ -1094,7 +1102,7 @@ func (term *WindowsTerminal) ReadChars(w io.Reader, p []byte) (n int, err error)
|
||||||
}
|
}
|
||||||
|
|
||||||
// HandleInputSequence interprets the input sequence command
|
// HandleInputSequence interprets the input sequence command
|
||||||
func (term *WindowsTerminal) HandleInputSequence(command []byte) (n int, err error) {
|
func (term *WindowsTerminal) HandleInputSequence(fd uintptr, command []byte) (n int, err error) {
|
||||||
return 0, nil
|
return 0, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -27,10 +27,10 @@ const (
|
||||||
|
|
||||||
// Interface that implements terminal handling
|
// Interface that implements terminal handling
|
||||||
type terminalEmulator interface {
|
type terminalEmulator interface {
|
||||||
HandleOutputCommand(command []byte) (n int, err error)
|
HandleOutputCommand(fd uintptr, command []byte) (n int, err error)
|
||||||
HandleInputSequence(command []byte) (n int, err error)
|
HandleInputSequence(fd uintptr, command []byte) (n int, err error)
|
||||||
WriteChars(w io.Writer, p []byte) (n int, err error)
|
WriteChars(fd uintptr, w io.Writer, p []byte) (n int, err error)
|
||||||
ReadChars(w io.Reader, p []byte) (n int, err error)
|
ReadChars(fd uintptr, w io.Reader, p []byte) (n int, err error)
|
||||||
}
|
}
|
||||||
|
|
||||||
type terminalWriter struct {
|
type terminalWriter struct {
|
||||||
|
@ -38,6 +38,7 @@ type terminalWriter struct {
|
||||||
emulator terminalEmulator
|
emulator terminalEmulator
|
||||||
command []byte
|
command []byte
|
||||||
inSequence bool
|
inSequence bool
|
||||||
|
fd uintptr
|
||||||
}
|
}
|
||||||
|
|
||||||
type terminalReader struct {
|
type terminalReader struct {
|
||||||
|
@ -45,6 +46,7 @@ type terminalReader struct {
|
||||||
emulator terminalEmulator
|
emulator terminalEmulator
|
||||||
command []byte
|
command []byte
|
||||||
inSequence bool
|
inSequence bool
|
||||||
|
fd uintptr
|
||||||
}
|
}
|
||||||
|
|
||||||
// http://manpages.ubuntu.com/manpages/intrepid/man4/console_codes.4.html
|
// http://manpages.ubuntu.com/manpages/intrepid/man4/console_codes.4.html
|
||||||
|
@ -91,7 +93,7 @@ func (tw *terminalWriter) Write(p []byte) (n int, err error) {
|
||||||
if !isXtermOscSequence(tw.command, p[current]) {
|
if !isXtermOscSequence(tw.command, p[current]) {
|
||||||
// found the last command character.
|
// found the last command character.
|
||||||
// Now we have a complete command.
|
// Now we have a complete command.
|
||||||
nchar, err := tw.emulator.HandleOutputCommand(tw.command)
|
nchar, err := tw.emulator.HandleOutputCommand(tw.fd, tw.command)
|
||||||
totalWritten += nchar
|
totalWritten += nchar
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return totalWritten, err
|
return totalWritten, err
|
||||||
|
@ -110,7 +112,7 @@ func (tw *terminalWriter) Write(p []byte) (n int, err error) {
|
||||||
tw.inSequence = true
|
tw.inSequence = true
|
||||||
// indicates end of "normal sequence", write whatever you have so far
|
// indicates end of "normal sequence", write whatever you have so far
|
||||||
if len(p[start:current]) > 0 {
|
if len(p[start:current]) > 0 {
|
||||||
nw, err := tw.emulator.WriteChars(tw.wrappedWriter, p[start:current])
|
nw, err := tw.emulator.WriteChars(tw.fd, tw.wrappedWriter, p[start:current])
|
||||||
totalWritten += nw
|
totalWritten += nw
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return totalWritten, err
|
return totalWritten, err
|
||||||
|
@ -126,7 +128,7 @@ func (tw *terminalWriter) Write(p []byte) (n int, err error) {
|
||||||
if !tw.inSequence {
|
if !tw.inSequence {
|
||||||
// assumption is that we can't be inside sequence and therefore command should be empty
|
// assumption is that we can't be inside sequence and therefore command should be empty
|
||||||
if len(p[start:]) > 0 {
|
if len(p[start:]) > 0 {
|
||||||
nw, err := tw.emulator.WriteChars(tw.wrappedWriter, p[start:])
|
nw, err := tw.emulator.WriteChars(tw.fd, tw.wrappedWriter, p[start:])
|
||||||
totalWritten += nw
|
totalWritten += nw
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return totalWritten, err
|
return totalWritten, err
|
||||||
|
@ -148,7 +150,7 @@ func (tr *terminalReader) Read(p []byte) (n int, err error) {
|
||||||
if nil == tr.emulator {
|
if nil == tr.emulator {
|
||||||
return tr.readFromWrappedReader(p)
|
return tr.readFromWrappedReader(p)
|
||||||
}
|
}
|
||||||
return tr.emulator.ReadChars(tr.wrappedReader, p)
|
return tr.emulator.ReadChars(tr.fd, tr.wrappedReader, p)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Close the underlying stream
|
// Close the underlying stream
|
||||||
|
|
|
@ -71,21 +71,21 @@ func (mt *mockTerminal) record(operation int, data []byte) {
|
||||||
mt.OutputCommandSequence = append(mt.OutputCommandSequence, op)
|
mt.OutputCommandSequence = append(mt.OutputCommandSequence, op)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (mt *mockTerminal) HandleOutputCommand(command []byte) (n int, err error) {
|
func (mt *mockTerminal) HandleOutputCommand(fd uintptr, command []byte) (n int, err error) {
|
||||||
mt.record(COMMAND_OPERATION, command)
|
mt.record(COMMAND_OPERATION, command)
|
||||||
return len(command), nil
|
return len(command), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (mt *mockTerminal) HandleInputSequence(command []byte) (n int, err error) {
|
func (mt *mockTerminal) HandleInputSequence(fd uintptr, command []byte) (n int, err error) {
|
||||||
return 0, nil
|
return 0, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (mt *mockTerminal) WriteChars(w io.Writer, p []byte) (n int, err error) {
|
func (mt *mockTerminal) WriteChars(fd uintptr, w io.Writer, p []byte) (n int, err error) {
|
||||||
mt.record(WRITE_OPERATION, p)
|
mt.record(WRITE_OPERATION, p)
|
||||||
return len(p), nil
|
return len(p), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (mt *mockTerminal) ReadChars(w io.Reader, p []byte) (n int, err error) {
|
func (mt *mockTerminal) ReadChars(fd uintptr, w io.Reader, p []byte) (n int, err error) {
|
||||||
return len(p), nil
|
return len(p), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue