Initial bring over of VUI code. (Won't work yet.)
This commit is contained in:
@@ -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
|
||||
@@ -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
|
||||
@@ -0,0 +1 @@
|
||||
Joypy log
|
||||
@@ -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
|
||||
@@ -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.
|
||||
@@ -0,0 +1 @@
|
||||
(t.
|
||||
Reference in New Issue
Block a user