Using a Leo Outline On Another Computer?

177 views
Skip to first unread message

tbp1...@gmail.com

unread,
Mar 8, 2022, 5:12:39 PM3/8/22
to leo-editor
I'd like to open a Leo outline that is on another computer - strictly within my home LAN.  I could do that by sharing a directory and putting the outline into that directory.  But I'd rather have that outline be in its intended place on the drive, not in some other shared directory.

I could put a soft link to the outline in its intended location, and put the actual outline in the shared folder.  But that's still not ideal.

Is there a way to use the Leo Bridge to accomplish this?  How would it be set up?

Félix

unread,
Mar 8, 2022, 8:08:31 PM3/8/22
to leo-editor
(english is not my native language so i may miss some meaning)

I've read your question and i'm tempted to ask you to elaborate a little, or give a bit more details by being more explicit in your vision. 

obviously, this peeked my curiosity because with leoserver you can do this - even more: you can edit more than one client at once on the same Leo instance running :)
--
Félix

tbp1...@gmail.com

unread,
Mar 8, 2022, 8:21:26 PM3/8/22
to leo-editor
Of course I thought of your project right away.  What I'm thing of is doing the same thing, but instead of vscode as a client on the same computer, I'm thinking of Leo on a different computer as the client.  And the communication would be via my local LAN instead of webchannels on the same machine.

All I want to do, really, is to take an easily portable laptop somewhere else in the house - so I'm not stuck here at the desk all the time - and run Leo on it but working on outlines stored on the main computer.  I only want to stay on my home LAN, so I'm not worried about security risks you might get with open connectivity to the wild internet.

jkn

unread,
Mar 9, 2022, 2:52:13 AM3/9/22
to leo-editor
Not quite what you are asking, but I use Nextcloud to automatically share files and directories between computers on my home LAN:

I tend to be a bit careful about having an outline open in two instances of Leo, but this approach works OK for me.

tbp1...@gmail.com

unread,
Mar 9, 2022, 9:07:55 AM3/9/22
to leo-editor
Thanks, I'll look at that.  I can do file sharing for particular folders already, for that matter.

Robert-Felix

unread,
Mar 9, 2022, 10:38:25 AM3/9/22
to leo-e...@googlegroups.com
> but instead of vscode as a client on the same computer, I'm thinking of Leo on a different computer as the client.  And the communication would be via my local LAN instead of webchannels on the same machine.

just to reiterate, leoserver can run on another computer on lan or even wan. just start it  with command line argument of file you want open , and you can connect to it from any computer on network. (of course for now only client that exist is leointeg but i just wanted to clarify)
--
Félix

--
You received this message because you are subscribed to a topic in the Google Groups "leo-editor" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/leo-editor/lbrgq0YBG-0/unsubscribe.
To unsubscribe from this group and all its topics, send an email to leo-editor+...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/leo-editor/7b202db9-8d4f-430f-84c4-8c4bebdbe7d4n%40googlegroups.com.

tbp1...@gmail.com

unread,
Mar 9, 2022, 11:37:39 AM3/9/22
to leo-editor
Thanks, I wasn't sure I remembered how it works.  So really, I need a Leo client.  Hmm.  I remember running leointeg while a Leo window was running, and seeing outline changes in Leo when I did something in leointeg.  I wonder if there's an almost-no-effort solution lurking here (apart from running leointeg on the remote machine, I mean).

Edward K. Ream

unread,
Mar 9, 2022, 12:00:14 PM3/9/22
to leo-editor
On Wed, Mar 9, 2022 at 9:38 AM Robert-Felix <felix...@gmail.com> wrote:

just to reiterate, leoserver can run on another computer on lan or even wan. just start it  with command line argument of file you want open , and you can connect to it from any computer on network. (of course for now only client that exist is leointeg but i just wanted to clarify)

Thanks for this reminder!

Edward

Edward K. Ream

unread,
Mar 9, 2022, 12:18:15 PM3/9/22
to leo-editor
On Wed, Mar 9, 2022 at 10:37 AM tbp1...@gmail.com <tbp1...@gmail.com> wrote:
So really, I need a Leo client...I wonder if there's an almost-no-effort solution lurking here (apart from running leointeg on the remote machine, I mean).

Sounds like exactly the right question to ask. 

There is no need to duplicate leointeg's logic because Leo itself is available remotely. Perhaps the remote Leo needs only two new commands:

1: get a remote outline by name and
2: save the remote outline (possibly with another name)

Presumably these commands would work by making requests of the server using a simple client.

leo/core/leoclient.py would be a good start. client_main_loop does all the heavy lifting. At present, this function just echos responses from the server, but it could run silently.

Summary

Two new commands might suffice to allow Leo to use a remote outline. These two commands imply two (new?) server responses: get_remote_outline and save_remote_outline.

This seems like a low (not-quite-almost-no-effort :-) solution.

Félix, what do you think?

Edward

tbp1...@gmail.com

unread,
Mar 9, 2022, 1:45:13 PM3/9/22
to leo-editor
Cool!  I'll look into this after I finish with the Winkey-bad-symbols issue.

Edward K. Ream

unread,
Mar 9, 2022, 2:16:19 PM3/9/22
to leo-editor
On Wednesday, March 9, 2022 at 11:18:15 AM UTC-6 Edward K. Ream wrote:

...Perhaps the remote Leo needs only two new commands:

1: get a remote outline by name and
2: save the remote outline (possibly with another name)

And maybe commands to list and change the remote working directory. However, some kind of shell could do this without Leo.

Edward

Félix

unread,
Mar 9, 2022, 8:29:18 PM3/9/22
to leo-editor
Hi :)

Here are my thoughts after reading this thread so far, (English is not my first language so i may still be confused about what is suggested in the setup Thomas is describing)

> There is no need to duplicate leointeg's logic because Leo itself is available remotely. Perhaps the remote Leo needs only two new commands:


leointeg does not do what leo's core does. it only gives what it asked from leoserver to it's "vscode-GUI-api-interfaces". (leojs does though, but still in early beta) 

& I'm guessing here Thomas is using the term "leoBridge" interchangeably with "leoserver". - correct me if I'm wrong.

>1: get a remote outline by name and
>2: save the remote outline (possibly with another name)

Hmmm. that's already what leoserver does. (unless the meaning of 'remote' is opposite of what I see it as) In my mind, the new functions it would need are rather: 
1-get a leo file over the wire as a string in a json package, (sent from local clients filesystem to the remote server's) almost akin to a 'paste as root node'
2- maybe a "copy root node" (whole outline) - to mirror #1 in opposite direction to save modifications.

Please correct me and/or comment on what I just layed out as my understanding of this subject. :)

Hey btw: Thanks to Thomas for bringing this up now at this point in time, because the thing about this subject, is that i'm considering needing those two functionalities for combining leojs as a new front end for the whole 'leointeg' setup. 

in the meantime, those last few days I'm still working on the nav tab and functionality, and trying to get that going before Edward's 6.6 final deadline !  hehe! :P

Félix

tbp1...@gmail.com

unread,
Mar 9, 2022, 10:09:24 PM3/9/22
to leo-editor
@Felix: " I'm guessing here Thomas is using the term "leoBridge" interchangeably with "leoserver". - correct me if I'm wrong."
Yes, I was unclear in my own mind which one does what, but I knew that leoserver opens leoBridge.

Basically, what I want to do is to work on a Leo outline that lives in computer A, and I want to sometimes work on it on Computer B without having to copy the outline to and from a privileged directory.  At first, I pictured the outline open in Computer A, and Leo in Computer B seeing the same thing, like an echo.  But then I thought why not have Leo/A be a null gui?  Or maybe Leo/A isn't actually needed?

Edward K. Ream

unread,
Mar 10, 2022, 6:11:09 AM3/10/22
to leo-editor


On Wed, Mar 9, 2022 at 7:29 PM Félix <felix...@gmail.com> wrote:

> In my mind, the new functions it would need are rather: 
1-get a leo file over the wire as a string in a json package, (sent from local clients filesystem to the remote server's) almost akin to a 'paste as root node'
2- maybe a "copy root node" (whole outline) - to mirror #1 in opposite direction to save modifications.

Thanks for these comments.

I have just created #2475 for this project. As noted in the issue itself, I would like to delegate this project to you and Thomas. It might be good for you two to zoom to compare notes.

As an experiment in delegating work, I would rather stay out of the loop :-)  Thomas is the one who wants this feature, and you are the expert in leoserver.py. Of course, I'll be willing to help as needed.

What do you two think?

Edward

Félix

unread,
Mar 10, 2022, 8:55:31 PM3/10/22
to leo-editor
@Thomas, Thanks for the details given! Now I understand. (I wasn't sure i understood your main inquiry/request because that's already implemented and working in leoserver, so I thought: "i'm probably not understanding what he's trying to do if he needs something different")

So yeah, leoserver already is capable of multiuser, simultaneous connections to work on the SAME leobridge instance running in leoserver. To try it out, you'll have to use leointeg to connect to it, or take the time to implement a new client :) hehe!

This server feature is obviously useful for two main usages, first, to work on the same Leo file(s) in multiple client window (instead of each having it's own independent leoserver) the second, obviously, is sharing an open leoserver instance running live to multiple window/people on different computers on a network (lan or internet) - because leoserver accepts clients and does not know nor differentiate if they're on localhost, or on the other side of the planet.

Take a look a this section of the leoserver documentation for the details to allow multiple connections:


Of course, when editing, the leoserver sends 'refresh' notice events to the other connected clients so that they update their UI, so that all editing and changes are reflected 'live' in all other connected clients. allowing for "multiuser LIVE editing sessions" 

On the other hand, I hope to finish squashing the remaining leointeg bugs, and adding some more features so that people (like you ;) ) who still prefer the original Leo, to eventually switch to using leointeg, altough I dont blame you: the refreshing bug that happens when expanding/collapsing nodes of big outlines is pretty annoying. Good news is I've already made a new outline renderer in leojs, which does not have those bugs, and is much more fast and responsive, so I'll duplicate that new framework to leointeg in the following months when I've gotten leojs up to a particular point.

Anyways Thomas i want  to thank you very much for considering and having interest in those matters! I hope you try it out first with leointeg as client, just to check if it works with that as a first step, before endeavoring in writing a new client with qt/tcltk/or some other python gui framework. You are one of the best and promordial Leointeg tester ! so thanks again for that!

@Edward Those 2 features are going to be needed sooner than later. so I'll gladly add them to the server even tho it's not needed for now in the particular case Thomas was inquiring about. (but like i said, it might be useful for leojs or some other clients that want to change/set/reset the whole outline at once.)

Please Don't hesitate to ask more about any aspect, or to correct me if you think i'm wrong on something! :)

Félix

tbp1...@gmail.com

unread,
Mar 10, 2022, 10:11:54 PM3/10/22
to leo-editor
Thanks, @Felix.  I thought it was obvious that leoserver *could* play the role we needed.  After all, if it can connect Leo and Leo outlines to vscode, why not to another Leo instance instead of a vsc instance?  I didn't know, though, what changes, if any,  would be needed to let Leo play that role, nor how to configure any of it.  I'll look at the docs you link to and see if I can make some progress.

tbp1...@gmail.com

unread,
Mar 10, 2022, 10:20:42 PM3/10/22
to leo-editor
So here is my first question.  In the linked docs:

"leoserver.py has optional command line arguments that you can provide to get specific behaviors from the server.

–file <filename> or -f <filename>

Open the given file after starting the server."

What does it mean for leoserver to "open a file"?  Does this mean, for example, that an outline that *seems to be* open in vsc is not really?  Does it mean that any operation that vsc or Leo does to the file is actually performed by leoserver?  Or is leoserver relaying instructions to the outline's commander in Leo (that is, in the nullgui instance of Leo that the Bridge has instantiated)?  And if this latter is so, then isn't the outline "open" in the commander rather than leoserver?


tbp1...@gmail.com

unread,
Mar 11, 2022, 2:54:46 PM3/11/22
to leo-editor
It seems to me that this is the simplest thing that could possibly work:

Write a new Leo method: openFileViaServer(host_address, file_path)

1. The command on the remote computer sends an open file request to a leoserver instance on the host machine.
2. The server sends back the requested outline, wrapped in a server data package.
3. The remote Leo instance unpacks the outline and creates a new commander for it.

Saving the file would require another, complementary save command.  Actually, since I'm thinking here of only sending an outline, I suppose that any file server would do.  We don't really need to open the outline on the host machine.  But why not use leoserver, since it is at hand?

With this technique, an open instance of Leo on the host machine wouldn't know that the file is being edited on the remote.  For my limited use case, that is probably OK since I presumably wouldn't be changing the outline on both machines at the same time.  If the same outline were open in a Leo instance on the host computer, then it would notice when the file on disk has been changed and put up the usual dialog asking if it should reload the outline.  This is just how things work with leointeg (or used to - maybe Felix has changed it by now).  I think that's acceptable.

Edward K. Ream

unread,
Mar 11, 2022, 3:33:20 PM3/11/22
to leo-editor
On Fri, Mar 11, 2022 at 1:54 PM tbp1...@gmail.com <tbp1...@gmail.com> wrote:
It seems to me that this is the simplest thing that could possibly work:

Write a new Leo method: openFileViaServer(host_address, file_path)

1. The command on the remote computer sends an open file request to a leoserver instance on the host machine.
2. The server sends back the requested outline, wrapped in a server data package.
3. The remote Leo instance unpacks the outline and creates a new commander for it.

Saving the file would require another, complementary save command.  Actually, since I'm thinking here of only sending an outline, I suppose that any file server would do.  We don't really need to open the outline on the host machine.  But why not use leoserver, since it is at hand?

With this technique, an open instance of Leo on the host machine wouldn't know that the file is being edited on the remote.  For my limited use case, that is probably OK since I presumably wouldn't be changing the outline on both machines at the same time.  If the same outline were open in a Leo instance on the host computer, then it would notice when the file on disk has been changed and put up the usual dialog asking if it should reload the outline.  This is just how things work with leointeg (or used to - maybe Felix has changed it by now).  I think that's acceptable.

Yes, this is what I was thinking when I wrote my initial reply.  That is, we want the desktop version of Leo to be the "client".

Edward

Félix

unread,
Mar 12, 2022, 1:25:05 AM3/12/22
to leo-editor
> That is, we want the desktop version of Leo to be the "client".
Oh! I get it now! - (I thought Thomas was thinking about writing a Leo-dumb-terminal client (à la leointeg) in python  with Qt5/Qt6/tcl-tk or some other gui framework)

Yeah well this is an even better, and easy thing to accomplish then! Thanks again to Tomas for bringing this concept up! I'm going to have to do this with leojs in the short-middle term anyways!  :)

So to re-state the concept, (with very loosely defined and half-baked terminology): indeed, Leo could have a third 'mode' where it considers an opened outline, (aka 'commander') as 'remote-server-side-based' ... (the two other 'modes' being. first the "untitled-unsaved" new file, and second a saved file on/from disk )

Throwing ideas here:

1- i like the idea of openFileViaServer(host_address, file_path) , there also could be a connectToServer(host_address) which might just connect and present the currently opened files on the server as opened files in the leo "Client"... as if opened with "openFileViaServer", in that new 'remote-server-side-based' mode.

2-Like Thomas stated, the files operations have to be intercepted. for example, a save command needs to be intercepted and instead sent as a sequence of two server commands : send-outline-to-server and save-outline. (those methods names are not definitive and just brainstorming here) Another example, the server detects a file change (either derived external file or the leo file itself), so it send the alert-websocket-package to ask the user dialog: 'external file changed, reload?' if so, the client sends it's accepting packet and the server sends back a new model of the outline... 

Although very optimist and simplified scenarios presented here, it's pretty much it ...

in conclusion, the server needs only, as a preliminary estimate, two new methods: copy_root and paste_root_as_clone to replace the whole of it's outline. Some kind of whole outline + body transfer method instead of the existing 'partial' transfer methods like regular copy and paste outline.

other methods such as open_outline(path), save to file,  etc..  are all already in place in the server. I'll write those methods this week as I finish the server modifications neede for the nav panel which is almost complete.

In the new web client mode of Leo side of things though, some work is to be done too! ...I guess,  save and export command intercepts and redirection, along with accepting a whole xml string to replace the whole outline at the hidden root node level. (note: doing this whole outline replace is similar to opening an Leo xml file the normal way, but without all the startup scripts re-running, plugin initialisations and without replacing the state of the find panel, nav tab, etc) I'll leave some time to Thomas to come up with listing other required changes on Leo itself, for it to be run in a 'network-client' mode.

Thanks again to both of you for those great ideas and suggestions! :) 

please comment and correct me as you see fit !

Félix

Edward K. Ream

unread,
Mar 12, 2022, 5:23:26 AM3/12/22
to leo-editor
On Sat, Mar 12, 2022 at 12:25 AM Félix <felix...@gmail.com> wrote:
> That is, we want the desktop version of Leo to be the "client".
Oh! I get it now!

Glad to hear it.  There are considerable details to work out.  For example, Leo could remember that a file is remote. Perhaps no other "mode" is necessary, but I could well be wrong.

Edward

tbp1...@gmail.com

unread,
Mar 12, 2022, 8:23:14 AM3/12/22
to leo-editor
On Saturday, March 12, 2022 at 1:25:05 AM UTC-5 Félix wrote:
> That is, we want the desktop version of Leo to be the "client".
Oh! I get it now! - (I thought Thomas was thinking about writing a Leo-dumb-terminal client (à la leointeg) in python  with Qt5/Qt6/tcl-tk or some other gui framework)

Throwing ideas here:

1- i like the idea of openFileViaServer(host_address, file_path) , there also could be a connectToServer(host_address) which might just connect and present the currently opened files on the server as opened files in the leo "Client"... as if opened with "openFileViaServer", in that new 'remote-server-side-based' mode.

I'm sure we'd need a connect_to_server() method;  I see it as needed to make to openViaServer() and saveViaServer() work, not as top-level desire.
 
2-Like Thomas stated, the files operations have to be intercepted. for example, a save command needs to be intercepted and instead sent as a sequence of two server commands : send-outline-to-server and save-outline. (those methods names are not definitive and just brainstorming here) Another example, the server detects a file change (either derived external file or the leo file itself), so it send the alert-websocket-package to ask the user dialog: 'external file changed, reload?' if so, the client sends it's accepting packet and the server sends back a new model of the outline... 

I wouldn't think of the file operations needing to be intercepted, exactly.  There are two possibilities:

1) The commander will know what to do about saving/reopening because it will know the original network address of the outline. The commander already knows about a file's path, so this would be a minor extension.

2) The user should be able to optionally save an outline to the computer in use.  There are several reasons this would be a good idea, e.g., the host has shut down or gone to sleep, or lost the network connection;  the user wants to travel and needs the outline on to be the current machine; etc.

in conclusion, the server needs only, as a preliminary estimate, two new methods: copy_root and paste_root_as_clone to replace the whole of it's outline. Some kind of whole outline + body transfer method instead of the existing 'partial' transfer methods like regular copy and paste outline.

I think the clone aspect is good thinking.  For example, my zettelkasten system relies on the gnxs for its internal links and relationships.  If they were to change, the whole knowledge base would get wrecked.  There are probably other cases where the gnxs need to be preserved.

It seems to me that almost everything we need already exists except for the actual  acquire-from-the-leoserver. part.
 
other methods such as open_outline(path), save to file,  etc..  are all already in place in the server. I'll write those methods this week as I finish the server modifications needed for the nav panel which is almost complete.

Great! As we move forward, let's try to keep in mind that simplicity is good.  My maxim is to start out as simple as possible because because things will always get more complicated later.

Edward

tbp1...@gmail.com

unread,
Mar 12, 2022, 8:31:35 AM3/12/22
to leo-editor
On Saturday, March 12, 2022 at 8:23:14 AM UTC-5 tbp1...@gmail.com wrote:
It seems to me that almost everything we need already exists except for the actual  acquire-from-the-leoserver. part.

For instance, once Leo has the bytes from the other computer, loading them is essentially the  existing CreateOutline + PasteAsClone  operations.  Sending the changed outline back is essentially copyNode, then SendBytes (the only new part).

tbp1...@gmail.com

unread,
Mar 12, 2022, 3:36:21 PM3/12/22
to leo-editor
I've actually got this working (as a rough proof-of-principle).  I added a new command to leoserver: send_outline(self, param). My tiny client sends a file path to leoserver, which reads the file and sends the resulting string back to the client, which copies it to the clipboard.  The client then simulates the "new" command  and then the "paste-retaining-clones"  command to that new outline. 

The only thing is that the outline gets pasted in as a sibling of the empty node that gets put there when the new outline is created.  There must be some simple way to insert at the top of the outline, but I don't know what that is yet.  Anyway, in practice we'd probably like to use commander methods instead of simulating commands.  But it's almost usable this way, modulo error handling and getting the remote file path into the client script.

def send_outline(self, param):
    filename = param.get('path', '')
    result = ''
    if filename and os.path.exists(filename):
        with open(filename) as f:
            result = f.read()
    data = {"outline": result}
    return self._make_response(data)


In the client main loop:
# ...
        while n < 6:
            n += 1
            json_s = g.toUnicode(await websocket.recv())
            d = json.loads(json_s)
            id = d.get('id', '??')
            if id != 4:   # the id of my request
                continue
            if 'outline' in d:
                file = d['outline']
                print('outline length:', len(file))
                g.app.gui.replaceClipboardWith(file)
                c.k.simulateCommand('new')
                c1 = g.app.commanders()[-1]
                c1.k.simulateCommand('paste-retaining-clones')
            return
        return

In practice I suppose we wouldn't want to return from the client this way because we wouldn't want to shut down the remote leoserver instance.

tbp1...@gmail.com

unread,
Mar 12, 2022, 11:59:50 PM3/12/22
to leo-editor
And here is the entire client main loop using commander methods instead of c.k.simulateCommand():

async def client_main_loop(timeout):
    uri = f"ws://{wsHost}:{wsPort}"

    async with websockets.connect(uri) as websocket:  # pylint: disable=no-member
        # Await the startup package.
        json_s = g.toUnicode(await websocket.recv())

        request_package = {
            "id": 4,
            "action": '!send_outline', # New command for leoserver
            "param": {'path': r'c:\temp\leo\zettel_cmds.leo'}
        }

        n = 0
        request = json.dumps(request_package, separators=(',', ':'))
        await websocket.send(request)

        while n < 6:
            n += 1
            json_s = g.toUnicode(await websocket.recv())
            d = json.loads(json_s)
            id = d.get('id', '??')
            if id != 4:   # the id we are interested in

                continue
            if 'outline' in d:
                file = d['outline']
                print('outline length:', len(file))
                c1 = c.new()
                c1.pasteOutlineRetainingClones(None, file)
                break

tbp1...@gmail.com

unread,
Mar 13, 2022, 12:07:20 AM3/13/22
to leo-editor
And the new (very simpleminded) leoserver command is:

def send_outline(self, param):
    filename = param.get('path', '')
    result = ''
    if filename and os.path.exists(filename):
        with open(filename, encoding='utf-8') as f:

            result = f.read()

    data = {"outline": result}
    return self._make_response(data)

Edward K. Ream

unread,
Mar 13, 2022, 7:09:14 AM3/13/22
to leo-editor
On Saturday, March 12, 2022 at 11:07:20 PM UTC-6 tbp1...@gmail.com wrote:
And the new (very simpleminded) leoserver command is:

[Snip]

Thanks for all this work.  I spoke with Félix yesterday on zoom about this issue, among others. I suggested that you and Félix collaborate on this issue.  I would like to stay in the background on this, but I'll be happy to help as needed.  Thomas, is this plan OK with you?

Edward

Edward K. Ream

unread,
Mar 13, 2022, 7:27:08 AM3/13/22
to leo-editor
On Tuesday, March 8, 2022 at 4:12:39 PM UTC-6 tbp1...@gmail.com wrote:
I'd like to open a Leo outline that is on another computer - strictly within my home LAN.  I could do that by sharing a directory and putting the outline into that directory.  But I'd rather have that outline be in its intended place on the drive, not in some other shared directory.

While looking into how Leo handles .json.leo files (still haven't found that :-) I stumbled across Terry's leo_cloud plugin.  The docstring starts with:

    "synchronize Leo subtrees with remote central server"

I'm not sure how leo_cloud.py fits into this project, but I want to remind everyone of the plugin's existence.

Edward

tbp1...@gmail.com

unread,
Mar 13, 2022, 7:59:32 AM3/13/22
to leo-editor
Yes it is.

tbp1...@gmail.com

unread,
Mar 13, 2022, 8:00:51 AM3/13/22
to leo-editor
I'll take a look.
Reply all
Reply to author
Forward
0 new messages