...

Source file src/github.com/Azure/go-ansiterm/parser.go

Documentation: github.com/Azure/go-ansiterm

     1  package ansiterm
     2  
     3  import (
     4  	"errors"
     5  	"log"
     6  	"os"
     7  )
     8  
     9  type AnsiParser struct {
    10  	currState          state
    11  	eventHandler       AnsiEventHandler
    12  	context            *ansiContext
    13  	csiEntry           state
    14  	csiParam           state
    15  	dcsEntry           state
    16  	escape             state
    17  	escapeIntermediate state
    18  	error              state
    19  	ground             state
    20  	oscString          state
    21  	stateMap           []state
    22  
    23  	logf func(string, ...interface{})
    24  }
    25  
    26  type Option func(*AnsiParser)
    27  
    28  func WithLogf(f func(string, ...interface{})) Option {
    29  	return func(ap *AnsiParser) {
    30  		ap.logf = f
    31  	}
    32  }
    33  
    34  func CreateParser(initialState string, evtHandler AnsiEventHandler, opts ...Option) *AnsiParser {
    35  	ap := &AnsiParser{
    36  		eventHandler: evtHandler,
    37  		context:      &ansiContext{},
    38  	}
    39  	for _, o := range opts {
    40  		o(ap)
    41  	}
    42  
    43  	if isDebugEnv := os.Getenv(LogEnv); isDebugEnv == "1" {
    44  		logFile, _ := os.Create("ansiParser.log")
    45  		logger := log.New(logFile, "", log.LstdFlags)
    46  		if ap.logf != nil {
    47  			l := ap.logf
    48  			ap.logf = func(s string, v ...interface{}) {
    49  				l(s, v...)
    50  				logger.Printf(s, v...)
    51  			}
    52  		} else {
    53  			ap.logf = logger.Printf
    54  		}
    55  	}
    56  
    57  	if ap.logf == nil {
    58  		ap.logf = func(string, ...interface{}) {}
    59  	}
    60  
    61  	ap.csiEntry = csiEntryState{baseState{name: "CsiEntry", parser: ap}}
    62  	ap.csiParam = csiParamState{baseState{name: "CsiParam", parser: ap}}
    63  	ap.dcsEntry = dcsEntryState{baseState{name: "DcsEntry", parser: ap}}
    64  	ap.escape = escapeState{baseState{name: "Escape", parser: ap}}
    65  	ap.escapeIntermediate = escapeIntermediateState{baseState{name: "EscapeIntermediate", parser: ap}}
    66  	ap.error = errorState{baseState{name: "Error", parser: ap}}
    67  	ap.ground = groundState{baseState{name: "Ground", parser: ap}}
    68  	ap.oscString = oscStringState{baseState{name: "OscString", parser: ap}}
    69  
    70  	ap.stateMap = []state{
    71  		ap.csiEntry,
    72  		ap.csiParam,
    73  		ap.dcsEntry,
    74  		ap.escape,
    75  		ap.escapeIntermediate,
    76  		ap.error,
    77  		ap.ground,
    78  		ap.oscString,
    79  	}
    80  
    81  	ap.currState = getState(initialState, ap.stateMap)
    82  
    83  	ap.logf("CreateParser: parser %p", ap)
    84  	return ap
    85  }
    86  
    87  func getState(name string, states []state) state {
    88  	for _, el := range states {
    89  		if el.Name() == name {
    90  			return el
    91  		}
    92  	}
    93  
    94  	return nil
    95  }
    96  
    97  func (ap *AnsiParser) Parse(bytes []byte) (int, error) {
    98  	for i, b := range bytes {
    99  		if err := ap.handle(b); err != nil {
   100  			return i, err
   101  		}
   102  	}
   103  
   104  	return len(bytes), ap.eventHandler.Flush()
   105  }
   106  
   107  func (ap *AnsiParser) handle(b byte) error {
   108  	ap.context.currentChar = b
   109  	newState, err := ap.currState.Handle(b)
   110  	if err != nil {
   111  		return err
   112  	}
   113  
   114  	if newState == nil {
   115  		ap.logf("WARNING: newState is nil")
   116  		return errors.New("New state of 'nil' is invalid.")
   117  	}
   118  
   119  	if newState != ap.currState {
   120  		if err := ap.changeState(newState); err != nil {
   121  			return err
   122  		}
   123  	}
   124  
   125  	return nil
   126  }
   127  
   128  func (ap *AnsiParser) changeState(newState state) error {
   129  	ap.logf("ChangeState %s --> %s", ap.currState.Name(), newState.Name())
   130  
   131  	// Exit old state
   132  	if err := ap.currState.Exit(); err != nil {
   133  		ap.logf("Exit state '%s' failed with : '%v'", ap.currState.Name(), err)
   134  		return err
   135  	}
   136  
   137  	// Perform transition action
   138  	if err := ap.currState.Transition(newState); err != nil {
   139  		ap.logf("Transition from '%s' to '%s' failed with: '%v'", ap.currState.Name(), newState.Name, err)
   140  		return err
   141  	}
   142  
   143  	// Enter new state
   144  	if err := newState.Enter(); err != nil {
   145  		ap.logf("Enter state '%s' failed with: '%v'", newState.Name(), err)
   146  		return err
   147  	}
   148  
   149  	ap.currState = newState
   150  	return nil
   151  }
   152  

View as plain text