Curses gui progress report

251 views
Skip to first unread message

Edward K. Ream

unread,
May 3, 2017, 3:30:44 PM5/3/17
to leo-editor
The attached is a screen shot. It demonstrates the present layout. Almost nothing is functional.

There are quite a few details below.  Feel free to ignore or skim.

The outline pane

I was a bit worried about getting MLTree to work. There's no docs.  Happily, some really easy patterns appear in the code, and I was able to use them.  Here is the code that creates the outline pane as you see it in the screen shot:

def createCursesTree(self, c, form):
    '''Create the curses tree widget in the given curses Form.'''

    class BoxTitleTree(npyscreen.BoxTitle):
        _contained_widget = npyscreen.MLTree

    data = npyscreen.TreeData(ignore_root=True)
    for i in range(4):
        data.new_child(content='child %s' % (i))

    w = form.add(
        BoxTitleTree,
        max_height=8, # Subtract 4 lines
        name='Tree Pane',
        footer="Press i or o to insert text",
        values=data,
        slow_scroll=False,
    )
    assert hasattr(c.frame, 'tree_widget')
    c.frame.body_widget = w

As you can see, subclassing BoxTitle is the way to go.  Just this is enough to tell npyscreen to put the MLTree in the Boxed area.  It's slick.  I don't really know how it works, but then that's not important...

    class BoxTitleTree(npyscreen.BoxTitle):
        _contained_widget = npyscreen.MLTree

At present, the tree contains dummy data, created with these lines:

    data = npyscreen.TreeData(ignore_root=True)
    for i in range(4):
        data.new_child(content='child %s' % (i))

I'm not yet sure how to create nested data.  A bit of experimentation is needed.

Key handling

Leo now handles F-keys and Control keys passed to it. Ctrl-Q quits, Ctrl-S goes through the save logic. etc. F4 invokes my local binding: run-selected-unit-tests-locally = F4. This required a special case in IH.handle_input  in npyscreen/wgwidget.py. Apparently npyscreen handles (eats) all F-keys before Leo has a chance to handle them.

Unit testing

unitTest.leo now loads from the curses pane without any problem. Some unit tests are working, and mostly they do not interfere with (write into) the curses pane. More work is needed in this regard, but it's not necessary.

Still to do

1. Complete the linkage between wrapper classes and the curses widgets they wrap. A few ivars are still bound to g.NullObject.  These are about to disappear.  This work is a bit tricky, but there isn't much of it.

2. Make all high-level interface methods work.  The high-level interface involves wrapper classes.  The wrapper class then call widget (curses) methods to actually do the work.  This could be difficult work.  Happily, however, all of the widgets, including MLTree are subclasses of the MultiLine class in npyscreen/wgmultiline.py. Subclasses override stuff like key bindings, so only MultiLine needs to be studied in detail. It's not yet clear how capable MultiLine is, but I suspect it can do the job just as it is.

3. Complete "the circle". This typically is the trickiest phase.  I said in Ashland that Leo's tree code probably stresses outline classes more than any other app in the world.  The high-level interface is one part of completing the circle--control flows from Leo's core (commands or scripts) to the gui. Conversely, changes to the gui must call crucial methods in Leo's core, like LeoTree.select, LeoBody.onBodyChanged, etc. In such cases, control flows from the gui to Leo's core.  This is the circle of control/events that can't be allowed to loop endlessly.

Important: LeoTree.select and LeoBody.onBodyChanged are members of base classes.  They should not be overridden in subclasses.  Indeed, these methods are very tricky and should be left alone.  So it suffices that the gui manages to call these methods.

Schedule

Work has gone quickly so far.  My energy level is high.  Still, it's hard to say how much work remains.  I would say at least another week, but it could be much longer.

Edward
curses.png

Edward K. Ream

unread,
May 4, 2017, 7:10:35 AM5/4/17
to leo-editor
On Wednesday, May 3, 2017 at 2:30:44 PM UTC-5, Edward K. Ream wrote:
The attached is a screen shot. It demonstrates the present layout. Almost nothing is functional.

Recent revs add the high-level API to the body pane.  A largely non-functional CursesTextWrapper replaces a g.NullObject. Startup works, which is non-trivial.  Running all unit tests is revealing other problems.

The next, crucial, step is to make CursesTextWrapper work with the curses MultiLine widget. That may take a day or three.

Edward

Edward K. Ream

unread,
May 4, 2017, 3:33:50 PM5/4/17
to leo-editor
On Thursday, May 4, 2017 at 6:10:35 AM UTC-5, Edward K. Ream wrote:

The next, crucial, step is to make CursesTextWrapper work with the curses MultiLine widget.

It's now possible to run all unit tests using the curses gui without disrupting the curses app.

Ran 902 tests in 15.017s
FAILED (failures=177, errors=46, skipped=15)

Edward

Edward K. Ream

unread,
May 7, 2017, 9:02:24 PM5/7/17
to leo-editor
On Wednesday, May 3, 2017 at 2:30:44 PM UTC-5, Edward K. Ream wrote:
The attached is a screen shot. It demonstrates the present layout. Almost nothing is functional.

Here is a new screen shot:

- The "i" key inserted the "new headline" node. This took a bit of doing.
- Editing headlines is not functional yet.
- Changed the "OK" button to "Quit Leo".

Today's work added several new helper classes. The work is relatively straightforward, if a bit slow. I remain confident that all panes can be made fully functional.

Edward

Edward K. Ream

unread,
May 7, 2017, 9:04:01 PM5/7/17
to leo-editor
On Sunday, May 7, 2017 at 8:02:24 PM UTC-5, Edward K. Ream wrote:

Here is a new screen shot:

Attached.
curses-2.png

Terry Brown

unread,
May 7, 2017, 11:07:17 PM5/7/17
to leo-e...@googlegroups.com
Very nice.

Cheers -Terry

Edward K. Ream

unread,
May 8, 2017, 6:18:51 AM5/8/17
to leo-editor
On Sun, May 7, 2017 at 10:07 PM, Terry Brown <terry...@gmail.com> wrote:

> Today's work added several new helper classes. The work is relatively
> straightforward, if a bit slow. I remain confident that all panes can
> be made fully functional.

Very nice.

​Glad you like it.  But don't hold your breath ;-)

Edward

john lunzer

unread,
May 8, 2017, 2:34:43 PM5/8/17
to leo-editor
Exciting progress. This is going to be valuable work not just for using Leo in a console but also for any future work on integrating a new UI framework. 

Edward K. Ream

unread,
May 10, 2017, 12:21:11 PM5/10/17
to leo-editor
On Wednesday, May 3, 2017 at 2:30:44 PM UTC-5, Edward K. Ream wrote:

Almost nothing is functional.

The minibuffer now works. For example, typing exit-leo <return> exits Leo.

Most other commands will likely fail. Nevertheless, this is an important milestone. Considerable work was required to get key bindings working.

The next step will be to implement the high-level interface between wrapper and the underlying npyscreen widgets. This should be relatively straightforward. This will allow many more unit tests to pass.

Edward

john lunzer

unread,
May 10, 2017, 1:18:39 PM5/10/17
to leo-editor
Just tested this in the wild on Windows for the first time. While minimally functional it's exciting to see this running. The command "print-bindings" works, but doesn't wrap properly in the log window (which is fine). I just wanted to check that anything other that "exit-leo" would work, and it does!

It may go without saying but Python on Windows does not by default come with curses. Anyone wanting to demo the curses GUI on Windows can go to http://www.lfd.uci.edu/~gohlke/pythonlibs/#curses to get a curses wheel for your version of Python.

Fantastic work Edward. 

Edward K. Ream

unread,
May 10, 2017, 4:25:32 PM5/10/17
to leo-editor
On Wed, May 10, 2017 at 12:18 PM, john lunzer <lun...@gmail.com> wrote:
Just tested this in the wild on Windows for the first time. While minimally functional it's exciting to see this running. The command "print-bindings" works, but doesn't wrap properly in the log window (which is fine). I just wanted to check that anything other that "exit-leo" would work, and it does!

It's also possible to execute run-all-unit-tests-locally from the minibuffer. The results look like they are the same as before.

It may go without saying but Python on Windows does not by default come with curses. Anyone wanting to demo the curses GUI on Windows can go to http://www.lfd.uci.edu/~gohlke/pythonlibs/#curses to get a curses wheel for your version of Python.

​Yes, that's how I got curses up on Windows.  I thought I had documented that, but maybe not.​
 

Fantastic work Edward.

​Thanks. The pace picked up today.​
 
​The minibuffer now works in an intuitive manner.  I'll retrofit the headline code to match.

Please note, everyone, that there is a lot of work still to do:

- Just now I've been making sure that all classes refer to each other properly.  Each of the helpers of createCursesTop now contain "link checks", asserts that all the links are as expected and were not created previously.

- Next, all the wrapper classes will be made functional.  This will allow Leo's core to update widgets. This should be straightforward and the code should be very fast.

- Next, selecting headline widgets must select the proper nodes in the tree, and vice versa.  The wrapper tree code will use dicts similar to these dicts in qt_tree.py:

    self.item2positionDict = {}
    self.item2vnodeDict = {}
    self.position2itemDict = {}
    self.vnode2itemsDict = {} # values are lists of items.
    self.editWidgetsDict = {} # keys are native edit widgets, values are wrappers.

The code might be simpler than the Qt code because the curses headline widgets might not be recycled when trees are redrawn.  Or not.

This step can be tricky because the code must be careful to get in an endless "selection loop".  The user selects a tree node, which calls the base leoTree.select logic, which selects a tree node, which calls the leoTree.select logic...Happily, npyscreen generates no events on its own.  The gui code is free to generate just those "events" (calls to Leo's core) that it needs.

It will likely be a week or three before all this is working.

Oh yes. One more thing.  When the LeoMLTree class is working smoothly, I'd like to refactor it, creating a suggested npyscreen.MLTreeEditable class and a LeoMLTree subclass. My experience suggests that an "Editable" tree class can't be obtained merely by having a class inherit from both MLTree and some other "Editable" class.  I'll then propose that MLTreeEditable be part of the npyscreen.

Edward

Edward K. Ream

unread,
May 13, 2017, 9:35:59 AM5/13/17
to leo-editor
On Wednesday, May 10, 2017 at 3:25:32 PM UTC-5, Edward K. Ream wrote:

Please note, everyone, that there is a lot of work still to do:

As mentioned in a recent Engineering notebook post, the next phase involves having the drawing code understand (or generate) wrapper widgets for headlines.

I am now in what I call a "wrestling with code" phase. It's definitely a physical process. I also think of it as sculpting clay.

Leo is the perfect tool for this kind of thing.  I can copy/paste code from npyscreen classes for reference while working on subclasses.

The goal is to use Leo's existing vnode structure instead of the corresponding npyscreen TreeData objects.  Clearly, the goal is feasible. Leo's tree resources are far richer than npyscreen's. In practice, only the LeoMLTree.update method will change, so the task is in some sense bounded.

But this task is not straightforward.  I am in the process of "unwinding" the twisty little maze of calls to adapter methods in the MLTree class. This unwinding process will simplify the code and deepen my understanding of what exactly is going on. As the code gets simpler the way forward will start to emerge.

Edward

Edward K. Ream

unread,
May 13, 2017, 3:07:37 PM5/13/17
to leo-editor
On Sat, May 13, 2017 at 8:35 AM, Edward K. Ream <edre...@gmail.com> wrote:

I am now in what I call a "wrestling with code" phase.

​Good progress to report.  LeoMLTree.update has been refactored within an inch of its life. As a result, I am much more comfortable with what is happening, and I also can see the dogs that aren't barking.

The way forward is as follows:

1. Don't use any of the MultiLine base code for drawing the tree or keeping track of the contents of the tree.  Replace all that with vnodes. LeoMLTree will see be a subclass of MultiLine, so as to have access to event handling, widget layout, etc.

2. There is no need for any persistent headline widgets! The reason is simple: the npyscreen code doesn't use widgets to draw outlines!

3. tree.edit_widget can just return a string wrapper every time it is called!  This will be a subclass of StringTextWrapper in leoFrame.py. No need for any of the "association" dict used in the Qt gui code. 

All this will collapse the complexity of the tree code. The curses gui may soon be fully functional.

Edward

Edward K. Ream

unread,
May 14, 2017, 8:28:28 PM5/14/17
to leo-e...@googlegroups.com
On Saturday, May 13, 2017 at 2:07:37 PM UTC-5, Edward K. Ream wrote:

> I am now in what I call a "wrestling with code" phase.

Still true. I've just proved that it is necessary to over-ride neither the _print nor the update methods of the LeoTreeLine class.  That's great, because they are both complex methods.

Even better is the reason why: over-ridding the much simpler _get_string_to_print and display_value methods of the LeoTreeLine class suffices, at least for now. The _print and update methods are still around, but they are named XXX_print and XXX_update so they will never be called.

The next step will be to find some way of writing the outline using just vnodes rather than a separate tree of LeoTreeData nodes. This may require a complete rewrite of _print or _update, maybe combined with a rewrite of the LeoMLTree.update method. Significant invention/hacks will be required. The complexities involved are mind-boggling.

Still, today's work is clearly real progress. I'll be taking the great leap tomorrow.

Edward

Edward K. Ream

unread,
May 18, 2017, 10:08:21 AM5/18/17
to leo-editor
On Sunday, May 14, 2017 at 7:28:28 PM UTC-5, Edward K. Ream wrote:

>> I am now in what I call a "wrestling with code" phase.

Rev 290bfe9 is a significant milestone. Top-level nodes of the real Leo outline are drawn correctly with the "native" top-level switch enabled. Considerable work is still required in this phase of the project, which is far from the final phase. Otoh, this is arguably the most difficult phase, and it is now nearing its end.

Edward

Edward K. Ream

unread,
May 19, 2017, 5:26:33 PM5/19/17
to leo-editor
On Thursday, May 18, 2017 at 9:08:21 AM UTC-5, Edward K. Ream wrote:

Rev 290bfe9 is a significant milestone. Top-level nodes of the real Leo outline are drawn correctly with the "native" top-level switch enabled. Considerable work is still required in this phase of the project, which is far from the final phase. Otoh, this is arguably the most difficult phase, and it is now nearing its end.

f3df1d marks the end of this phase of the project.  The outline is drawn correctly using actual outline nodes (vnodes and positions), all arrows keys work as in Leo, headline editing works and nodes can be inserted and deleted correctly.

This was tedious and difficult work.  It accelerated this afternoon after fixing a nasty bug in the LeoValues cacher. Happily, the resulting code is straightforward. The "native" top-level switch highlights the changes needed to use Leo's vnode tree rather than a tree of npyscreen.TreeData objects.

Actually, such objects still exist (LeoTreeData nodes) but these nodes don't "carry" outline structure directly.  Instead, they just refer to Leo positions. LeoMLTree._set_line_values sets printing ivars as needed from the Leo positions.  This is the only place where outline structure is actually used, so there is no need for LeoTreeData (or LeoTreeLine) to define properties that would "deliver" the structure data in the form that used by other npyscreen classes. So this is a good encapsulation on npyscreen's part.

I am going to take a break to write up the work for the npyscreen list while I remember all relevant details. I am proud of the work. It should be helpful to others. The "native" switch highlights the changes. Btw, _set_line_values doesn't exist in the base MLTree class. It came into existence as the result of a major refactoring of MLTree.update. During this refactoring, all wretched weakref's disappeared from tree-related classes, never to be missed.

The next phases of this project will complete the circle of events.  Leo must be able to drive the screen, and user events must affect the Leo outline.  The various 'i', 'd', 'h', npyscreen outline commands (and others, such as '{', '}', '<', '>', etc) could be called prototypes of needed code. I expect the last phases of the project to be relatively straightforward.  We shall see...

Edward

lewis

unread,
May 19, 2017, 6:39:03 PM5/19/17
to leo-editor
This is an enormous body of work, congratulations.
I'm certain you will catch all issues as you continue this task. In the last few commits I have noticed that for Leo to load I need to increase the dimensions of my console from a default 80x23 to 80x31 minimum.
If I have 80x23 it fails with error:
"npyscreen\wgmultiline.py", line 90, in __init__
    self.height, str(self)))
npyscreen.wgwidget.NotEnoughSpaceForWidget: Height of 1 allocated. Not enough space allowed for <npyscreen.wgmultilineeditable.MultiLineEditable object at 0x000001EE31759F98>"

Apologies for this miniscule issue in the scheme of things, but it may be worth noting.

Regards
Lewis

Edward K. Ream

unread,
May 20, 2017, 3:05:50 AM5/20/17
to leo-editor
On Fri, May 19, 2017 at 5:39 PM, lewis <lewi...@operamail.com> wrote:
This is an enormous body of work, congratulations.

​Thanks.
 
In the last few commits I have noticed that for Leo to load I need to increase the dimensions of my console from a default 80x23 to 80x31 minimum.
If I have 80x23 it fails with error:
"npyscreen\wgmultiline.py", line 90, in __init__
    self.height, str(self)))
npyscreen.wgwidget.NotEnoughSpaceForWidget: Height of 1 allocated. Not enough space allowed for <npyscreen.wgmultilineeditable.MultiLineEditable object at 0x000001EE31759F98>"

​This has been so since the first commits that showed the tree widget​
​. I am not aware of any fix except to resize the console.

Edward

Edward K. Ream

unread,
May 21, 2017, 7:17:32 AM5/21/17
to leo-editor
On Friday, May 19, 2017 at 4:26:33 PM UTC-5, Edward K. Ream wrote:

> I expect the last phases of the project to be relatively straightforward.  We shall see...

Big progress last night. Previously, running all unit tests resulted in 150 failures. Now, all tests run with 21 failures and 3 errors. Just 4 or 5 real bugs likely cause all the remaining problems.

I expect the entire project to be complete in a week or less.

The breakthrough was discovering that the 2 or 3 unit tests that contain:
   
    exec(g.findTestScript(c,'@common x-marked-nodes test code'))

somehow ruin most following tests. I temporarily disabled these "toxic" tests. Eventually all tests must pass with them re-enabled.

Edward

P.S. A note about recent commits.  The F4 key is now bound (in my copy of myLeoSettings.leo) to the run-marked-unit-tests-locally. I mark nodes in unitTest.leo so I can zero in on specific failures.

Running unit tests from the curses gui sometimes changes unitTest.leo unexpectedly. This may be a bug that must be fixed, but that's for later. In the meantime, I commit unitTest.leo after marking nodes.  If running tests changes unitTest.leo, I do "git checkout leo\test" to restore it.

EKR

Edward K. Ream

unread,
May 22, 2017, 11:00:12 AM5/22/17
to leo-editor
On Sunday, May 21, 2017 at 6:17:32 AM UTC-5, Edward K. Ream wrote:

> ...all tests run with 21 failures and 3 errors.

Just now:

Ran 901 tests in 26.473s
FAILED
(failures=3, skipped=38)

These three failures are real, but minor problems. They can be ignored for now. There are much bigger fish to fry...

Important warning

This project is entering its most dangerous phase users. The possiblity for data loss is large. This is a direct consequence of the progress that is being made.

As the code really begins to look like it works, you must use extreme caution while trying it out. Please test the cursesGui2 plugin out only on expendable files, or files under git control.


> I expect the entire project to be complete in a week or less.

Heh.  Maybe still true, but I am beginning to remember just how complex the testing phase will be. There are no guarantees as to schedule. In particular, having all unit tests pass is no guarantee against data loss.

Edward

Edward K. Ream

unread,
May 22, 2017, 11:07:39 AM5/22/17
to leo-editor
On Monday, May 22, 2017 at 10:00:12 AM UTC-5, Edward K. Ream wrote:

> As the code really begins to look like it works, you must use extreme caution while trying it out. Please test the cursesGui2 plugin out only on expendable files, or files under git control.

Imo, the only sane strategy for early testers is as follows:

1. Before running Leo with --gui=curses, use git stash or git commit until git status reports nothing changed.

2. Do a git status after running Leo with --gui=curses.

3. If there are changes, expected or not, use git checkout to restore everything.

You have been warned.

Edward

Terry Brown

unread,
May 22, 2017, 11:49:25 AM5/22/17
to leo-e...@googlegroups.com
On Mon, 22 May 2017 08:00:12 -0700 (PDT)
"Edward K. Ream" <edre...@gmail.com> wrote:

> *Important warning*This project is entering its* most dangerous*
> phase users. The possiblity for data loss is large. This is a direct
> consequence of the progress that is being made.

I assume this risk is limited to people testing curses gui and not just
people following trunk. Out of interest, how many changes to
non-curses Leo code has the project required?

Cheers -Terry

Edward K. Ream

unread,
May 22, 2017, 12:21:25 PM5/22/17
to leo-editor
On Mon, May 22, 2017 at 10:49 AM, Terry Brown <terry...@gmail.com> wrote:
On Mon, 22 May 2017 08:00:12 -0700 (PDT)
"Edward K. Ream" <edre...@gmail.com> wrote:

> *Important warning*This project is entering its* most dangerous*
> phase users. The possiblity for data loss is large. This is a direct
> consequence of the progress that is being made.

I assume this risk is limited to people testing curses gui and not just
people following trunk.

​Yes. All real changes are in cursesGui2.py.
 
how many changes to
​ ​
non-curses Leo code has the project required?

​None of any consequence.  Yesterday I added a guard in the undo code. Most other changes involved improved traces.  See for yourself.

It would be surprising if real changes were needed.  This is the fourth or fifth gui that Leo has supported.

Edward

Edward K. Ream

unread,
May 22, 2017, 3:39:01 PM5/22/17
to leo-editor
On Monday, May 22, 2017 at 11:21:25 AM UTC-5, Edward K. Ream wrote:
On Mon, May 22, 2017 at 10:49 AM, Terry Brown <terry...@gmail.com> wrote:
 
>> how many changes to
 non-curses Leo code has the project required?

​> None of any consequence...Most other changes involved improved traces.  See for yourself.

I thought about this on my walk today.  Here are some attempts to have git show us the changes in leo\core since April 18, the day I started work on this project:

    git whatchanged --since="4/18/2017" leo\core >git_log.txt

This works, but alas most entries are for commit_timestamp.json. Stack overflow contains a discussion about excluding files with git filespecs, but I have yet to make that work.

This is much better:

    git whatchanged --since="4/19/2017" leo\core\leo*.py >git_log.txt

However, this shows only the commit messages, not the actual diffs. I made (by hand) the following list of files that have been changed:

    leoApp.py
    leoAst.py
    leoAtFile.py
    leoBeautify.py
    leoBridge.py
    leoCache.py
    leoChapters.py
    leoColorizer.py
    leoCompare.py
    leoConfig.py
    leoCommands.py
    leoExternalFiles.py
    leoFileCommands.py
    leoFind.py
    leoFrame.py
    leoGlobals.py
    leoGui.py
    leoHistory.py
    leoImport.py
    leoKeys.py
    leoMenu.py
    leoNodes.py
    leoPlugins.py
    leoRst.py
    leoTangle.py
    leoTest.py
    leoUndo.py
    leoVim.py

That's a surprising number of files, but the important question is whether there have been any significant changes in any of those files. I think not.  I like gitk the best for detailed inspections.  Like this:

    gitk --since="4/18/2017" leo\core\leoApp.py

Note that the last (bottom) entry shown is the commit before 4/18/2017.

This uses gitk to diff all files at once:

    gitk --since="4/18/2017" leo\core\leo*.py

I don't recall having any qualms about any of the changes make to Leo's core for this work, and I think I would have remembered any ;-) I would be shocked if any changes made to Leo's core caused any problems.  Certainly all unit tests have continued to pass and I have been eating my own dog food without any problems.  Still, I'll give this last set of diffs a look-see.

Edward

P. S. As a separate issue, I would like to suppress diffs that involve moving only a block of lines (maybe even only those delimited by Leo's node sentinels!). It may be possible to determine easily whether the moved block differs in any other way from the original block, but I'm not sure. Imo, this would be a really nice post-pass to apply to git diff.  I've wanted something like this for a long time...

Edward

Edward K. Ream

unread,
May 22, 2017, 3:52:26 PM5/22/17
to leo-editor
On Monday, May 22, 2017 at 2:39:01 PM UTC-5, Edward K. Ream wrote:

 > gitk --since="4/18/2017" leo\core\leo*.py
...

> I'll give this last set of diffs a look-see.

There's nothing of great interest. As expected, most changes involved tracing and headline comments.  Here are the most important changes, almost a month ago now:

May 5, 957c58: Reverted changes at the ill-fated d4f481bf commit that was supposed to fix #466, but broke body editors.
  
May 1-4: Added broadcaster/listener logging.

May 1: Added support for --gui=curses in LeoApp.py.

And that's it.

Edward

Edward K. Ream

unread,
May 23, 2017, 6:17:34 PM5/23/17
to leo-editor
On Sunday, May 21, 2017 at 6:17:32 AM UTC-5, Edward K. Ream wrote:

Big progress last night. Previously, running all unit tests resulted in 150 failures. Now, all tests run with 21 failures and 3 errors.

And now only one test fails. This is a thorny headline-update issue. It will get fixed eventually, but probably near the end of the project.

More importantly, the code now looks and acts like a real Leo.  See the attached screen shot.

- Mouse clicks properly switches nodes (change c.p), as do arrow keys.
- Body text properly tracks c.p.
- An "Icon area", delimited by colons, indicates status:  For example :*TCM:
     *  The node is the selected node.
     T The node has text.
     C The node is a clone.
     M The node is marked.

Summary

Today's work added just a few dozen lines of code. More importantly, lots of code is gone. At last I am beginning to understand what is, and isn't, necessary.

Significant work remains. For example, changes to headline and body text probably do not update vnodes properly.

The save command is disabled in several places, to minimize the risk of data loss. However, please do remember prior warnings. They still apply.

Edward
CursesLeo.png

Edward K. Ream

unread,
May 24, 2017, 6:51:02 AM5/24/17
to leo-editor
On Tuesday, May 23, 2017 at 5:17:34 PM UTC-5, Edward K. Ream wrote:

> At last I am beginning to understand what is, and isn't, necessary.

You could call this post an Engineering Notebook post, but it may be of more general interest. This project looks to be almost complete, except for optional details like syntax coloring, tab completion in the minibuffer, etc.

When I awoke this morning I realized that an ugly hack has a bigger meaning.  The get_nth_visible_position method returns the nth visible node, in Leo's tree. It starts at the c.rootPosition() and calls p.moveToVisNext until it has reached the nth node. Nothing could be more simple minded.

Yes, this is slow, but that doesn't matter, for several reasons:

1. In practice, few nodes are ever visible.

2. You could say that this single method replaces all the Qt tree-drawing code.  Of course, the npyscreen tree drawing code still exists, so really this method actually replaces all the complex "item caching" logic in the Qt tree-drawing code.

3. There is no good alternative ;-) Without having npyscreen redraw the screen (and that would be expensive), there is no other way to associate areas on the screen (MLTree.cursor_line) with positions in the outline. Caching data (of any kind) wouldn't work because the cache must be invalidated on every redraw!

As I write this, I see that get_nth_visible_position doesn't handle chapters and clones correctly.  That will be easy to fix.

I realized one more thing when I awoke. After the initial irritation with the twisty little maze of npyscreen code, I see that the npyscreen classes (and especially their data) have been surprisingly easy to use. The proof is in the LeoMLTree event handlers. All are perfectly straightforward.  I'll have to congratulate the npyscreen folks.

Edward

Edward K. Ream

unread,
May 24, 2017, 7:01:40 AM5/24/17
to leo-editor
On Wednesday, May 24, 2017 at 5:51:02 AM UTC-5, Edward K. Ream wrote:

> get_nth_visible_position doesn't handle chapters and clones correctly.  That will be easy to fix.

This became apparent after studying and simplifying p.moveToVisNext. This is a potentially dangerous change to Leo's core, completely unrelated to the curses work. The old code was simply too ugly to endure ;-)

All tests pass, and I am happily eating my own dog food, but I might not have had the gumption to make this change without git.

Edward

Edward K. Ream

unread,
May 24, 2017, 9:56:40 AM5/24/17
to leo-editor
On Tuesday, May 23, 2017 at 5:17:34 PM UTC-5, Edward K. Ream wrote:

> the code now looks and acts like a real Leo.  See the attached screen shot.

Rev bb711d removes the confusing structure lines from the outline. Attached is a new screen shot.  Happily, this also collapses the code.

Now, + indicates an unexpanded node, - indicates an expanded node, and a blank indicates a node without children.

Edward
NewOutline.png

Edward K. Ream

unread,
Jun 2, 2017, 11:26:41 AM6/2/17
to leo-editor
On Wednesday, May 24, 2017 at 6:01:40 AM UTC-5, Edward K. Ream wrote:

I am back at work on the curses gui project.  Key handling is insanely complicated, much as in Leo itself.

My goal is to leave npyscreen.InputHandler.handle_input unchanged. The reason is simple--I don't know how to change it without unintended consequences.

Many handlers must be over-ridden so they update both Leo and npyscreen data. Alas, subclassing event handlers doesn't connect them.  They must be entered into tables, which sounds easy but isn't. Maybe in a day or three.

Edward

Edward K. Ream

unread,
Jun 5, 2017, 8:18:10 AM6/5/17
to leo-editor
On Friday, June 2, 2017 at 10:26:41 AM UTC-5, Edward K. Ream wrote:

> I am back at work on the curses gui project.  Key handling is insanely complicated, much as in Leo itself.

This weekend's work has been full of tedious, picky details.  Happily, the results are fairly good:

The various classes now set their bindings rather than add to their bindings. This makes the intent of the code clearer and prevents unintended interactions.  The Log and Body pane now work tolerably well, and in the same way, as follows:

Outer mode (not editing): Only the following bindings are in effect:

- e: enter edit mode.
- d: delete the presently selected line.
- tab and shift-tab: select another pane.
- up/down arrows: select another line.
- page up/down keys: select another line.

No other printable character does anything, which eliminates confusion and odd behaviour.

Edit mode: This takes getting used to. I would like to change it, but that's beyond my abilities at present. Edit mode defines a range of lines that are being edited.  Hitting return extends the range.  Initially, the range consists of a single line, with the cursor at the end of the line.

Moving outside the range with up/down arrow keys ends editing. It's not always clear what the range of lines is, or whether edit mode is in effect.  To fix the latter problem, the surrounding pane now says "Body Pane (editing)" or "Log Pane (editing)" when edit mode is in effect.

It is possible to add new lines when editing, but at present the new "empty" line must end in a blank(!!). It seems impossible to delete a line (that is a newline) in editing mode.  That's why there is the 'd' binding in outer mode.

Imo, the various body editing classes are far from great, but short of a complete rewrite I am stuck trying to make do with what exists.

Summary

The present operation of the body and log panes will do for now. The results of all this difficult and picky work look like perfectly ordinary and straightforward code. In fact, it is the interactions between bindings that are important, and those interactions are hidden in plain sight in various binding tables.

The crucial last steps are making sure that the screen always stays in sync with Leo's underlying data structures. This involves updating those structures whenever the outline or body pane changes.  Only a few (tricky?) lines of code will be involved.

I hope to have the curses gui fit for real testing in a day or three.  At that time I'll re-enable the save command.  When that happens the curses gui will become quite dangerous, as I've explained before.

Edward
Reply all
Reply to author
Forward
0 new messages