This is Leo’s Frequently Asked Questions document.
Contents
You can get the latest official releases of Leo at http://sourceforge.net/project/showfiles.php?group_id=3458&package_id=29106
However, if at all possible, it is better to use bzr to get the latest sources. See the next entry.
Many users will want to track the development version of Leo, in order to stay on top of the latest features and bug fixes. Running the development version is quite safe and easy, and it’s also a requirement if you want to contribute to Leo.
First, you need to get Bazaar (bzr) from http://bazaar-vcs.org. For windows users we recommend the standalone installer - the python installer may have problems pushing to Launchpad. Plain bzr installer only contains the command line version, so you might want to augment that with a friendly GUI - qbzr is recommended as it’s the easiest one to install. It provides command like ‘bzr qlog’, ‘bzr qannotate’ etc.
Get Leo from launchpad by doing:
bzr branch lp:leo-editor
And that’s it! You can run the launchLeo script (in the top-level branch directory) directly. When you want to refresh the code with latest modifications from Launchpad, ‘run bzr pull’.
If you make modifications to Leo (with the interest in sharing them with the Leo community), you can check them in to your local branch by doing ‘bzr checkin’. Now, to actually request your changes to be merged to Leo trunk, you need a Launchpad account with RSA keys in place. There is showmedo video about how to accomplish this on Windows using puttygen and pageant at http://showmedo.com/videos/video?name=1510070&fromSeriesID=151.
After your Launchpad account is set up, go to https://launchpad.net/leo-editor, choose Code tab -> Register Branch, select Branch type “Hosted” and fill in descriptive details about the branch. After that, go to the branch home page from Code tab again, and copy-paste the push command line to terminal. For example, for branch:
https://code.launchpad.net/~leo-editor-team/leo-editor/mod_rclick
The push command is:
bzr push bzr+ssh://my_name@bazaar.launchpad.net/~leo-editor-team/leo-editor/mod_rclick
You may wish to add –remember command line option to bzr push, to direct all future pushes to that location. Then, you only need to execute ‘bzr push’.
After your branch is pushed, you can email the Leo mailing list and request it to be reviewed and merged to trunk.
– Ville M. Vainio - vivainio.googlepages.com
Daily snapshots are available at http://www.greygreen.org/leo/
You can simply unpack Leo anywhere and run from there. You don’t need the installer.
From a console window, cd to the top-level leo folder. Run Leo as follows:
python launchLeo.py
To run Leo with Qt look and feel, use the –gui=qt option:
python launchLeo.py --gui=qt
To load Leo’s source, load leoPyRef.leo:
python launchLeo.py --gui=qt leo\\core\\leoPyRef.leo
Missing modules can cause installation problems. If the installer doesn’t work (or puts up a dialog containing no text), you may install Leo from the .zip file as described at How to install Leo on Windows. However you are installing Leo, be sure to run Leo in a console window. because as a last resort Leo prints error messages to the console.
Leo’s setup.py script is intended only to create source distributions. It can’t be used to install Leo because Leo is not a Python package.
First, read the tutorial. This will be enough to get you started if you just want to use Leo as an outliner. If you intend to use Leo for programming, read the Quick start for programmers, then look at Leo’s source code in the file LeoPy.leo. Spend 5 or 10 minutes browsing through the outline. Don’t worry about details; just look for the following common usage patterns:
You will lose much of Leo’s power if you don’t use clones. See Clones & views for full details.
Use methods for any code that is used (called or referenced) more than once.
Sections are convenient in the following circumstances:
When you want to refer to snippets of code the can not be turned into methods. For example, many plugins start with the code like this:
<< docstring >>
<< imports >>
<< version history >>
<< globals >>
None of these sections could be replaced by methods.
When you want to refer to a snippet of code that shares local variables with the enclosing code. This is surprisingly easy and safe to do, provided the section is used only in one place. Section names in such contexts can be clearer than method names. For example:
<< init ivars for writing >>
In short, I create sections when convenient, and convert them to functions or methods if they need to be used in several places.
A dangerous delete is a deletion of a node so that all the data in the node is deleted everywhere in an outline. The data is gone, to be retrieved only via undo or via backups. It may not be obvious which deletes are dangerous in an outline containing clones. Happily, there is a very simple rule of thumb:
Deleting a non-cloned node is *always* dangerous.
Deleting a cloned node is *never* dangerous.
We could also consider a delete to be dangerous if it results in a node being omitted from an external file. This can happen as follows. Suppose we have the following outline (As usual, A’ indicates that A is marked with a clone mark):
- @file spam.py
- A'
- B
- Projects
- A'
- B
Now suppose we clone B, and move the clone so the tree looks like this:
- @file spam.py
- A'
- B'
- Projects
- A'
- B'
- B'
If (maybe much later), we eliminate B’ as a child of A will get:
- @file spam.py
- A'
- Projects
- A'
- B
B has not been destroyed, but B is gone from @file spam.py! So in this sense deleting a clone node can also be called dangerous.
Cross-file clones are cloned nodes in one outline that refer to data in another outline. This is a frequently requested feature. For example:
I would absolutely love to have the leo files in different project
directories, and a "master" leo file to rule them all.
However, cross-file clones will never be a part of Leo. Indeed, cross-file clones would violate the principle that data should be defined and managed in exactly one place. Just as human managers would not willingly accept shared responsibility for even a single line of code, every piece of Leonine data should be the responsibility of one and only one .leo file.
The problem fundamental. If the same (cloned) data were “owned” by two different Leo files we would have a classic “multiple update problem” for the data. Each outline could change the data in incompatible ways, and whichever outline changed the data last would “win.”
To make such a scheme workable and safe, one would have to devise a scheme that would keep the data in “component” .leo files consistent even when the component .leo files changed “randomly”, without the “master” .leo file being in any way in “control” of the changes. Good luck :-)
Let us be clear: it’s no good having a scheme that works most of the time, it must work all the time, even with unexpected or even pathological file updates. If it doesn’t you are asking for, and will eventually get, catastrophic data loss, without being aware of the loss for an arbitrarily long period of time. Even with a source code control system this would be an intolerable situation.
Here is the workflow I use to develop Leo. The intention is to help present and potential developers use Leo effectively.
These two points are covered in a bit more detail in This FAQ entry.
A. Avoid using the mouse whenever possible. For example, use alt-tab to switch between windows.
Speaking of g.trace, I hardly ever use ‘print’ because g.trace prints the name of the function or method in which it appears. The typical pattern for enabling traces is:
trace = True and not g.unitTesting
if trace: g.trace(whatever)
This pattern is especially useful when a method contains multiple calls to g.trace.
I use scripts to open particular Leo files. These are batch files on Windows, and aliases on Linux, but invoking them is the same on either platform:
all: opens all my main development files using the qt-tabs gui.
t: opens test.leo.
e: opens ekr.leo. I use this file for private testing.
d: opens LeoDocs.leo.
s: opens LeoPy.leo.
plugins: opens leoPlugins.leo.
gui: opens leoGui.leo.
u: opens unitTest.leo.
These run Leo with Python 3.x. There are similar scripts, ending in 2, that run Leo with Python 2.x. For example, u2 opens unitTest.leo with Python 2.x. Thus, to run a test, I alt-tab to an available console window, then type ‘e’ or ‘t’ or ‘u’ or, if I want Python 2.x, ‘e2’ or ‘t2’ or ‘u2’.
Use postings as pre-writing for documentation.
I don’t mind blabbing on and on about Leo because all my posts become pre-writing for Leo’s documentation. I simply copy posts to nodes in the “documentation to-do” section. At release time, I edit these nodes and put them in Leo’s main documentation or the release notes. This posting is an example.
pane updates as you type. This makes Leo a killer app for rST.
Never rely on memory.
A project like this contains thousands and thousands of details. Everything eventually goes into a Leo node somewhere. If it doesn’t it surely will be forgotten.
Do easy items first.
This keeps to-do lists short, which keeps energy high.
I use the following batch files related to bzr:
b: short for bzr
b c: short for bzr commit
bs: short for bzr status
tr: short for cd <path to trunk>
main: short for cd <path to copy of trunk>
The “main” (copy) of the trunk is purely for handling bzr conflicts. If one happens I do this:
main
b pull
b merge ../trunk
b c -m "my commit message"
b push
If the merge goes well (it usually does), I do this to resolve the conflict:
tr
b pull
You have two options, depending on whether you want to be able to use sections or not.
Use @asis trees. Files derived from @asis trees contain no sentinels. Leo creates the external file simply by writing all body text in outline order. Leo can’t update the outline unless the external file contains sentinels, so Leo does not update @asis trees automatically when you change the external file in an external editor.
Question: I’m writing a Windows Script Component, which is an XML file with a CData section containing javascript. I can get the XML as I want it by using @language html, but how can I get the tangling comments inside the CData section to be java-style comments rather than html ones?
Answer: In @file trees you use the @delims directive to change comment delimiters. For example:
@delims /* */
Javascript stuff
@delims <-- -->
HTML stuff
Important: Leo can not revert to previous delimiters automatically; you must change back to previous delimiters using another @delims directive.
By Zvi Boshernitzan: I was having trouble disabling ‘<?php’ with comments (and couldn’t override the comment character for the start of the page). Finally, I found a solution that worked, using php’s heredoc string syntax:
@first <?php
@first $comment = <<<EOD
EOD;
// php code goes here.
echo "boogie";
$comment2 = <<<EOD
@last EOD;
@last ?>
or:
@first <?php
@first /*
*/
echo "hi";
@delims /* */
@last ?>
Here is a posting which might be helpful: http://sourceforge.net/forum/message.php?msg_id=2300457 The @first directive is the key to output usable code in unsupported languages. For example, to use Leo with the Basic language, use the following:
@first $IFDEF LEOHEADER
@delims '
@c
$ENDIF
So this would enable a basic compiler to “jump” over the “true” LEO-header-lines. Like this:
$IFDEF LEOHEADER <-conditional compilation directive
#@+leo-ver=4 <-these lines not compiled
#@+node:@file QParser005.INC
#@@first
#@delims '
'@@c
$ENDIF <-... Until here!
<rest of derived code file ... >
This changes the comment symbol the apostrophe, making comments parseable by a BASIC (or other language.)
Use the @first directive in @file trees or @nosent trees.
The @first directive puts lines at the very start of files derived from @file. For example, the body text of @file spam.py might be:
@first #! /usr/bin/env python
The body text of @file foo.pl might be:
@first #/usr/bin/perl
Leo recognizes the @first directive only at the start of the body text of @file nodes. No text may precede @first directives. More than one @first directive may exist, like this:
@first #! /usr/bin/env python
@first # more comments.
No. Everything in an @file trees must be part of the external file: orphan and @ignore nodes are invalid in @file trees. This restriction should not be troublesome. For example, you can organize your outline like this:
+ myClass
..+ ignored stuff
..+ @file myClass
(As usual, + denotes a headline.) So you simply create a new node, called myClass, that holds your @file trees and stuff you don’t want in the @file trees.
By Rich Ries. Some older C compilers don’t understand the “//” comment symbol, so using @language C won’t work. Moreover, the following does not always work either:
@comment /* */
This generates the following sentinel line:
/*@@comment /* */*/
in the output file, and not all C compilers allow nested comments, so the last */ generates an error. The solution is to use:
#if 0
@comment /* */
#endif
Leo is happy: it recognizes the @comment directive. The C compiler is happy: the C preprocessor strips out the offending line before the C compiler gets it.
The @ignore directive can not be used elsewhere in @file trees because of the way Leo recreates outlines from external files. This is an absolutely crucial restriction and will never go away. For a few more details, see Leo 4.0: Eliminating error ‘recovery’ in History of Leo.
There are several workaround, as shown in LeoPy.leo:
Question: I must follow a coding standard when writing source code. It includes a maximum line length restriction. How can I know the length of a line when it gets written to the external file?
Answer: If a node belongs to a external file hierarchy, its body might get indented when it is written to the external file. It happens when an @others directive or a section name appears indented in a higher-level node body. While (line, col) in status area show the line and column containing the body text’s cursor, fcol shows the cursor coordinate relative to the external file, not to the current node. The relation fcol >= col is always true.
See the instructions are in LeoPy.leo in:
Notes:How To:How to add support for a new language section.
This section contains clones of all relevant parts of Leo that you will change. Coming in Leo 4.4: Leo will use JEdit’s language description files to drive the syntax colorer. To add support for a new language, just add another such description file.
You have two options:
You can ‘revert’ to old key bindings as follows:
Find the @file leoApp.py node in leoPy.leo. In the ctor for the LeoApp class set self.use_psyco to True or False. You will find this ctor in the node:
Code-->Core classes...-->@file leoApp.py-->app.__init__
Note that this ivar can not be set using settings in leoSettings.leo because Leo uses g.app.use_psyco before processing configuration settings.
When using the Qt gui, you specify fonts using the node in leoSettings.leo called:
@data qt-gui-plugin-style-sheet
As usual, you will probably want to put this node in your myLeoSettings.leo file.
You set selection colors in the following settings node:
@data qt-gui-plugin-style-sheet
After further reflection, there does not seem to be much that can be done.
Suppose, for example, that Leo converts an @setting node to a mini stylesheet. (In fact, Leo sometimes does do this, in other contexts.)
We now have a conundrum: which should take precedence: the @data
qt-gui-plugin-style-sheet setting or the @color body_text_selection_foreground_color setting?
Rather than open that can of worms, the best solution seems to be to declare that yes, some settings are gui dependent. Use @data qt-gui-plugin-style-sheet to set those settings.
I had a need to figure out why a part of some python code I had written was taking too long.
I pulled the code into LEO and the relevant part of the outline looked something like this:
+ Main module
-- Generate cryptographic key
-- Hashing algorithm
etc. So I cloned just the segment I wanted to profile and pulled it under a new section:
+ Main module
-- [clone] Generate cryptographic key
-- Hashing algorithm
+ Profiling Experiment
-- [clone] Generate cryptographic key
And in the body of the “Profiling experiment”, I used this code:
code_under_here = """
@others
"""
from timeit import Timer
t = Timer("print my_key_generator()", code_under_here)
print t.timeit(number = 10)
And then I hit Control-B to execute the Profiling Experiment body. This let me make adjustments to the code in the clone body and keep hitting Control-B to execute the code with the timeit module to see immediately if what I had done was making a difference.
The great thing about this was that I just used the LEO @others construct to create a wrapper around the code and did not need to litter my code with debug or profiling statements. – Kayvan
The ‘official’ way to start a replace command is:
<Ctrl-shift-r>find-pattern<return>replace-text<return>
But suppose you with start with:
<ctrl-f>find-pattern
and then realize you want to do a replace instead of a find. No problem. The following also works:
<Ctrl-f>find-pattern<Ctrl-shift-r>replace-text<return>
In other words, you can think of <ctrl-f> as meaning ‘show the find dialog’. There is another trick you should know. After typing <ctrl-f> or <shift-ctrl-r> you can use <alt-ctrl> keys to set or clear find options. For example:
<ctrl-f><alt-ctrl-w><find-pattern><return>
That is, <ctrl-f>`shows the find dialog, `<alt-ctrl-w> toggles the Whole Word checkbox and <return> starts the search. You can type the <alt-ctrl> keys anytime after <ctrl-f> (or <shift-ctrl-r>) and before <return>. You can also type multiple <alt-ctrl-keys> to toggle multiple checkboxes.
The trick is to create a workflow that separates editing from testing. Putting test code in LeoPy.leo would waste a lot of time. To run tests you would have to exit Leo and reload LeoPy.leo. A much quicker way is to put all test code in a test.leo file. So to change and test code, do the following:
That’s all. Python will recompile any changed .py files in the new copy of Leo. Note: I create a batch file called t.bat that runs test.leo, so to the “edit-reload-test” cycle is just:
The benefits of the new workflow:
The Import Files dialog allows you to select multiple files provided you are running Python 2.3 or above. There is also an importFiles script in LeoPy.leo. You can use that script as follows:
import leo.core.leoImport as leoImport
leoImport.importFiles(aDirectory, ".py")
This will import all .py files from aDirectory, which should be a full path to a particular directory. You could use ”.c” to import all .c files, etc.
By Rich Ries. I often rework C code that’s already been “Leo-ized”–the first pass was quick and dirty to get it going. When I do subsequent passes, I wind up with subnodes that are out of order with the sequence found in the main node. It’s not a big deal, but I like ‘em ordered. With just one editor pane, clicking on the node to move would switch focus to that node. I’d then need to re-focus on the main node. A minor nuisance, but it does slow you down.
My solution is to open a second editor with its focus on the main node. Switch to the other editor, and, referring to the first editor pane, move the nodes as you like. The second editor’s pane will change focus to the node you’re moving, but the first editor will stay focused on the main node. It’s a lot easier to do than to describe!
One way is to link directly to the media file from a Leo node (with @url) and write a script button to wrap all URL-nodes under the current node in a single HTML page (using the HTML browser trick at http://sourceforge.net/forum/forum.php?thread_id=1201579&forum_id=10226).
Then, you can view your media in two ways:
You could probably generalize this idea of “collect all @url nodes under current node and display as HTML in browser” into a general-purpose plugin. However, the plugin would have to be somewhat smart in mapping a link to its corresponding HTML code (e.g. an image link gets mapped to an <img> HTML tag, a link to a Flash file gets mapped to an <embed> tag, etc).
Question: It would be nice if Leo could open empty files. I tend to be “document oriented” rather than “application oriented” in my thinking and prefer “create empty file at location -> open it with program” to “start program -> create new file -> save it at location”.
Answer by Paul Paterson: If you are on Windows 98/2000/XP then the procedure is as follows...
Now you should have a New:Leo File option in Explorer. This creates a duplicate of the file you saved. This can be useful because you could make a template Leo file containing some standard nodes that you always have and then save this.
From: http://sourceforge.net/forum/message.php?msg_id=3240374 Using Leo’s File-Export-Flatten Outline commands creates a MORE style outline which places all Leo body sections on the left margin. The headlines are indented with tabs which Excel will read as a tab delimited format. Once inside Excel there are benefits.
The most obvious benefit inside Excel is that the body sections (Excel first column) can be selected easily and highlighted with a different font color. This makes the MORE format very readable. Save a copy of your sheet as HTML and now you have a web page with the body sections highlighted.
It is possible to hide columns in Excel. Hiding the first column leaves just the headlines showing.
Formulas based on searching for a string can do calculations in Excel. For example if a heading “Current Assets” appears on level 4 then the body formula:
=INDEX(A:A,MATCH("Current Assets",D:D,0)+1)
will retrieve it. The +1 after match looks down one row below the matched headline. The trick is to place all your headlines in quotes because Excel will see + “Current Assets” from the MORE outline. When Excel tries without the quotes it thinks it is a range name and displays a #N/A error instead of the headline. Also you must place a child node below to get the + sign instead of a - sign which would give a MORE headline of -“Current assets” , also is an error.
I think there is some interesting possibility here because of the enforcement of Leo body text being always in the first column. The Leo outline provides additional reference to organizing the problem not typical of spreadsheet models. Beyond scripting in Python, Excel is good at doing interrelated calculations and detecting problems like circular references. In Excel Tools-Options-General is a setting for r1c1 format which then shows numbers instead of letters for column references. Using this would allow entries like this in the leo body:
1000
3500
=R[-1]C+R[-2]C
In Excel you would see 4500 below those two numbers. This is completely independent of where the block of three cells exists on the sheet.
By Rich Ries
There is no direct way to make script buttons available in multiple Leo files. Sure, you could copy and paste the @button nodes, but there is a slightly easier way using the “New Buttons” plugin.
Open a new Leo file.
It’s easier to do this than to explain it!
All questions are welcome at http://groups.google.com/group/leo-editor
You can discuss possible bugs at http://groups.google.com/group/leo-editor
Please report bugs at http://bugs.launchpad.net/leo-editor
When reporting a bug, please include all of the following:
It’s polite to make the bug report self contained, so that six weeks later somebody will be able to understand the report as it stands.
In version 4.5, Leo changed to using a sax parser for .leo files. This can cause problems if your .leo file contains invalid characters. Bugs in previous versions of Leo permitted these bad characters to appear.
The sax parser complains that these characters are not valid in .xml files. Remove these invalid characters as follows:
run Leo in a console window, and load the .leo file. Near the bottom of the error message you will see a line like:
SAXParseException: <unknown>:123:25: not well-formed (invalid token)
This line reports a bad character at character 25 of line 123.
Open the .leo file in an external editor. The Scite editor, http://www.scintilla.org/SciTE.html, is a good choice because it clearly shows non-printing characters. Remove the invalid character, save the .leo file.
Repeat steps 1 and 2 until all invalid characters are gone.
For the most part, docutils does a good job of reporting errors. docutils prints a message to the console and inserts an unmistakable error message in the generated .html file. Important: On Windows it is helpful to run Leo in a console window.
However, in some cases, docutils crashes instead of properly reporting the problem. There are several workarounds:
The crashes I have seen arise from the following bug in docutils. Hyperlinks in image:: markup must be lower case. This will work:
.. .. |back| image:: arrow_lt.gif
:target: faq_
This will crash:
.. .. |back| image:: arrow_lt.gif
:target: FAQ_
So avoid this crash by making sure to use lower case targets in ‘:target:’ markup.
You can change the docutils source slightly so that it prints a traceback when it crashes. (The rst3 plugin should be able to do this, but I haven’t figured out how yet.) It’s easy enough to do this:
Find the file core.py in top-level docutils folder. Typically this folder will be in Python’s site-packages folder.
Open core.py in some editor other than Leo.
Find the method called report_Exceptions.
Insert the following lines at the very start of this method:
print 'EKR: added traceback'
import traceback ; traceback.print_exc()
This will cause a traceback whenever docutils crashes. I have found that such tracebacks are generally enough to locate the general area of the problem. Note: These tracebacks go to the console window, so you should run Leo in a console window.
As a last resort, you can isolate syntax errors by reducing your input files until they work again, then adding sections until you get a crash. This is easy enough to do (when using the rst3 plugin) by change a headline ‘x’ to @rst-ignore-tree x.
Leo (and other programs) often send more detailed error messages to stderr, the output stream that goes to the console window. In Linux and MacOS environments, python programs normally execute with the console window visible. On Windows, can run Leo with the console window visible by associating .leo files with python.exe not pythonw.exe.
Just run Leo in a console window. At the point you want to drop into the debugger, execute this line:
g.pdb()
All output from pdb goes to stdout, which is the console window. It would be good to create a subclass of pdb.Pdb that uses Leo’s log pane rather than a console window, but I haven’t done that. It could be done easily enough in a plugin...
Important: I recommend using g.trace instead of pdb. For example:
g.trace(x)
prints the name of the function or method containing the trace, and the value of x. g.callers is often useful in combination with g.trace. g.callers(5) returns the last 5 entries of the call stack. For example:
g.trace(x,g.callers(5))
Used this way, g.trace shows you patterns that will be invisible using pdb.
The import commands insert @ignore directives in the top-level node. Leo does this so that you won’t accidentally overwrite your files after importing them. Change the filename following @file (or @file) as desired, then remove the @ignore directive. Saving the outline will then create the external file.
Missing modules can cause installation problems. If the installer doesn’t work (or puts up a dialog containing no text), you may install Leo from the .zip file as described at How to install Leo on Windows. However you are installing Leo, be sure to run Leo in a console window. because as a last resort Leo prints error messages to the console.
Python’s decorator syntax is ill-conceived. This syntax file hack works well enough anyway to work with Leo ‘@’ markup:
syn region leoComment start="^@\\s*" end="^@c\\s*$"
syn match pythonDecorator "@\\S\\S+" display nextgroup=pythonFunction skipwhite
Leo’s setup.py script is intended only to create source distributions. It can’t be used to install Leo because Leo is not a Python package.
Question and answer from plumloco.
Add the equivalent of:
import sys
leocore = "path/to/leo/core"
if leocore not in sys.path: sys.path.append(leocore)
import leo.core.leoBridge as leoBridge
at the head of each file that uses leoBridge.
The problem is not importing leoBridge itself but (if I use ‘from leo.core’) the importing of plugins, who get a different leoGlobals from leoBridge, without g.app etc, and so do not work if they rely on dynamic values in g.etc.
> Why can’t you simply add leo/core to sys.path in sitecustomize.py?
Putting leo/core on the python path as you suggest would put forty python modules in the global module namespace for all python programs when I want just one. Also, I have a safe working copy of leo and a cvs/testing version. I would wish to test any programs against the testing version while using the working version, but both /core directories can’t be exposed at the same time.
> Do you need plugins while running from the leoBridge?
Afraid so, at least the rst3 plugin. The solution I am using now is to place:
sys.modules['leoGlobals'] = leoGlobals
in leoBridge after import leo.core.leoGlobals as leoGlobals
This allows my scripts to be portable over the several computers/platforms I need to use them on, and makes testing scripts against multiple leo versions easy. It does mean that my scripts are not portable to other leo users but that is not likely to be a problem.
As explained here, the fundamental @shadow algorithm guarantees only that writing an updated @shadow outline will generate the updated public file. There is no way to guarantee that the updated outline structure will be as expected. The @shadow algorithm can not in principle guess between two or more ways of updating the private file when each of the ways yields the same public file.
Happily, this “fact of life” about @shadow is not serious. If you don’t like the “guesses” that the @shadow algorithm has made, you can simply change the @shadow tree. After saving the outline, the private file will record your choice. The next time you open the outline, you will see the choices you made, not the guesses that the @shadow algorithm made.
Set @bool ignore_unbound_non_ascii_keys = False in LeoSettings.leo or myLeoSettings.leo.
Internally, Leo represents all strings as unicode. Leo translates from a particular encoding to Unicode when reading .leo files or external files. Leo translates from Unicode to a particular encoding when writing external files. You may see strange looking characters if your text editor is expecting a different encoding. The encoding used in any external file is shown in the #@+leo sentinel line like this:
#@+leo-encoding=iso-8859-1.
Exception: the encoding is UTF-8 if no -encoding= field exists. You can also use the @encoding directive to set the encoding for individual external files. If no @encoding directive is in effect, Leo uses the following settings to translate to and from unicode:
The encoding specified in the following line of new .leo files:
<?xml version="1.0" encoding="UTF-8">
The default is UTF-8 (upper case for compatibility for old versions of Leo).
Add the following to the start of your scripts:
@first # -*- coding: utf-8 -*-
Without this line, constructs such as:
u = u'a-(2 unicode characters here)-z'
u = 'a-(2 unicode characters here)-z'
will not work when executed with Leo’s execute script command. Indeed, the Execute Script command creates the script by writing the tree containing the script to a string. This is done using Leo’s write logic, and this logic converts the unicode input to a utf-8 encoded string. So all non-ascii characters get converted to their equivalent in the utf-8 encoding. Call these encoding <e1> and <e2>. In effect the script becomes:
u = u'a-<e1>-<e2>-z'
u = 'a-<e2>-<e>-z'
which is certainly not what the script writer intended! Rather than defining strings using actual characters, Instead, one should use the equivalent escape sequences. For example:
u = u'a-\\u0233-\\u8ce2-z'
u = 'a-\\u0233-\\u8ce2-z'
The encoding used in the file being imported doesn’t match the encoding in effect for Leo. You have two options:
First, you must change Python’s default encoding to something other than ‘ascii’. To do this, put the following in your sitecustomize.py file in Python’s Lib folder:
import sys
sys.setdefaultencoding('utf-8') # 'iso-8859-1' is another choice.
You must restart Python after doing this: sys.setdefaultencoding can not be called after Python starts up.
Leo’s g.es_print and g.pr functions attempts to convert incoming arguments to unicode using the default encoding. For example, the following Leo script shows various ways of printing La Peña properly:
@first # -*- coding: utf-8 -*-
import sys
e = sys.getdefaultencoding()
print 'encoding',e
table = (
'La Peña',
unicode('La Peña','utf-8'),
u'La Peña',
u'La Pe\\xf1a',
)
for s in table:
print type(s)
g.es_print('g.es_print',s)
if type(s) != type(u'a'):
s = unicode(s,e)
print 'print ',s
print 'repr(s) ',repr(s)
For still more details, see: http://www.diveintopython.org/xml_processing/unicode.html