Factor out target sym navigation handling

This commit is contained in:
lash 2023-04-08 08:54:55 +01:00
parent 6221e1dce2
commit 8b1f91e859
Signed by untrusted user who does not match committer: lash
GPG Key ID: 21D2E7BB88C2A746
4 changed files with 94 additions and 25 deletions

View File

@ -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 {

View File

@ -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.

View File

@ -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
}
}
_ = 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)
case '>':
idx, err = st.Next()
if err != nil {
return "", err
return sym, idx, err
}
st.Down(inputString)
return inputString, nil
case '<':
idx, err = st.Previous()
if err != nil {
return sym, idx, err
}
default:
sym = string(target)
st.Down(sym)
idx = 0
}
return sym, idx, nil
}

View File

@ -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