vise.git

module
v0.2.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Sep 28, 2024 License: AGPL-3.0

README

vise: A Constrained Size Output Virtual Machine

Consider the following interaction:

This is the root page
You have visited 1 time.
0:foo
1:bar

$ 1
Please visit foo first.
Any input to return.

$ x
This is the root page.
You have visited 2 times.
0:foo
1:bar

$ 0
Welcome to page foo.
Please write seomthing.

$ blah blah blah
This is the root page.
You have visited 3 times.
0:foo
1:bar

$ 1
Thanks for visiting foo and bar.
You have written:
blah blah blah

Components

This simple interface above involves four different menu nodes.

In order to engineer these using vise, three types of components are involved:

  • An assembly-like menu handling script.
  • A display template.
  • External code handlers for the counter and the "something" input.

Nodes

  • root - The first page
  • foo - The "foo" page
  • bar - The "bar" page after "foo" has been visited
  • ouch - The "bar" page before "foo" has been visited

Templates

Each page has a template that may or may not contain dynamic elements.

In this example the root and bar nodes contains dynamic content.

root
This is the root page
You have visited {{.count}}.
foo
Welcome to page foo.
Please write something.
bar
Thanks for visiting foo and bar.
You have written:
{{.something}}
ouch
Please visit foo first.
Any input to return.

Scripts

The scripts are responsible for defining menus, handling navigation flow control, and triggering external code handlers.

root
LOAD count 8        # trigger external code handler "count"
LOAD something 0    # trigger external code handler "something"
RELOAD count        # explicitly trigger "count" every time this code is executed.
MAP count           # make the result from "count" available to the template renderer
MOUT foo 0          # menu item
MOUT bar 1          # menu item
HALT                # render template and wait for input
INCMP foo 0         # match menu selection 0, move to node "foo" on match
INCMP bar 1         # match menu selection 1, move to node "bar" on match
foo
HALT                # render template and wait for input
RELOAD something    # pass input to the "something" external code handler.
                    # The input will be appended to the stored value. 
                    # The "HAVESOMETHING" flag (8) will be set.
MOVE _              # move up one level
bar
CATCH ouch 8 0      # if the "HAVESOMETHING" (8) flag has NOT (0) been set, move to "ouch"
MNEXT next 11       # menu choice to display for advancing one page
MPREV back 22       # menu choice to display for going back to the previous page
MAP something       # make the result from "something" available to the template renderer
HALT                # render template and wait for input
INCMP > 11          # handle the "next" menu choice
INCMP < 22          # handle to "back" menu choice
INCMP _ *           # move to the root node on any input
ouch
HALT            # render template and wait for input
INCMP ^ *       # move to the root node on any input

External code handlers

The script code contains LOAD instructions for two different methods.

import (
    "context"
    "fmt"
    "path"
    "strings"

	testdataloader "github.com/peteole/testdata-loader"

	"git.defalsify.org/vise.git/state"
	"git.defalsify.org/vise.git/resource"
)

const (
	USERFLAG_HAVESOMETHING = iota + state.FLAG_USERSTART
)

var (
	baseDir = testdataloader.GetBasePath()
	scriptDir = path.Join(baseDir, "examples", "intro")
)

type introResource struct {
	*resource.FsResource 
	c int64
	v []string
}

func newintroResource() introResource {
	fs := resource.NewFsResource(scriptDir)
	return introResource{fs, 0, []string{}}
}

// increment counter.
// return a string representing the current value of the counter.
func(c *introResource) count(ctx context.Context, sym string, input []byte) (resource.Result, error) {
	s := "%v time"
	if c.c != 1 {
		s += "s"
	}
	r := resource.Result{
		Content: fmt.Sprintf(s, c.c),
	}
	c.c += 1 
	return  r, nil
}

// if input is suppled, append it to the stored string vector and set the HAVESOMETHING flag.
// return the stored string vector value, one string per line.
func(c *introResource) something(ctx context.Context, sym string, input []byte) (resource.Result, error) {
	c.v = append(c.v, string(input))
	r := resource.Result{
		Content: strings.Join(c.v, "\n"),
	}
	if len(input) > 0 {
		r.FlagSet = []uint32{USERFLAG_HAVESOMETHING}
	}
	return r, nil
}

Handling long values

In the above example, the more times the foo page is supplied with a value, the longer the vector of values that need to be displayed by the bar page will be.

A core feature of vise is to magically create browseable pages from these values from a pre-defined maximum output capacity for each page.

Consider the case where the contents of the something symbol has become:

foo bar
baz bazbaz
inky pinky
blinky
clyde

Given a size constaint of 90 characters, the display will be split into two pages:

Thanks for visiting foo and bar.
You have written:
foo bar
baz bazbaz
11:next
Thanks for visiting foo and bar.
You have written:
inky pinky
blinky
clyde
22:back

Working example

In the source code repository, a full working example of this menu can be found in examples/intro.

To run it:

make -B intro
go run ./examples/intro

Use go run -tags logtrace ... to peek at what is going on under the hood.

To play the "Handling long values" case above, limit the output size by adding -s 90.

Directories

Path Synopsis
Package asm parses and compiles vise assembly code to bytecode.
Package asm parses and compiles vise assembly code to bytecode.
Package cache is a memory store for key-value pairs for all loaded symbols available for output.
Package cache is a memory store for key-value pairs for all loaded symbols available for output.
db
Package db contains a generalized data provider interface aswell as a number of built-in implementations.
Package db contains a generalized data provider interface aswell as a number of built-in implementations.
dbtest
Package dbtest provides test vectors to verify correct operation of a db.Db implementation.
Package dbtest provides test vectors to verify correct operation of a db.Db implementation.
fs
Package fs is a filesystem backed implementation of the db.Db interface.
Package fs is a filesystem backed implementation of the db.Db interface.
gdbm
Package gdbm is a gdbm database backed implementation of the db.Db interface.
Package gdbm is a gdbm database backed implementation of the db.Db interface.
mem
Package mem is a volatile in-process memory implementation of the db.Db interface.
Package mem is a volatile in-process memory implementation of the db.Db interface.
postgres
Package postgres is a Postgres database backed implementation of the db.Db interface.
Package postgres is a Postgres database backed implementation of the db.Db interface.
dev
asm
Executable asm compiles festival assembly code to bytecode instructions.
Executable asm compiles festival assembly code to bytecode instructions.
dbconvert
Executable dbconvert processes a given directory recursively and inserts all legacy template files, menu files and bytecode files into corresponding db.Db entries of the chosen backend.
Executable dbconvert processes a given directory recursively and inserts all legacy template files, menu files and bytecode files into corresponding db.Db entries of the chosen backend.
disasm
Executable disasm generates festival assembly code from bytecode instructions.
Executable disasm generates festival assembly code from bytecode instructions.
gendata
Execution gendata output testdata provisions compatible with resource.FsResource to a filesystem directory.
Execution gendata output testdata provisions compatible with resource.FsResource to a filesystem directory.
interactive
Executable interactive runs the Engine execution loop against interactive client input in the terminal.
Executable interactive runs the Engine execution loop against interactive client input in the terminal.
Package engine orchestrates client input with vm execution.
Package engine orchestrates client input with vm execution.
examples
db
Example: Use db.Db provider for all local data.
Example: Use db.Db provider for all local data.
first
Example: Sub-machine using the first function feature in engine
Example: Sub-machine using the first function feature in engine
gdbm
Example: Use gdbm backend to retrieve resources.
Example: Use gdbm backend to retrieve resources.
helloworld
Example: Simplest code implementation to be executed by external driver (/dev/interactive)
Example: Simplest code implementation to be executed by external driver (/dev/interactive)
http
Example: HTTP server wrapper (to be used with manual client).
Example: HTTP server wrapper (to be used with manual client).
intro
Example: Basic flags and input processing, and symbol execution.
Example: Basic flags and input processing, and symbol execution.
languages
Example: Set and apply language translation based on input, with and without Gettext.
Example: Set and apply language translation based on input, with and without Gettext.
longmenu
Example: Pagination of long resource result content.
Example: Pagination of long resource result content.
pincheck
Example: States and branching to check a PIN for access.
Example: States and branching to check a PIN for access.
preprocessor
Example: Assemble and retrieve state flags using string identifiers specified in csv file.
Example: Assemble and retrieve state flags using string identifiers specified in csv file.
profile
Example: Profile data completion menu.
Example: Profile data completion menu.
quit
Example: Graceful termination that will be resumed from top on next execution.
Example: Graceful termination that will be resumed from top on next execution.
reuse
Example: Reuse go functions for multiple LOAD symbols.
Example: Reuse go functions for multiple LOAD symbols.
session
Example: Manual data storage using session id provided to engine.
Example: Manual data storage using session id provided to engine.
state
Example: Toggling states with external functions, with engine debugger.
Example: Toggling states with external functions, with engine debugger.
state_passive
Example: Asynchronous state persistence.
Example: Asynchronous state persistence.
static
Example: Profile data completion menu.
Example: Profile data completion menu.
validate
Example: Input checker.
Example: Input checker.
internal
Package lang provides definitions to specify translation language for template selection and output rendering.
Package lang provides definitions to specify translation language for template selection and output rendering.
Package logging provides a logging implementation for use with vise.
Package logging provides a logging implementation for use with vise.
Package persist enables persistent storage of the execution state.
Package persist enables persistent storage of the execution state.
Package render handles output size constraints and paginated rendering of contents and menus using templates.
Package render handles output size constraints and paginated rendering of contents and menus using templates.
Package resource interfaces retrieval of bytecode, output templates and external code execution.
Package resource interfaces retrieval of bytecode, output templates and external code execution.
Package state handles execution state, including navigation and state flags.
Package state handles execution state, including navigation and state flags.
Package vm handles the line-by-line execution of vise bytecode.
Package vm handles the line-by-line execution of vise bytecode.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL