Here is the code for the command that I mentioned before, to go to a node 
and insert a backlink in the target node.  I put this code into an @setting 
node with the headline:

@command zettel-goto-node @key=Alt+F6

The @setting node goes into the myLeoSettings.leo file.

This code could use a bit more work.  The main thing is that it may reorder 
the metadata lines in a zettel node.  This does not change any behavior, 
but I like to have those lines in a particular order.  I like them to start 
with the node id, then a timestamp, like this:

:id: TomP.20200221124629.1
:timestamp: 02/22/2020 08:24:58
:link: TomP.20200221221759.1 TM4J
:link: TomP.20200223153257.1 

The order may get changed when the code inserts a new backlink in the 
target node because one did not exist before.

I decided to have the link meta-lines have optional labels, because they 
help you know which links goes where. In the older paper-based system, 
identifiers generally looked like this (from 
https://www.lesswrong.com/posts/NfdHG6oHBJ8Qxc26s/the-zettelkasten-method-1
):

"I might have a train of thought which goes across cards 11, 11a, 11b, 
11b1, 11b1a, 11b1a1, 18, 18a…"

All well and good, but a few months later, if you see "11b1a1" in a link, 
you probably won't know what it goes to.  You would have to fish around 
trying all the link references in your zettel to see which ones you might 
be interested it.

Using an optional label seems better.

-- 
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 leo-editor+unsubscr...@googlegroups.com.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/leo-editor/4c34df33-c030-400a-918d-5866aa789c44%40googlegroups.com.
# Get gnx (node id) of target node from the ":link:" line of this node,
# insert a backlink to this node in the target if the target does not have one,
# and jump to the target node.
# Does nothing if cursor is not on a line starting with ":link:".

# If the backlink exists on the target node, but it has no label, then
# add a label.  The :link: specifier line is expected to look like this:
# :link: TomP.20200223153257.1 About Leo
# The "About Leo" part is the label.  If a label on the backlink exists,
# it is not changed, but if the link has no label, then one is constructed
# from the headline of the node.

def get_gnx_from_link(line):
    line = line.lstrip()
    is_link_line = line.startswith(':link:')

    gnx = ''
    label = ''
    if is_link_line:
        splits = line.split(':link:')
        if len(splits) > 1:
            fields = splits[1].split()
            gnx = fields[0]
            label = ' '.join(fields[1:]) if len(fields) > 1 else ''

    return gnx, label

# List of line(s) containing cursor or selection
cursor_lines = c.getBodyLines()[1]

line = cursor_lines[0] if cursor_lines else ''
line = line.lstrip()

gnx, sending_label = get_gnx_from_link(line)

if gnx:
    start_gnx = p.gnx
    node_label = p.h
    if node_label.startswith('@'):
        node_label = ' '.join(node_label.split()[1:])
    start_link = f':link: {start_gnx}'
    start_link_label = f'{start_link} {node_label}'

    _found_target = False
    for _p in c.all_unique_positions():
        if _p.gnx == gnx:
            c.selectPosition(_p)
            _found_target = True
            break

    if _found_target:
        lines = _p.b.split('\n')

        # Three cases for backlinks to sending node:
            # 1. Sending node has no backlink
            # 2. Sending node has backlink, but the backlink has no label
            # 3. Sending node has backlink with label.
        got_start_link = False
        for i, line in enumerate(lines):
            line = line.lstrip()
            if not line.startswith(':link:'): continue
            if start_link in line:
                got_start_link = True
                # case 2
                if start_link == line:
                    lines[i] = start_link_label
                    _p.b = '\n'.join(lines)
                else:
                    # Case 3
                    pass
                break

        if not got_start_link:
            # case 1
            _p.b = f'{start_link_label}\n{_p.b}'

Reply via email to