Revert "Use go-ansiterm version matching docker/pkg/term/windows v1.11"

This reverts commit 72044a11a1.
This commit is contained in:
Jeff Grafton 2017-07-14 17:33:21 -07:00
parent 226b39c6b5
commit f52615894f
26 changed files with 333 additions and 697 deletions

4
Godeps/Godeps.json generated
View File

@ -60,11 +60,11 @@
}, },
{ {
"ImportPath": "github.com/Azure/go-ansiterm", "ImportPath": "github.com/Azure/go-ansiterm",
"Rev": "70b2c90b260171e829f1ebd7c17f600c11858dbe" "Rev": "fa152c58bc15761d0200cb75fe958b89a9d4888e"
}, },
{ {
"ImportPath": "github.com/Azure/go-ansiterm/winterm", "ImportPath": "github.com/Azure/go-ansiterm/winterm",
"Rev": "70b2c90b260171e829f1ebd7c17f600c11858dbe" "Rev": "fa152c58bc15761d0200cb75fe958b89a9d4888e"
}, },
{ {
"ImportPath": "github.com/Azure/go-autorest/autorest", "ImportPath": "github.com/Azure/go-autorest/autorest",

View File

@ -22,10 +22,7 @@ go_library(
"parser.go", "parser.go",
"parser_action_helpers.go", "parser_action_helpers.go",
"parser_actions.go", "parser_actions.go",
"parser_test_helpers.go",
"parser_test_utilities.go",
"states.go", "states.go",
"test_event_handler.go",
"utilities.go", "utilities.go",
], ],
tags = ["automanaged"], tags = ["automanaged"],

View File

@ -7,3 +7,6 @@ For example the parser might receive "ESC, [, A" as a stream of three characters
The parser (parser.go) is a partial implementation of this state machine (http://vt100.net/emu/vt500_parser.png). There are also two event handler implementations, one for tests (test_event_handler.go) to validate that the expected events are being produced and called, the other is a Windows implementation (winterm/win_event_handler.go). The parser (parser.go) is a partial implementation of this state machine (http://vt100.net/emu/vt500_parser.png). There are also two event handler implementations, one for tests (test_event_handler.go) to validate that the expected events are being produced and called, the other is a Windows implementation (winterm/win_event_handler.go).
See parser_test.go for examples exercising the state machine and generating appropriate function calls. See parser_test.go for examples exercising the state machine and generating appropriate function calls.
-----
This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/). For more information see the [Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) or contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with any additional questions or comments.

View File

@ -124,32 +124,32 @@ func getByteRange(start byte, end byte) []byte {
return bytes return bytes
} }
var ToGroundBytes = getToGroundBytes() var toGroundBytes = getToGroundBytes()
var Executors = getExecuteBytes() var executors = getExecuteBytes()
// SPACE 20+A0 hex Always and everywhere a blank space // SPACE 20+A0 hex Always and everywhere a blank space
// Intermediate 20-2F hex !"#$%&'()*+,-./ // Intermediate 20-2F hex !"#$%&'()*+,-./
var Intermeds = getByteRange(0x20, 0x2F) var intermeds = getByteRange(0x20, 0x2F)
// Parameters 30-3F hex 0123456789:;<=>? // Parameters 30-3F hex 0123456789:;<=>?
// CSI Parameters 30-39, 3B hex 0123456789; // CSI Parameters 30-39, 3B hex 0123456789;
var CsiParams = getByteRange(0x30, 0x3F) var csiParams = getByteRange(0x30, 0x3F)
var CsiCollectables = append(getByteRange(0x30, 0x39), getByteRange(0x3B, 0x3F)...) var csiCollectables = append(getByteRange(0x30, 0x39), getByteRange(0x3B, 0x3F)...)
// Uppercase 40-5F hex @ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_ // Uppercase 40-5F hex @ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_
var UpperCase = getByteRange(0x40, 0x5F) var upperCase = getByteRange(0x40, 0x5F)
// Lowercase 60-7E hex `abcdefghijlkmnopqrstuvwxyz{|}~ // Lowercase 60-7E hex `abcdefghijlkmnopqrstuvwxyz{|}~
var LowerCase = getByteRange(0x60, 0x7E) var lowerCase = getByteRange(0x60, 0x7E)
// Alphabetics 40-7E hex (all of upper and lower case) // Alphabetics 40-7E hex (all of upper and lower case)
var Alphabetics = append(UpperCase, LowerCase...) var alphabetics = append(upperCase, lowerCase...)
var Printables = getByteRange(0x20, 0x7F) var printables = getByteRange(0x20, 0x7F)
var EscapeIntermediateToGroundBytes = getByteRange(0x30, 0x7E) var escapeIntermediateToGroundBytes = getByteRange(0x30, 0x7E)
var EscapeToGroundBytes = getEscapeToGroundBytes() var escapeToGroundBytes = getEscapeToGroundBytes()
// See http://www.vt100.net/emu/vt500_parser.png for description of the complex // See http://www.vt100.net/emu/vt500_parser.png for description of the complex
// byte ranges below // byte ranges below

View File

@ -1,6 +1,6 @@
package ansiterm package ansiterm
type AnsiContext struct { type ansiContext struct {
currentChar byte currentChar byte
paramBuffer []byte paramBuffer []byte
interBuffer []byte interBuffer []byte

View File

@ -1,41 +1,41 @@
package ansiterm package ansiterm
type CsiEntryState struct { type csiEntryState struct {
BaseState baseState
} }
func (csiState CsiEntryState) Handle(b byte) (s State, e error) { func (csiState csiEntryState) Handle(b byte) (s state, e error) {
logger.Infof("CsiEntry::Handle %#x", b) logger.Infof("CsiEntry::Handle %#x", b)
nextState, err := csiState.BaseState.Handle(b) nextState, err := csiState.baseState.Handle(b)
if nextState != nil || err != nil { if nextState != nil || err != nil {
return nextState, err return nextState, err
} }
switch { switch {
case sliceContains(Alphabetics, b): case sliceContains(alphabetics, b):
return csiState.parser.Ground, nil return csiState.parser.ground, nil
case sliceContains(CsiCollectables, b): case sliceContains(csiCollectables, b):
return csiState.parser.CsiParam, nil return csiState.parser.csiParam, nil
case sliceContains(Executors, b): case sliceContains(executors, b):
return csiState, csiState.parser.execute() return csiState, csiState.parser.execute()
} }
return csiState, nil return csiState, nil
} }
func (csiState CsiEntryState) Transition(s State) error { func (csiState csiEntryState) Transition(s state) error {
logger.Infof("CsiEntry::Transition %s --> %s", csiState.Name(), s.Name()) logger.Infof("CsiEntry::Transition %s --> %s", csiState.Name(), s.Name())
csiState.BaseState.Transition(s) csiState.baseState.Transition(s)
switch s { switch s {
case csiState.parser.Ground: case csiState.parser.ground:
return csiState.parser.csiDispatch() return csiState.parser.csiDispatch()
case csiState.parser.CsiParam: case csiState.parser.csiParam:
switch { switch {
case sliceContains(CsiParams, csiState.parser.context.currentChar): case sliceContains(csiParams, csiState.parser.context.currentChar):
csiState.parser.collectParam() csiState.parser.collectParam()
case sliceContains(Intermeds, csiState.parser.context.currentChar): case sliceContains(intermeds, csiState.parser.context.currentChar):
csiState.parser.collectInter() csiState.parser.collectInter()
} }
} }
@ -43,7 +43,7 @@ func (csiState CsiEntryState) Transition(s State) error {
return nil return nil
} }
func (csiState CsiEntryState) Enter() error { func (csiState csiEntryState) Enter() error {
csiState.parser.clear() csiState.parser.clear()
return nil return nil
} }

View File

@ -1,36 +1,36 @@
package ansiterm package ansiterm
type CsiParamState struct { type csiParamState struct {
BaseState baseState
} }
func (csiState CsiParamState) Handle(b byte) (s State, e error) { func (csiState csiParamState) Handle(b byte) (s state, e error) {
logger.Infof("CsiParam::Handle %#x", b) logger.Infof("CsiParam::Handle %#x", b)
nextState, err := csiState.BaseState.Handle(b) nextState, err := csiState.baseState.Handle(b)
if nextState != nil || err != nil { if nextState != nil || err != nil {
return nextState, err return nextState, err
} }
switch { switch {
case sliceContains(Alphabetics, b): case sliceContains(alphabetics, b):
return csiState.parser.Ground, nil return csiState.parser.ground, nil
case sliceContains(CsiCollectables, b): case sliceContains(csiCollectables, b):
csiState.parser.collectParam() csiState.parser.collectParam()
return csiState, nil return csiState, nil
case sliceContains(Executors, b): case sliceContains(executors, b):
return csiState, csiState.parser.execute() return csiState, csiState.parser.execute()
} }
return csiState, nil return csiState, nil
} }
func (csiState CsiParamState) Transition(s State) error { func (csiState csiParamState) Transition(s state) error {
logger.Infof("CsiParam::Transition %s --> %s", csiState.Name(), s.Name()) logger.Infof("CsiParam::Transition %s --> %s", csiState.Name(), s.Name())
csiState.BaseState.Transition(s) csiState.baseState.Transition(s)
switch s { switch s {
case csiState.parser.Ground: case csiState.parser.ground:
return csiState.parser.csiDispatch() return csiState.parser.csiDispatch()
} }

View File

@ -1,34 +1,34 @@
package ansiterm package ansiterm
type EscapeIntermediateState struct { type escapeIntermediateState struct {
BaseState baseState
} }
func (escState EscapeIntermediateState) Handle(b byte) (s State, e error) { func (escState escapeIntermediateState) Handle(b byte) (s state, e error) {
logger.Infof("EscapeIntermediateState::Handle %#x", b) logger.Infof("escapeIntermediateState::Handle %#x", b)
nextState, err := escState.BaseState.Handle(b) nextState, err := escState.baseState.Handle(b)
if nextState != nil || err != nil { if nextState != nil || err != nil {
return nextState, err return nextState, err
} }
switch { switch {
case sliceContains(Intermeds, b): case sliceContains(intermeds, b):
return escState, escState.parser.collectInter() return escState, escState.parser.collectInter()
case sliceContains(Executors, b): case sliceContains(executors, b):
return escState, escState.parser.execute() return escState, escState.parser.execute()
case sliceContains(EscapeIntermediateToGroundBytes, b): case sliceContains(escapeIntermediateToGroundBytes, b):
return escState.parser.Ground, nil return escState.parser.ground, nil
} }
return escState, nil return escState, nil
} }
func (escState EscapeIntermediateState) Transition(s State) error { func (escState escapeIntermediateState) Transition(s state) error {
logger.Infof("EscapeIntermediateState::Transition %s --> %s", escState.Name(), s.Name()) logger.Infof("escapeIntermediateState::Transition %s --> %s", escState.Name(), s.Name())
escState.BaseState.Transition(s) escState.baseState.Transition(s)
switch s { switch s {
case escState.parser.Ground: case escState.parser.ground:
return escState.parser.escDispatch() return escState.parser.escDispatch()
} }

View File

@ -1,47 +1,47 @@
package ansiterm package ansiterm
type EscapeState struct { type escapeState struct {
BaseState baseState
} }
func (escState EscapeState) Handle(b byte) (s State, e error) { func (escState escapeState) Handle(b byte) (s state, e error) {
logger.Infof("EscapeState::Handle %#x", b) logger.Infof("escapeState::Handle %#x", b)
nextState, err := escState.BaseState.Handle(b) nextState, err := escState.baseState.Handle(b)
if nextState != nil || err != nil { if nextState != nil || err != nil {
return nextState, err return nextState, err
} }
switch { switch {
case b == ANSI_ESCAPE_SECONDARY: case b == ANSI_ESCAPE_SECONDARY:
return escState.parser.CsiEntry, nil return escState.parser.csiEntry, nil
case b == ANSI_OSC_STRING_ENTRY: case b == ANSI_OSC_STRING_ENTRY:
return escState.parser.OscString, nil return escState.parser.oscString, nil
case sliceContains(Executors, b): case sliceContains(executors, b):
return escState, escState.parser.execute() return escState, escState.parser.execute()
case sliceContains(EscapeToGroundBytes, b): case sliceContains(escapeToGroundBytes, b):
return escState.parser.Ground, nil return escState.parser.ground, nil
case sliceContains(Intermeds, b): case sliceContains(intermeds, b):
return escState.parser.EscapeIntermediate, nil return escState.parser.escapeIntermediate, nil
} }
return escState, nil return escState, nil
} }
func (escState EscapeState) Transition(s State) error { func (escState escapeState) Transition(s state) error {
logger.Infof("Escape::Transition %s --> %s", escState.Name(), s.Name()) logger.Infof("Escape::Transition %s --> %s", escState.Name(), s.Name())
escState.BaseState.Transition(s) escState.baseState.Transition(s)
switch s { switch s {
case escState.parser.Ground: case escState.parser.ground:
return escState.parser.escDispatch() return escState.parser.escDispatch()
case escState.parser.EscapeIntermediate: case escState.parser.escapeIntermediate:
return escState.parser.collectInter() return escState.parser.collectInter()
} }
return nil return nil
} }
func (escState EscapeState) Enter() error { func (escState escapeState) Enter() error {
escState.parser.clear() escState.parser.clear()
return nil return nil
} }

View File

@ -1,22 +1,22 @@
package ansiterm package ansiterm
type GroundState struct { type groundState struct {
BaseState baseState
} }
func (gs GroundState) Handle(b byte) (s State, e error) { func (gs groundState) Handle(b byte) (s state, e error) {
gs.parser.context.currentChar = b gs.parser.context.currentChar = b
nextState, err := gs.BaseState.Handle(b) nextState, err := gs.baseState.Handle(b)
if nextState != nil || err != nil { if nextState != nil || err != nil {
return nextState, err return nextState, err
} }
switch { switch {
case sliceContains(Printables, b): case sliceContains(printables, b):
return gs, gs.parser.print() return gs, gs.parser.print()
case sliceContains(Executors, b): case sliceContains(executors, b):
return gs, gs.parser.execute() return gs, gs.parser.execute()
} }

View File

@ -1,19 +1,19 @@
package ansiterm package ansiterm
type OscStringState struct { type oscStringState struct {
BaseState baseState
} }
func (oscState OscStringState) Handle(b byte) (s State, e error) { func (oscState oscStringState) Handle(b byte) (s state, e error) {
logger.Infof("OscString::Handle %#x", b) logger.Infof("OscString::Handle %#x", b)
nextState, err := oscState.BaseState.Handle(b) nextState, err := oscState.baseState.Handle(b)
if nextState != nil || err != nil { if nextState != nil || err != nil {
return nextState, err return nextState, err
} }
switch { switch {
case isOscStringTerminator(b): case isOscStringTerminator(b):
return oscState.parser.Ground, nil return oscState.parser.ground, nil
} }
return oscState, nil return oscState, nil

View File

@ -2,7 +2,6 @@ package ansiterm
import ( import (
"errors" "errors"
"fmt"
"io/ioutil" "io/ioutil"
"os" "os"
@ -12,18 +11,18 @@ import (
var logger *logrus.Logger var logger *logrus.Logger
type AnsiParser struct { type AnsiParser struct {
currState State currState state
eventHandler AnsiEventHandler eventHandler AnsiEventHandler
context *AnsiContext context *ansiContext
CsiEntry State csiEntry state
CsiParam State csiParam state
DcsEntry State dcsEntry state
Escape State escape state
EscapeIntermediate State escapeIntermediate state
Error State error state
Ground State ground state
OscString State oscString state
stateMap []State stateMap []state
} }
func CreateParser(initialState string, evtHandler AnsiEventHandler) *AnsiParser { func CreateParser(initialState string, evtHandler AnsiEventHandler) *AnsiParser {
@ -41,27 +40,27 @@ func CreateParser(initialState string, evtHandler AnsiEventHandler) *AnsiParser
parser := &AnsiParser{ parser := &AnsiParser{
eventHandler: evtHandler, eventHandler: evtHandler,
context: &AnsiContext{}, context: &ansiContext{},
} }
parser.CsiEntry = CsiEntryState{BaseState{name: "CsiEntry", parser: parser}} parser.csiEntry = csiEntryState{baseState{name: "CsiEntry", parser: parser}}
parser.CsiParam = CsiParamState{BaseState{name: "CsiParam", parser: parser}} parser.csiParam = csiParamState{baseState{name: "CsiParam", parser: parser}}
parser.DcsEntry = DcsEntryState{BaseState{name: "DcsEntry", parser: parser}} parser.dcsEntry = dcsEntryState{baseState{name: "DcsEntry", parser: parser}}
parser.Escape = EscapeState{BaseState{name: "Escape", parser: parser}} parser.escape = escapeState{baseState{name: "Escape", parser: parser}}
parser.EscapeIntermediate = EscapeIntermediateState{BaseState{name: "EscapeIntermediate", parser: parser}} parser.escapeIntermediate = escapeIntermediateState{baseState{name: "EscapeIntermediate", parser: parser}}
parser.Error = ErrorState{BaseState{name: "Error", parser: parser}} parser.error = errorState{baseState{name: "Error", parser: parser}}
parser.Ground = GroundState{BaseState{name: "Ground", parser: parser}} parser.ground = groundState{baseState{name: "Ground", parser: parser}}
parser.OscString = OscStringState{BaseState{name: "OscString", parser: parser}} parser.oscString = oscStringState{baseState{name: "OscString", parser: parser}}
parser.stateMap = []State{ parser.stateMap = []state{
parser.CsiEntry, parser.csiEntry,
parser.CsiParam, parser.csiParam,
parser.DcsEntry, parser.dcsEntry,
parser.Escape, parser.escape,
parser.EscapeIntermediate, parser.escapeIntermediate,
parser.Error, parser.error,
parser.Ground, parser.ground,
parser.OscString, parser.oscString,
} }
parser.currState = getState(initialState, parser.stateMap) parser.currState = getState(initialState, parser.stateMap)
@ -70,7 +69,7 @@ func CreateParser(initialState string, evtHandler AnsiEventHandler) *AnsiParser
return parser return parser
} }
func getState(name string, states []State) State { func getState(name string, states []state) state {
for _, el := range states { for _, el := range states {
if el.Name() == name { if el.Name() == name {
return el return el
@ -99,7 +98,7 @@ func (ap *AnsiParser) handle(b byte) error {
if newState == nil { if newState == nil {
logger.Warning("newState is nil") logger.Warning("newState is nil")
return errors.New(fmt.Sprintf("New state of 'nil' is invalid.")) return errors.New("New state of 'nil' is invalid.")
} }
if newState != ap.currState { if newState != ap.currState {
@ -111,7 +110,7 @@ func (ap *AnsiParser) handle(b byte) error {
return nil return nil
} }
func (ap *AnsiParser) changeState(newState State) error { func (ap *AnsiParser) changeState(newState state) error {
logger.Infof("ChangeState %s --> %s", ap.currState.Name(), newState.Name()) logger.Infof("ChangeState %s --> %s", ap.currState.Name(), newState.Name())
// Exit old state // Exit old state

View File

@ -31,7 +31,7 @@ func parseParams(bytes []byte) ([]string, error) {
return params, nil return params, nil
} }
func parseCmd(context AnsiContext) (string, error) { func parseCmd(context ansiContext) (string, error) {
return string(context.currentChar), nil return string(context.currentChar), nil
} }

View File

@ -113,7 +113,7 @@ func (ap *AnsiParser) print() error {
} }
func (ap *AnsiParser) clear() error { func (ap *AnsiParser) clear() error {
ap.context = &AnsiContext{} ap.context = &ansiContext{}
return nil return nil
} }

View File

@ -1,114 +0,0 @@
package ansiterm
import (
"fmt"
"testing"
)
func getStateNames() []string {
parser, _ := createTestParser("Ground")
stateNames := []string{}
for _, state := range parser.stateMap {
stateNames = append(stateNames, state.Name())
}
return stateNames
}
func stateTransitionHelper(t *testing.T, start string, end string, bytes []byte) {
for _, b := range bytes {
bytes := []byte{byte(b)}
parser, _ := createTestParser(start)
parser.Parse(bytes)
validateState(t, parser.currState, end)
}
}
func anyToXHelper(t *testing.T, bytes []byte, expectedState string) {
for _, s := range getStateNames() {
stateTransitionHelper(t, s, expectedState, bytes)
}
}
func funcCallParamHelper(t *testing.T, bytes []byte, start string, expected string, expectedCalls []string) {
parser, evtHandler := createTestParser(start)
parser.Parse(bytes)
validateState(t, parser.currState, expected)
validateFuncCalls(t, evtHandler.FunctionCalls, expectedCalls)
}
func parseParamsHelper(t *testing.T, bytes []byte, expectedParams []string) {
params, err := parseParams(bytes)
if err != nil {
t.Errorf("Parameter parse error: %v", err)
return
}
if len(params) != len(expectedParams) {
t.Errorf("Parsed parameters: %v", params)
t.Errorf("Expected parameters: %v", expectedParams)
t.Errorf("Parameter length failure: %d != %d", len(params), len(expectedParams))
return
}
for i, v := range expectedParams {
if v != params[i] {
t.Errorf("Parsed parameters: %v", params)
t.Errorf("Expected parameters: %v", expectedParams)
t.Errorf("Parameter parse failure: %s != %s at position %d", v, params[i], i)
}
}
}
func cursorSingleParamHelper(t *testing.T, command byte, funcName string) {
funcCallParamHelper(t, []byte{command}, "CsiEntry", "Ground", []string{fmt.Sprintf("%s([1])", funcName)})
funcCallParamHelper(t, []byte{'0', command}, "CsiEntry", "Ground", []string{fmt.Sprintf("%s([1])", funcName)})
funcCallParamHelper(t, []byte{'2', command}, "CsiEntry", "Ground", []string{fmt.Sprintf("%s([2])", funcName)})
funcCallParamHelper(t, []byte{'2', '3', command}, "CsiEntry", "Ground", []string{fmt.Sprintf("%s([23])", funcName)})
funcCallParamHelper(t, []byte{'2', ';', '3', command}, "CsiEntry", "Ground", []string{fmt.Sprintf("%s([2])", funcName)})
funcCallParamHelper(t, []byte{'2', ';', '3', ';', '4', command}, "CsiEntry", "Ground", []string{fmt.Sprintf("%s([2])", funcName)})
}
func cursorTwoParamHelper(t *testing.T, command byte, funcName string) {
funcCallParamHelper(t, []byte{command}, "CsiEntry", "Ground", []string{fmt.Sprintf("%s([1 1])", funcName)})
funcCallParamHelper(t, []byte{'0', command}, "CsiEntry", "Ground", []string{fmt.Sprintf("%s([1 1])", funcName)})
funcCallParamHelper(t, []byte{'2', command}, "CsiEntry", "Ground", []string{fmt.Sprintf("%s([2 1])", funcName)})
funcCallParamHelper(t, []byte{'2', '3', command}, "CsiEntry", "Ground", []string{fmt.Sprintf("%s([23 1])", funcName)})
funcCallParamHelper(t, []byte{'2', ';', '3', command}, "CsiEntry", "Ground", []string{fmt.Sprintf("%s([2 3])", funcName)})
funcCallParamHelper(t, []byte{'2', ';', '3', ';', '4', command}, "CsiEntry", "Ground", []string{fmt.Sprintf("%s([2 3])", funcName)})
}
func eraseHelper(t *testing.T, command byte, funcName string) {
funcCallParamHelper(t, []byte{command}, "CsiEntry", "Ground", []string{fmt.Sprintf("%s([0])", funcName)})
funcCallParamHelper(t, []byte{'0', command}, "CsiEntry", "Ground", []string{fmt.Sprintf("%s([0])", funcName)})
funcCallParamHelper(t, []byte{'1', command}, "CsiEntry", "Ground", []string{fmt.Sprintf("%s([1])", funcName)})
funcCallParamHelper(t, []byte{'2', command}, "CsiEntry", "Ground", []string{fmt.Sprintf("%s([2])", funcName)})
funcCallParamHelper(t, []byte{'3', command}, "CsiEntry", "Ground", []string{fmt.Sprintf("%s([3])", funcName)})
funcCallParamHelper(t, []byte{'4', command}, "CsiEntry", "Ground", []string{fmt.Sprintf("%s([0])", funcName)})
funcCallParamHelper(t, []byte{'1', ';', '2', command}, "CsiEntry", "Ground", []string{fmt.Sprintf("%s([1])", funcName)})
}
func scrollHelper(t *testing.T, command byte, funcName string) {
funcCallParamHelper(t, []byte{command}, "CsiEntry", "Ground", []string{fmt.Sprintf("%s([1])", funcName)})
funcCallParamHelper(t, []byte{'0', command}, "CsiEntry", "Ground", []string{fmt.Sprintf("%s([1])", funcName)})
funcCallParamHelper(t, []byte{'1', command}, "CsiEntry", "Ground", []string{fmt.Sprintf("%s([1])", funcName)})
funcCallParamHelper(t, []byte{'5', command}, "CsiEntry", "Ground", []string{fmt.Sprintf("%s([5])", funcName)})
funcCallParamHelper(t, []byte{'4', ';', '6', command}, "CsiEntry", "Ground", []string{fmt.Sprintf("%s([4])", funcName)})
}
func clearOnStateChangeHelper(t *testing.T, start string, end string, bytes []byte) {
p, _ := createTestParser(start)
fillContext(p.context)
p.Parse(bytes)
validateState(t, p.currState, end)
validateEmptyContext(t, p.context)
}
func c0Helper(t *testing.T, bytes []byte, expectedState string, expectedCalls []string) {
parser, evtHandler := createTestParser("Ground")
parser.Parse(bytes)
validateState(t, parser.currState, expectedState)
validateFuncCalls(t, evtHandler.FunctionCalls, expectedCalls)
}

View File

@ -1,66 +0,0 @@
package ansiterm
import (
"testing"
)
func createTestParser(s string) (*AnsiParser, *TestAnsiEventHandler) {
evtHandler := CreateTestAnsiEventHandler()
parser := CreateParser(s, evtHandler)
return parser, evtHandler
}
func validateState(t *testing.T, actualState State, expectedStateName string) {
actualName := "Nil"
if actualState != nil {
actualName = actualState.Name()
}
if actualName != expectedStateName {
t.Errorf("Invalid State: '%s' != '%s'", actualName, expectedStateName)
}
}
func validateFuncCalls(t *testing.T, actualCalls []string, expectedCalls []string) {
actualCount := len(actualCalls)
expectedCount := len(expectedCalls)
if actualCount != expectedCount {
t.Errorf("Actual calls: %v", actualCalls)
t.Errorf("Expected calls: %v", expectedCalls)
t.Errorf("Call count error: %d != %d", actualCount, expectedCount)
return
}
for i, v := range actualCalls {
if v != expectedCalls[i] {
t.Errorf("Actual calls: %v", actualCalls)
t.Errorf("Expected calls: %v", expectedCalls)
t.Errorf("Mismatched calls: %s != %s with lengths %d and %d", v, expectedCalls[i], len(v), len(expectedCalls[i]))
}
}
}
func fillContext(context *AnsiContext) {
context.currentChar = 'A'
context.paramBuffer = []byte{'C', 'D', 'E'}
context.interBuffer = []byte{'F', 'G', 'H'}
}
func validateEmptyContext(t *testing.T, context *AnsiContext) {
var expectedCurrChar byte = 0x0
if context.currentChar != expectedCurrChar {
t.Errorf("Currentchar mismatch '%#x' != '%#x'", context.currentChar, expectedCurrChar)
}
if len(context.paramBuffer) != 0 {
t.Errorf("Non-empty parameter buffer: %v", context.paramBuffer)
}
if len(context.paramBuffer) != 0 {
t.Errorf("Non-empty intermediate buffer: %v", context.interBuffer)
}
}

View File

@ -1,52 +1,52 @@
package ansiterm package ansiterm
type StateId int type stateID int
type State interface { type state interface {
Enter() error Enter() error
Exit() error Exit() error
Handle(byte) (State, error) Handle(byte) (state, error)
Name() string Name() string
Transition(State) error Transition(state) error
} }
type BaseState struct { type baseState struct {
name string name string
parser *AnsiParser parser *AnsiParser
} }
func (base BaseState) Enter() error { func (base baseState) Enter() error {
return nil return nil
} }
func (base BaseState) Exit() error { func (base baseState) Exit() error {
return nil return nil
} }
func (base BaseState) Handle(b byte) (s State, e error) { func (base baseState) Handle(b byte) (s state, e error) {
switch { switch {
case b == CSI_ENTRY: case b == CSI_ENTRY:
return base.parser.CsiEntry, nil return base.parser.csiEntry, nil
case b == DCS_ENTRY: case b == DCS_ENTRY:
return base.parser.DcsEntry, nil return base.parser.dcsEntry, nil
case b == ANSI_ESCAPE_PRIMARY: case b == ANSI_ESCAPE_PRIMARY:
return base.parser.Escape, nil return base.parser.escape, nil
case b == OSC_STRING: case b == OSC_STRING:
return base.parser.OscString, nil return base.parser.oscString, nil
case sliceContains(ToGroundBytes, b): case sliceContains(toGroundBytes, b):
return base.parser.Ground, nil return base.parser.ground, nil
} }
return nil, nil return nil, nil
} }
func (base BaseState) Name() string { func (base baseState) Name() string {
return base.name return base.name
} }
func (base BaseState) Transition(s State) error { func (base baseState) Transition(s state) error {
if s == base.parser.Ground { if s == base.parser.ground {
execBytes := []byte{0x18} execBytes := []byte{0x18}
execBytes = append(execBytes, 0x1A) execBytes = append(execBytes, 0x1A)
execBytes = append(execBytes, getByteRange(0x80, 0x8F)...) execBytes = append(execBytes, getByteRange(0x80, 0x8F)...)
@ -62,10 +62,10 @@ func (base BaseState) Transition(s State) error {
return nil return nil
} }
type DcsEntryState struct { type dcsEntryState struct {
BaseState baseState
} }
type ErrorState struct { type errorState struct {
BaseState baseState
} }

View File

@ -1,173 +0,0 @@
package ansiterm
import (
"fmt"
"strconv"
)
type TestAnsiEventHandler struct {
FunctionCalls []string
}
func CreateTestAnsiEventHandler() *TestAnsiEventHandler {
evtHandler := TestAnsiEventHandler{}
evtHandler.FunctionCalls = make([]string, 0)
return &evtHandler
}
func (h *TestAnsiEventHandler) recordCall(call string, params []string) {
s := fmt.Sprintf("%s(%v)", call, params)
h.FunctionCalls = append(h.FunctionCalls, s)
}
func (h *TestAnsiEventHandler) Print(b byte) error {
h.recordCall("Print", []string{string(b)})
return nil
}
func (h *TestAnsiEventHandler) Execute(b byte) error {
h.recordCall("Execute", []string{string(b)})
return nil
}
func (h *TestAnsiEventHandler) CUU(param int) error {
h.recordCall("CUU", []string{strconv.Itoa(param)})
return nil
}
func (h *TestAnsiEventHandler) CUD(param int) error {
h.recordCall("CUD", []string{strconv.Itoa(param)})
return nil
}
func (h *TestAnsiEventHandler) CUF(param int) error {
h.recordCall("CUF", []string{strconv.Itoa(param)})
return nil
}
func (h *TestAnsiEventHandler) CUB(param int) error {
h.recordCall("CUB", []string{strconv.Itoa(param)})
return nil
}
func (h *TestAnsiEventHandler) CNL(param int) error {
h.recordCall("CNL", []string{strconv.Itoa(param)})
return nil
}
func (h *TestAnsiEventHandler) CPL(param int) error {
h.recordCall("CPL", []string{strconv.Itoa(param)})
return nil
}
func (h *TestAnsiEventHandler) CHA(param int) error {
h.recordCall("CHA", []string{strconv.Itoa(param)})
return nil
}
func (h *TestAnsiEventHandler) VPA(param int) error {
h.recordCall("VPA", []string{strconv.Itoa(param)})
return nil
}
func (h *TestAnsiEventHandler) CUP(x int, y int) error {
xS, yS := strconv.Itoa(x), strconv.Itoa(y)
h.recordCall("CUP", []string{xS, yS})
return nil
}
func (h *TestAnsiEventHandler) HVP(x int, y int) error {
xS, yS := strconv.Itoa(x), strconv.Itoa(y)
h.recordCall("HVP", []string{xS, yS})
return nil
}
func (h *TestAnsiEventHandler) DECTCEM(visible bool) error {
h.recordCall("DECTCEM", []string{strconv.FormatBool(visible)})
return nil
}
func (h *TestAnsiEventHandler) DECOM(visible bool) error {
h.recordCall("DECOM", []string{strconv.FormatBool(visible)})
return nil
}
func (h *TestAnsiEventHandler) DECCOLM(use132 bool) error {
h.recordCall("DECOLM", []string{strconv.FormatBool(use132)})
return nil
}
func (h *TestAnsiEventHandler) ED(param int) error {
h.recordCall("ED", []string{strconv.Itoa(param)})
return nil
}
func (h *TestAnsiEventHandler) EL(param int) error {
h.recordCall("EL", []string{strconv.Itoa(param)})
return nil
}
func (h *TestAnsiEventHandler) IL(param int) error {
h.recordCall("IL", []string{strconv.Itoa(param)})
return nil
}
func (h *TestAnsiEventHandler) DL(param int) error {
h.recordCall("DL", []string{strconv.Itoa(param)})
return nil
}
func (h *TestAnsiEventHandler) ICH(param int) error {
h.recordCall("ICH", []string{strconv.Itoa(param)})
return nil
}
func (h *TestAnsiEventHandler) DCH(param int) error {
h.recordCall("DCH", []string{strconv.Itoa(param)})
return nil
}
func (h *TestAnsiEventHandler) SGR(params []int) error {
strings := []string{}
for _, v := range params {
strings = append(strings, strconv.Itoa(v))
}
h.recordCall("SGR", strings)
return nil
}
func (h *TestAnsiEventHandler) SU(param int) error {
h.recordCall("SU", []string{strconv.Itoa(param)})
return nil
}
func (h *TestAnsiEventHandler) SD(param int) error {
h.recordCall("SD", []string{strconv.Itoa(param)})
return nil
}
func (h *TestAnsiEventHandler) DA(params []string) error {
h.recordCall("DA", params)
return nil
}
func (h *TestAnsiEventHandler) DECSTBM(top int, bottom int) error {
topS, bottomS := strconv.Itoa(top), strconv.Itoa(bottom)
h.recordCall("DECSTBM", []string{topS, bottomS})
return nil
}
func (h *TestAnsiEventHandler) RI() error {
h.recordCall("RI", nil)
return nil
}
func (h *TestAnsiEventHandler) IND() error {
h.recordCall("IND", nil)
return nil
}
func (h *TestAnsiEventHandler) Flush() error {
return nil
}

View File

@ -9,7 +9,7 @@ import (
"strings" "strings"
"syscall" "syscall"
. "github.com/Azure/go-ansiterm" "github.com/Azure/go-ansiterm"
) )
// Windows keyboard constants // Windows keyboard constants
@ -85,17 +85,17 @@ func newAnsiCommand(command []byte) *ansiCommand {
if lastCharIndex != 0 { if lastCharIndex != 0 {
start := 1 start := 1
// skip if double char escape sequence // skip if double char escape sequence
if command[0] == ANSI_ESCAPE_PRIMARY && command[1] == ANSI_ESCAPE_SECONDARY { if command[0] == ansiterm.ANSI_ESCAPE_PRIMARY && command[1] == ansiterm.ANSI_ESCAPE_SECONDARY {
start++ start++
} }
// convert this to GetNextParam method // convert this to GetNextParam method
ac.Parameters = strings.Split(string(command[start:lastCharIndex]), ANSI_PARAMETER_SEP) ac.Parameters = strings.Split(string(command[start:lastCharIndex]), ansiterm.ANSI_PARAMETER_SEP)
} }
return ac return ac
} }
func (ac *ansiCommand) paramAsSHORT(index int, defaultValue SHORT) SHORT { func (ac *ansiCommand) paramAsSHORT(index int, defaultValue int16) int16 {
if index < 0 || index >= len(ac.Parameters) { if index < 0 || index >= len(ac.Parameters) {
return defaultValue return defaultValue
} }
@ -105,7 +105,7 @@ func (ac *ansiCommand) paramAsSHORT(index int, defaultValue SHORT) SHORT {
return defaultValue return defaultValue
} }
return SHORT(param) return int16(param)
} }
func (ac *ansiCommand) String() string { func (ac *ansiCommand) String() string {
@ -119,12 +119,12 @@ func (ac *ansiCommand) String() string {
// See http://manpages.ubuntu.com/manpages/intrepid/man4/console_codes.4.html. // See http://manpages.ubuntu.com/manpages/intrepid/man4/console_codes.4.html.
func isAnsiCommandChar(b byte) bool { func isAnsiCommandChar(b byte) bool {
switch { switch {
case ANSI_COMMAND_FIRST <= b && b <= ANSI_COMMAND_LAST && b != ANSI_ESCAPE_SECONDARY: case ansiterm.ANSI_COMMAND_FIRST <= b && b <= ansiterm.ANSI_COMMAND_LAST && b != ansiterm.ANSI_ESCAPE_SECONDARY:
return true return true
case b == ANSI_CMD_G1 || b == ANSI_CMD_OSC || b == ANSI_CMD_DECPAM || b == ANSI_CMD_DECPNM: case b == ansiterm.ANSI_CMD_G1 || b == ansiterm.ANSI_CMD_OSC || b == ansiterm.ANSI_CMD_DECPAM || b == ansiterm.ANSI_CMD_DECPNM:
// non-CSI escape sequence terminator // non-CSI escape sequence terminator
return true return true
case b == ANSI_CMD_STR_TERM || b == ANSI_BEL: case b == ansiterm.ANSI_CMD_STR_TERM || b == ansiterm.ANSI_BEL:
// String escape sequence terminator // String escape sequence terminator
return true return true
} }
@ -132,11 +132,11 @@ func isAnsiCommandChar(b byte) bool {
} }
func isXtermOscSequence(command []byte, current byte) bool { func isXtermOscSequence(command []byte, current byte) bool {
return (len(command) >= 2 && command[0] == ANSI_ESCAPE_PRIMARY && command[1] == ANSI_CMD_OSC && current != ANSI_BEL) return (len(command) >= 2 && command[0] == ansiterm.ANSI_ESCAPE_PRIMARY && command[1] == ansiterm.ANSI_CMD_OSC && current != ansiterm.ANSI_BEL)
} }
func isCharacterSelectionCmdChar(b byte) bool { func isCharacterSelectionCmdChar(b byte) bool {
return (b == ANSI_CMD_G0 || b == ANSI_CMD_G1 || b == ANSI_CMD_G2 || b == ANSI_CMD_G3) return (b == ansiterm.ANSI_CMD_G0 || b == ansiterm.ANSI_CMD_G1 || b == ansiterm.ANSI_CMD_G2 || b == ansiterm.ANSI_CMD_G3)
} }
// bytesToHex converts a slice of bytes to a human-readable string. // bytesToHex converts a slice of bytes to a human-readable string.
@ -150,7 +150,7 @@ func bytesToHex(b []byte) string {
// ensureInRange adjusts the passed value, if necessary, to ensure it is within // ensureInRange adjusts the passed value, if necessary, to ensure it is within
// the passed min / max range. // the passed min / max range.
func ensureInRange(n SHORT, min SHORT, max SHORT) SHORT { func ensureInRange(n int16, min int16, max int16) int16 {
if n < min { if n < min {
return min return min
} else if n > max { } else if n > max {

View File

@ -66,21 +66,21 @@ const (
// -- The attributes are combined to produce various colors (e.g., Blue + Green will create Cyan). // -- The attributes are combined to produce various colors (e.g., Blue + Green will create Cyan).
// Clearing all foreground or background colors results in black; setting all creates white. // Clearing all foreground or background colors results in black; setting all creates white.
// See https://msdn.microsoft.com/en-us/library/windows/desktop/ms682088(v=vs.85).aspx#_win32_character_attributes. // See https://msdn.microsoft.com/en-us/library/windows/desktop/ms682088(v=vs.85).aspx#_win32_character_attributes.
FOREGROUND_BLUE WORD = 0x0001 FOREGROUND_BLUE uint16 = 0x0001
FOREGROUND_GREEN WORD = 0x0002 FOREGROUND_GREEN uint16 = 0x0002
FOREGROUND_RED WORD = 0x0004 FOREGROUND_RED uint16 = 0x0004
FOREGROUND_INTENSITY WORD = 0x0008 FOREGROUND_INTENSITY uint16 = 0x0008
FOREGROUND_MASK WORD = 0x000F FOREGROUND_MASK uint16 = 0x000F
BACKGROUND_BLUE WORD = 0x0010 BACKGROUND_BLUE uint16 = 0x0010
BACKGROUND_GREEN WORD = 0x0020 BACKGROUND_GREEN uint16 = 0x0020
BACKGROUND_RED WORD = 0x0040 BACKGROUND_RED uint16 = 0x0040
BACKGROUND_INTENSITY WORD = 0x0080 BACKGROUND_INTENSITY uint16 = 0x0080
BACKGROUND_MASK WORD = 0x00F0 BACKGROUND_MASK uint16 = 0x00F0
COMMON_LVB_MASK WORD = 0xFF00 COMMON_LVB_MASK uint16 = 0xFF00
COMMON_LVB_REVERSE_VIDEO WORD = 0x4000 COMMON_LVB_REVERSE_VIDEO uint16 = 0x4000
COMMON_LVB_UNDERSCORE WORD = 0x8000 COMMON_LVB_UNDERSCORE uint16 = 0x8000
// Input event types // Input event types
// See https://msdn.microsoft.com/en-us/library/windows/desktop/ms683499(v=vs.85).aspx. // See https://msdn.microsoft.com/en-us/library/windows/desktop/ms683499(v=vs.85).aspx.
@ -104,60 +104,53 @@ const (
) )
// Windows API Console types // Windows API Console types
// -- See https://msdn.microsoft.com/en-us/library/windows/desktop/aa383751(v=vs.85).aspx for core types (e.g., SHORT)
// -- See https://msdn.microsoft.com/en-us/library/windows/desktop/ms682101(v=vs.85).aspx for Console specific types (e.g., COORD) // -- See https://msdn.microsoft.com/en-us/library/windows/desktop/ms682101(v=vs.85).aspx for Console specific types (e.g., COORD)
// -- See https://msdn.microsoft.com/en-us/library/aa296569(v=vs.60).aspx for comments on alignment // -- See https://msdn.microsoft.com/en-us/library/aa296569(v=vs.60).aspx for comments on alignment
type ( type (
SHORT int16
BOOL int32
WORD uint16
WCHAR uint16
DWORD uint32
CHAR_INFO struct { CHAR_INFO struct {
UnicodeChar WCHAR UnicodeChar uint16
Attributes WORD Attributes uint16
} }
CONSOLE_CURSOR_INFO struct { CONSOLE_CURSOR_INFO struct {
Size DWORD Size uint32
Visible BOOL Visible int32
} }
CONSOLE_SCREEN_BUFFER_INFO struct { CONSOLE_SCREEN_BUFFER_INFO struct {
Size COORD Size COORD
CursorPosition COORD CursorPosition COORD
Attributes WORD Attributes uint16
Window SMALL_RECT Window SMALL_RECT
MaximumWindowSize COORD MaximumWindowSize COORD
} }
COORD struct { COORD struct {
X SHORT X int16
Y SHORT Y int16
} }
SMALL_RECT struct { SMALL_RECT struct {
Left SHORT Left int16
Top SHORT Top int16
Right SHORT Right int16
Bottom SHORT Bottom int16
} }
// INPUT_RECORD is a C/C++ union of which KEY_EVENT_RECORD is one case, it is also the largest // INPUT_RECORD is a C/C++ union of which KEY_EVENT_RECORD is one case, it is also the largest
// See https://msdn.microsoft.com/en-us/library/windows/desktop/ms683499(v=vs.85).aspx. // See https://msdn.microsoft.com/en-us/library/windows/desktop/ms683499(v=vs.85).aspx.
INPUT_RECORD struct { INPUT_RECORD struct {
EventType WORD EventType uint16
KeyEvent KEY_EVENT_RECORD KeyEvent KEY_EVENT_RECORD
} }
KEY_EVENT_RECORD struct { KEY_EVENT_RECORD struct {
KeyDown BOOL KeyDown int32
RepeatCount WORD RepeatCount uint16
VirtualKeyCode WORD VirtualKeyCode uint16
VirtualScanCode WORD VirtualScanCode uint16
UnicodeChar WCHAR UnicodeChar uint16
ControlKeyState DWORD ControlKeyState uint32
} }
WINDOW_BUFFER_SIZE struct { WINDOW_BUFFER_SIZE struct {
@ -165,12 +158,12 @@ type (
} }
) )
// boolToBOOL converts a Go bool into a Windows BOOL. // boolToBOOL converts a Go bool into a Windows int32.
func boolToBOOL(f bool) BOOL { func boolToBOOL(f bool) int32 {
if f { if f {
return BOOL(1) return int32(1)
} else { } else {
return BOOL(0) return int32(0)
} }
} }
@ -242,7 +235,7 @@ func SetConsoleScreenBufferSize(handle uintptr, coord COORD) error {
// SetConsoleTextAttribute sets the attributes of characters written to the // SetConsoleTextAttribute sets the attributes of characters written to the
// console screen buffer by the WriteFile or WriteConsole function. // console screen buffer by the WriteFile or WriteConsole function.
// See http://msdn.microsoft.com/en-us/library/windows/desktop/ms686047(v=vs.85).aspx. // See http://msdn.microsoft.com/en-us/library/windows/desktop/ms686047(v=vs.85).aspx.
func SetConsoleTextAttribute(handle uintptr, attribute WORD) error { func SetConsoleTextAttribute(handle uintptr, attribute uint16) error {
r1, r2, err := setConsoleTextAttributeProc.Call(handle, uintptr(attribute), 0) r1, r2, err := setConsoleTextAttributeProc.Call(handle, uintptr(attribute), 0)
use(attribute) use(attribute)
return checkError(r1, r2, err) return checkError(r1, r2, err)
@ -280,7 +273,7 @@ func ReadConsoleInput(handle uintptr, buffer []INPUT_RECORD, count *uint32) erro
// It returns true if the handle was signaled; false otherwise. // It returns true if the handle was signaled; false otherwise.
// See https://msdn.microsoft.com/en-us/library/windows/desktop/ms687032(v=vs.85).aspx. // See https://msdn.microsoft.com/en-us/library/windows/desktop/ms687032(v=vs.85).aspx.
func WaitForSingleObject(handle uintptr, msWait uint32) (bool, error) { func WaitForSingleObject(handle uintptr, msWait uint32) (bool, error) {
r1, _, err := waitForSingleObjectProc.Call(handle, uintptr(DWORD(msWait))) r1, _, err := waitForSingleObjectProc.Call(handle, uintptr(uint32(msWait)))
switch r1 { switch r1 {
case WAIT_ABANDONED, WAIT_TIMEOUT: case WAIT_ABANDONED, WAIT_TIMEOUT:
return false, nil return false, nil
@ -320,8 +313,8 @@ func checkError(r1, r2 uintptr, err error) error {
// coordToPointer converts a COORD into a uintptr (by fooling the type system). // coordToPointer converts a COORD into a uintptr (by fooling the type system).
func coordToPointer(c COORD) uintptr { func coordToPointer(c COORD) uintptr {
// Note: This code assumes the two SHORTs are correctly laid out; the "cast" to DWORD is just to get a pointer to pass. // Note: This code assumes the two SHORTs are correctly laid out; the "cast" to uint32 is just to get a pointer to pass.
return uintptr(*((*DWORD)(unsafe.Pointer(&c)))) return uintptr(*((*uint32)(unsafe.Pointer(&c))))
} }
// use is a no-op, but the compiler cannot see that it is. // use is a no-op, but the compiler cannot see that it is.

View File

@ -2,9 +2,7 @@
package winterm package winterm
import ( import "github.com/Azure/go-ansiterm"
. "github.com/Azure/go-ansiterm"
)
const ( const (
FOREGROUND_COLOR_MASK = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE FOREGROUND_COLOR_MASK = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE
@ -13,83 +11,83 @@ const (
// collectAnsiIntoWindowsAttributes modifies the passed Windows text mode flags to reflect the // collectAnsiIntoWindowsAttributes modifies the passed Windows text mode flags to reflect the
// request represented by the passed ANSI mode. // request represented by the passed ANSI mode.
func collectAnsiIntoWindowsAttributes(windowsMode WORD, inverted bool, baseMode WORD, ansiMode SHORT) (WORD, bool) { func collectAnsiIntoWindowsAttributes(windowsMode uint16, inverted bool, baseMode uint16, ansiMode int16) (uint16, bool) {
switch ansiMode { switch ansiMode {
// Mode styles // Mode styles
case ANSI_SGR_BOLD: case ansiterm.ANSI_SGR_BOLD:
windowsMode = windowsMode | FOREGROUND_INTENSITY windowsMode = windowsMode | FOREGROUND_INTENSITY
case ANSI_SGR_DIM, ANSI_SGR_BOLD_DIM_OFF: case ansiterm.ANSI_SGR_DIM, ansiterm.ANSI_SGR_BOLD_DIM_OFF:
windowsMode &^= FOREGROUND_INTENSITY windowsMode &^= FOREGROUND_INTENSITY
case ANSI_SGR_UNDERLINE: case ansiterm.ANSI_SGR_UNDERLINE:
windowsMode = windowsMode | COMMON_LVB_UNDERSCORE windowsMode = windowsMode | COMMON_LVB_UNDERSCORE
case ANSI_SGR_REVERSE: case ansiterm.ANSI_SGR_REVERSE:
inverted = true inverted = true
case ANSI_SGR_REVERSE_OFF: case ansiterm.ANSI_SGR_REVERSE_OFF:
inverted = false inverted = false
case ANSI_SGR_UNDERLINE_OFF: case ansiterm.ANSI_SGR_UNDERLINE_OFF:
windowsMode &^= COMMON_LVB_UNDERSCORE windowsMode &^= COMMON_LVB_UNDERSCORE
// Foreground colors // Foreground colors
case ANSI_SGR_FOREGROUND_DEFAULT: case ansiterm.ANSI_SGR_FOREGROUND_DEFAULT:
windowsMode = (windowsMode &^ FOREGROUND_MASK) | (baseMode & FOREGROUND_MASK) windowsMode = (windowsMode &^ FOREGROUND_MASK) | (baseMode & FOREGROUND_MASK)
case ANSI_SGR_FOREGROUND_BLACK: case ansiterm.ANSI_SGR_FOREGROUND_BLACK:
windowsMode = (windowsMode &^ FOREGROUND_COLOR_MASK) windowsMode = (windowsMode &^ FOREGROUND_COLOR_MASK)
case ANSI_SGR_FOREGROUND_RED: case ansiterm.ANSI_SGR_FOREGROUND_RED:
windowsMode = (windowsMode &^ FOREGROUND_COLOR_MASK) | FOREGROUND_RED windowsMode = (windowsMode &^ FOREGROUND_COLOR_MASK) | FOREGROUND_RED
case ANSI_SGR_FOREGROUND_GREEN: case ansiterm.ANSI_SGR_FOREGROUND_GREEN:
windowsMode = (windowsMode &^ FOREGROUND_COLOR_MASK) | FOREGROUND_GREEN windowsMode = (windowsMode &^ FOREGROUND_COLOR_MASK) | FOREGROUND_GREEN
case ANSI_SGR_FOREGROUND_YELLOW: case ansiterm.ANSI_SGR_FOREGROUND_YELLOW:
windowsMode = (windowsMode &^ FOREGROUND_COLOR_MASK) | FOREGROUND_RED | FOREGROUND_GREEN windowsMode = (windowsMode &^ FOREGROUND_COLOR_MASK) | FOREGROUND_RED | FOREGROUND_GREEN
case ANSI_SGR_FOREGROUND_BLUE: case ansiterm.ANSI_SGR_FOREGROUND_BLUE:
windowsMode = (windowsMode &^ FOREGROUND_COLOR_MASK) | FOREGROUND_BLUE windowsMode = (windowsMode &^ FOREGROUND_COLOR_MASK) | FOREGROUND_BLUE
case ANSI_SGR_FOREGROUND_MAGENTA: case ansiterm.ANSI_SGR_FOREGROUND_MAGENTA:
windowsMode = (windowsMode &^ FOREGROUND_COLOR_MASK) | FOREGROUND_RED | FOREGROUND_BLUE windowsMode = (windowsMode &^ FOREGROUND_COLOR_MASK) | FOREGROUND_RED | FOREGROUND_BLUE
case ANSI_SGR_FOREGROUND_CYAN: case ansiterm.ANSI_SGR_FOREGROUND_CYAN:
windowsMode = (windowsMode &^ FOREGROUND_COLOR_MASK) | FOREGROUND_GREEN | FOREGROUND_BLUE windowsMode = (windowsMode &^ FOREGROUND_COLOR_MASK) | FOREGROUND_GREEN | FOREGROUND_BLUE
case ANSI_SGR_FOREGROUND_WHITE: case ansiterm.ANSI_SGR_FOREGROUND_WHITE:
windowsMode = (windowsMode &^ FOREGROUND_COLOR_MASK) | FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE windowsMode = (windowsMode &^ FOREGROUND_COLOR_MASK) | FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE
// Background colors // Background colors
case ANSI_SGR_BACKGROUND_DEFAULT: case ansiterm.ANSI_SGR_BACKGROUND_DEFAULT:
// Black with no intensity // Black with no intensity
windowsMode = (windowsMode &^ BACKGROUND_MASK) | (baseMode & BACKGROUND_MASK) windowsMode = (windowsMode &^ BACKGROUND_MASK) | (baseMode & BACKGROUND_MASK)
case ANSI_SGR_BACKGROUND_BLACK: case ansiterm.ANSI_SGR_BACKGROUND_BLACK:
windowsMode = (windowsMode &^ BACKGROUND_COLOR_MASK) windowsMode = (windowsMode &^ BACKGROUND_COLOR_MASK)
case ANSI_SGR_BACKGROUND_RED: case ansiterm.ANSI_SGR_BACKGROUND_RED:
windowsMode = (windowsMode &^ BACKGROUND_COLOR_MASK) | BACKGROUND_RED windowsMode = (windowsMode &^ BACKGROUND_COLOR_MASK) | BACKGROUND_RED
case ANSI_SGR_BACKGROUND_GREEN: case ansiterm.ANSI_SGR_BACKGROUND_GREEN:
windowsMode = (windowsMode &^ BACKGROUND_COLOR_MASK) | BACKGROUND_GREEN windowsMode = (windowsMode &^ BACKGROUND_COLOR_MASK) | BACKGROUND_GREEN
case ANSI_SGR_BACKGROUND_YELLOW: case ansiterm.ANSI_SGR_BACKGROUND_YELLOW:
windowsMode = (windowsMode &^ BACKGROUND_COLOR_MASK) | BACKGROUND_RED | BACKGROUND_GREEN windowsMode = (windowsMode &^ BACKGROUND_COLOR_MASK) | BACKGROUND_RED | BACKGROUND_GREEN
case ANSI_SGR_BACKGROUND_BLUE: case ansiterm.ANSI_SGR_BACKGROUND_BLUE:
windowsMode = (windowsMode &^ BACKGROUND_COLOR_MASK) | BACKGROUND_BLUE windowsMode = (windowsMode &^ BACKGROUND_COLOR_MASK) | BACKGROUND_BLUE
case ANSI_SGR_BACKGROUND_MAGENTA: case ansiterm.ANSI_SGR_BACKGROUND_MAGENTA:
windowsMode = (windowsMode &^ BACKGROUND_COLOR_MASK) | BACKGROUND_RED | BACKGROUND_BLUE windowsMode = (windowsMode &^ BACKGROUND_COLOR_MASK) | BACKGROUND_RED | BACKGROUND_BLUE
case ANSI_SGR_BACKGROUND_CYAN: case ansiterm.ANSI_SGR_BACKGROUND_CYAN:
windowsMode = (windowsMode &^ BACKGROUND_COLOR_MASK) | BACKGROUND_GREEN | BACKGROUND_BLUE windowsMode = (windowsMode &^ BACKGROUND_COLOR_MASK) | BACKGROUND_GREEN | BACKGROUND_BLUE
case ANSI_SGR_BACKGROUND_WHITE: case ansiterm.ANSI_SGR_BACKGROUND_WHITE:
windowsMode = (windowsMode &^ BACKGROUND_COLOR_MASK) | BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE windowsMode = (windowsMode &^ BACKGROUND_COLOR_MASK) | BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE
} }
@ -97,6 +95,6 @@ func collectAnsiIntoWindowsAttributes(windowsMode WORD, inverted bool, baseMode
} }
// invertAttributes inverts the foreground and background colors of a Windows attributes value // invertAttributes inverts the foreground and background colors of a Windows attributes value
func invertAttributes(windowsMode WORD) WORD { func invertAttributes(windowsMode uint16) uint16 {
return (COMMON_LVB_MASK & windowsMode) | ((FOREGROUND_MASK & windowsMode) << 4) | ((BACKGROUND_MASK & windowsMode) >> 4) return (COMMON_LVB_MASK & windowsMode) | ((FOREGROUND_MASK & windowsMode) << 4) | ((BACKGROUND_MASK & windowsMode) >> 4)
} }

View File

@ -3,11 +3,11 @@
package winterm package winterm
const ( const (
Horizontal = iota horizontal = iota
Vertical vertical
) )
func (h *WindowsAnsiEventHandler) getCursorWindow(info *CONSOLE_SCREEN_BUFFER_INFO) SMALL_RECT { func (h *windowsAnsiEventHandler) getCursorWindow(info *CONSOLE_SCREEN_BUFFER_INFO) SMALL_RECT {
if h.originMode { if h.originMode {
sr := h.effectiveSr(info.Window) sr := h.effectiveSr(info.Window)
return SMALL_RECT{ return SMALL_RECT{
@ -27,7 +27,7 @@ func (h *WindowsAnsiEventHandler) getCursorWindow(info *CONSOLE_SCREEN_BUFFER_IN
} }
// setCursorPosition sets the cursor to the specified position, bounded to the screen size // setCursorPosition sets the cursor to the specified position, bounded to the screen size
func (h *WindowsAnsiEventHandler) setCursorPosition(position COORD, window SMALL_RECT) error { func (h *windowsAnsiEventHandler) setCursorPosition(position COORD, window SMALL_RECT) error {
position.X = ensureInRange(position.X, window.Left, window.Right) position.X = ensureInRange(position.X, window.Left, window.Right)
position.Y = ensureInRange(position.Y, window.Top, window.Bottom) position.Y = ensureInRange(position.Y, window.Top, window.Bottom)
err := SetConsoleCursorPosition(h.fd, position) err := SetConsoleCursorPosition(h.fd, position)
@ -38,15 +38,15 @@ func (h *WindowsAnsiEventHandler) setCursorPosition(position COORD, window SMALL
return err return err
} }
func (h *WindowsAnsiEventHandler) moveCursorVertical(param int) error { func (h *windowsAnsiEventHandler) moveCursorVertical(param int) error {
return h.moveCursor(Vertical, param) return h.moveCursor(vertical, param)
} }
func (h *WindowsAnsiEventHandler) moveCursorHorizontal(param int) error { func (h *windowsAnsiEventHandler) moveCursorHorizontal(param int) error {
return h.moveCursor(Horizontal, param) return h.moveCursor(horizontal, param)
} }
func (h *WindowsAnsiEventHandler) moveCursor(moveMode int, param int) error { func (h *windowsAnsiEventHandler) moveCursor(moveMode int, param int) error {
info, err := GetConsoleScreenBufferInfo(h.fd) info, err := GetConsoleScreenBufferInfo(h.fd)
if err != nil { if err != nil {
return err return err
@ -54,10 +54,10 @@ func (h *WindowsAnsiEventHandler) moveCursor(moveMode int, param int) error {
position := info.CursorPosition position := info.CursorPosition
switch moveMode { switch moveMode {
case Horizontal: case horizontal:
position.X += SHORT(param) position.X += int16(param)
case Vertical: case vertical:
position.Y += SHORT(param) position.Y += int16(param)
} }
if err = h.setCursorPosition(position, h.getCursorWindow(info)); err != nil { if err = h.setCursorPosition(position, h.getCursorWindow(info)); err != nil {
@ -67,7 +67,7 @@ func (h *WindowsAnsiEventHandler) moveCursor(moveMode int, param int) error {
return nil return nil
} }
func (h *WindowsAnsiEventHandler) moveCursorLine(param int) error { func (h *windowsAnsiEventHandler) moveCursorLine(param int) error {
info, err := GetConsoleScreenBufferInfo(h.fd) info, err := GetConsoleScreenBufferInfo(h.fd)
if err != nil { if err != nil {
return err return err
@ -75,7 +75,7 @@ func (h *WindowsAnsiEventHandler) moveCursorLine(param int) error {
position := info.CursorPosition position := info.CursorPosition
position.X = 0 position.X = 0
position.Y += SHORT(param) position.Y += int16(param)
if err = h.setCursorPosition(position, h.getCursorWindow(info)); err != nil { if err = h.setCursorPosition(position, h.getCursorWindow(info)); err != nil {
return err return err
@ -84,14 +84,14 @@ func (h *WindowsAnsiEventHandler) moveCursorLine(param int) error {
return nil return nil
} }
func (h *WindowsAnsiEventHandler) moveCursorColumn(param int) error { func (h *windowsAnsiEventHandler) moveCursorColumn(param int) error {
info, err := GetConsoleScreenBufferInfo(h.fd) info, err := GetConsoleScreenBufferInfo(h.fd)
if err != nil { if err != nil {
return err return err
} }
position := info.CursorPosition position := info.CursorPosition
position.X = SHORT(param) - 1 position.X = int16(param) - 1
if err = h.setCursorPosition(position, h.getCursorWindow(info)); err != nil { if err = h.setCursorPosition(position, h.getCursorWindow(info)); err != nil {
return err return err

View File

@ -2,11 +2,9 @@
package winterm package winterm
import ( import "github.com/Azure/go-ansiterm"
. "github.com/Azure/go-ansiterm"
)
func (h *WindowsAnsiEventHandler) clearRange(attributes WORD, fromCoord COORD, toCoord COORD) error { func (h *windowsAnsiEventHandler) clearRange(attributes uint16, fromCoord COORD, toCoord COORD) error {
// Ignore an invalid (negative area) request // Ignore an invalid (negative area) request
if toCoord.Y < fromCoord.Y { if toCoord.Y < fromCoord.Y {
return nil return nil
@ -60,7 +58,7 @@ func (h *WindowsAnsiEventHandler) clearRange(attributes WORD, fromCoord COORD, t
return nil return nil
} }
func (h *WindowsAnsiEventHandler) clearRect(attributes WORD, fromCoord COORD, toCoord COORD) error { func (h *windowsAnsiEventHandler) clearRect(attributes uint16, fromCoord COORD, toCoord COORD) error {
region := SMALL_RECT{Top: fromCoord.Y, Left: fromCoord.X, Bottom: toCoord.Y, Right: toCoord.X} region := SMALL_RECT{Top: fromCoord.Y, Left: fromCoord.X, Bottom: toCoord.Y, Right: toCoord.X}
width := toCoord.X - fromCoord.X + 1 width := toCoord.X - fromCoord.X + 1
height := toCoord.Y - fromCoord.Y + 1 height := toCoord.Y - fromCoord.Y + 1
@ -72,7 +70,7 @@ func (h *WindowsAnsiEventHandler) clearRect(attributes WORD, fromCoord COORD, to
buffer := make([]CHAR_INFO, size) buffer := make([]CHAR_INFO, size)
char := CHAR_INFO{WCHAR(FILL_CHARACTER), attributes} char := CHAR_INFO{ansiterm.FILL_CHARACTER, attributes}
for i := 0; i < int(size); i++ { for i := 0; i < int(size); i++ {
buffer[i] = char buffer[i] = char
} }

View File

@ -3,9 +3,9 @@
package winterm package winterm
// effectiveSr gets the current effective scroll region in buffer coordinates // effectiveSr gets the current effective scroll region in buffer coordinates
func (h *WindowsAnsiEventHandler) effectiveSr(window SMALL_RECT) scrollRegion { func (h *windowsAnsiEventHandler) effectiveSr(window SMALL_RECT) scrollRegion {
top := AddInRange(window.Top, h.sr.top, window.Top, window.Bottom) top := addInRange(window.Top, h.sr.top, window.Top, window.Bottom)
bottom := AddInRange(window.Top, h.sr.bottom, window.Top, window.Bottom) bottom := addInRange(window.Top, h.sr.bottom, window.Top, window.Bottom)
if top >= bottom { if top >= bottom {
top = window.Top top = window.Top
bottom = window.Bottom bottom = window.Bottom
@ -13,7 +13,7 @@ func (h *WindowsAnsiEventHandler) effectiveSr(window SMALL_RECT) scrollRegion {
return scrollRegion{top: top, bottom: bottom} return scrollRegion{top: top, bottom: bottom}
} }
func (h *WindowsAnsiEventHandler) scrollUp(param int) error { func (h *windowsAnsiEventHandler) scrollUp(param int) error {
info, err := GetConsoleScreenBufferInfo(h.fd) info, err := GetConsoleScreenBufferInfo(h.fd)
if err != nil { if err != nil {
return err return err
@ -23,11 +23,11 @@ func (h *WindowsAnsiEventHandler) scrollUp(param int) error {
return h.scroll(param, sr, info) return h.scroll(param, sr, info)
} }
func (h *WindowsAnsiEventHandler) scrollDown(param int) error { func (h *windowsAnsiEventHandler) scrollDown(param int) error {
return h.scrollUp(-param) return h.scrollUp(-param)
} }
func (h *WindowsAnsiEventHandler) deleteLines(param int) error { func (h *windowsAnsiEventHandler) deleteLines(param int) error {
info, err := GetConsoleScreenBufferInfo(h.fd) info, err := GetConsoleScreenBufferInfo(h.fd)
if err != nil { if err != nil {
return err return err
@ -44,12 +44,12 @@ func (h *WindowsAnsiEventHandler) deleteLines(param int) error {
} }
} }
func (h *WindowsAnsiEventHandler) insertLines(param int) error { func (h *windowsAnsiEventHandler) insertLines(param int) error {
return h.deleteLines(-param) return h.deleteLines(-param)
} }
// scroll scrolls the provided scroll region by param lines. The scroll region is in buffer coordinates. // scroll scrolls the provided scroll region by param lines. The scroll region is in buffer coordinates.
func (h *WindowsAnsiEventHandler) scroll(param int, sr scrollRegion, info *CONSOLE_SCREEN_BUFFER_INFO) error { func (h *windowsAnsiEventHandler) scroll(param int, sr scrollRegion, info *CONSOLE_SCREEN_BUFFER_INFO) error {
logger.Infof("scroll: scrollTop: %d, scrollBottom: %d", sr.top, sr.bottom) logger.Infof("scroll: scrollTop: %d, scrollBottom: %d", sr.top, sr.bottom)
logger.Infof("scroll: windowTop: %d, windowBottom: %d", info.Window.Top, info.Window.Bottom) logger.Infof("scroll: windowTop: %d, windowBottom: %d", info.Window.Top, info.Window.Bottom)
@ -64,7 +64,7 @@ func (h *WindowsAnsiEventHandler) scroll(param int, sr scrollRegion, info *CONSO
// Origin to which area should be copied // Origin to which area should be copied
destOrigin := COORD{ destOrigin := COORD{
X: 0, X: 0,
Y: sr.top - SHORT(param), Y: sr.top - int16(param),
} }
char := CHAR_INFO{ char := CHAR_INFO{
@ -78,7 +78,7 @@ func (h *WindowsAnsiEventHandler) scroll(param int, sr scrollRegion, info *CONSO
return nil return nil
} }
func (h *WindowsAnsiEventHandler) deleteCharacters(param int) error { func (h *windowsAnsiEventHandler) deleteCharacters(param int) error {
info, err := GetConsoleScreenBufferInfo(h.fd) info, err := GetConsoleScreenBufferInfo(h.fd)
if err != nil { if err != nil {
return err return err
@ -86,12 +86,12 @@ func (h *WindowsAnsiEventHandler) deleteCharacters(param int) error {
return h.scrollLine(param, info.CursorPosition, info) return h.scrollLine(param, info.CursorPosition, info)
} }
func (h *WindowsAnsiEventHandler) insertCharacters(param int) error { func (h *windowsAnsiEventHandler) insertCharacters(param int) error {
return h.deleteCharacters(-param) return h.deleteCharacters(-param)
} }
// scrollLine scrolls a line horizontally starting at the provided position by a number of columns. // scrollLine scrolls a line horizontally starting at the provided position by a number of columns.
func (h *WindowsAnsiEventHandler) scrollLine(columns int, position COORD, info *CONSOLE_SCREEN_BUFFER_INFO) error { func (h *windowsAnsiEventHandler) scrollLine(columns int, position COORD, info *CONSOLE_SCREEN_BUFFER_INFO) error {
// Copy from and clip to the scroll region (full buffer width) // Copy from and clip to the scroll region (full buffer width)
scrollRect := SMALL_RECT{ scrollRect := SMALL_RECT{
Top: position.Y, Top: position.Y,
@ -102,7 +102,7 @@ func (h *WindowsAnsiEventHandler) scrollLine(columns int, position COORD, info *
// Origin to which area should be copied // Origin to which area should be copied
destOrigin := COORD{ destOrigin := COORD{
X: position.X - SHORT(columns), X: position.X - int16(columns),
Y: position.Y, Y: position.Y,
} }

View File

@ -4,6 +4,6 @@ package winterm
// AddInRange increments a value by the passed quantity while ensuring the values // AddInRange increments a value by the passed quantity while ensuring the values
// always remain within the supplied min / max range. // always remain within the supplied min / max range.
func AddInRange(n SHORT, increment SHORT, min SHORT, max SHORT) SHORT { func addInRange(n int16, increment int16, min int16, max int16) int16 {
return ensureInRange(n+increment, min, max) return ensureInRange(n+increment, min, max)
} }

View File

@ -8,19 +8,19 @@ import (
"os" "os"
"strconv" "strconv"
. "github.com/Azure/go-ansiterm" "github.com/Azure/go-ansiterm"
"github.com/Sirupsen/logrus" "github.com/Sirupsen/logrus"
) )
var logger *logrus.Logger var logger *logrus.Logger
type WindowsAnsiEventHandler struct { type windowsAnsiEventHandler struct {
fd uintptr fd uintptr
file *os.File file *os.File
infoReset *CONSOLE_SCREEN_BUFFER_INFO infoReset *CONSOLE_SCREEN_BUFFER_INFO
sr scrollRegion sr scrollRegion
buffer bytes.Buffer buffer bytes.Buffer
attributes WORD attributes uint16
inverted bool inverted bool
wrapNext bool wrapNext bool
drewMarginByte bool drewMarginByte bool
@ -30,10 +30,10 @@ type WindowsAnsiEventHandler struct {
curPos COORD curPos COORD
} }
func CreateWinEventHandler(fd uintptr, file *os.File) AnsiEventHandler { func CreateWinEventHandler(fd uintptr, file *os.File) ansiterm.AnsiEventHandler {
logFile := ioutil.Discard logFile := ioutil.Discard
if isDebugEnv := os.Getenv(LogEnv); isDebugEnv == "1" { if isDebugEnv := os.Getenv(ansiterm.LogEnv); isDebugEnv == "1" {
logFile, _ = os.Create("winEventHandler.log") logFile, _ = os.Create("winEventHandler.log")
} }
@ -48,7 +48,7 @@ func CreateWinEventHandler(fd uintptr, file *os.File) AnsiEventHandler {
return nil return nil
} }
return &WindowsAnsiEventHandler{ return &windowsAnsiEventHandler{
fd: fd, fd: fd,
file: file, file: file,
infoReset: infoReset, infoReset: infoReset,
@ -57,8 +57,8 @@ func CreateWinEventHandler(fd uintptr, file *os.File) AnsiEventHandler {
} }
type scrollRegion struct { type scrollRegion struct {
top SHORT top int16
bottom SHORT bottom int16
} }
// simulateLF simulates a LF or CR+LF by scrolling if necessary to handle the // simulateLF simulates a LF or CR+LF by scrolling if necessary to handle the
@ -68,7 +68,7 @@ type scrollRegion struct {
// //
// In the false case, the caller should ensure that a carriage return // In the false case, the caller should ensure that a carriage return
// and line feed are inserted or that the text is otherwise wrapped. // and line feed are inserted or that the text is otherwise wrapped.
func (h *WindowsAnsiEventHandler) simulateLF(includeCR bool) (bool, error) { func (h *windowsAnsiEventHandler) simulateLF(includeCR bool) (bool, error) {
if h.wrapNext { if h.wrapNext {
if err := h.Flush(); err != nil { if err := h.Flush(); err != nil {
return false, err return false, err
@ -89,24 +89,25 @@ func (h *WindowsAnsiEventHandler) simulateLF(includeCR bool) (bool, error) {
h.updatePos(pos) h.updatePos(pos)
} }
return false, nil return false, nil
} else {
// A custom scroll region is active. Scroll the window manually to simulate
// the LF.
if err := h.Flush(); err != nil {
return false, err
}
logger.Info("Simulating LF inside scroll region")
if err := h.scrollUp(1); err != nil {
return false, err
}
if includeCR {
pos.X = 0
if err := SetConsoleCursorPosition(h.fd, pos); err != nil {
return false, err
}
}
return true, nil
} }
// A custom scroll region is active. Scroll the window manually to simulate
// the LF.
if err := h.Flush(); err != nil {
return false, err
}
logger.Info("Simulating LF inside scroll region")
if err := h.scrollUp(1); err != nil {
return false, err
}
if includeCR {
pos.X = 0
if err := SetConsoleCursorPosition(h.fd, pos); err != nil {
return false, err
}
}
return true, nil
} else if pos.Y < info.Window.Bottom { } else if pos.Y < info.Window.Bottom {
// Let Windows handle the LF. // Let Windows handle the LF.
pos.Y++ pos.Y++
@ -133,7 +134,7 @@ func (h *WindowsAnsiEventHandler) simulateLF(includeCR bool) (bool, error) {
} }
// executeLF executes a LF without a CR. // executeLF executes a LF without a CR.
func (h *WindowsAnsiEventHandler) executeLF() error { func (h *windowsAnsiEventHandler) executeLF() error {
handled, err := h.simulateLF(false) handled, err := h.simulateLF(false)
if err != nil { if err != nil {
return err return err
@ -145,7 +146,7 @@ func (h *WindowsAnsiEventHandler) executeLF() error {
if err != nil { if err != nil {
return err return err
} }
h.buffer.WriteByte(ANSI_LINE_FEED) h.buffer.WriteByte(ansiterm.ANSI_LINE_FEED)
if pos.X != 0 { if pos.X != 0 {
if err := h.Flush(); err != nil { if err := h.Flush(); err != nil {
return err return err
@ -159,7 +160,7 @@ func (h *WindowsAnsiEventHandler) executeLF() error {
return nil return nil
} }
func (h *WindowsAnsiEventHandler) Print(b byte) error { func (h *windowsAnsiEventHandler) Print(b byte) error {
if h.wrapNext { if h.wrapNext {
h.buffer.WriteByte(h.marginByte) h.buffer.WriteByte(h.marginByte)
h.clearWrap() h.clearWrap()
@ -182,9 +183,9 @@ func (h *WindowsAnsiEventHandler) Print(b byte) error {
return nil return nil
} }
func (h *WindowsAnsiEventHandler) Execute(b byte) error { func (h *windowsAnsiEventHandler) Execute(b byte) error {
switch b { switch b {
case ANSI_TAB: case ansiterm.ANSI_TAB:
logger.Info("Execute(TAB)") logger.Info("Execute(TAB)")
// Move to the next tab stop, but preserve auto-wrap if already set. // Move to the next tab stop, but preserve auto-wrap if already set.
if !h.wrapNext { if !h.wrapNext {
@ -205,11 +206,11 @@ func (h *WindowsAnsiEventHandler) Execute(b byte) error {
} }
return nil return nil
case ANSI_BEL: case ansiterm.ANSI_BEL:
h.buffer.WriteByte(ANSI_BEL) h.buffer.WriteByte(ansiterm.ANSI_BEL)
return nil return nil
case ANSI_BACKSPACE: case ansiterm.ANSI_BACKSPACE:
if h.wrapNext { if h.wrapNext {
if err := h.Flush(); err != nil { if err := h.Flush(); err != nil {
return err return err
@ -223,15 +224,15 @@ func (h *WindowsAnsiEventHandler) Execute(b byte) error {
if pos.X > 0 { if pos.X > 0 {
pos.X-- pos.X--
h.updatePos(pos) h.updatePos(pos)
h.buffer.WriteByte(ANSI_BACKSPACE) h.buffer.WriteByte(ansiterm.ANSI_BACKSPACE)
} }
return nil return nil
case ANSI_VERTICAL_TAB, ANSI_FORM_FEED: case ansiterm.ANSI_VERTICAL_TAB, ansiterm.ANSI_FORM_FEED:
// Treat as true LF. // Treat as true LF.
return h.executeLF() return h.executeLF()
case ANSI_LINE_FEED: case ansiterm.ANSI_LINE_FEED:
// Simulate a CR and LF for now since there is no way in go-ansiterm // Simulate a CR and LF for now since there is no way in go-ansiterm
// to tell if the LF should include CR (and more things break when it's // to tell if the LF should include CR (and more things break when it's
// missing than when it's incorrectly added). // missing than when it's incorrectly added).
@ -239,9 +240,9 @@ func (h *WindowsAnsiEventHandler) Execute(b byte) error {
if handled || err != nil { if handled || err != nil {
return err return err
} }
return h.buffer.WriteByte(ANSI_LINE_FEED) return h.buffer.WriteByte(ansiterm.ANSI_LINE_FEED)
case ANSI_CARRIAGE_RETURN: case ansiterm.ANSI_CARRIAGE_RETURN:
if h.wrapNext { if h.wrapNext {
if err := h.Flush(); err != nil { if err := h.Flush(); err != nil {
return err return err
@ -255,7 +256,7 @@ func (h *WindowsAnsiEventHandler) Execute(b byte) error {
if pos.X != 0 { if pos.X != 0 {
pos.X = 0 pos.X = 0
h.updatePos(pos) h.updatePos(pos)
h.buffer.WriteByte(ANSI_CARRIAGE_RETURN) h.buffer.WriteByte(ansiterm.ANSI_CARRIAGE_RETURN)
} }
return nil return nil
@ -264,7 +265,7 @@ func (h *WindowsAnsiEventHandler) Execute(b byte) error {
} }
} }
func (h *WindowsAnsiEventHandler) CUU(param int) error { func (h *windowsAnsiEventHandler) CUU(param int) error {
if err := h.Flush(); err != nil { if err := h.Flush(); err != nil {
return err return err
} }
@ -273,7 +274,7 @@ func (h *WindowsAnsiEventHandler) CUU(param int) error {
return h.moveCursorVertical(-param) return h.moveCursorVertical(-param)
} }
func (h *WindowsAnsiEventHandler) CUD(param int) error { func (h *windowsAnsiEventHandler) CUD(param int) error {
if err := h.Flush(); err != nil { if err := h.Flush(); err != nil {
return err return err
} }
@ -282,7 +283,7 @@ func (h *WindowsAnsiEventHandler) CUD(param int) error {
return h.moveCursorVertical(param) return h.moveCursorVertical(param)
} }
func (h *WindowsAnsiEventHandler) CUF(param int) error { func (h *windowsAnsiEventHandler) CUF(param int) error {
if err := h.Flush(); err != nil { if err := h.Flush(); err != nil {
return err return err
} }
@ -291,7 +292,7 @@ func (h *WindowsAnsiEventHandler) CUF(param int) error {
return h.moveCursorHorizontal(param) return h.moveCursorHorizontal(param)
} }
func (h *WindowsAnsiEventHandler) CUB(param int) error { func (h *windowsAnsiEventHandler) CUB(param int) error {
if err := h.Flush(); err != nil { if err := h.Flush(); err != nil {
return err return err
} }
@ -300,7 +301,7 @@ func (h *WindowsAnsiEventHandler) CUB(param int) error {
return h.moveCursorHorizontal(-param) return h.moveCursorHorizontal(-param)
} }
func (h *WindowsAnsiEventHandler) CNL(param int) error { func (h *windowsAnsiEventHandler) CNL(param int) error {
if err := h.Flush(); err != nil { if err := h.Flush(); err != nil {
return err return err
} }
@ -309,7 +310,7 @@ func (h *WindowsAnsiEventHandler) CNL(param int) error {
return h.moveCursorLine(param) return h.moveCursorLine(param)
} }
func (h *WindowsAnsiEventHandler) CPL(param int) error { func (h *windowsAnsiEventHandler) CPL(param int) error {
if err := h.Flush(); err != nil { if err := h.Flush(); err != nil {
return err return err
} }
@ -318,7 +319,7 @@ func (h *WindowsAnsiEventHandler) CPL(param int) error {
return h.moveCursorLine(-param) return h.moveCursorLine(-param)
} }
func (h *WindowsAnsiEventHandler) CHA(param int) error { func (h *windowsAnsiEventHandler) CHA(param int) error {
if err := h.Flush(); err != nil { if err := h.Flush(); err != nil {
return err return err
} }
@ -327,7 +328,7 @@ func (h *WindowsAnsiEventHandler) CHA(param int) error {
return h.moveCursorColumn(param) return h.moveCursorColumn(param)
} }
func (h *WindowsAnsiEventHandler) VPA(param int) error { func (h *windowsAnsiEventHandler) VPA(param int) error {
if err := h.Flush(); err != nil { if err := h.Flush(); err != nil {
return err return err
} }
@ -339,11 +340,11 @@ func (h *WindowsAnsiEventHandler) VPA(param int) error {
} }
window := h.getCursorWindow(info) window := h.getCursorWindow(info)
position := info.CursorPosition position := info.CursorPosition
position.Y = window.Top + SHORT(param) - 1 position.Y = window.Top + int16(param) - 1
return h.setCursorPosition(position, window) return h.setCursorPosition(position, window)
} }
func (h *WindowsAnsiEventHandler) CUP(row int, col int) error { func (h *windowsAnsiEventHandler) CUP(row int, col int) error {
if err := h.Flush(); err != nil { if err := h.Flush(); err != nil {
return err return err
} }
@ -355,11 +356,11 @@ func (h *WindowsAnsiEventHandler) CUP(row int, col int) error {
} }
window := h.getCursorWindow(info) window := h.getCursorWindow(info)
position := COORD{window.Left + SHORT(col) - 1, window.Top + SHORT(row) - 1} position := COORD{window.Left + int16(col) - 1, window.Top + int16(row) - 1}
return h.setCursorPosition(position, window) return h.setCursorPosition(position, window)
} }
func (h *WindowsAnsiEventHandler) HVP(row int, col int) error { func (h *windowsAnsiEventHandler) HVP(row int, col int) error {
if err := h.Flush(); err != nil { if err := h.Flush(); err != nil {
return err return err
} }
@ -368,7 +369,7 @@ func (h *WindowsAnsiEventHandler) HVP(row int, col int) error {
return h.CUP(row, col) return h.CUP(row, col)
} }
func (h *WindowsAnsiEventHandler) DECTCEM(visible bool) error { func (h *windowsAnsiEventHandler) DECTCEM(visible bool) error {
if err := h.Flush(); err != nil { if err := h.Flush(); err != nil {
return err return err
} }
@ -377,7 +378,7 @@ func (h *WindowsAnsiEventHandler) DECTCEM(visible bool) error {
return nil return nil
} }
func (h *WindowsAnsiEventHandler) DECOM(enable bool) error { func (h *windowsAnsiEventHandler) DECOM(enable bool) error {
if err := h.Flush(); err != nil { if err := h.Flush(); err != nil {
return err return err
} }
@ -387,7 +388,7 @@ func (h *WindowsAnsiEventHandler) DECOM(enable bool) error {
return h.CUP(1, 1) return h.CUP(1, 1)
} }
func (h *WindowsAnsiEventHandler) DECCOLM(use132 bool) error { func (h *windowsAnsiEventHandler) DECCOLM(use132 bool) error {
if err := h.Flush(); err != nil { if err := h.Flush(); err != nil {
return err return err
} }
@ -400,7 +401,7 @@ func (h *WindowsAnsiEventHandler) DECCOLM(use132 bool) error {
if err != nil { if err != nil {
return err return err
} }
targetWidth := SHORT(80) targetWidth := int16(80)
if use132 { if use132 {
targetWidth = 132 targetWidth = 132
} }
@ -426,7 +427,7 @@ func (h *WindowsAnsiEventHandler) DECCOLM(use132 bool) error {
return SetConsoleCursorPosition(h.fd, COORD{0, 0}) return SetConsoleCursorPosition(h.fd, COORD{0, 0})
} }
func (h *WindowsAnsiEventHandler) ED(param int) error { func (h *windowsAnsiEventHandler) ED(param int) error {
if err := h.Flush(); err != nil { if err := h.Flush(); err != nil {
return err return err
} }
@ -485,7 +486,7 @@ func (h *WindowsAnsiEventHandler) ED(param int) error {
return nil return nil
} }
func (h *WindowsAnsiEventHandler) EL(param int) error { func (h *windowsAnsiEventHandler) EL(param int) error {
if err := h.Flush(); err != nil { if err := h.Flush(); err != nil {
return err return err
} }
@ -526,7 +527,7 @@ func (h *WindowsAnsiEventHandler) EL(param int) error {
return nil return nil
} }
func (h *WindowsAnsiEventHandler) IL(param int) error { func (h *windowsAnsiEventHandler) IL(param int) error {
if err := h.Flush(); err != nil { if err := h.Flush(); err != nil {
return err return err
} }
@ -535,7 +536,7 @@ func (h *WindowsAnsiEventHandler) IL(param int) error {
return h.insertLines(param) return h.insertLines(param)
} }
func (h *WindowsAnsiEventHandler) DL(param int) error { func (h *windowsAnsiEventHandler) DL(param int) error {
if err := h.Flush(); err != nil { if err := h.Flush(); err != nil {
return err return err
} }
@ -544,7 +545,7 @@ func (h *WindowsAnsiEventHandler) DL(param int) error {
return h.deleteLines(param) return h.deleteLines(param)
} }
func (h *WindowsAnsiEventHandler) ICH(param int) error { func (h *windowsAnsiEventHandler) ICH(param int) error {
if err := h.Flush(); err != nil { if err := h.Flush(); err != nil {
return err return err
} }
@ -553,7 +554,7 @@ func (h *WindowsAnsiEventHandler) ICH(param int) error {
return h.insertCharacters(param) return h.insertCharacters(param)
} }
func (h *WindowsAnsiEventHandler) DCH(param int) error { func (h *windowsAnsiEventHandler) DCH(param int) error {
if err := h.Flush(); err != nil { if err := h.Flush(); err != nil {
return err return err
} }
@ -562,7 +563,7 @@ func (h *WindowsAnsiEventHandler) DCH(param int) error {
return h.deleteCharacters(param) return h.deleteCharacters(param)
} }
func (h *WindowsAnsiEventHandler) SGR(params []int) error { func (h *windowsAnsiEventHandler) SGR(params []int) error {
if err := h.Flush(); err != nil { if err := h.Flush(); err != nil {
return err return err
} }
@ -579,13 +580,13 @@ func (h *WindowsAnsiEventHandler) SGR(params []int) error {
} else { } else {
for _, attr := range params { for _, attr := range params {
if attr == ANSI_SGR_RESET { if attr == ansiterm.ANSI_SGR_RESET {
h.attributes = h.infoReset.Attributes h.attributes = h.infoReset.Attributes
h.inverted = false h.inverted = false
continue continue
} }
h.attributes, h.inverted = collectAnsiIntoWindowsAttributes(h.attributes, h.inverted, h.infoReset.Attributes, SHORT(attr)) h.attributes, h.inverted = collectAnsiIntoWindowsAttributes(h.attributes, h.inverted, h.infoReset.Attributes, int16(attr))
} }
} }
@ -601,7 +602,7 @@ func (h *WindowsAnsiEventHandler) SGR(params []int) error {
return nil return nil
} }
func (h *WindowsAnsiEventHandler) SU(param int) error { func (h *windowsAnsiEventHandler) SU(param int) error {
if err := h.Flush(); err != nil { if err := h.Flush(); err != nil {
return err return err
} }
@ -610,7 +611,7 @@ func (h *WindowsAnsiEventHandler) SU(param int) error {
return h.scrollUp(param) return h.scrollUp(param)
} }
func (h *WindowsAnsiEventHandler) SD(param int) error { func (h *windowsAnsiEventHandler) SD(param int) error {
if err := h.Flush(); err != nil { if err := h.Flush(); err != nil {
return err return err
} }
@ -619,29 +620,29 @@ func (h *WindowsAnsiEventHandler) SD(param int) error {
return h.scrollDown(param) return h.scrollDown(param)
} }
func (h *WindowsAnsiEventHandler) DA(params []string) error { func (h *windowsAnsiEventHandler) DA(params []string) error {
logger.Infof("DA: [%v]", params) logger.Infof("DA: [%v]", params)
// DA cannot be implemented because it must send data on the VT100 input stream, // DA cannot be implemented because it must send data on the VT100 input stream,
// which is not available to go-ansiterm. // which is not available to go-ansiterm.
return nil return nil
} }
func (h *WindowsAnsiEventHandler) DECSTBM(top int, bottom int) error { func (h *windowsAnsiEventHandler) DECSTBM(top int, bottom int) error {
if err := h.Flush(); err != nil { if err := h.Flush(); err != nil {
return err return err
} }
logger.Infof("DECSTBM: [%d, %d]", top, bottom) logger.Infof("DECSTBM: [%d, %d]", top, bottom)
// Windows is 0 indexed, Linux is 1 indexed // Windows is 0 indexed, Linux is 1 indexed
h.sr.top = SHORT(top - 1) h.sr.top = int16(top - 1)
h.sr.bottom = SHORT(bottom - 1) h.sr.bottom = int16(bottom - 1)
// This command also moves the cursor to the origin. // This command also moves the cursor to the origin.
h.clearWrap() h.clearWrap()
return h.CUP(1, 1) return h.CUP(1, 1)
} }
func (h *WindowsAnsiEventHandler) RI() error { func (h *windowsAnsiEventHandler) RI() error {
if err := h.Flush(); err != nil { if err := h.Flush(); err != nil {
return err return err
} }
@ -656,17 +657,17 @@ func (h *WindowsAnsiEventHandler) RI() error {
sr := h.effectiveSr(info.Window) sr := h.effectiveSr(info.Window)
if info.CursorPosition.Y == sr.top { if info.CursorPosition.Y == sr.top {
return h.scrollDown(1) return h.scrollDown(1)
} else {
return h.moveCursorVertical(-1)
} }
return h.moveCursorVertical(-1)
} }
func (h *WindowsAnsiEventHandler) IND() error { func (h *windowsAnsiEventHandler) IND() error {
logger.Info("IND: []") logger.Info("IND: []")
return h.executeLF() return h.executeLF()
} }
func (h *WindowsAnsiEventHandler) Flush() error { func (h *windowsAnsiEventHandler) Flush() error {
h.curInfo = nil h.curInfo = nil
if h.buffer.Len() > 0 { if h.buffer.Len() > 0 {
logger.Infof("Flush: [%s]", h.buffer.Bytes()) logger.Infof("Flush: [%s]", h.buffer.Bytes())
@ -683,7 +684,7 @@ func (h *WindowsAnsiEventHandler) Flush() error {
return err return err
} }
charInfo := []CHAR_INFO{{UnicodeChar: WCHAR(h.marginByte), Attributes: info.Attributes}} charInfo := []CHAR_INFO{{UnicodeChar: uint16(h.marginByte), Attributes: info.Attributes}}
size := COORD{1, 1} size := COORD{1, 1}
position := COORD{0, 0} position := COORD{0, 0}
region := SMALL_RECT{Left: info.CursorPosition.X, Top: info.CursorPosition.Y, Right: info.CursorPosition.X, Bottom: info.CursorPosition.Y} region := SMALL_RECT{Left: info.CursorPosition.X, Top: info.CursorPosition.Y, Right: info.CursorPosition.X, Bottom: info.CursorPosition.Y}
@ -697,7 +698,7 @@ func (h *WindowsAnsiEventHandler) Flush() error {
// cacheConsoleInfo ensures that the current console screen information has been queried // cacheConsoleInfo ensures that the current console screen information has been queried
// since the last call to Flush(). It must be called before accessing h.curInfo or h.curPos. // since the last call to Flush(). It must be called before accessing h.curInfo or h.curPos.
func (h *WindowsAnsiEventHandler) getCurrentInfo() (COORD, *CONSOLE_SCREEN_BUFFER_INFO, error) { func (h *windowsAnsiEventHandler) getCurrentInfo() (COORD, *CONSOLE_SCREEN_BUFFER_INFO, error) {
if h.curInfo == nil { if h.curInfo == nil {
info, err := GetConsoleScreenBufferInfo(h.fd) info, err := GetConsoleScreenBufferInfo(h.fd)
if err != nil { if err != nil {
@ -709,7 +710,7 @@ func (h *WindowsAnsiEventHandler) getCurrentInfo() (COORD, *CONSOLE_SCREEN_BUFFE
return h.curPos, h.curInfo, nil return h.curPos, h.curInfo, nil
} }
func (h *WindowsAnsiEventHandler) updatePos(pos COORD) { func (h *windowsAnsiEventHandler) updatePos(pos COORD) {
if h.curInfo == nil { if h.curInfo == nil {
panic("failed to call getCurrentInfo before calling updatePos") panic("failed to call getCurrentInfo before calling updatePos")
} }
@ -719,7 +720,7 @@ func (h *WindowsAnsiEventHandler) updatePos(pos COORD) {
// clearWrap clears the state where the cursor is in the margin // clearWrap clears the state where the cursor is in the margin
// waiting for the next character before wrapping the line. This must // waiting for the next character before wrapping the line. This must
// be done before most operations that act on the cursor. // be done before most operations that act on the cursor.
func (h *WindowsAnsiEventHandler) clearWrap() { func (h *windowsAnsiEventHandler) clearWrap() {
h.wrapNext = false h.wrapNext = false
h.drewMarginByte = false h.drewMarginByte = false
} }