changeset 1b4d236c3443 in joypy/Joypy details: http://hg.osdn.jp/view/joypy/Joypy?cmd=changeset;node=1b4d236c3443 user: Simon Forman <sform****@hushm*****> date: Wed May 27 09:14:21 2020 -0700 description: Remove logging. changeset 2fabf83489a6 in joypy/Joypy details: http://hg.osdn.jp/view/joypy/Joypy?cmd=changeset;node=2fabf83489a6 user: Simon Forman <sform****@hushm*****> date: Wed May 27 11:29:12 2020 -0700 description: Minor cleanup. changeset 43291649011f in joypy/Joypy details: http://hg.osdn.jp/view/joypy/Joypy?cmd=changeset;node=43291649011f user: Simon Forman <sform****@hushm*****> date: Wed May 27 11:39:05 2020 -0700 description: Change `main.py` to a proper script called `xerblin`. changeset 831c0acb1d00 in joypy/Joypy details: http://hg.osdn.jp/view/joypy/Joypy?cmd=changeset;node=831c0acb1d00 user: Simon Forman <sform****@hushm*****> date: Wed May 27 11:53:17 2020 -0700 description: A start on docs for world module. changeset 041a805aec34 in joypy/Joypy details: http://hg.osdn.jp/view/joypy/Joypy?cmd=changeset;node=041a805aec34 user: Simon Forman <sform****@hushm*****> date: Wed May 27 11:58:20 2020 -0700 description: Worlds don't need text_widget. changeset f5e6b86968db in joypy/Joypy details: http://hg.osdn.jp/view/joypy/Joypy?cmd=changeset;node=f5e6b86968db user: Simon Forman <sform****@hushm*****> date: Wed May 27 11:59:44 2020 -0700 description: xerblin is a script now. changeset 7b91ef2f0f91 in joypy/Joypy details: http://hg.osdn.jp/view/joypy/Joypy?cmd=changeset;node=7b91ef2f0f91 user: Simon Forman <sform****@hushm*****> date: Wed May 27 12:41:23 2020 -0700 description: Docs for world module. changeset 14269904230b in joypy/Joypy details: http://hg.osdn.jp/view/joypy/Joypy?cmd=changeset;node=14269904230b user: Simon Forman <sform****@hushm*****> date: Wed May 27 17:45:39 2020 -0700 description: Some bits of docs. diffstat: docs/GUI-docs/source/index.rst | 122 ++++++++++++++++++++++++- docs/GUI-docs/source/main.rst | 6 - docs/GUI-docs/source/world.rst | 3 + scripts/xerblin | 200 +++++++++++++++++++++++++++++++++++++++++ setup.py | 6 +- start-with-i3.sh | 2 +- start.bat | 1 - xerblin/gui/__main__.py | 24 ---- xerblin/gui/main.py | 198 ---------------------------------------- xerblin/gui/textwidget.py | 25 +--- xerblin/gui/world.py | 110 +++++++++++++++------ 11 files changed, 410 insertions(+), 287 deletions(-) diffs (truncated from 909 to 300 lines): diff -r 52e2ea9f5874 -r 14269904230b docs/GUI-docs/source/index.rst --- a/docs/GUI-docs/source/index.rst Mon May 25 21:45:27 2020 -0700 +++ b/docs/GUI-docs/source/index.rst Wed May 27 17:45:39 2020 -0700 @@ -3,14 +3,130 @@ You can adapt this file completely to your liking, but it should at least contain the root `toctree` directive. -Welcome to Xerblin's documentation! +Xerblin Documentation =================================== +A Graphical User Interface for `Thun <https://joypy.osdn.io>`_. + +History +---------------------------- + +A long ago I found a copy of `"System Design from Provably Correct Constructs" <https://archive.org/details/systemdesignfrom00mart>`_ +at the Seattle public library. I didn't realize it at the time but I now +know that it is basically a presentation of Dr. Margaret +Hamilton's Higher-Order Software (HOS). + +Dr. Hamilton coined the term "software engineering" while developing the +software for Apollo 11. She went on to design a system that permitted +bug-free software development and +attempted to market it. + +In essence it's a thin AST that is only modified by operations that +preserve certain kinds of correctness (i.e. type safety), with a tiny +core of essential combinators that are combined (in "provably correct" +ways) to form control-flow constructs. I was struck by the essential +simplicity and spent time on and off trying to get a implementation +working. (It never amounted to much but it DID get me my first job as a +programmer!) + + + + + +Edsger Dijkstra panned it: `EWD852: Judging "HOS" from a distance <https://www.cs.utexas.edu/users/EWD/transcriptions/EWD08xx/EWD852.html>`_. +I don't think he was right, but I include a link to it here for +completeness. + + +It is described in `Universal Systems Language <https://en.wikipedia.org/wiki/Universal_Systems_Language>`_. + + +Eventually, I found Manfred von Thun's Joy language and realized that it was better than my thing and now I've implemented that in Python in Continuation-Passing Style. + +Structure +---------------------------- + +This simple GUI takes innovations from +`the Oberon OS <http://www.projectoberon.com>`_ +and +`Jef Raskin's "Humane Interface". <https://archive.org/details/humaneinterfacen00rask>`_ +There are no separate "apps" or programs, only one +body of commands that can be "scripted" by the user. Mouse interaction +and CLI are unified. For example, you can click on commands, and then +make a "script" (a new command) out of the commands after the fact. + +All files are kept in a VCS including the current system state, and +autosaved after every change (so you can literally kick out the plug, +plug it back in, and keep going from where you left off.) Never lose +work. + + +Commands +---------------------------- + +Mouse Chords +^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Mouse button chords (to cancel a chord, click all three mouse buttons.) + ++--------+--------+------------------------------------------------+ +| First | Second | Action | ++========+========+================================================+ +| Left | | Point, sweep selection. | ++--------+--------+------------------------------------------------+ +| Left | Middle | Copy selection to stack. | ++--------+--------+------------------------------------------------+ +| Left | Right | Run the selection as a Joy expression. | ++--------+--------+------------------------------------------------+ +| Middle | | Paste selection (bypassing stack). | +| | | Click and drag to scroll. | ++--------+--------+------------------------------------------------+ +| Middle | Left | Paste copy as text from top of stack. | ++--------+--------+------------------------------------------------+ +| Middle | Right | Pop from top of stack, paste as test. | ++--------+--------+------------------------------------------------+ +| Right | | Execute command. | ++--------+--------+------------------------------------------------+ +| Right | Left | Print docs of command. | ++--------+--------+------------------------------------------------+ +| Right | Middle | Lookup word (kinda useless now) | ++--------+--------+------------------------------------------------+ + + +Keyboard +^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +- ``Control-Enter`` - Run the selection as Joy code, or if there's no selection the line containing the cursor. +- ``F3`` - Copy selection to stack. +- ``Shift-F3`` - Cut selection to stack. +- ``F4`` - Paste item on top of stack to insertion cursor. +- ``Shift-F4`` - Pop and paste top of stack to insertion cursor. + +There are some commands bound to keys in the config file: + +- ``F5`` - ``swap`` +- ``F6`` - ``dup`` +- ``Shift-F5`` - ``roll<`` +- ``Shift-F6`` - ``roll>`` +- ``F7`` - ``over`` +- ``Shift-F7`` - ``tuck`` +- ``F8`` - ``parse`` +- ``F12`` - ``words`` +- ``F1`` - ``reset_log show_log`` +- ``Escape`` - ``clear reset_log show_log`` +- ``Control-Delete`` - ``pop`` +- ``Control-i`` - ``i`` + +You can edit the ``thun.config`` file to change these. + + +Modules +---------------------------- + .. toctree:: :maxdepth: 2 - :caption: Contents: - main + world textwidget diff -r 52e2ea9f5874 -r 14269904230b docs/GUI-docs/source/main.rst --- a/docs/GUI-docs/source/main.rst Mon May 25 21:45:27 2020 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,6 +0,0 @@ - -``xerblin.gui.main`` -=================================== - -.. automodule:: xerblin.gui.main - :members: diff -r 52e2ea9f5874 -r 14269904230b docs/GUI-docs/source/world.rst --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/docs/GUI-docs/source/world.rst Wed May 27 17:45:39 2020 -0700 @@ -0,0 +1,3 @@ + +.. automodule:: xerblin.gui.world + :members: diff -r 52e2ea9f5874 -r 14269904230b scripts/xerblin --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/scripts/xerblin Wed May 27 17:45:39 2020 -0700 @@ -0,0 +1,200 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +# +# Copyright © 2018-2020 Simon Forman +# +# This file is part of Xerblin. +# +# Xerblin is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Xerblin is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with Xerblin. If not see <http://www.gnu.org/licenses/>. +# +# +# This is a script, the module namespace is used as a kind of singleton +# for organizing the moving parts of the system. +# +# (The docstring doubles as a header that the system prints, see below. +# It's a two-line string broken up into chunks so you can read it in the +# source without wrapping. In the Text widgets it will be wrapped.) +('''\ +Xerblin - Copyright © 2018 Simon Forman +''' +'This program comes with ABSOLUTELY NO WARRANTY; for details right-click "warranty".' +' This is free software, and you are welcome to redistribute it under certain conditions;' +' right-click "sharing" for details.' +' Right-click on these commands to see docs on UI commands: key_bindings mouse_bindings') + +import logging, os, pickle, sys +from datetime import datetime +from textwrap import dedent +from configparser import RawConfigParser + +from xerblin.gui.utils import init_home, argparser, FileFaker +from xerblin.gui.textwidget import TextViewerWidget, tk, get_font +from xerblin.gui.world import StackWorld +from xerblin.gui.controllerlistbox import StackListbox +from joy.library import initialize, DefinitionWrapper +from joy.utils.stack import stack_to_string + + +DATETIME_FORMAT = 'Thun • %B %d %a • %I:%M %p' +VIEWER_DEFAULTS = dict(width=80, height=25) + + +args = argparser.parse_args() +JOY_HOME = args.joy_home +repo = init_home(JOY_HOME) +homed = lambda fn: os.path.join(JOY_HOME, fn) + + +cp = RawConfigParser() +# Don't mess with uppercase. We need it for Tk event binding. +cp.optionxform = str +with open(os.path.join(args.joy_home, 'thun.config')) as f: + cp.read_file(f) + + +GLOBAL_COMMANDS = dict(cp.items('key bindings')) + + +def repo_relative_path(path): + return os.path.relpath( + path, + os.path.commonprefix((repo.controldir(), path)) + ) + + +def commands(): + ''' + We define a bunch of meta-interpreter command functions here and + return them in a dictionary. They have all the contents of this + module in their scope so they can e.g. modify the log viewer window. + ''' + # pylint: disable=unused-variable + + def key_bindings(*args): + commands = [ # These are bound in the TextViewerWidget. + 'Control-Enter - Run the selection as Joy code, or if there\'s no selection the line containing the cursor.', + 'F3 - Copy selection to stack.', + 'Shift-F3 - Cut selection to stack.', + 'F4 - Paste item on top of stack to insertion cursor.', + 'Shift-F4 - Pop and paste top of stack to insertion cursor.', + ] + for key, command in GLOBAL_COMMANDS.items(): + commands.append('%s - %s' % (key.lstrip('<').rstrip('>'), command)) + print('\n'.join([''] + sorted(commands))) + return args + + + def mouse_bindings(*args): + print(dedent(''' + Mouse button chords (to cancel a chord, click the third mouse button.) + + Left - Point, sweep selection + Left-Middle - Copy the selection, place text on stack + Left-Right - Run the selection as Joy code + + Middle - Paste selection (bypass stack); click and drag to scroll. + Middle-Left - Paste from top of stack, preserve + Middle-Right - Paste from top of stack, pop + + Right - Execute command word under mouse cursor + Right-Left - Print docs of command word under mouse cursor + Right-Middle - Lookup word (kinda useless now) + ''')) + return args + + + def reset_log(*args): + log.delete('0.0', tk.END) + print(datetime.now().strftime(DATETIME_FORMAT)) + return args + + + def Thun(*args): + print(__doc__) + return args + + + def show_log(*args): + log_window.wm_deiconify() + log_window.update() + return args + + + def show_stack(*args): + stack_window.wm_deiconify() + stack_window.update() + return args + + + def grand_reset(s, e, d): + stack = world.load_stack() or () + log.reset()