mirror of
				https://gitea.com/Lydanne/buildx.git
				synced 2025-10-26 05:33:43 +08:00 
			
		
		
		
	
		
			
				
	
	
		
			152 lines
		
	
	
		
			3.4 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			152 lines
		
	
	
		
			3.4 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
| 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
 | |
| }
 | 
