This post will be of interest only to those with a strong interest in
Leo's internals.  It will be pre-writing for some new technical
documentation.  Feel free to ignore.

For almost 15 years Leo has been written using a limited set of
classes.  These were "big" classes, implementing major modules of
Leo.  There is nothing wrong with these classes, and they will remain
unchanged, except insofar as they will be simplified by the classes I
am about to discuss.

Recently, I have become aware that Leo's code could be considerably
simplified by adding "smallish" classes.  Indeed, I now think the
distinction between big and small classes is unhelpful.  The most
important part of the design of a class is simply whether a class
implements an understandable concept.

With this introduction, here is a short summary of Leo's new classes.
Some have not been fully implemented.  Getting them all to work is a
big part of the rewrite of Leo's config, loading and key-handling
code.

===== LoadManager

This class handles all the messy details of loading .leo files at
startup.  That's its *purpose*.

At the code level, it encapsulates almost all the code in runLeo.py,
as well as some methods in leoGlobals.py that really belong somewhere
else.  Creating a class simplifies the code to a surprising degree: 5
or 6 ivars of the class represent command-line options.  These ivars
are always available: there is no need to pass them around as
arguments.

Defining a new class means that it might be possible to reuse this
code in the leoBridge module, which would eliminate a lot of duplicate
code.

===== ModeController and ModeInfo

The ModeController class represents a collection of modes.  The
ModeInfo class represents a single mode.

Without these classes, the code in leoKeys.py is extremely hard to
understand.  In fact, the present code is a perfect example of the
problems with procedural programming: client code is burdened with
knowing way too many details about matters that it shouldn't have to
know about.  Furthermore, that data itself is hard to understand:
it's too "raw".  These classes provide "identity" for data.  The value
of repr(aModeInfo) is surprisingly large.

===== LogManager

This class represents the global log.  It hides the details of the log
from the g.app class and several other pieces of code.

At present, the interface to this class is procedural.  That is, the
present g.app methods that will be moved into this class have a
procedural rather than descriptive nature.  I'm not sure how much this
will change, but creating this class may create opportunities that
were not apparently previously.

===== KeyStroke and ShortcutInfo

I've discussed these previously.  The KeyStroke class is a wrapper for
plain strings.  It's most important attribute is its *identity*.  It
announces that its contents is a canonicalized value, not a raw user
settings string or any other kind of data associated with key
handling.

Similar remarks apply to ShortcutInfo objects.  Their identity
clarifies the code.  The former code used g.bunches.  In complex code
such as leoKeys.py, such anonymous objects really obfuscate matters.

===== EditCommandsManager

I wrote and tested this class last night.  It solves a problem that
has been annoying me ever since I created leoEditCommands.py.  The
problem is this:  without this class the classesList has to be defined
at the end of the module, after all classes have been imported.
Worse, several module-level methods were needed to manage the
classesList.

In the new scheme, each Commander creates an EditCommandsManager, and
the code that previously had to call the module-level method
leoEditCommands.x(c) now simply calls c.editCommandManager.x().  This
is much cleaner and avoids several very ugly imports.  Which brings me
to...

===== Avoiding imports of Leo files

I would like to avoid having Leo's modules import each other wherever
possible.  This would simplify Leo's startup process considerably.

At present, the ctor for the Commands class imports many modules.
This is essential to break what would otherwise be circular
dependencies among Python imports.  We can extend this pattern by
creating more classes, as was done with the EditCommandsManager class.

I'm not sure exactly how this will play out, but removing circular
imports between Leo's module seems like a worthy goal.  The leoGlobals
module is an important exception.  All of Leo's modules do::

    import leo.core.leoGlobals as g

To make this work, it is *essential* that leoGlobals.py import *no*
other Leo modules.

===== A new (limited!) use for section references

I am going to create a new section in leoGlobals.py called << global
switches >>  It will contain code such as:

    new_load = False # True: .leo files are loaded at most once.
    if new_load: print('***** new_load')

    new_modes = False # True: use ModeController and ModeInfo classes.
    if new_modes: print('***** new_modes')

This section is useful because I can clone it.  I can then enable and
disable switches in the clone, without having to keep "@file
leoGlobals.py" visible.  Very handy.

Edward

-- 
You received this message because you are subscribed to the Google Groups 
"leo-editor" group.
To post to this group, send email to [email protected].
To unsubscribe from this group, send email to 
[email protected].
For more options, visit this group at 
http://groups.google.com/group/leo-editor?hl=en.

Reply via email to