Initial bring over of VUI code. (Won't work yet.)

This commit is contained in:
Simon Forman
2019-05-06 13:07:01 -07:00
parent 67f042cc57
commit d4fdde50f9
19 changed files with 2891 additions and 0 deletions
+17
View File
@@ -0,0 +1,17 @@
see_stack == good_viewer_location open_stack
see_resources == list_resources good_viewer_location open_viewer
open_resource_at_good_location == good_viewer_location open_resource
see_log == "log.txt" open_resource_at_good_location
see_definitions == "definitions.txt" open_resource_at_good_location
round_to_cents == 100 * ++ floor 100 /
reset_log == "del log.lines[1:] ; log.at_line = 0" evaluate
see_menu == "menu.txt" good_viewer_location open_resource
# Ordered Binary Tree datastructure functions.
BTree-new == swap [[] []] cons cons
_BTree-P == over [popop popop first] nullary
_BTree-T> == [cons cons dipdd] cons cons cons infra
_BTree-T< == [cons cons dipd] cons cons cons infra
_BTree-E == pop swap roll< rest rest cons cons
_BTree-recur == _BTree-P [_BTree-T>] [_BTree-E] [_BTree-T<] cmp
BTree-add == [popop not] [[pop] dipd BTree-new] [] [_BTree-recur] genrec
+206
View File
@@ -0,0 +1,206 @@
'''
This file is execfile()'d with a namespace containing:
D - the Joy dictionary
d - the Display object
pt - the PersistTask object
log - the log.txt viewer
loop - the TheLoop main loop object
stack_holder - the Python list object that holds the Joy stack tuple
world - the Joy environment
'''
from joy.library import (
DefinitionWrapper,
FunctionWrapper,
SimpleFunctionWrapper,
)
from joy.utils.stack import list_to_stack, concat
from vui import core, text_viewer, stack_viewer
def install(command): D[command.name] = command
@install
@SimpleFunctionWrapper
def list_resources(stack):
'''
Put a string on the stack with the names of all the known resources
one-per-line.
'''
return '\n'.join(pt.scan()), stack
@install
@SimpleFunctionWrapper
def open_stack(stack):
'''
Given a coordinate pair [x y] (in pixels) open a StackViewer there.
'''
(x, (y, _)), stack = stack
V = d.open_viewer(x, y, stack_viewer.StackViewer)
V.draw()
return stack
@install
@SimpleFunctionWrapper
def open_resource(stack):
'''
Given a coordinate pair [x y] (in pixels) and the name of a resource
(from list_resources command) open a viewer on that resource at that
location.
'''
((x, (y, _)), (name, stack)) = stack
om = core.OpenMessage(world, name)
d.broadcast(om)
if om.status == core.SUCCESS:
V = d.open_viewer(x, y, text_viewer.TextViewer)
V.content_id, V.lines = om.content_id, om.thing
V.draw()
return stack
@install
@SimpleFunctionWrapper
def name_viewer(stack):
'''
Given a string name on the stack, if the currently focused viewer is
anonymous, name the viewer and persist it in the resource store under
that name.
'''
name, stack = stack
assert isinstance(name, str), repr(name)
if d.focused_viewer and not d.focused_viewer.content_id:
d.focused_viewer.content_id = name
pm = core.PersistMessage(world, name, thing=d.focused_viewer.lines)
d.broadcast(pm)
d.focused_viewer.draw_menu()
return stack
##@install
##@SimpleFunctionWrapper
##def persist_viewer(stack):
## if self.focused_viewer:
##
## self.focused_viewer.content_id = name
## self.focused_viewer.draw_menu()
## return stack
@install
@SimpleFunctionWrapper
def inscribe(stack):
'''
Create a new Joy function definition in the Joy dictionary. A
definition is given as a string with a name followed by a double
equal sign then one or more Joy functions, the body. for example:
sqr == dup mul
If you want the definition to persist over restarts, enter it into
the definitions.txt resource.
'''
definition, stack = stack
DefinitionWrapper.add_def(definition, D)
return stack
@install
@SimpleFunctionWrapper
def open_viewer(stack):
'''
Given a coordinate pair [x y] (in pixels) and a string, open a new
unnamed viewer on that string at that location.
'''
((x, (y, _)), (content, stack)) = stack
V = d.open_viewer(x, y, text_viewer.TextViewer)
V.lines = content.splitlines()
V.draw()
return stack
@install
@SimpleFunctionWrapper
def good_viewer_location(stack):
'''
Leave a coordinate pair [x y] (in pixels) on the stack that would
be a good location at which to open a new viewer. (The heuristic
employed is to take up the bottom half of the currently open viewer
with the greatest area.)
'''
viewers = list(d.iter_viewers())
if viewers:
viewers.sort(key=lambda (V, x, y): V.w * V.h)
V, x, y = viewers[-1]
coords = (x + 1, (y + V.h / 2, ()))
else:
coords = (0, (0, ()))
return coords, stack
@install
@FunctionWrapper
def cmp_(stack, expression, dictionary):
'''
The cmp combinator takes two values and three quoted programs on the
stack and runs one of the three depending on the results of comparing
the two values:
a b [G] [E] [L] cmp
------------------------- a > b
G
a b [G] [E] [L] cmp
------------------------- a = b
E
a b [G] [E] [L] cmp
------------------------- a < b
L
'''
L, (E, (G, (b, (a, stack)))) = stack
expression = concat(G if a > b else L if a < b else E, expression)
return stack, expression, dictionary
@install
@SimpleFunctionWrapper
def list_viewers(stack):
'''
Put a string on the stack with some information about the currently
open viewers, one-per-line. This is kind of a demo function, rather
than something really useful.
'''
lines = []
for x, T in d.tracks:
#lines.append('x: %i, w: %i, %r' % (x, T.w, T))
for y, V in T.viewers:
lines.append('x: %i y: %i h: %i %r %r' % (x, y, V.h, V.content_id, V))
return '\n'.join(lines), stack
@install
@SimpleFunctionWrapper
def splitlines(stack):
'''
Given a string on the stack replace it with a list of the lines in
the string.
'''
text, stack = stack
assert isinstance(text, str), repr(text)
return list_to_stack(text.splitlines()), stack
@install
@SimpleFunctionWrapper
def hiya(stack):
'''
Demo function to insert "Hi World!" into the current viewer, if any.
'''
if d.focused_viewer:
d.focused_viewer.insert('Hi World!')
return stack
+1
View File
@@ -0,0 +1 @@
Joypy log
+51
View File
@@ -0,0 +1,51 @@
name_viewer
list_resources
open_resource_at_good_location
good_viewer_location
open_viewer
see_stack
see_resources
see_definitions
see_log
reset_log
inscribe
evaluate
pop clear dup swap
add sub mul div truediv modulus divmod
pm ++ -- sum product pow sqr sqrt
< <= = >= > <>
& << >>
i dupdip
!= % & * *fraction *fraction0 + ++ - -- / < << <= <> = > >= >> ? ^
abs add anamorphism and app1 app2 app3 at average
b binary branch
choice clear cleave concat cons
dinfrirst dip dipd dipdd disenstacken div divmod down_to_zero drop
dudipd dup dupd dupdip
enstacken eq
first flatten floor floordiv
gcd ge genrec getitem grand_reset gt
help
i id ifte infra inscribe
key_bindings
le least_fraction loop lshift lt
map max min mod modulus mouse_bindings mul
ne neg not nullary
of or over
pam parse pick pm pop popd popdd popop pow pred primrec product
quoted
range range_to_zero rem remainder remove reset_log rest reverse
roll< roll> rolldown rollup rshift run
second select sharing show_log shunt size sort sqr sqrt stack step
step_zero sub succ sum swaack swap swoncat swons
take ternary third times truediv truthy tuck
unary uncons unique unit unquoted unstack
void
warranty while words
x xor
zip
+85
View File
@@ -0,0 +1,85 @@
What is it?
A simple Graphical User Interface for the Joy programming language,
written using Pygame to bypass X11 et. al., modeled on the Oberon OS, and
intended to be just functional enough to support bootstrapping further Joy
development.
It's basic functionality is more-or-less as a crude text editor along with
a simple Joy runtime (interpreter, stack, and dictionary.) It auto- saves
any named files (in a versioned home directory) and you can write new Joy
primitives in Python and Joy definitions and immediately install and use
them, as well as recording them for reuse (after restarts.)
Currently, there are only two kinds of (interesting) viewers: TextViewers
and StackViewer. The TextViewers are crude text editors. They provide
just enough functionality to let the user write text and code (Python and
Joy) and execute Joy functions. One important thing they do is
automatically save their content after changes. No more lost work.
The StackViewer is a specialized TextViewer that shows the contents of the
Joy stack one line per stack item. It's a very handy visual aid to keep
track of what's going on. There's also a log.txt file that gets written
to when commands are executed, and so records the log of user actions and
system events. It tends to fill up quickly so there's a reset_log command
that clears it out.
Viewers have "grow" and "close" in their menu bars. These are buttons.
When you right-click on grow a viewer a copy is created that covers that
viewer's entire track. If you grow a viewer that already takes up its
whole track then a copy is created that takes up an additional track, up
to the whole screen. Closing a viewer just deletes that viewer, and when
a track has no more viewers, it is deleted and that exposes any previous
tracks and viewers that were hidden.
(Note: if you ever close all the viewers and are sitting at a blank screen
with nowhere to type and execute commands, press the Pause/Break key.
This will open a new "trap" viewer which you can then use to recover.)
Copies of a viewer all share the same model and update their display as it
changes. (If you have two viewers open on the same named resource and edit
one you'll see the other update as you type.)
UI Guide
left mouse sets cursor in text, in menu bar resizes viewer interactively
(this is a little buggy in that you can move the mouse quickly and get
outside the menu, leaving the viewer in the "resizing" state. Until I fix
this, the workaround is to just grab the menu bar again and wiggle it a
few pixels and let go. This will reset the machinery.)
Right mouse executes Joy command (functions), and you can drag with the
right button to highlight (well, underline) commands. Words that aren't
names of Joy commands won't be underlined. Release the button to execute
the command.
The middle mouse button (usually a wheel these days) scrolls the text but
you can also click and drag any viewer with it to move that viewer to
another track or to a different location in the same track. There's no
direct visual feedback for this (yet) but that dosen't seem to impair its
usefulness.
F1, F2 - set selection begin and end markers (crude but usable.)
F3 - copy selected text to the top of the stack.
Shift-F3 - as copy then run "parse" command on the string.
F4 - cut selected text to the top of the stack.
Shift-F4 - as cut then run "pop" (delete selection.)
Joy
Pretty much all of the rest of the functionality of the system is provided
by executing Joy commands (aka functions, aka "words" in Forth) by right-
clicking on their names in any text.
To get help on a Joy function select the name of the function in a
TextViewer using F1 and F2, then press shift-F3 to parse the selection.
The function (really its Symbol) will appear on the stack in brackets (a
"quoted program" such as "[pop]".) Then right-click on the word help in
any TextViewer (if it's not already there, just type it in somewhere.)
This will print the docstring or definition of the word (function) to
stdout. At some point I'll write a thing to send that to the log.txt file
instead, but for now look for output in the terminal.
+1
View File
@@ -0,0 +1 @@
(t.