forked from toolshed/abra
		
	
		
			
				
	
	
		
			274 lines
		
	
	
		
			12 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			274 lines
		
	
	
		
			12 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
| package parser
 | |
| 
 | |
| // Table values are generated like this:
 | |
| //
 | |
| //	index:  currentState << IndexStateShift | charCode
 | |
| //	value:  action << TransitionActionShift | nextState
 | |
| const (
 | |
| 	TransitionActionShift = 4
 | |
| 	TransitionStateMask   = 15
 | |
| 	IndexStateShift       = 8
 | |
| 
 | |
| 	// DefaultTableSize is the default size of the transition table.
 | |
| 	DefaultTableSize = 4096
 | |
| )
 | |
| 
 | |
| // Table is a DEC ANSI transition table.
 | |
| var Table = GenerateTransitionTable()
 | |
| 
 | |
| // TransitionTable is a DEC ANSI transition table.
 | |
| // https://vt100.net/emu/dec_ansi_parser
 | |
| type TransitionTable []byte
 | |
| 
 | |
| // NewTransitionTable returns a new DEC ANSI transition table.
 | |
| func NewTransitionTable(size int) TransitionTable {
 | |
| 	if size <= 0 {
 | |
| 		size = DefaultTableSize
 | |
| 	}
 | |
| 	return TransitionTable(make([]byte, size))
 | |
| }
 | |
| 
 | |
| // SetDefault sets default transition.
 | |
| func (t TransitionTable) SetDefault(action Action, state State) {
 | |
| 	for i := range t {
 | |
| 		t[i] = action<<TransitionActionShift | state
 | |
| 	}
 | |
| }
 | |
| 
 | |
| // AddOne adds a transition.
 | |
| func (t TransitionTable) AddOne(code byte, state State, action Action, next State) {
 | |
| 	idx := int(state)<<IndexStateShift | int(code)
 | |
| 	value := action<<TransitionActionShift | next
 | |
| 	t[idx] = value
 | |
| }
 | |
| 
 | |
| // AddMany adds many transitions.
 | |
| func (t TransitionTable) AddMany(codes []byte, state State, action Action, next State) {
 | |
| 	for _, code := range codes {
 | |
| 		t.AddOne(code, state, action, next)
 | |
| 	}
 | |
| }
 | |
| 
 | |
| // AddRange adds a range of transitions.
 | |
| func (t TransitionTable) AddRange(start, end byte, state State, action Action, next State) {
 | |
| 	for i := int(start); i <= int(end); i++ {
 | |
| 		t.AddOne(byte(i), state, action, next)
 | |
| 	}
 | |
| }
 | |
| 
 | |
| // Transition returns the next state and action for the given state and byte.
 | |
| func (t TransitionTable) Transition(state State, code byte) (State, Action) {
 | |
| 	index := int(state)<<IndexStateShift | int(code)
 | |
| 	value := t[index]
 | |
| 	return value & TransitionStateMask, value >> TransitionActionShift
 | |
| }
 | |
| 
 | |
| // byte range macro.
 | |
| func r(start, end byte) []byte {
 | |
| 	var a []byte
 | |
| 	for i := int(start); i <= int(end); i++ {
 | |
| 		a = append(a, byte(i))
 | |
| 	}
 | |
| 	return a
 | |
| }
 | |
| 
 | |
| // GenerateTransitionTable generates a DEC ANSI transition table compatible
 | |
| // with the VT500-series of terminals. This implementation includes a few
 | |
| // modifications that include:
 | |
| //   - A new Utf8State is introduced to handle UTF8 sequences.
 | |
| //   - Osc and Dcs data accept UTF8 sequences by extending the printable range
 | |
| //     to 0xFF and 0xFE respectively.
 | |
| //   - We don't ignore 0x3A (':') when building Csi and Dcs parameters and
 | |
| //     instead use it to denote sub-parameters.
 | |
| //   - Support dispatching SosPmApc sequences.
 | |
| //   - The DEL (0x7F) character is executed in the Ground state.
 | |
| //   - The DEL (0x7F) character is collected in the DcsPassthrough string state.
 | |
| //   - The ST C1 control character (0x9C) is executed and not ignored.
 | |
| func GenerateTransitionTable() TransitionTable {
 | |
| 	table := NewTransitionTable(DefaultTableSize)
 | |
| 	table.SetDefault(NoneAction, GroundState)
 | |
| 
 | |
| 	// Anywhere
 | |
| 	for _, state := range r(GroundState, Utf8State) {
 | |
| 		// Anywhere -> Ground
 | |
| 		table.AddMany([]byte{0x18, 0x1a, 0x99, 0x9a}, state, ExecuteAction, GroundState)
 | |
| 		table.AddRange(0x80, 0x8F, state, ExecuteAction, GroundState)
 | |
| 		table.AddRange(0x90, 0x97, state, ExecuteAction, GroundState)
 | |
| 		table.AddOne(0x9C, state, ExecuteAction, GroundState)
 | |
| 		// Anywhere -> Escape
 | |
| 		table.AddOne(0x1B, state, ClearAction, EscapeState)
 | |
| 		// Anywhere -> SosStringState
 | |
| 		table.AddOne(0x98, state, StartAction, SosStringState)
 | |
| 		// Anywhere -> PmStringState
 | |
| 		table.AddOne(0x9E, state, StartAction, PmStringState)
 | |
| 		// Anywhere -> ApcStringState
 | |
| 		table.AddOne(0x9F, state, StartAction, ApcStringState)
 | |
| 		// Anywhere -> CsiEntry
 | |
| 		table.AddOne(0x9B, state, ClearAction, CsiEntryState)
 | |
| 		// Anywhere -> DcsEntry
 | |
| 		table.AddOne(0x90, state, ClearAction, DcsEntryState)
 | |
| 		// Anywhere -> OscString
 | |
| 		table.AddOne(0x9D, state, StartAction, OscStringState)
 | |
| 		// Anywhere -> Utf8
 | |
| 		table.AddRange(0xC2, 0xDF, state, CollectAction, Utf8State) // UTF8 2 byte sequence
 | |
| 		table.AddRange(0xE0, 0xEF, state, CollectAction, Utf8State) // UTF8 3 byte sequence
 | |
| 		table.AddRange(0xF0, 0xF4, state, CollectAction, Utf8State) // UTF8 4 byte sequence
 | |
| 	}
 | |
| 
 | |
| 	// Ground
 | |
| 	table.AddRange(0x00, 0x17, GroundState, ExecuteAction, GroundState)
 | |
| 	table.AddOne(0x19, GroundState, ExecuteAction, GroundState)
 | |
| 	table.AddRange(0x1C, 0x1F, GroundState, ExecuteAction, GroundState)
 | |
| 	table.AddRange(0x20, 0x7E, GroundState, PrintAction, GroundState)
 | |
| 	table.AddOne(0x7F, GroundState, ExecuteAction, GroundState)
 | |
| 
 | |
| 	// EscapeIntermediate
 | |
| 	table.AddRange(0x00, 0x17, EscapeIntermediateState, ExecuteAction, EscapeIntermediateState)
 | |
| 	table.AddOne(0x19, EscapeIntermediateState, ExecuteAction, EscapeIntermediateState)
 | |
| 	table.AddRange(0x1C, 0x1F, EscapeIntermediateState, ExecuteAction, EscapeIntermediateState)
 | |
| 	table.AddRange(0x20, 0x2F, EscapeIntermediateState, CollectAction, EscapeIntermediateState)
 | |
| 	table.AddOne(0x7F, EscapeIntermediateState, IgnoreAction, EscapeIntermediateState)
 | |
| 	// EscapeIntermediate -> Ground
 | |
| 	table.AddRange(0x30, 0x7E, EscapeIntermediateState, DispatchAction, GroundState)
 | |
| 
 | |
| 	// Escape
 | |
| 	table.AddRange(0x00, 0x17, EscapeState, ExecuteAction, EscapeState)
 | |
| 	table.AddOne(0x19, EscapeState, ExecuteAction, EscapeState)
 | |
| 	table.AddRange(0x1C, 0x1F, EscapeState, ExecuteAction, EscapeState)
 | |
| 	table.AddOne(0x7F, EscapeState, IgnoreAction, EscapeState)
 | |
| 	// Escape -> Ground
 | |
| 	table.AddRange(0x30, 0x4F, EscapeState, DispatchAction, GroundState)
 | |
| 	table.AddRange(0x51, 0x57, EscapeState, DispatchAction, GroundState)
 | |
| 	table.AddOne(0x59, EscapeState, DispatchAction, GroundState)
 | |
| 	table.AddOne(0x5A, EscapeState, DispatchAction, GroundState)
 | |
| 	table.AddOne(0x5C, EscapeState, DispatchAction, GroundState)
 | |
| 	table.AddRange(0x60, 0x7E, EscapeState, DispatchAction, GroundState)
 | |
| 	// Escape -> Escape_intermediate
 | |
| 	table.AddRange(0x20, 0x2F, EscapeState, CollectAction, EscapeIntermediateState)
 | |
| 	// Escape -> Sos_pm_apc_string
 | |
| 	table.AddOne('X', EscapeState, StartAction, SosStringState) // SOS
 | |
| 	table.AddOne('^', EscapeState, StartAction, PmStringState)  // PM
 | |
| 	table.AddOne('_', EscapeState, StartAction, ApcStringState) // APC
 | |
| 	// Escape -> Dcs_entry
 | |
| 	table.AddOne('P', EscapeState, ClearAction, DcsEntryState)
 | |
| 	// Escape -> Csi_entry
 | |
| 	table.AddOne('[', EscapeState, ClearAction, CsiEntryState)
 | |
| 	// Escape -> Osc_string
 | |
| 	table.AddOne(']', EscapeState, StartAction, OscStringState)
 | |
| 
 | |
| 	// Sos_pm_apc_string
 | |
| 	for _, state := range r(SosStringState, ApcStringState) {
 | |
| 		table.AddRange(0x00, 0x17, state, PutAction, state)
 | |
| 		table.AddOne(0x19, state, PutAction, state)
 | |
| 		table.AddRange(0x1C, 0x1F, state, PutAction, state)
 | |
| 		table.AddRange(0x20, 0x7F, state, PutAction, state)
 | |
| 		// ESC, ST, CAN, and SUB terminate the sequence
 | |
| 		table.AddOne(0x1B, state, DispatchAction, EscapeState)
 | |
| 		table.AddOne(0x9C, state, DispatchAction, GroundState)
 | |
| 		table.AddMany([]byte{0x18, 0x1A}, state, IgnoreAction, GroundState)
 | |
| 	}
 | |
| 
 | |
| 	// Dcs_entry
 | |
| 	table.AddRange(0x00, 0x07, DcsEntryState, IgnoreAction, DcsEntryState)
 | |
| 	table.AddRange(0x0E, 0x17, DcsEntryState, IgnoreAction, DcsEntryState)
 | |
| 	table.AddOne(0x19, DcsEntryState, IgnoreAction, DcsEntryState)
 | |
| 	table.AddRange(0x1C, 0x1F, DcsEntryState, IgnoreAction, DcsEntryState)
 | |
| 	table.AddOne(0x7F, DcsEntryState, IgnoreAction, DcsEntryState)
 | |
| 	// Dcs_entry -> Dcs_intermediate
 | |
| 	table.AddRange(0x20, 0x2F, DcsEntryState, CollectAction, DcsIntermediateState)
 | |
| 	// Dcs_entry -> Dcs_param
 | |
| 	table.AddRange(0x30, 0x3B, DcsEntryState, ParamAction, DcsParamState)
 | |
| 	table.AddRange(0x3C, 0x3F, DcsEntryState, PrefixAction, DcsParamState)
 | |
| 	// Dcs_entry -> Dcs_passthrough
 | |
| 	table.AddRange(0x08, 0x0D, DcsEntryState, PutAction, DcsStringState) // Follows ECMA-48 § 8.3.27
 | |
| 	// XXX: allows passing ESC (not a ECMA-48 standard) this to allow for
 | |
| 	// passthrough of ANSI sequences like in Screen or Tmux passthrough mode.
 | |
| 	table.AddOne(0x1B, DcsEntryState, PutAction, DcsStringState)
 | |
| 	table.AddRange(0x40, 0x7E, DcsEntryState, StartAction, DcsStringState)
 | |
| 
 | |
| 	// Dcs_intermediate
 | |
| 	table.AddRange(0x00, 0x17, DcsIntermediateState, IgnoreAction, DcsIntermediateState)
 | |
| 	table.AddOne(0x19, DcsIntermediateState, IgnoreAction, DcsIntermediateState)
 | |
| 	table.AddRange(0x1C, 0x1F, DcsIntermediateState, IgnoreAction, DcsIntermediateState)
 | |
| 	table.AddRange(0x20, 0x2F, DcsIntermediateState, CollectAction, DcsIntermediateState)
 | |
| 	table.AddOne(0x7F, DcsIntermediateState, IgnoreAction, DcsIntermediateState)
 | |
| 	// Dcs_intermediate -> Dcs_passthrough
 | |
| 	table.AddRange(0x30, 0x3F, DcsIntermediateState, StartAction, DcsStringState)
 | |
| 	table.AddRange(0x40, 0x7E, DcsIntermediateState, StartAction, DcsStringState)
 | |
| 
 | |
| 	// Dcs_param
 | |
| 	table.AddRange(0x00, 0x17, DcsParamState, IgnoreAction, DcsParamState)
 | |
| 	table.AddOne(0x19, DcsParamState, IgnoreAction, DcsParamState)
 | |
| 	table.AddRange(0x1C, 0x1F, DcsParamState, IgnoreAction, DcsParamState)
 | |
| 	table.AddRange(0x30, 0x3B, DcsParamState, ParamAction, DcsParamState)
 | |
| 	table.AddOne(0x7F, DcsParamState, IgnoreAction, DcsParamState)
 | |
| 	table.AddRange(0x3C, 0x3F, DcsParamState, IgnoreAction, DcsParamState)
 | |
| 	// Dcs_param -> Dcs_intermediate
 | |
| 	table.AddRange(0x20, 0x2F, DcsParamState, CollectAction, DcsIntermediateState)
 | |
| 	// Dcs_param -> Dcs_passthrough
 | |
| 	table.AddRange(0x40, 0x7E, DcsParamState, StartAction, DcsStringState)
 | |
| 
 | |
| 	// Dcs_passthrough
 | |
| 	table.AddRange(0x00, 0x17, DcsStringState, PutAction, DcsStringState)
 | |
| 	table.AddOne(0x19, DcsStringState, PutAction, DcsStringState)
 | |
| 	table.AddRange(0x1C, 0x1F, DcsStringState, PutAction, DcsStringState)
 | |
| 	table.AddRange(0x20, 0x7E, DcsStringState, PutAction, DcsStringState)
 | |
| 	table.AddOne(0x7F, DcsStringState, PutAction, DcsStringState)
 | |
| 	table.AddRange(0x80, 0xFF, DcsStringState, PutAction, DcsStringState) // Allow Utf8 characters by extending the printable range from 0x7F to 0xFF
 | |
| 	// ST, CAN, SUB, and ESC terminate the sequence
 | |
| 	table.AddOne(0x1B, DcsStringState, DispatchAction, EscapeState)
 | |
| 	table.AddOne(0x9C, DcsStringState, DispatchAction, GroundState)
 | |
| 	table.AddMany([]byte{0x18, 0x1A}, DcsStringState, IgnoreAction, GroundState)
 | |
| 
 | |
| 	// Csi_param
 | |
| 	table.AddRange(0x00, 0x17, CsiParamState, ExecuteAction, CsiParamState)
 | |
| 	table.AddOne(0x19, CsiParamState, ExecuteAction, CsiParamState)
 | |
| 	table.AddRange(0x1C, 0x1F, CsiParamState, ExecuteAction, CsiParamState)
 | |
| 	table.AddRange(0x30, 0x3B, CsiParamState, ParamAction, CsiParamState)
 | |
| 	table.AddOne(0x7F, CsiParamState, IgnoreAction, CsiParamState)
 | |
| 	table.AddRange(0x3C, 0x3F, CsiParamState, IgnoreAction, CsiParamState)
 | |
| 	// Csi_param -> Ground
 | |
| 	table.AddRange(0x40, 0x7E, CsiParamState, DispatchAction, GroundState)
 | |
| 	// Csi_param -> Csi_intermediate
 | |
| 	table.AddRange(0x20, 0x2F, CsiParamState, CollectAction, CsiIntermediateState)
 | |
| 
 | |
| 	// Csi_intermediate
 | |
| 	table.AddRange(0x00, 0x17, CsiIntermediateState, ExecuteAction, CsiIntermediateState)
 | |
| 	table.AddOne(0x19, CsiIntermediateState, ExecuteAction, CsiIntermediateState)
 | |
| 	table.AddRange(0x1C, 0x1F, CsiIntermediateState, ExecuteAction, CsiIntermediateState)
 | |
| 	table.AddRange(0x20, 0x2F, CsiIntermediateState, CollectAction, CsiIntermediateState)
 | |
| 	table.AddOne(0x7F, CsiIntermediateState, IgnoreAction, CsiIntermediateState)
 | |
| 	// Csi_intermediate -> Ground
 | |
| 	table.AddRange(0x40, 0x7E, CsiIntermediateState, DispatchAction, GroundState)
 | |
| 	// Csi_intermediate -> Csi_ignore
 | |
| 	table.AddRange(0x30, 0x3F, CsiIntermediateState, IgnoreAction, GroundState)
 | |
| 
 | |
| 	// Csi_entry
 | |
| 	table.AddRange(0x00, 0x17, CsiEntryState, ExecuteAction, CsiEntryState)
 | |
| 	table.AddOne(0x19, CsiEntryState, ExecuteAction, CsiEntryState)
 | |
| 	table.AddRange(0x1C, 0x1F, CsiEntryState, ExecuteAction, CsiEntryState)
 | |
| 	table.AddOne(0x7F, CsiEntryState, IgnoreAction, CsiEntryState)
 | |
| 	// Csi_entry -> Ground
 | |
| 	table.AddRange(0x40, 0x7E, CsiEntryState, DispatchAction, GroundState)
 | |
| 	// Csi_entry -> Csi_intermediate
 | |
| 	table.AddRange(0x20, 0x2F, CsiEntryState, CollectAction, CsiIntermediateState)
 | |
| 	// Csi_entry -> Csi_param
 | |
| 	table.AddRange(0x30, 0x3B, CsiEntryState, ParamAction, CsiParamState)
 | |
| 	table.AddRange(0x3C, 0x3F, CsiEntryState, PrefixAction, CsiParamState)
 | |
| 
 | |
| 	// Osc_string
 | |
| 	table.AddRange(0x00, 0x06, OscStringState, IgnoreAction, OscStringState)
 | |
| 	table.AddRange(0x08, 0x17, OscStringState, IgnoreAction, OscStringState)
 | |
| 	table.AddOne(0x19, OscStringState, IgnoreAction, OscStringState)
 | |
| 	table.AddRange(0x1C, 0x1F, OscStringState, IgnoreAction, OscStringState)
 | |
| 	table.AddRange(0x20, 0xFF, OscStringState, PutAction, OscStringState) // Allow Utf8 characters by extending the printable range from 0x7F to 0xFF
 | |
| 
 | |
| 	// ST, CAN, SUB, ESC, and BEL terminate the sequence
 | |
| 	table.AddOne(0x1B, OscStringState, DispatchAction, EscapeState)
 | |
| 	table.AddOne(0x07, OscStringState, DispatchAction, GroundState)
 | |
| 	table.AddOne(0x9C, OscStringState, DispatchAction, GroundState)
 | |
| 	table.AddMany([]byte{0x18, 0x1A}, OscStringState, IgnoreAction, GroundState)
 | |
| 
 | |
| 	return table
 | |
| }
 |