go-vise

Constrained Size Output Virtual Machine
Info | Log | Files | Refs | README | LICENSE

README.md (5617B)


      1 # vise: A Constrained Size Output Virtual Machine
      2 
      3 Consider the following interaction:
      4 
      5 
      6 ```
      7 This is the root page
      8 You have visited 1 time.
      9 0:foo
     10 1:bar
     11 
     12 $ 1
     13 Please visit foo first.
     14 Any input to return.
     15 
     16 $ x
     17 This is the root page.
     18 You have visited 2 times.
     19 0:foo
     20 1:bar
     21 
     22 $ 0
     23 Welcome to page foo.
     24 Please write seomthing.
     25 
     26 $ blah blah blah
     27 This is the root page.
     28 You have visited 3 times.
     29 0:foo
     30 1:bar
     31 
     32 $ 1
     33 Thanks for visiting foo and bar.
     34 You have written:
     35 blah blah blah
     36 ```
     37 
     38 ## Components
     39 
     40 This simple interface above involves four different menu nodes.
     41 
     42 In order to engineer these using vise, three types of components are involved:
     43 
     44 * An assembly-like menu handling script.
     45 * A display template.
     46 * External code handlers for the counter and the "something" input.
     47 
     48 
     49 ## Nodes
     50 
     51 * `root` - The first page
     52 * `foo` - The "foo" page
     53 * `bar` - The "bar" page after "foo" has been visited
     54 * `ouch` - The "bar" page before "foo" has been visited
     55 
     56 
     57 ## Templates
     58 Each page has a template that may or may not contain dynamic elements.
     59 
     60 In this example the root and bar nodes contains dynamic content.
     61 
     62 ### root
     63 
     64 ```
     65 This is the root page
     66 You have visited {{.count}}.
     67 ```
     68 
     69 
     70 ### foo
     71 
     72 ```
     73 Welcome to page foo.
     74 Please write something.
     75 ```
     76 
     77 
     78 ### bar
     79 
     80 ```
     81 Thanks for visiting foo and bar.
     82 You have written:
     83 {{.something}}
     84 ```
     85 
     86 
     87 ### ouch
     88 
     89 ```
     90 Please visit foo first.
     91 Any input to return.
     92 ```
     93 
     94 
     95 ## Scripts
     96 
     97 The scripts are responsible for defining menus, handling navigation flow control, and triggering external code handlers.
     98 
     99 ### root
    100 
    101 ```
    102 LOAD count 8        # trigger external code handler "count"
    103 LOAD something 0    # trigger external code handler "something"
    104 RELOAD count        # explicitly trigger "count" every time this code is executed.
    105 MAP count           # make the result from "count" available to the template renderer
    106 MOUT foo 0          # menu item
    107 MOUT bar 1          # menu item
    108 HALT                # render template and wait for input
    109 INCMP foo 0         # match menu selection 0, move to node "foo" on match
    110 INCMP bar 1         # match menu selection 1, move to node "bar" on match
    111 ```
    112 
    113 ### foo
    114 
    115 ```
    116 HALT                # render template and wait for input
    117 RELOAD something    # pass input to the "something" external code handler.
    118                     # The input will be appended to the stored value. 
    119                     # The "HAVESOMETHING" flag (8) will be set.
    120 MOVE _              # move up one level
    121 ```
    122 
    123 
    124 ### bar
    125 
    126 ```
    127 CATCH ouch 8 0      # if the "HAVESOMETHING" (8) flag has NOT (0) been set, move to "ouch"
    128 MNEXT next 11       # menu choice to display for advancing one page
    129 MPREV back 22       # menu choice to display for going back to the previous page
    130 MAP something       # make the result from "something" available to the template renderer
    131 HALT                # render template and wait for input
    132 INCMP > 11          # handle the "next" menu choice
    133 INCMP < 22          # handle to "back" menu choice
    134 INCMP _ *           # move to the root node on any input
    135 ```
    136 
    137 
    138 ### ouch
    139 
    140 ```
    141 HALT            # render template and wait for input
    142 INCMP ^ *       # move to the root node on any input
    143 ```
    144 
    145 ## External code handlers
    146 
    147 The script code contains `LOAD` instructions for two different methods. 
    148 
    149 ```
    150 import (
    151     "context"
    152     "fmt"
    153     "path"
    154     "strings"
    155 
    156 	testdataloader "github.com/peteole/testdata-loader"
    157 
    158 	"git.defalsify.org/vise.git/state"
    159 	"git.defalsify.org/vise.git/resource"
    160 )
    161 
    162 const (
    163 	USERFLAG_HAVESOMETHING = iota + state.FLAG_USERSTART
    164 )
    165 
    166 var (
    167 	baseDir = testdataloader.GetBasePath()
    168 	scriptDir = path.Join(baseDir, "examples", "intro")
    169 )
    170 
    171 type introResource struct {
    172 	*resource.FsResource 
    173 	c int64
    174 	v []string
    175 }
    176 
    177 func newintroResource() introResource {
    178 	fs := resource.NewFsResource(scriptDir)
    179 	return introResource{fs, 0, []string{}}
    180 }
    181 
    182 // increment counter.
    183 // return a string representing the current value of the counter.
    184 func(c *introResource) count(ctx context.Context, sym string, input []byte) (resource.Result, error) {
    185 	s := "%v time"
    186 	if c.c != 1 {
    187 		s += "s"
    188 	}
    189 	r := resource.Result{
    190 		Content: fmt.Sprintf(s, c.c),
    191 	}
    192 	c.c += 1 
    193 	return  r, nil
    194 }
    195 
    196 // if input is suppled, append it to the stored string vector and set the HAVESOMETHING flag.
    197 // return the stored string vector value, one string per line.
    198 func(c *introResource) something(ctx context.Context, sym string, input []byte) (resource.Result, error) {
    199 	c.v = append(c.v, string(input))
    200 	r := resource.Result{
    201 		Content: strings.Join(c.v, "\n"),
    202 	}
    203 	if len(input) > 0 {
    204 		r.FlagSet = []uint32{USERFLAG_HAVESOMETHING}
    205 	}
    206 	return r, nil
    207 }
    208 ```
    209 
    210 ## Handling long values
    211 
    212 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.
    213 
    214 A core feature of `vise` is to magically create browseable pages from these values from a pre-defined maximum output capacity for each page.
    215 
    216 Consider the case where the contents of the `something` symbol has become:
    217 
    218 ```
    219 foo bar
    220 baz bazbaz
    221 inky pinky
    222 blinky
    223 clyde
    224 ```
    225 
    226 Given a size constaint of 90 characters, the display will be split into two pages:
    227 
    228 ```
    229 Thanks for visiting foo and bar.
    230 You have written:
    231 foo bar
    232 baz bazbaz
    233 11:next
    234 ```
    235 
    236 ```
    237 Thanks for visiting foo and bar.
    238 You have written:
    239 inky pinky
    240 blinky
    241 clyde
    242 22:back
    243 ```
    244 
    245 
    246 ## Working example
    247 
    248 In the source code repository, a full working example of this menu can be found in `examples/intro`.
    249 
    250 To run it:
    251 
    252 ```
    253 make -B intro
    254 go run ./examples/intro
    255 ```
    256 
    257 Use `go run -tags logtrace ...` to peek at what is going on under the hood.
    258 
    259 To play the "Handling long values" case above, limit the output size by adding `-s 90`.