Merge pull request #48 from kadel/fix-win-build

Fix failing windows build
This commit is contained in:
Tuna 2016-07-22 01:34:28 +07:00 committed by GitHub
commit 713aadff8f
35 changed files with 333 additions and 2105 deletions

13
Godeps/Godeps.json generated
View File

@ -8,11 +8,11 @@
"Deps": [ "Deps": [
{ {
"ImportPath": "github.com/Azure/go-ansiterm", "ImportPath": "github.com/Azure/go-ansiterm",
"Rev": "70b2c90b260171e829f1ebd7c17f600c11858dbe" "Rev": "388960b655244e76e24c75f48631564eaefade62"
}, },
{ {
"ImportPath": "github.com/Azure/go-ansiterm/winterm", "ImportPath": "github.com/Azure/go-ansiterm/winterm",
"Rev": "70b2c90b260171e829f1ebd7c17f600c11858dbe" "Rev": "388960b655244e76e24c75f48631564eaefade62"
}, },
{ {
"ImportPath": "github.com/Microsoft/go-winio", "ImportPath": "github.com/Microsoft/go-winio",
@ -407,11 +407,6 @@
"Comment": "v0.1.0-21-g0bbddae", "Comment": "v0.1.0-21-g0bbddae",
"Rev": "0bbddae09c5a5419a8c6dcdd7ff90da3d450393b" "Rev": "0bbddae09c5a5419a8c6dcdd7ff90da3d450393b"
}, },
{
"ImportPath": "github.com/docker/libcompose/cli/logger",
"Comment": "v0.2.0-186-ga12288b",
"Rev": "a12288bd636066e330b5d39197737cd04882d164"
},
{ {
"ImportPath": "github.com/docker/libcompose/config", "ImportPath": "github.com/docker/libcompose/config",
"Comment": "v0.2.0-186-ga12288b", "Comment": "v0.2.0-186-ga12288b",
@ -588,10 +583,6 @@
"ImportPath": "github.com/xeipuuv/gojsonschema", "ImportPath": "github.com/xeipuuv/gojsonschema",
"Rev": "ac452913faa25c08bb78810d3e6f88b8a39f8f25" "Rev": "ac452913faa25c08bb78810d3e6f88b8a39f8f25"
}, },
{
"ImportPath": "golang.org/x/crypto/ssh/terminal",
"Rev": "c84e1f8e3a7e322d497cd16c0e8a13c7e127baf3"
},
{ {
"ImportPath": "golang.org/x/net/context", "ImportPath": "golang.org/x/net/context",
"Rev": "62685c2d7ca23c807425dca88b11a3e2323dab41" "Rev": "62685c2d7ca23c807425dca88b11a3e2323dab41"

View File

@ -19,5 +19,6 @@ rm -f kompose*
# Build binaries # Build binaries
gox "${OS_PLATFORM_ARG[@]}" "${OS_ARCH_ARG[@]}" \ gox "${OS_PLATFORM_ARG[@]}" "${OS_ARCH_ARG[@]}" \
-output="bundles/kompose_{{.OS}}-{{.Arch}}/kompose" \ -output="bundles/kompose_{{.OS}}-{{.Arch}}/kompose" \
-tags experimental \
./cli/main ./cli/main

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,7 +89,8 @@ 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 // A custom scroll region is active. Scroll the window manually to simulate
// the LF. // the LF.
if err := h.Flush(); err != nil { if err := h.Flush(); err != nil {
@ -106,7 +107,7 @@ func (h *WindowsAnsiEventHandler) simulateLF(includeCR bool) (bool, error) {
} }
} }
return true, nil 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
} }

View File

@ -1,3 +1,5 @@
// +build experimental
package bundlefile package bundlefile
import ( import (

View File

@ -1,102 +0,0 @@
package logger
import (
"fmt"
"io"
"os"
"strconv"
"github.com/docker/libcompose/logger"
"golang.org/x/crypto/ssh/terminal"
)
// ColorLoggerFactory implements logger.Factory interface using ColorLogger.
type ColorLoggerFactory struct {
maxLength int
tty bool
}
// ColorLogger implements logger.Logger interface with color support.
type ColorLogger struct {
name string
colorPrefix string
factory *ColorLoggerFactory
}
// NewColorLoggerFactory creates a new ColorLoggerFactory.
func NewColorLoggerFactory() *ColorLoggerFactory {
return &ColorLoggerFactory{
tty: terminal.IsTerminal(int(os.Stdout.Fd())),
}
}
// CreateContainerLogger implements logger.Factory.CreateContainerLogger.
func (c *ColorLoggerFactory) CreateContainerLogger(name string) logger.Logger {
return c.create(name)
}
// CreateBuildLogger implements logger.Factory.CreateBuildLogger.
func (c *ColorLoggerFactory) CreateBuildLogger(name string) logger.Logger {
return &logger.RawLogger{}
}
// CreatePullLogger implements logger.Factory.CreatePullLogger.
func (c *ColorLoggerFactory) CreatePullLogger(name string) logger.Logger {
return &logger.NullLogger{}
}
// CreateBuildLogger implements logger.Factory.CreateContainerLogger.
func (c *ColorLoggerFactory) create(name string) logger.Logger {
if c.maxLength < len(name) {
c.maxLength = len(name)
}
return &ColorLogger{
name: name,
factory: c,
colorPrefix: <-colorPrefix,
}
}
// Out implements logger.Logger.Out.
func (c *ColorLogger) Out(bytes []byte) {
if len(bytes) == 0 {
return
}
logFmt, name := c.getLogFmt()
message := fmt.Sprintf(logFmt, name, string(bytes))
fmt.Print(message)
}
// Err implements logger.Logger.Err.
func (c *ColorLogger) Err(bytes []byte) {
if len(bytes) == 0 {
return
}
logFmt, name := c.getLogFmt()
message := fmt.Sprintf(logFmt, name, string(bytes))
fmt.Fprint(os.Stderr, message)
}
// OutWriter returns the base writer
func (c *ColorLogger) OutWriter() io.Writer {
return os.Stdout
}
// ErrWriter returns the base writer
func (c *ColorLogger) ErrWriter() io.Writer {
return os.Stderr
}
func (c *ColorLogger) getLogFmt() (string, string) {
pad := c.factory.maxLength
logFmt := "%s | %s"
if c.factory.tty {
logFmt = c.colorPrefix + " %s"
}
name := fmt.Sprintf("%-"+strconv.Itoa(pad)+"s", c.name)
return logFmt, name
}

View File

@ -1,34 +0,0 @@
package logger
import "fmt"
var (
colorPrefix = make(chan string)
)
func generateColors() {
i := 0
colorOrder := []string{
"36", // cyan
"33", // yellow
"32", // green
"35", // magenta
"31", // red
"34", // blue
"36;1", // intense cyan
"33;1", // intense yellow
"32;1", // intense green
"35;1", // intense magenta
"31;1", // intense red
"34;1", // intense blue
}
for {
colorPrefix <- fmt.Sprintf("\033[%sm%%s |\033[0m", colorOrder[i])
i = (i + 1) % len(colorOrder)
}
}
func init() {
go generateColors()
}

27
vendor/golang.org/x/crypto/LICENSE generated vendored
View File

@ -1,27 +0,0 @@
Copyright (c) 2009 The Go Authors. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the following disclaimer
in the documentation and/or other materials provided with the
distribution.
* Neither the name of Google Inc. nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

22
vendor/golang.org/x/crypto/PATENTS generated vendored
View File

@ -1,22 +0,0 @@
Additional IP Rights Grant (Patents)
"This implementation" means the copyrightable works distributed by
Google as part of the Go project.
Google hereby grants to You a perpetual, worldwide, non-exclusive,
no-charge, royalty-free, irrevocable (except as stated in this section)
patent license to make, have made, use, offer to sell, sell, import,
transfer and otherwise run, modify and propagate the contents of this
implementation of Go, where such license applies only to those patent
claims, both currently owned or controlled by Google and acquired in
the future, licensable by Google that are necessarily infringed by this
implementation of Go. This grant does not include claims that would be
infringed only as a consequence of further modification of this
implementation. If you or your agent or exclusive licensee institute or
order or agree to the institution of patent litigation against any
entity (including a cross-claim or counterclaim in a lawsuit) alleging
that this implementation of Go or any code incorporated within this
implementation of Go constitutes direct or contributory patent
infringement, or inducement of patent infringement, then any patent
rights granted to you under this License for this implementation of Go
shall terminate as of the date such litigation is filed.

View File

@ -1,892 +0,0 @@
// Copyright 2011 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package terminal
import (
"bytes"
"io"
"sync"
"unicode/utf8"
)
// EscapeCodes contains escape sequences that can be written to the terminal in
// order to achieve different styles of text.
type EscapeCodes struct {
// Foreground colors
Black, Red, Green, Yellow, Blue, Magenta, Cyan, White []byte
// Reset all attributes
Reset []byte
}
var vt100EscapeCodes = EscapeCodes{
Black: []byte{keyEscape, '[', '3', '0', 'm'},
Red: []byte{keyEscape, '[', '3', '1', 'm'},
Green: []byte{keyEscape, '[', '3', '2', 'm'},
Yellow: []byte{keyEscape, '[', '3', '3', 'm'},
Blue: []byte{keyEscape, '[', '3', '4', 'm'},
Magenta: []byte{keyEscape, '[', '3', '5', 'm'},
Cyan: []byte{keyEscape, '[', '3', '6', 'm'},
White: []byte{keyEscape, '[', '3', '7', 'm'},
Reset: []byte{keyEscape, '[', '0', 'm'},
}
// Terminal contains the state for running a VT100 terminal that is capable of
// reading lines of input.
type Terminal struct {
// AutoCompleteCallback, if non-null, is called for each keypress with
// the full input line and the current position of the cursor (in
// bytes, as an index into |line|). If it returns ok=false, the key
// press is processed normally. Otherwise it returns a replacement line
// and the new cursor position.
AutoCompleteCallback func(line string, pos int, key rune) (newLine string, newPos int, ok bool)
// Escape contains a pointer to the escape codes for this terminal.
// It's always a valid pointer, although the escape codes themselves
// may be empty if the terminal doesn't support them.
Escape *EscapeCodes
// lock protects the terminal and the state in this object from
// concurrent processing of a key press and a Write() call.
lock sync.Mutex
c io.ReadWriter
prompt []rune
// line is the current line being entered.
line []rune
// pos is the logical position of the cursor in line
pos int
// echo is true if local echo is enabled
echo bool
// pasteActive is true iff there is a bracketed paste operation in
// progress.
pasteActive bool
// cursorX contains the current X value of the cursor where the left
// edge is 0. cursorY contains the row number where the first row of
// the current line is 0.
cursorX, cursorY int
// maxLine is the greatest value of cursorY so far.
maxLine int
termWidth, termHeight int
// outBuf contains the terminal data to be sent.
outBuf []byte
// remainder contains the remainder of any partial key sequences after
// a read. It aliases into inBuf.
remainder []byte
inBuf [256]byte
// history contains previously entered commands so that they can be
// accessed with the up and down keys.
history stRingBuffer
// historyIndex stores the currently accessed history entry, where zero
// means the immediately previous entry.
historyIndex int
// When navigating up and down the history it's possible to return to
// the incomplete, initial line. That value is stored in
// historyPending.
historyPending string
}
// NewTerminal runs a VT100 terminal on the given ReadWriter. If the ReadWriter is
// a local terminal, that terminal must first have been put into raw mode.
// prompt is a string that is written at the start of each input line (i.e.
// "> ").
func NewTerminal(c io.ReadWriter, prompt string) *Terminal {
return &Terminal{
Escape: &vt100EscapeCodes,
c: c,
prompt: []rune(prompt),
termWidth: 80,
termHeight: 24,
echo: true,
historyIndex: -1,
}
}
const (
keyCtrlD = 4
keyCtrlU = 21
keyEnter = '\r'
keyEscape = 27
keyBackspace = 127
keyUnknown = 0xd800 /* UTF-16 surrogate area */ + iota
keyUp
keyDown
keyLeft
keyRight
keyAltLeft
keyAltRight
keyHome
keyEnd
keyDeleteWord
keyDeleteLine
keyClearScreen
keyPasteStart
keyPasteEnd
)
var pasteStart = []byte{keyEscape, '[', '2', '0', '0', '~'}
var pasteEnd = []byte{keyEscape, '[', '2', '0', '1', '~'}
// bytesToKey tries to parse a key sequence from b. If successful, it returns
// the key and the remainder of the input. Otherwise it returns utf8.RuneError.
func bytesToKey(b []byte, pasteActive bool) (rune, []byte) {
if len(b) == 0 {
return utf8.RuneError, nil
}
if !pasteActive {
switch b[0] {
case 1: // ^A
return keyHome, b[1:]
case 5: // ^E
return keyEnd, b[1:]
case 8: // ^H
return keyBackspace, b[1:]
case 11: // ^K
return keyDeleteLine, b[1:]
case 12: // ^L
return keyClearScreen, b[1:]
case 23: // ^W
return keyDeleteWord, b[1:]
}
}
if b[0] != keyEscape {
if !utf8.FullRune(b) {
return utf8.RuneError, b
}
r, l := utf8.DecodeRune(b)
return r, b[l:]
}
if !pasteActive && len(b) >= 3 && b[0] == keyEscape && b[1] == '[' {
switch b[2] {
case 'A':
return keyUp, b[3:]
case 'B':
return keyDown, b[3:]
case 'C':
return keyRight, b[3:]
case 'D':
return keyLeft, b[3:]
case 'H':
return keyHome, b[3:]
case 'F':
return keyEnd, b[3:]
}
}
if !pasteActive && len(b) >= 6 && b[0] == keyEscape && b[1] == '[' && b[2] == '1' && b[3] == ';' && b[4] == '3' {
switch b[5] {
case 'C':
return keyAltRight, b[6:]
case 'D':
return keyAltLeft, b[6:]
}
}
if !pasteActive && len(b) >= 6 && bytes.Equal(b[:6], pasteStart) {
return keyPasteStart, b[6:]
}
if pasteActive && len(b) >= 6 && bytes.Equal(b[:6], pasteEnd) {
return keyPasteEnd, b[6:]
}
// If we get here then we have a key that we don't recognise, or a
// partial sequence. It's not clear how one should find the end of a
// sequence without knowing them all, but it seems that [a-zA-Z~] only
// appears at the end of a sequence.
for i, c := range b[0:] {
if c >= 'a' && c <= 'z' || c >= 'A' && c <= 'Z' || c == '~' {
return keyUnknown, b[i+1:]
}
}
return utf8.RuneError, b
}
// queue appends data to the end of t.outBuf
func (t *Terminal) queue(data []rune) {
t.outBuf = append(t.outBuf, []byte(string(data))...)
}
var eraseUnderCursor = []rune{' ', keyEscape, '[', 'D'}
var space = []rune{' '}
func isPrintable(key rune) bool {
isInSurrogateArea := key >= 0xd800 && key <= 0xdbff
return key >= 32 && !isInSurrogateArea
}
// moveCursorToPos appends data to t.outBuf which will move the cursor to the
// given, logical position in the text.
func (t *Terminal) moveCursorToPos(pos int) {
if !t.echo {
return
}
x := visualLength(t.prompt) + pos
y := x / t.termWidth
x = x % t.termWidth
up := 0
if y < t.cursorY {
up = t.cursorY - y
}
down := 0
if y > t.cursorY {
down = y - t.cursorY
}
left := 0
if x < t.cursorX {
left = t.cursorX - x
}
right := 0
if x > t.cursorX {
right = x - t.cursorX
}
t.cursorX = x
t.cursorY = y
t.move(up, down, left, right)
}
func (t *Terminal) move(up, down, left, right int) {
movement := make([]rune, 3*(up+down+left+right))
m := movement
for i := 0; i < up; i++ {
m[0] = keyEscape
m[1] = '['
m[2] = 'A'
m = m[3:]
}
for i := 0; i < down; i++ {
m[0] = keyEscape
m[1] = '['
m[2] = 'B'
m = m[3:]
}
for i := 0; i < left; i++ {
m[0] = keyEscape
m[1] = '['
m[2] = 'D'
m = m[3:]
}
for i := 0; i < right; i++ {
m[0] = keyEscape
m[1] = '['
m[2] = 'C'
m = m[3:]
}
t.queue(movement)
}
func (t *Terminal) clearLineToRight() {
op := []rune{keyEscape, '[', 'K'}
t.queue(op)
}
const maxLineLength = 4096
func (t *Terminal) setLine(newLine []rune, newPos int) {
if t.echo {
t.moveCursorToPos(0)
t.writeLine(newLine)
for i := len(newLine); i < len(t.line); i++ {
t.writeLine(space)
}
t.moveCursorToPos(newPos)
}
t.line = newLine
t.pos = newPos
}
func (t *Terminal) advanceCursor(places int) {
t.cursorX += places
t.cursorY += t.cursorX / t.termWidth
if t.cursorY > t.maxLine {
t.maxLine = t.cursorY
}
t.cursorX = t.cursorX % t.termWidth
if places > 0 && t.cursorX == 0 {
// Normally terminals will advance the current position
// when writing a character. But that doesn't happen
// for the last character in a line. However, when
// writing a character (except a new line) that causes
// a line wrap, the position will be advanced two
// places.
//
// So, if we are stopping at the end of a line, we
// need to write a newline so that our cursor can be
// advanced to the next line.
t.outBuf = append(t.outBuf, '\n')
}
}
func (t *Terminal) eraseNPreviousChars(n int) {
if n == 0 {
return
}
if t.pos < n {
n = t.pos
}
t.pos -= n
t.moveCursorToPos(t.pos)
copy(t.line[t.pos:], t.line[n+t.pos:])
t.line = t.line[:len(t.line)-n]
if t.echo {
t.writeLine(t.line[t.pos:])
for i := 0; i < n; i++ {
t.queue(space)
}
t.advanceCursor(n)
t.moveCursorToPos(t.pos)
}
}
// countToLeftWord returns then number of characters from the cursor to the
// start of the previous word.
func (t *Terminal) countToLeftWord() int {
if t.pos == 0 {
return 0
}
pos := t.pos - 1
for pos > 0 {
if t.line[pos] != ' ' {
break
}
pos--
}
for pos > 0 {
if t.line[pos] == ' ' {
pos++
break
}
pos--
}
return t.pos - pos
}
// countToRightWord returns then number of characters from the cursor to the
// start of the next word.
func (t *Terminal) countToRightWord() int {
pos := t.pos
for pos < len(t.line) {
if t.line[pos] == ' ' {
break
}
pos++
}
for pos < len(t.line) {
if t.line[pos] != ' ' {
break
}
pos++
}
return pos - t.pos
}
// visualLength returns the number of visible glyphs in s.
func visualLength(runes []rune) int {
inEscapeSeq := false
length := 0
for _, r := range runes {
switch {
case inEscapeSeq:
if (r >= 'a' && r <= 'z') || (r >= 'A' && r <= 'Z') {
inEscapeSeq = false
}
case r == '\x1b':
inEscapeSeq = true
default:
length++
}
}
return length
}
// handleKey processes the given key and, optionally, returns a line of text
// that the user has entered.
func (t *Terminal) handleKey(key rune) (line string, ok bool) {
if t.pasteActive && key != keyEnter {
t.addKeyToLine(key)
return
}
switch key {
case keyBackspace:
if t.pos == 0 {
return
}
t.eraseNPreviousChars(1)
case keyAltLeft:
// move left by a word.
t.pos -= t.countToLeftWord()
t.moveCursorToPos(t.pos)
case keyAltRight:
// move right by a word.
t.pos += t.countToRightWord()
t.moveCursorToPos(t.pos)
case keyLeft:
if t.pos == 0 {
return
}
t.pos--
t.moveCursorToPos(t.pos)
case keyRight:
if t.pos == len(t.line) {
return
}
t.pos++
t.moveCursorToPos(t.pos)
case keyHome:
if t.pos == 0 {
return
}
t.pos = 0
t.moveCursorToPos(t.pos)
case keyEnd:
if t.pos == len(t.line) {
return
}
t.pos = len(t.line)
t.moveCursorToPos(t.pos)
case keyUp:
entry, ok := t.history.NthPreviousEntry(t.historyIndex + 1)
if !ok {
return "", false
}
if t.historyIndex == -1 {
t.historyPending = string(t.line)
}
t.historyIndex++
runes := []rune(entry)
t.setLine(runes, len(runes))
case keyDown:
switch t.historyIndex {
case -1:
return
case 0:
runes := []rune(t.historyPending)
t.setLine(runes, len(runes))
t.historyIndex--
default:
entry, ok := t.history.NthPreviousEntry(t.historyIndex - 1)
if ok {
t.historyIndex--
runes := []rune(entry)
t.setLine(runes, len(runes))
}
}
case keyEnter:
t.moveCursorToPos(len(t.line))
t.queue([]rune("\r\n"))
line = string(t.line)
ok = true
t.line = t.line[:0]
t.pos = 0
t.cursorX = 0
t.cursorY = 0
t.maxLine = 0
case keyDeleteWord:
// Delete zero or more spaces and then one or more characters.
t.eraseNPreviousChars(t.countToLeftWord())
case keyDeleteLine:
// Delete everything from the current cursor position to the
// end of line.
for i := t.pos; i < len(t.line); i++ {
t.queue(space)
t.advanceCursor(1)
}
t.line = t.line[:t.pos]
t.moveCursorToPos(t.pos)
case keyCtrlD:
// Erase the character under the current position.
// The EOF case when the line is empty is handled in
// readLine().
if t.pos < len(t.line) {
t.pos++
t.eraseNPreviousChars(1)
}
case keyCtrlU:
t.eraseNPreviousChars(t.pos)
case keyClearScreen:
// Erases the screen and moves the cursor to the home position.
t.queue([]rune("\x1b[2J\x1b[H"))
t.queue(t.prompt)
t.cursorX, t.cursorY = 0, 0
t.advanceCursor(visualLength(t.prompt))
t.setLine(t.line, t.pos)
default:
if t.AutoCompleteCallback != nil {
prefix := string(t.line[:t.pos])
suffix := string(t.line[t.pos:])
t.lock.Unlock()
newLine, newPos, completeOk := t.AutoCompleteCallback(prefix+suffix, len(prefix), key)
t.lock.Lock()
if completeOk {
t.setLine([]rune(newLine), utf8.RuneCount([]byte(newLine)[:newPos]))
return
}
}
if !isPrintable(key) {
return
}
if len(t.line) == maxLineLength {
return
}
t.addKeyToLine(key)
}
return
}
// addKeyToLine inserts the given key at the current position in the current
// line.
func (t *Terminal) addKeyToLine(key rune) {
if len(t.line) == cap(t.line) {
newLine := make([]rune, len(t.line), 2*(1+len(t.line)))
copy(newLine, t.line)
t.line = newLine
}
t.line = t.line[:len(t.line)+1]
copy(t.line[t.pos+1:], t.line[t.pos:])
t.line[t.pos] = key
if t.echo {
t.writeLine(t.line[t.pos:])
}
t.pos++
t.moveCursorToPos(t.pos)
}
func (t *Terminal) writeLine(line []rune) {
for len(line) != 0 {
remainingOnLine := t.termWidth - t.cursorX
todo := len(line)
if todo > remainingOnLine {
todo = remainingOnLine
}
t.queue(line[:todo])
t.advanceCursor(visualLength(line[:todo]))
line = line[todo:]
}
}
func (t *Terminal) Write(buf []byte) (n int, err error) {
t.lock.Lock()
defer t.lock.Unlock()
if t.cursorX == 0 && t.cursorY == 0 {
// This is the easy case: there's nothing on the screen that we
// have to move out of the way.
return t.c.Write(buf)
}
// We have a prompt and possibly user input on the screen. We
// have to clear it first.
t.move(0 /* up */, 0 /* down */, t.cursorX /* left */, 0 /* right */)
t.cursorX = 0
t.clearLineToRight()
for t.cursorY > 0 {
t.move(1 /* up */, 0, 0, 0)
t.cursorY--
t.clearLineToRight()
}
if _, err = t.c.Write(t.outBuf); err != nil {
return
}
t.outBuf = t.outBuf[:0]
if n, err = t.c.Write(buf); err != nil {
return
}
t.writeLine(t.prompt)
if t.echo {
t.writeLine(t.line)
}
t.moveCursorToPos(t.pos)
if _, err = t.c.Write(t.outBuf); err != nil {
return
}
t.outBuf = t.outBuf[:0]
return
}
// ReadPassword temporarily changes the prompt and reads a password, without
// echo, from the terminal.
func (t *Terminal) ReadPassword(prompt string) (line string, err error) {
t.lock.Lock()
defer t.lock.Unlock()
oldPrompt := t.prompt
t.prompt = []rune(prompt)
t.echo = false
line, err = t.readLine()
t.prompt = oldPrompt
t.echo = true
return
}
// ReadLine returns a line of input from the terminal.
func (t *Terminal) ReadLine() (line string, err error) {
t.lock.Lock()
defer t.lock.Unlock()
return t.readLine()
}
func (t *Terminal) readLine() (line string, err error) {
// t.lock must be held at this point
if t.cursorX == 0 && t.cursorY == 0 {
t.writeLine(t.prompt)
t.c.Write(t.outBuf)
t.outBuf = t.outBuf[:0]
}
lineIsPasted := t.pasteActive
for {
rest := t.remainder
lineOk := false
for !lineOk {
var key rune
key, rest = bytesToKey(rest, t.pasteActive)
if key == utf8.RuneError {
break
}
if !t.pasteActive {
if key == keyCtrlD {
if len(t.line) == 0 {
return "", io.EOF
}
}
if key == keyPasteStart {
t.pasteActive = true
if len(t.line) == 0 {
lineIsPasted = true
}
continue
}
} else if key == keyPasteEnd {
t.pasteActive = false
continue
}
if !t.pasteActive {
lineIsPasted = false
}
line, lineOk = t.handleKey(key)
}
if len(rest) > 0 {
n := copy(t.inBuf[:], rest)
t.remainder = t.inBuf[:n]
} else {
t.remainder = nil
}
t.c.Write(t.outBuf)
t.outBuf = t.outBuf[:0]
if lineOk {
if t.echo {
t.historyIndex = -1
t.history.Add(line)
}
if lineIsPasted {
err = ErrPasteIndicator
}
return
}
// t.remainder is a slice at the beginning of t.inBuf
// containing a partial key sequence
readBuf := t.inBuf[len(t.remainder):]
var n int
t.lock.Unlock()
n, err = t.c.Read(readBuf)
t.lock.Lock()
if err != nil {
return
}
t.remainder = t.inBuf[:n+len(t.remainder)]
}
panic("unreachable") // for Go 1.0.
}
// SetPrompt sets the prompt to be used when reading subsequent lines.
func (t *Terminal) SetPrompt(prompt string) {
t.lock.Lock()
defer t.lock.Unlock()
t.prompt = []rune(prompt)
}
func (t *Terminal) clearAndRepaintLinePlusNPrevious(numPrevLines int) {
// Move cursor to column zero at the start of the line.
t.move(t.cursorY, 0, t.cursorX, 0)
t.cursorX, t.cursorY = 0, 0
t.clearLineToRight()
for t.cursorY < numPrevLines {
// Move down a line
t.move(0, 1, 0, 0)
t.cursorY++
t.clearLineToRight()
}
// Move back to beginning.
t.move(t.cursorY, 0, 0, 0)
t.cursorX, t.cursorY = 0, 0
t.queue(t.prompt)
t.advanceCursor(visualLength(t.prompt))
t.writeLine(t.line)
t.moveCursorToPos(t.pos)
}
func (t *Terminal) SetSize(width, height int) error {
t.lock.Lock()
defer t.lock.Unlock()
if width == 0 {
width = 1
}
oldWidth := t.termWidth
t.termWidth, t.termHeight = width, height
switch {
case width == oldWidth:
// If the width didn't change then nothing else needs to be
// done.
return nil
case len(t.line) == 0 && t.cursorX == 0 && t.cursorY == 0:
// If there is nothing on current line and no prompt printed,
// just do nothing
return nil
case width < oldWidth:
// Some terminals (e.g. xterm) will truncate lines that were
// too long when shinking. Others, (e.g. gnome-terminal) will
// attempt to wrap them. For the former, repainting t.maxLine
// works great, but that behaviour goes badly wrong in the case
// of the latter because they have doubled every full line.
// We assume that we are working on a terminal that wraps lines
// and adjust the cursor position based on every previous line
// wrapping and turning into two. This causes the prompt on
// xterms to move upwards, which isn't great, but it avoids a
// huge mess with gnome-terminal.
if t.cursorX >= t.termWidth {
t.cursorX = t.termWidth - 1
}
t.cursorY *= 2
t.clearAndRepaintLinePlusNPrevious(t.maxLine * 2)
case width > oldWidth:
// If the terminal expands then our position calculations will
// be wrong in the future because we think the cursor is
// |t.pos| chars into the string, but there will be a gap at
// the end of any wrapped line.
//
// But the position will actually be correct until we move, so
// we can move back to the beginning and repaint everything.
t.clearAndRepaintLinePlusNPrevious(t.maxLine)
}
_, err := t.c.Write(t.outBuf)
t.outBuf = t.outBuf[:0]
return err
}
type pasteIndicatorError struct{}
func (pasteIndicatorError) Error() string {
return "terminal: ErrPasteIndicator not correctly handled"
}
// ErrPasteIndicator may be returned from ReadLine as the error, in addition
// to valid line data. It indicates that bracketed paste mode is enabled and
// that the returned line consists only of pasted data. Programs may wish to
// interpret pasted data more literally than typed data.
var ErrPasteIndicator = pasteIndicatorError{}
// SetBracketedPasteMode requests that the terminal bracket paste operations
// with markers. Not all terminals support this but, if it is supported, then
// enabling this mode will stop any autocomplete callback from running due to
// pastes. Additionally, any lines that are completely pasted will be returned
// from ReadLine with the error set to ErrPasteIndicator.
func (t *Terminal) SetBracketedPasteMode(on bool) {
if on {
io.WriteString(t.c, "\x1b[?2004h")
} else {
io.WriteString(t.c, "\x1b[?2004l")
}
}
// stRingBuffer is a ring buffer of strings.
type stRingBuffer struct {
// entries contains max elements.
entries []string
max int
// head contains the index of the element most recently added to the ring.
head int
// size contains the number of elements in the ring.
size int
}
func (s *stRingBuffer) Add(a string) {
if s.entries == nil {
const defaultNumEntries = 100
s.entries = make([]string, defaultNumEntries)
s.max = defaultNumEntries
}
s.head = (s.head + 1) % s.max
s.entries[s.head] = a
if s.size < s.max {
s.size++
}
}
// NthPreviousEntry returns the value passed to the nth previous call to Add.
// If n is zero then the immediately prior value is returned, if one, then the
// next most recent, and so on. If such an element doesn't exist then ok is
// false.
func (s *stRingBuffer) NthPreviousEntry(n int) (value string, ok bool) {
if n >= s.size {
return "", false
}
index := s.head - n
if index < 0 {
index += s.max
}
return s.entries[index], true
}

View File

@ -1,128 +0,0 @@
// Copyright 2011 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build darwin dragonfly freebsd linux,!appengine netbsd openbsd
// Package terminal provides support functions for dealing with terminals, as
// commonly found on UNIX systems.
//
// Putting a terminal into raw mode is the most common requirement:
//
// oldState, err := terminal.MakeRaw(0)
// if err != nil {
// panic(err)
// }
// defer terminal.Restore(0, oldState)
package terminal
import (
"io"
"syscall"
"unsafe"
)
// State contains the state of a terminal.
type State struct {
termios syscall.Termios
}
// IsTerminal returns true if the given file descriptor is a terminal.
func IsTerminal(fd int) bool {
var termios syscall.Termios
_, _, err := syscall.Syscall6(syscall.SYS_IOCTL, uintptr(fd), ioctlReadTermios, uintptr(unsafe.Pointer(&termios)), 0, 0, 0)
return err == 0
}
// MakeRaw put the terminal connected to the given file descriptor into raw
// mode and returns the previous state of the terminal so that it can be
// restored.
func MakeRaw(fd int) (*State, error) {
var oldState State
if _, _, err := syscall.Syscall6(syscall.SYS_IOCTL, uintptr(fd), ioctlReadTermios, uintptr(unsafe.Pointer(&oldState.termios)), 0, 0, 0); err != 0 {
return nil, err
}
newState := oldState.termios
newState.Iflag &^= syscall.ISTRIP | syscall.INLCR | syscall.ICRNL | syscall.IGNCR | syscall.IXON | syscall.IXOFF
newState.Lflag &^= syscall.ECHO | syscall.ICANON | syscall.ISIG
if _, _, err := syscall.Syscall6(syscall.SYS_IOCTL, uintptr(fd), ioctlWriteTermios, uintptr(unsafe.Pointer(&newState)), 0, 0, 0); err != 0 {
return nil, err
}
return &oldState, nil
}
// GetState returns the current state of a terminal which may be useful to
// restore the terminal after a signal.
func GetState(fd int) (*State, error) {
var oldState State
if _, _, err := syscall.Syscall6(syscall.SYS_IOCTL, uintptr(fd), ioctlReadTermios, uintptr(unsafe.Pointer(&oldState.termios)), 0, 0, 0); err != 0 {
return nil, err
}
return &oldState, nil
}
// Restore restores the terminal connected to the given file descriptor to a
// previous state.
func Restore(fd int, state *State) error {
_, _, err := syscall.Syscall6(syscall.SYS_IOCTL, uintptr(fd), ioctlWriteTermios, uintptr(unsafe.Pointer(&state.termios)), 0, 0, 0)
return err
}
// GetSize returns the dimensions of the given terminal.
func GetSize(fd int) (width, height int, err error) {
var dimensions [4]uint16
if _, _, err := syscall.Syscall6(syscall.SYS_IOCTL, uintptr(fd), uintptr(syscall.TIOCGWINSZ), uintptr(unsafe.Pointer(&dimensions)), 0, 0, 0); err != 0 {
return -1, -1, err
}
return int(dimensions[1]), int(dimensions[0]), nil
}
// ReadPassword reads a line of input from a terminal without local echo. This
// is commonly used for inputting passwords and other sensitive data. The slice
// returned does not include the \n.
func ReadPassword(fd int) ([]byte, error) {
var oldState syscall.Termios
if _, _, err := syscall.Syscall6(syscall.SYS_IOCTL, uintptr(fd), ioctlReadTermios, uintptr(unsafe.Pointer(&oldState)), 0, 0, 0); err != 0 {
return nil, err
}
newState := oldState
newState.Lflag &^= syscall.ECHO
newState.Lflag |= syscall.ICANON | syscall.ISIG
newState.Iflag |= syscall.ICRNL
if _, _, err := syscall.Syscall6(syscall.SYS_IOCTL, uintptr(fd), ioctlWriteTermios, uintptr(unsafe.Pointer(&newState)), 0, 0, 0); err != 0 {
return nil, err
}
defer func() {
syscall.Syscall6(syscall.SYS_IOCTL, uintptr(fd), ioctlWriteTermios, uintptr(unsafe.Pointer(&oldState)), 0, 0, 0)
}()
var buf [16]byte
var ret []byte
for {
n, err := syscall.Read(fd, buf[:])
if err != nil {
return nil, err
}
if n == 0 {
if len(ret) == 0 {
return nil, io.EOF
}
break
}
if buf[n-1] == '\n' {
n--
}
ret = append(ret, buf[:n]...)
if n < len(buf) {
break
}
}
return ret, nil
}

View File

@ -1,12 +0,0 @@
// Copyright 2013 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build darwin dragonfly freebsd netbsd openbsd
package terminal
import "syscall"
const ioctlReadTermios = syscall.TIOCGETA
const ioctlWriteTermios = syscall.TIOCSETA

View File

@ -1,11 +0,0 @@
// Copyright 2013 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package terminal
// These constants are declared here, rather than importing
// them from the syscall package as some syscall packages, even
// on linux, for example gccgo, do not declare them.
const ioctlReadTermios = 0x5401 // syscall.TCGETS
const ioctlWriteTermios = 0x5402 // syscall.TCSETS

View File

@ -1,174 +0,0 @@
// Copyright 2011 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build windows
// Package terminal provides support functions for dealing with terminals, as
// commonly found on UNIX systems.
//
// Putting a terminal into raw mode is the most common requirement:
//
// oldState, err := terminal.MakeRaw(0)
// if err != nil {
// panic(err)
// }
// defer terminal.Restore(0, oldState)
package terminal
import (
"io"
"syscall"
"unsafe"
)
const (
enableLineInput = 2
enableEchoInput = 4
enableProcessedInput = 1
enableWindowInput = 8
enableMouseInput = 16
enableInsertMode = 32
enableQuickEditMode = 64
enableExtendedFlags = 128
enableAutoPosition = 256
enableProcessedOutput = 1
enableWrapAtEolOutput = 2
)
var kernel32 = syscall.NewLazyDLL("kernel32.dll")
var (
procGetConsoleMode = kernel32.NewProc("GetConsoleMode")
procSetConsoleMode = kernel32.NewProc("SetConsoleMode")
procGetConsoleScreenBufferInfo = kernel32.NewProc("GetConsoleScreenBufferInfo")
)
type (
short int16
word uint16
coord struct {
x short
y short
}
smallRect struct {
left short
top short
right short
bottom short
}
consoleScreenBufferInfo struct {
size coord
cursorPosition coord
attributes word
window smallRect
maximumWindowSize coord
}
)
type State struct {
mode uint32
}
// IsTerminal returns true if the given file descriptor is a terminal.
func IsTerminal(fd int) bool {
var st uint32
r, _, e := syscall.Syscall(procGetConsoleMode.Addr(), 2, uintptr(fd), uintptr(unsafe.Pointer(&st)), 0)
return r != 0 && e == 0
}
// MakeRaw put the terminal connected to the given file descriptor into raw
// mode and returns the previous state of the terminal so that it can be
// restored.
func MakeRaw(fd int) (*State, error) {
var st uint32
_, _, e := syscall.Syscall(procGetConsoleMode.Addr(), 2, uintptr(fd), uintptr(unsafe.Pointer(&st)), 0)
if e != 0 {
return nil, error(e)
}
st &^= (enableEchoInput | enableProcessedInput | enableLineInput | enableProcessedOutput)
_, _, e = syscall.Syscall(procSetConsoleMode.Addr(), 2, uintptr(fd), uintptr(st), 0)
if e != 0 {
return nil, error(e)
}
return &State{st}, nil
}
// GetState returns the current state of a terminal which may be useful to
// restore the terminal after a signal.
func GetState(fd int) (*State, error) {
var st uint32
_, _, e := syscall.Syscall(procGetConsoleMode.Addr(), 2, uintptr(fd), uintptr(unsafe.Pointer(&st)), 0)
if e != 0 {
return nil, error(e)
}
return &State{st}, nil
}
// Restore restores the terminal connected to the given file descriptor to a
// previous state.
func Restore(fd int, state *State) error {
_, _, err := syscall.Syscall(procSetConsoleMode.Addr(), 2, uintptr(fd), uintptr(state.mode), 0)
return err
}
// GetSize returns the dimensions of the given terminal.
func GetSize(fd int) (width, height int, err error) {
var info consoleScreenBufferInfo
_, _, e := syscall.Syscall(procGetConsoleScreenBufferInfo.Addr(), 2, uintptr(fd), uintptr(unsafe.Pointer(&info)), 0)
if e != 0 {
return 0, 0, error(e)
}
return int(info.size.x), int(info.size.y), nil
}
// ReadPassword reads a line of input from a terminal without local echo. This
// is commonly used for inputting passwords and other sensitive data. The slice
// returned does not include the \n.
func ReadPassword(fd int) ([]byte, error) {
var st uint32
_, _, e := syscall.Syscall(procGetConsoleMode.Addr(), 2, uintptr(fd), uintptr(unsafe.Pointer(&st)), 0)
if e != 0 {
return nil, error(e)
}
old := st
st &^= (enableEchoInput)
st |= (enableProcessedInput | enableLineInput | enableProcessedOutput)
_, _, e = syscall.Syscall(procSetConsoleMode.Addr(), 2, uintptr(fd), uintptr(st), 0)
if e != 0 {
return nil, error(e)
}
defer func() {
syscall.Syscall(procSetConsoleMode.Addr(), 2, uintptr(fd), uintptr(old), 0)
}()
var buf [16]byte
var ret []byte
for {
n, err := syscall.Read(syscall.Handle(fd), buf[:])
if err != nil {
return nil, err
}
if n == 0 {
if len(ret) == 0 {
return nil, io.EOF
}
break
}
if buf[n-1] == '\n' {
n--
}
if n > 0 && buf[n-1] == '\r' {
n--
}
ret = append(ret, buf[:n]...)
if n < len(buf) {
break
}
}
return ret, nil
}