Factor out target sym navigation handling
This commit is contained in:
parent
6221e1dce2
commit
8b1f91e859
@ -212,7 +212,6 @@ func parseOne(op vm.Opcode, instruction *Instruction, w io.Writer) (int, error)
|
||||
n, err = writeSym(b, *a.Sym)
|
||||
n_buf += n
|
||||
return flush(b, w)
|
||||
|
||||
}
|
||||
|
||||
func (a Arg) String() string {
|
||||
|
@ -212,6 +212,34 @@ func(st State) Where() (string, uint16) {
|
||||
return st.execPath[l-1], st.sizeIdx
|
||||
}
|
||||
|
||||
// Next moves to the next sink page index.
|
||||
func(st State) Next() (uint16, error) {
|
||||
st.sizeIdx += 1
|
||||
return st.sizeIdx, nil
|
||||
}
|
||||
|
||||
// Previous moves to the next sink page index.
|
||||
//
|
||||
// Fails if try to move beyond index 0.
|
||||
func(st *State) Previous() (uint16, error) {
|
||||
if st.sizeIdx == 0 {
|
||||
return 0, fmt.Errorf("already at first index")
|
||||
}
|
||||
st.sizeIdx -= 1
|
||||
return st.sizeIdx, nil
|
||||
}
|
||||
|
||||
// Sides informs the caller which index page options will currently succeed.
|
||||
//
|
||||
// Two values are returned, for the "next" and "previous" options in that order. A false value means the option is not available in the current state.
|
||||
func(st *State) Sides() (bool, bool) {
|
||||
next := true
|
||||
if st.sizeIdx == 0 {
|
||||
return next, false
|
||||
}
|
||||
return next, true
|
||||
}
|
||||
|
||||
// Down adds the given symbol to the command stack.
|
||||
//
|
||||
// Clears mapping and sink.
|
||||
|
@ -11,42 +11,82 @@ import (
|
||||
var (
|
||||
inputRegexStr = "^[a-zA-Z0-9].*$"
|
||||
inputRegex = regexp.MustCompile(inputRegexStr)
|
||||
ctrlInputRegexStr = "^[<>_]$"
|
||||
ctrlInputRegex = regexp.MustCompile(inputRegexStr)
|
||||
ctrlRegexStr = "^[<>_]$"
|
||||
ctrlRegex = regexp.MustCompile(inputRegexStr)
|
||||
symRegexStr = "^[a-zA-Z0-9][a-zA-Z0-9_]+$"
|
||||
symRegex = regexp.MustCompile(inputRegexStr)
|
||||
|
||||
)
|
||||
|
||||
|
||||
// CheckInput validates the given byte string as client input.
|
||||
func CheckInput(input []byte) error {
|
||||
if !inputRegex.Match(input) {
|
||||
return fmt.Errorf("Input '%s' does not match format /%s/", input, inputRegexStr)
|
||||
return fmt.Errorf("Input '%s' does not match input format /%s/", input, inputRegexStr)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func applyControlInput(input []byte, st *state.State, ctx context.Context) (string, error) {
|
||||
// control characters for relative navigation.
|
||||
func checkControl(input []byte) error {
|
||||
if !ctrlRegex.Match(input) {
|
||||
return fmt.Errorf("Input '%s' does not match 'control' format /%s/", input, ctrlRegexStr)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// CheckSym validates the given byte string as a node symbol.
|
||||
func CheckSym(input []byte) error {
|
||||
if !symRegex.Match(input) {
|
||||
return fmt.Errorf("Input '%s' does not match 'sym' format /%s/", input, symRegexStr)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// route parsed target symbol to navigation state change method,
|
||||
func applyTarget(target []byte, st *state.State, ctx context.Context) (string, uint16, error) {
|
||||
var err error
|
||||
var valid bool
|
||||
sym, idx := st.Where()
|
||||
switch input[0] {
|
||||
|
||||
err = CheckInput(target)
|
||||
if err == nil {
|
||||
valid = true
|
||||
}
|
||||
|
||||
if !valid {
|
||||
err = CheckSym(target)
|
||||
if err == nil {
|
||||
valid = true
|
||||
}
|
||||
}
|
||||
|
||||
if !valid {
|
||||
err = checkControl(target)
|
||||
if err == nil {
|
||||
valid = true
|
||||
}
|
||||
}
|
||||
|
||||
switch target[0] {
|
||||
case '_':
|
||||
sym, err = st.Up()
|
||||
if err != nil {
|
||||
return sym, err
|
||||
return sym, idx, err
|
||||
}
|
||||
case '>':
|
||||
idx, err = st.Next()
|
||||
if err != nil {
|
||||
return sym, idx, err
|
||||
}
|
||||
case '<':
|
||||
idx, err = st.Previous()
|
||||
if err != nil {
|
||||
return sym, idx, err
|
||||
}
|
||||
default:
|
||||
sym = string(target)
|
||||
st.Down(sym)
|
||||
idx = 0
|
||||
}
|
||||
_ = idx
|
||||
return sym, nil
|
||||
}
|
||||
|
||||
func ApplyInput(inputString string, st *state.State, ctx context.Context) (string, error) {
|
||||
input := []byte(inputString)
|
||||
if ctrlInputRegex.Match(input) {
|
||||
return applyControlInput(input, st, ctx)
|
||||
}
|
||||
|
||||
err := CheckInput(input)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
st.Down(inputString)
|
||||
return inputString, nil
|
||||
return sym, idx, nil
|
||||
}
|
||||
|
@ -212,7 +212,9 @@ func RunInCmp(b []byte, st *state.State, rs resource.Resource, ctx context.Conte
|
||||
|
||||
log.Printf("input match for '%s'", input)
|
||||
_, err = st.SetFlag(state.FLAG_INMATCH)
|
||||
st.Down(target)
|
||||
|
||||
sym, _, err = applyTarget([]byte(target), st, ctx)
|
||||
|
||||
code, err := rs.GetCode(target)
|
||||
if err != nil {
|
||||
return b, err
|
||||
|
Loading…
Reference in New Issue
Block a user