My brother Speed and I have spent many happy hours in the past week 
discussing LeoWapp (Leo as a web app). My firm conclusion is that LeoWapp 
will be straightforward!  I expect to have working code in a matter of 
weeks. This is a *simpler *project than Leo's console gui.

This post is intended for Leo's devs, especially Joe Orr. This post 
explains why the design must be as it is. No real knowledge of Leo's code 
is needed.  I'll explain all required concepts as I go along.

*Big picture*

LeoWapp will have two components:

1. A *browser gui* for Leo, written in python, enabled by Leo's 
--gui=browser command-line option.
2. A *web component*, say *leowapp.py*, based on mod_http.py. leowapp.py 
will be written in python, but it will create a page containing significant 
javascript code.

That's all! This is the simplest design that could possibly meet the 
requirements discussed below.

To start LeoWapp, users will use --gui=browser on the command line.  This 
will start a python server in Leo's gui code and a javascript server in the 
web page. Later, we may well wrap the code in Docker or other virtual 
machine.  As explained in another post 
<https://groups.google.com/forum/#!topic/leo-editor/Gy6eMQdZq3g>, we can 
mostly ignore security concerns during development. However, Speed is 
investigating these issues as we speak.

*Terminology*

Speed and I use the words "python" and "javascript" as synecdoches 
<https://en.wikipedia.org/wiki/Synecdoche>. Aa part stands for the whole. 
Instead of saying, "the javascript code running on Leo's web page in the 
browser sends a message to the python server running in Leo's gui code", 
I'll just say, "javascript sends a message to python".


*Leo must have a new gui*

A new gui because is the one and *only *way to get all of Leo's features 
without rewriting all of Leo in javascript.  Happily, this is relatively 
straightforward.

All of Leo's guis implement the so-called *High Level Interface*.  Leo's 
core code knows (almost) *nothing *about what gui is being used.  For Qt, 
for example, the qt gui code translates calls to the high-level interface 
into calls to Qt methods.  Furthermore, *only* the Qt gui code knows 
anything about handling Qt events.

The situation will be exactly the same for the browser gui.  The browser 
gui will implement the high-level interface, calling the javascript code to 
implement the intended actions.  The browser gui code (python) will also 
handle events generated by javascript.  The details of the interaction 
between python and javascript constitute the *Private Interface*. We can 
change the private interface at any time, including after first release, 
because Leo's core will have absolutely no knowledge of it.

*About leowapp.py*

This plugin will be based initially on mod_http.py.  The javascript DOM can 
easily generate all required gui events.  leowapp.py will translate those 
events to messages on the private interface.

The final form of the javascript is an open question.  We'll likely start 
with jQuery.

*Debugging and testing*

As with the console gui, a top priority will be to run unit tests *using 
the browser gui*. There will be complications involved in making this 
happen, but this work will instantly pay off.

I'll be running Leo on a local machine, so the python code can call g.trace 
as usual.  No need for fancy logging.

It would be possible to *mirror* the browser outline by showing the Qt 
version of the outline in addition to the browser view.  Speed and I call 
this *two-headed Leo*.  It's not clear whether this is worth doing, but as 
a thought experiment it helps clarify the messages that must pass over the 
private interface.

*Requirements*

We want the user to be able do any of the following *from the browser:*

1. Ctrl-B (execute-script).
2. Alt-x<command-name><return>
3. Alt-x<command-prefix><tab>
4. Select a new node.

These requirements will drive the design of the private interface.  At 
present, I know only the general shape of the solution.  But clearly, it is 
*not 
possible* for the private api to enumerate all possible interactions 
explicitly.  Instead, a chain of messages must pass between python and 
javascript, very similar to how the Qt gui code interacts with Qt.

Several examples should make this clear.

*execute-script*: Suppose the body text contains just `g.es("hello")`  
Here's what happens with the Qt gui, and any other gui:

- Leo discovers the script by starting with the body and expanding section 
references and @others.
  Leo uses c.p.b (not gui calls) to get the body text, and p2.b to get 
another other required body text.
- Leo passes the script to exec, with a namespace that includes c, g and p.
- The executing script, via g.es, calls c.frame.log.put, which is part of 
the high-level interface.
- c.frame.log.put calls the corresponding gui code, which writes to actual 
Qt widget.
- Depending on what Qt method gets called, Qt may generate events, which 
the Qt gui code handles or ignores.

Exactly the same thing will happen with the browser interface, regardless 
of the complexity of the executed script.

*Minibuffer*: Leo's minibuffer code uses only the high-level interface, 
iirc, so all is well. If there are problems we could always add optional 
methods to the high-level interface.

*Tab completion in the minibuffer*: The high-level interface include 
methods to discover the text (in the gui) of any widget, so once again no 
new code needs to be written.  However, javascript might shortcut the 
process of typing completion if that were useful.

*Select a new node*: This is the acid test. I'll do this as soon as 
possible to ensure that there are no gotchas.

The *base *tree.select method should be used *as is* by all guis. That is, 
guis are *not* supposed to override this method.  I am confident that this 
will remain to be true for the browser gui, but the private interface 
should suffice to handle any complications.

*Non issues*

Nothing need be done to disable existing plugins.  Gui-related plugins, 
such as todo.py, already must test g.app.gui.guiName() to see whether they 
are compatible with the present gui.

Only minimal changes will be needed to Leo's core.  Just as with the 
console gui, Leo will support the --gui=browser option with a small piece 
of code in leoApp.py. This code will creates and starts the gui  The gui is 
responsible for implementing the event loop, etc.

*Summary*

Leo's browser gui will allow access to all of Leo's features from the 
browser. This gui will implement the full High Level Interface and will use 
the private interface to communicate with the browser.

The private interface connects the python and javascript code. It can be 
freely modified at any time, including after development. The private 
interface will define *commands *sent from python to javascript, and *events 
*sent from javascript to python. Speed thinks that synchronous events will 
simplify the code.  We'll see.

I have intentionally slid past many potential complications.  I know from 
implementing 5 or 6 previous guis that all such complications can be 
handled relatively easily.  The browser gui is likely to be *much easier* 
to do than the console gui.

The new design is the simplest thing that could possibly work, and the 
simplest thing that could meet all requirements.  Imo, it's time to start 
coding. Please let me know if I have forgotten anything important.

I will be doing the coding.  Speed is working on packaging and security 
issues. These will come into play if we ever want to allow remote access to 
LeoWapp.

Edward

-- 
You received this message because you are subscribed to the Google Groups 
"leo-editor" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
To post to this group, send email to [email protected].
Visit this group at https://groups.google.com/group/leo-editor.
For more options, visit https://groups.google.com/d/optout.

Reply via email to