In another thread I said, "I'm going to do #852
<https://github.com/leo-editor/leo-editor/issues/852>: (active settings
outline) first. I think I can do this in a few hours [sic] to a few days.
It's a frequently requested feature."
I spent about 15 hours on yesterday, from 2 am to 7pm, with just a few
breaks. And here I am again, at 2:30 am. This is a difficult, fascinating,
project. It took all yesterday to come up to speed on Leo's configuration
code. The "settings" branch contains the work.
The following are some notes, feel free to ignore. They might find their
way into an info issue dealing with settings. I am writing this now to
summarize yesterday's researches.
*About the active-settings-outline command*
The ActiveSettingsOutline class implements this command. At present, the
code creates an new, *real, *outline illustrating the overall form of the
final outline. You can save this outline if you want. It's name is
x-active-settings.leo, where x is the name of the outline that executed the
active-setting-outline command. This was the easy part ;-)
The aso.start method, and its helpers, now appears to recreate the required
initing of settings *exactly* as is done in Leo's startup code. *Subtle
bugs will abound if it doesn't*. The code is deceptively simple. There are
a frightening number of constraints on this code.
The aso.create_active_settings method shows the difficulties involved in
traversing the various @settings trees while simultaneously seeing where
the settings come from. Despite the present complications, I am pretty sure
the code can be simplified.
*About the configuration code*
The c.config.get* methods are the one and only interface between this code
and the rest of Leo. This interface hides the truly frightening complexity
of the underlying code.
The LoadManager class, in leoApp.py, does the heavy lifting involved with
reading *settings files*, leoSettings.leo, myLeoSettings.leo, the *theme
file*, specified by the @string theme-name setting (usually in
myLeoSettings.leo) and the *local files*, the actual outline files. Leo
can load leoSettings.leo, myLeoSettings.leo and any theme file, so that has
to work too. That is, local files can also be settings files or theme files.
I'll abbreviate the singleton g.app.loadManager instance by LM, which I
also use to denote the LoadManager class.
Leo *already* caches settings. There are two *global settings dicts*,
LM.globalSettingsDict and LM.globalBindingsDict. And there is *a*
corresponding *local settings dict*, c.config.settingsDict. Not sure
whether there is a local bindings dict :-)
The global dicts represent the settings in *both* leoSettings.leo and
myLeoSettings.leo. Not sure whether I would do things the same way if I
were starting from scratch. *Important*: the local settings dict contains
*all* the settings available to the outline. That is,
c.config.settingsDict is the *union* of all settings from settings files,
the theme file and the local file. This union gives first priority to the
settings in the local file, then the settings in the theme file, and last,
the settings from the settings files (the global settings dict).
This union is an important optimization. The fundamental c.config.get
method needs only access *one* dict, namely c.config.settingsDict. In
other words, the get method knows nothing about search order. That has
already been resolved.
Each value in the c.config.settingsDict is a g.GeneralSetting (GS)
instance. GS objects contain a path ivar, which is the full path of the
.leo file that is responsible for the setting. This path allows
gcm.config_iter to determine where the setting came from. As I write this,
I see that active settings outline will use gcm.config_iter as a model for
assigning settings to files.
That's all I want to say about the configuration code. More details would
be useless. Most people, including myself, have no chance of remembering
anything more.
*About changing the configuration code*
I plan to make *zero* substantive changes to the configuration code while
working on #852. The only changes I have made are to docstrings. I did
make one "hidden" change to readGlobalSettingsFiles. It now sets LM ivars
needed for the ActiveSettingsOutline class. Even this tiny change was
worrisome enough that I created a new git branch for the work.
It's extremely difficult to know what the code does, *in exact detail*. A
trace in LM.openSettingsFile shows that reading settings files happens in
two stages. LM.doPrePluginsInit does the first stage, LM.doPostPluginsInit
does the second stage. The ActiveSettingsOutline code must use *exactly*
this load order in order to faithfully recreate settings. Btw, the
--theme=name command-line argument changes the move order.
Given the complexities of the code, I simply do not understand how anyone
can be confident that proposed changes would work *exactly* as before.
After 15 hours of intense study, I don't understand the code well enough to
have any confidence in *any* real changes to the code.
*Global settings and problems*
The node "c.config.Getters: redirect to g.app.config" contains problematic
code. It contains four methods:
def getButtons(self):
'''Return a list of tuples (x,y) for common @button nodes.'''
return g.app.config.atCommonButtonsList # unusual.
def getCommands(self):
'''Return the list of tuples (headline,script) for common @command
nodes.'''
return g.app.config.atCommonCommandsList # unusual.
def getEnabledPlugins(self):
'''Return the body text of the @enabled-plugins node.'''
return g.app.config.enabledPluginsString # unusual.
def getRecentFiles(self):
'''Return the list of recently opened files.'''
return g.app.config.getRecentFiles() # unusual
The first two probably don't cause great problems. The second two are
somewhat dubious. I'll leave it at that for now. Anyone seriously
considering changes to the config code should be aware of these hacks.
*A possible source of theme misery*
While studying LM.readGlobalSettingsFiles I saw the following code:
if 0:
# Not necessary **provided** that theme .leo files
# set @string theme-name to the name of the .leo file.
g.app.theme_color = settings_d.get_string_setting('color-theme')
g.app.theme_name = settings_d.get_string_setting('theme-name')
Whoa! What's going on here? There is almost zero chance I'll enable this
code. But I may well issue a warning (somewhere!) if a theme file does not
contain an @string theme-name setting. This would be oh so hard to find.
It's a dog that isn't barking.
*Summary*
Work on the active-settings-outline command is progressing well. A day or
two more should suffice. All work is being done in the settings branch. I
shall make *no* substantive changes to Leo's configuration code.
The active-settings-outline command must recreate Leo's startup code
*exactly*. Subtle bugs will abound if it doesn't. If the command *does*
init settings correctly, gcm.config_iter shows how to find where settings
come from. This is possible because settings contain the path of the file
that define them.
*All theme files should defined @string theme-name to be the name of the
theme file itself*. If not, the theme file may not work properly. I plan
to add a warning if this is not so.
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 view this discussion on the web visit
https://groups.google.com/d/msgid/leo-editor/f899f49e-6fcd-4430-8b0b-45a4f8bcc440%40googlegroups.com.