123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152 |
- package ansiterm
- import (
- "errors"
- "log"
- "os"
- )
- type AnsiParser struct {
- currState state
- eventHandler AnsiEventHandler
- context *ansiContext
- csiEntry state
- csiParam state
- dcsEntry state
- escape state
- escapeIntermediate state
- error state
- ground state
- oscString state
- stateMap []state
- logf func(string, ...interface{})
- }
- type Option func(*AnsiParser)
- func WithLogf(f func(string, ...interface{})) Option {
- return func(ap *AnsiParser) {
- ap.logf = f
- }
- }
- func CreateParser(initialState string, evtHandler AnsiEventHandler, opts ...Option) *AnsiParser {
- ap := &AnsiParser{
- eventHandler: evtHandler,
- context: &ansiContext{},
- }
- for _, o := range opts {
- o(ap)
- }
- if isDebugEnv := os.Getenv(LogEnv); isDebugEnv == "1" {
- logFile, _ := os.Create("ansiParser.log")
- logger := log.New(logFile, "", log.LstdFlags)
- if ap.logf != nil {
- l := ap.logf
- ap.logf = func(s string, v ...interface{}) {
- l(s, v...)
- logger.Printf(s, v...)
- }
- } else {
- ap.logf = logger.Printf
- }
- }
- if ap.logf == nil {
- ap.logf = func(string, ...interface{}) {}
- }
- ap.csiEntry = csiEntryState{baseState{name: "CsiEntry", parser: ap}}
- ap.csiParam = csiParamState{baseState{name: "CsiParam", parser: ap}}
- ap.dcsEntry = dcsEntryState{baseState{name: "DcsEntry", parser: ap}}
- ap.escape = escapeState{baseState{name: "Escape", parser: ap}}
- ap.escapeIntermediate = escapeIntermediateState{baseState{name: "EscapeIntermediate", parser: ap}}
- ap.error = errorState{baseState{name: "Error", parser: ap}}
- ap.ground = groundState{baseState{name: "Ground", parser: ap}}
- ap.oscString = oscStringState{baseState{name: "OscString", parser: ap}}
- ap.stateMap = []state{
- ap.csiEntry,
- ap.csiParam,
- ap.dcsEntry,
- ap.escape,
- ap.escapeIntermediate,
- ap.error,
- ap.ground,
- ap.oscString,
- }
- ap.currState = getState(initialState, ap.stateMap)
- ap.logf("CreateParser: parser %p", ap)
- return ap
- }
- func getState(name string, states []state) state {
- for _, el := range states {
- if el.Name() == name {
- return el
- }
- }
- return nil
- }
- func (ap *AnsiParser) Parse(bytes []byte) (int, error) {
- for i, b := range bytes {
- if err := ap.handle(b); err != nil {
- return i, err
- }
- }
- return len(bytes), ap.eventHandler.Flush()
- }
- func (ap *AnsiParser) handle(b byte) error {
- ap.context.currentChar = b
- newState, err := ap.currState.Handle(b)
- if err != nil {
- return err
- }
- if newState == nil {
- ap.logf("WARNING: newState is nil")
- return errors.New("New state of 'nil' is invalid.")
- }
- if newState != ap.currState {
- if err := ap.changeState(newState); err != nil {
- return err
- }
- }
- return nil
- }
- func (ap *AnsiParser) changeState(newState state) error {
- ap.logf("ChangeState %s --> %s", ap.currState.Name(), newState.Name())
- // Exit old state
- if err := ap.currState.Exit(); err != nil {
- ap.logf("Exit state '%s' failed with : '%v'", ap.currState.Name(), err)
- return err
- }
- // Perform transition action
- if err := ap.currState.Transition(newState); err != nil {
- ap.logf("Transition from '%s' to '%s' failed with: '%v'", ap.currState.Name(), newState.Name, err)
- return err
- }
- // Enter new state
- if err := newState.Enter(); err != nil {
- ap.logf("Enter state '%s' failed with: '%v'", newState.Name(), err)
- return err
- }
- ap.currState = newState
- return nil
- }
|