Leo n00b on Mac OS X

144 views
Skip to first unread message

TEK42

unread,
Apr 9, 2021, 12:07:00 AM4/9/21
to leo-editor
Greetings,

I discovered Leo a couple of days ago and think it might be valuable while developing a new green field project (as well as maintaining some others). We are a Mac-only shop and I have Leo up and running from the devel git branch.

With the caveat that I am still trying to get the hang of it, it seems to be the case that Leo was not really targeted to OS X. There are areas some areas where I cannot tell if I am doing something "wrong" or if there is a "bug".

Examples:

  • When I've had multiple .leo files open (tabs?) and tried to do "insert child" nothing would happen in the visible outline, but would be inserting children in one of the other non-visible outlines. Then after closing the affected .leo file, save operations on the visible .leo file would save the closed .leo file. Perhaps I do not understand how to "Focus" an outline for operations?
  • Most of the commands that specify the Ctrl- modifier in the docs are mapped to "Command" correctly, but a lot of them don't actually work (possible conflicts with OS X - Cmd-H for instance). Is there a Mac OS X guide/cheat sheet available?
  • While setting up an outline with @path nodes, the '~' character does not expand (as in quickstart.leo "Programming" node). Is there some plugin I need for that to work?
I look forward to mastering Leo for my needs as well as the VSCode-Leo integration project (game changer?).

Thanks,
TK

tbp1...@gmail.com

unread,
Apr 9, 2021, 12:44:28 AM4/9/21
to leo-editor
I don't have a Mac, so I can't help much, but I can speak a bit about the @path ~ matter.  This does work on Linux.  When you wrote "does not expand", did you mean that the implied paths are not created when you save an "external" file?  If so, you can change this behavior by adding a node to your MyLeoSettings.leo file.  This node has to be a child of the @settings node, and have this headline:

@bool create_nonexistent_directories = True

Restart Leo after saving.  Then the following should happen.  Create a small subtree, for example:

- @path ~/aaa
   - @path bbb
      -@path ccc
          @clean test1.txt

After you save the outline, the file test1.txt should be there at ~/aaa/bbb/ccc/test1.txt.

There are Mac users who seem to have good success using Leo, so it ought to workable for you.  A lot of them read these posts, so I expect you will get some help pretty soon.

Leo is a remarkably useful and adaptable piece of software.  But it can be hard to learn about all the things, like the @bool setting above, that make it really sing for you.  Just keep asking here, and read the Leo docs about settings, customization, and so on.

TEK42

unread,
Apr 9, 2021, 1:02:45 PM4/9/21
to leo-editor
Thanks for the input.


I don't have a Mac, so I can't help much, but I can speak a bit about the @path ~ matter.  This does work on Linux.  When you wrote "does not expand", did you mean that the implied paths are not created when you save an "external" file?  If so, you can change this behavior by adding a node to your MyLeoSettings.leo file.  This node has to be a child of the @settings node, and have this headline:

@bool create_nonexistent_directories = True


What I mean by "does not expand: is that there is no "tilde expansion" taking place when I use '~', which I expect to "expand" to my home directory. 
 
Restart Leo after saving.  Then the following should happen.  Create a small subtree, for example:

- @path ~/aaa
   - @path bbb
      -@path ccc
          @clean test1.txt

After you save the outline, the file test1.txt should be there at ~/aaa/bbb/ccc/test1.txt.


Using the setting above the directories are indeed created, but not in my home directory. So if my outline file is in "/Users/leodude/projects/coolproj/" the structure gets created as:

            "/Users/leodude/projects/coolproj/~/aaa/bbb/ccc/test1.txt" instead of ""/Users/leodude/aaa/bbb/ccc/test1.txt" like I expect.

Using '.' works as expected (cwd) and is arguably more useful than referencing "home dir" in most cases.

 
There are Mac users who seem to have good success using Leo, so it ought to workable for you.  A lot of them read these posts, so I expect you will get some help pretty soon.

Leo is a remarkably useful and adaptable piece of software.  But it can be hard to learn about all the things, like the @bool setting above, that make it really sing for you.  Just keep asking here, and read the Leo docs about settings, customization, and so on.


That is good to hear.

Thanks,
TK 

tbp1...@gmail.com

unread,
Apr 9, 2021, 1:48:47 PM4/9/21
to leo-editor
I recreated that example file tree on Linux, and darned if  I didn't get the same result as you.  I must have had my eyes see the "~" and start reading from there because that's what I expected to see.  So, a real bug and not just a Mac quirk.

In fact, I get the same behavior on Windows.  It's a little weird because "~" isn't a normal shortcut on Windows.  But Python evaluates it correctly, for example by os.path.expanduser('~'), so we might think that expanding @path ~\test would act as expected, but instead it acts just like it does on Linux.

tbp1...@gmail.com

unread,
Apr 9, 2021, 5:51:29 PM4/9/21
to leo-editor
Subject to correction by Edward or some else who knows more, it looks like the place to intervene is in c.expand_path_expression() because  on even on Linux it returns this:

>>> c.expand_path_expression('~')
'~'

This method is in the class Commands.  I'm not sure how tricky this would be to adjust, because you would only want to substitute /home/{user} for "~" if it appears at the start of a path expression, and I don't know yet how to know.  Also, it needs to be checked if a change here would cause troubles anywhere else.

TEK42

unread,
Apr 9, 2021, 9:36:55 PM4/9/21
to leo-editor

I checked this on os x and get the same results:

import os
g.cls() # <-- does nothing on macos (darwin), probably same with linux since the procedure checks for "win" only

g.es(os.path.expanduser('~'))
# --> /Users/leodude

g.es(os.environ["HOME"])
# --> /Users/leodude

g.es(c.expand_path_expression('~'))
# --> ~

g.es(c.expand_path_expression('$HOME'))
# --> $HOME


It looks like there is opportunity to bring Leo into better usability with Linux-ey OS’s.

Depending on how much I end up using Leo (I already spent more time in Leo than in emacs org-mode this week), I may be up for contributing towards that end - at least for macos. 

tbp1...@gmail.com

unread,
Apr 9, 2021, 10:11:49 PM4/9/21
to leo-editor
It looks like there is a simple fix.  This hasn't had hardly any testing, but on the surface it's doing the right thing.  The little example that failed in an earlier post created the right directories.

In leoCommands.py, in the method expand_path_expression(self, s), add the line marked below

    val = ''.join(aList)
    val = os.path.expanduser(val)  # <===== Add this line
    if g.isWindows:
        val = val.replace('\\', '/')
    return val


@n00b, if you know how to find Leo's python code files, would you make this change and see if it works for you?  They would be in the Lib/sitepackages/leo directory for the python executable you are using.  There may be more than one sitepackages directory.  You can locate them this way:

import site
print(site.getsitepackages())

tbp1...@gmail.com

unread,
Apr 9, 2021, 10:26:10 PM4/9/21
to leo-editor
This fix works on Windows, too - the "~" expands correctly to my user home directory.

TEK42

unread,
Apr 10, 2021, 10:12:42 AM4/10/21
to leo-editor
Good find. That change works well for OS X too.  Additionally, environment variables can be handled:

    val = ''.join(aList)
    val = os.path.expanduser(val)  # <===== Add this line
    val = os.path.expandvars(val)  # eg. $HOME, $SOME_OTHER_PATH_VAR
    if g.isWindows:
        val = val.replace('\\', '/')
    return val

Thus:

import os
g.cls() # <-- does nothing on macos (darwin), probably same with linux since the procedure checks for "win" only

g.es(os.path.expanduser('~'))
# --> /Users/leodude

g.es(os.environ["HOME"])
# --> /Users/leodude

g.es(c.expand_path_expression('~'))
# --> /Users/leodude

g.es(c.expand_path_expression('$HOME'))
# --> /Users/leodude



I've installed from the devel git branch, so I'll just go ahead and look into how to contribute to this project. I'd like to enhance the "g.cls()" also.



It looks like there is a simple fix.  This hasn't had hardly any testing, but on the surface it's doing the right thing.  The little example that failed in an earlier post created the right directories.

In leoCommands.py, in the method expand_path_expression(self, s), add the line marked below

    val = ''.join(aList)
    val = os.path.expanduser(val)  # <===== Add this line
    if g.isWindows:
        val = val.replace('\\', '/')
    return val


@n00b, if you know how to find Leo's python code files, would you make this change and see if it works for you?  They would be in the Lib/sitepackages/leo directory for the python executable you are using.  There may be more than one sitepackages directory.  You can locate them this way:

tbp1...@gmail.com

unread,
Apr 10, 2021, 2:43:49 PM4/10/21
to leo-editor
On Saturday, April 10, 2021 at 10:12:42 AM UTC-4 TEK42 wrote:
Good find. That change works well for OS X too.  Additionally, environment variables can be handled:
...
I've installed from the devel git branch, so I'll just go ahead and look into how to contribute to this project. I'd like to enhance the "g.cls()" also.

For contributing, here is probably the best way.  Set up an account with Github, then clone the Leo Github repo to it.  Start by checking out the devel branch. The master branch isn't getting updated until an official release, so don't use that.  In your clone, create a branch for the change you want, and make your proposed changes.  Then in the Pull Request tab at Github, create a pull request.

You could do all your work in a virtual environment, but I like to set PYTHONPATH to point to the top of the repo instead.  Then Python will find Leo in the repo but all other python packages from their usual places.  On my Windows machine:

set PYTHONPATH=d:\tom\git\leo-editor
python3 -m leo.core.runLeo

One advantage of doing it this way is that you can run the ordinary Leo release simply by unsetting PYTHONPATH.  You don't have to try to remember which venv has got which configuration, or how to get the venv to use the repo. 

I've learned that it's best to make a new branch for each of your change projects, no matter how small.  Once the PR is closed, you can update from Leo's devel and again branch off it for your next effort, or merge your branch back into your clone of devel

Of course, you may be way more experienced at doing the PR dance and if so just keep doing whatever you have been doing!

tbp1...@gmail.com

unread,
Apr 10, 2021, 11:46:28 PM4/10/21
to leo-editor
Unfortunately, there is a fly in the ointment.  I have an external file at a location that uses "..", like this:

- @path d:/Tom/devel/leo/plugins
    -@file ../plugins/viewrendered3.py

Leo wants this @file path to contain the ../plugins path step.  With the expanduser() line, my file doesn't save.  I tried adding an os.path.abspath() operation, but then a lot of other files don't load and Leo operation are quite messed up.  Apparently certain calls expect relative paths to be returned.  So it's a mess, so far as creating correct directory @paths that contain "~" is concerned.

And without adding the os.path.expanduser() call, Leo doesn't make the correct directories when the @path subtree starts with "~".  So this is not such an easy thing to fix properly.

I have come up with completely  different code for opening a directory that properly expands "~".  Of course, it won't cause the correct directories to be made, but it does return the correct directory path, including "~",  and does not rely on ".".  It won't work right if an @path directory contains ".." but it does work right if the @file headline contains ".." as in my example above.

"""Return the full path on disk to an external file or directory.  

Honor all @path directives. Expand "~" in path to be the user's
home directory. If get_file is False, return only the directory's
path (less any filename).
"""
import os

steps = [d.get('path') for d in g.get_directives_dict_list(p) if 'path' in d]
steps.reverse()

# Comment in these four lines if you also want to include the file itself in the path.
#pth = g.fullPath(c, p)
#fn = os.path.basename(pth
) #file name if there is a file here.
#if fn: 
    #steps.append(fn)

if len(steps) > 1:
    pth = os.path.join(steps[0], *steps[1:])
elif len(steps) == 1:
    pth = steps[0]
else:
    pth = os.getcwd()

pth = os.path.expanduser(pth)
if g.isWindows:
    pth = pth.replace('/', '\\')
else:
    pth = pth.replace('\\', '/')



On Friday, April 9, 2021 at 10:11:49 PM UTC-4 tbp1...@gmail.com wrote:

Edward K. Ream

unread,
Apr 11, 2021, 3:42:02 AM4/11/21
to leo-editor
On Sat, Apr 10, 2021 at 10:46 PM tbp1...@gmail.com <tbp1...@gmail.com> wrote:
Unfortunately, there is a fly in the ointment.
...

I have come up with completely  different code...

Many thanks for all this work.

Please create a Leo issue for this, summarizing the problem. A new issue will ensure that I don't forget about this topic.

Edward

TEK42

unread,
Apr 11, 2021, 9:01:41 AM4/11/21
to leo-editor

You could do all your work in a virtual environment, but I like to set PYTHONPATH to point to the top of the repo instead.  Then Python will find Leo in the repo but all other python packages from their usual places.  On my Windows machine:

set PYTHONPATH=d:\tom\git\leo-editor
python3 -m leo.core.runLeo

One advantage of doing it this way is that you can run the ordinary Leo release simply by unsetting PYTHONPATH.  You don't have to try to remember which venv has got which configuration, or how to get the venv to use the repo. 

I've learned that it's best to make a new branch for each of your change projects, no matter how small.  Once the PR is closed, you can update from Leo's devel and again branch off it for your next effort, or merge your branch back into your clone of devel

Of course, you may be way more experienced at doing the PR dance and if so just keep doing whatever you have been doing!

Thanks for the python path tips - it’s been about 15 years since developed with python professionally.

As far as the PR dance goes, that is pretty much my everyday dance at work ;)


TEK42

unread,
Apr 11, 2021, 9:10:45 AM4/11/21
to leo-editor
That is all curios. I am unclear the expanduser() call would affect things that way. Then again I understand <1% of Leo code at this point.
What is clear is that I will need to get Leo setup on Windows and Linux as well.

tbp1...@gmail.com

unread,
Apr 11, 2021, 10:58:20 AM4/11/21
to leo-editor
I instrumented expand_path_expression() with print statements and found that it is being called all the time, apparently for every file that Leo knows about.  I'm thinking that it's Leo polling to see if each file has been changed outside of Leo.  Some of those call outputs were full paths, some of them were relative paths (possibly they were my "..\" paths, but too many were scrolling by for me to be sure).

The thing is that expand_path_expression() is used by a number of other routines, and some plugins.  All of those probably assume that they will receive a certain path format, and none of that seems to be documented, at least not in the methods themselves.  Any change would have to be checked to make sure that everything else keeps working.  And it seems that different parts of Leo's internals depend on the exact behavior of this method.

I know of at least three things Leo has to do with node paths:

1. Load/save external files whose location does not depend on @path directives;
2. Load/save external files whose location uses @path directives;
3. Poll all external files and outlines for changes.

There may easily be more.  The trick will be to get them all to work correctly if any changes are made.  And then existing external files might become inaccessible.  Consider a case where you specified @path ~/my-special-dir/test.txt.  We know that this will create a directory/file structure in the wrong - that is, not intended - place.  Now say we fix the code so that in the future it creates our file in the correct location.  Trouble is, Leo now won't be able to find the existing external file that it had created earlier in the wrong place.

This might be all right for you and your new outline that only has one or two such files.  You can fix that by hand.  But there may be large outlines out there that have dozens or hundreds of files created with the wrong paths.  For example, in LeoPy.leo, all the plugins have paths starting with "../" .  They have to keep working.  Fixing that up is a much larger task.  Not everyone has the script knowhow and desire to work up a script that reliably fixes this kind of problem.

tbp1...@gmail.com

unread,
Apr 11, 2021, 11:15:19 AM4/11/21
to leo-editor

TEK42

unread,
Apr 11, 2021, 5:17:29 PM4/11/21
to leo-editor
Unfortunately, there is a fly in the ointment.  I have an external file at a location that uses "..", like this:

- @path d:/Tom/devel/leo/plugins
    -@file ../plugins/viewrendered3.py


On my OS X machine the above pattern doesn’t work at all (unclear about the reasoning for the pattern too).
I must take out the “../plugins/“ part of the @file for it to be able write/read the file. 

And this is after a clean pull of devel branch.

-TK

Edward K. Ream

unread,
Apr 11, 2021, 8:04:57 PM4/11/21
to leo-editor
On Sun, Apr 11, 2021 at 4:17 PM TEK42 <kizz...@gmail.com> wrote:

Unfortunately, there is a fly in the ointment.  I have an external file at a location that uses "..", like this:

- @path d:/Tom/devel/leo/plugins
    -@file ../plugins/viewrendered3.py


On my OS X machine the above pattern doesn’t work at all (unclear about the reasoning for the pattern too).
I must take out the “../plugins/“ part of the @file for it to be able write/read the file. 

My apologies. All the obvious things are supposed to work. Leo has several wrappers around g.os.path.  Search for the node "g.os_path_ Wrappers" in leoPy.leo (LeoPyRef.leo).

g.os_path_finalize_join is the workhorse. It should handle just about everything, but apparently it doesn't.

It's surprisingly difficult to make everything work uniformly everywhere. There are gazillions of related calls in Leo.

Edward

TEK42

unread,
Apr 11, 2021, 11:59:38 PM4/11/21
to leo-editor
My apologies. 
I did a full “clean” install from devel branch and can verify that the @path with @file sub-node using “../“ pattern does indeed work just fine on my OS X machine.


Reply all
Reply to author
Forward
0 new messages