what to call after changing body text, please?

43 views
Skip to first unread message

jkn

unread,
Jul 28, 2024, 8:40:32 AM7/28/24
to leo-editor
I'm being a bit dim here, but:

I am writing a simple command to append text to the body of a node. The only commands I have written before set the entire body text to some value.

What do I have to call after using w.insert() etc. to make these changes persistent.?

c.redraw() does not seem to do the trick.

The (outdated?) scripting miscellany:

suggests that c.frame.body.onBodyChanged should be called; but it looks like this is not longer the case.

A trivial example (that I do not seem to be able to find) would be helpful - thanks.

w = c.frame.body.wrapper
for line in range(10):
    w.appendText("%d\n" % line)

# now what?

    J^n

Thomas Passin

unread,
Jul 28, 2024, 8:58:07 AM7/28/24
to leo-editor
Here's one I use and it works fine.  You should set up for undoing after an insert, and this script does that too:

"""Insert a node with id and creation timestamp strings"""

c.doCommandByName('insert-node')
undoType = 'xx-insert-node'
p.moveToNext()
w = c.frame.body.wrapper

oldSel = w.getSelectionRange()
w.deleteTextSelection()
w.setInsertPoint(0)

id_label = f':id: {p.gnx}\n'
time_string = ':created: ' + c.getTime(body=True) + '\n'
i = w.getInsertPoint()
w.insert(i, f'{id_label}{time_string}')

c.frame.body.onBodyChanged(undoType, oldSel=oldSel)
c.bodyWantsFocusNow()


jkn

unread,
Jul 28, 2024, 9:17:45 AM7/28/24
to leo-editor
Thanks. Hmm, looks like I was wrong about onBodyChanged being outdated - there seem to be hardly any uses in Leo's source, which perhaps misled me.

I removed my undo code from my example... ;-)

    Regards
    J^n

Thomas Passin

unread,
Jul 28, 2024, 9:52:47 AM7/28/24
to leo-editor
I think I forgot that the recommended way to do unto/redo has been changed since I wrote that script. Also, you can directly set p.b or p.v.b and those changes will stick.  Here's one I found in Leo's code base that does that and uses the newer undo system:

def insertBodyTime(self: Self, event: LeoKeyEvent = None) -> None:
    """Insert a time/date stamp at the cursor."""
    c, p, u = self, self.p, self.undoer
    w = c.frame.body.wrapper
    undoType = 'Insert Body Time'
    if g.app.batchMode:
        c.notValidInBatchMode(undoType)
        return
    bunch = u.beforeChangeBody(p)
    w.deleteTextSelection()
    s = self.getTime(body=True)
    i = w.getInsertPoint()
    w.insert(i, s)
    p.v.b = w.getAllText()
    u.afterChangeBody(p, undoType, bunch)


jkn

unread,
Jul 28, 2024, 9:59:09 AM7/28/24
to leo-editor
well ... yes, I have previously just totally **set** the body text (ie. I am creating a totally new node), and as you say this 'sticks'. For this new command, I want to add to any body text which is already there.

But I am puzzled about what seems to be a mixture in this example:

- you get the insertion point and then use w.insert() to write your text to ... the wrapper for the body??
- but then you do p.v.b = w.getAllText() to ... set the body text to ... that which you have just set for the body wrapper?

I am missing something in the paradigm here...

    J^n

Thomas Passin

unread,
Jul 28, 2024, 10:18:43 AM7/28/24
to leo-editor
"you" here is code in Leo's core. It's not mine.  I think the code is changing text in the wrapper, w, and then retrieving all the text from the wrapper and assigning it to p.b.  It seems a little strange to me too.  I will say that I have never had text vanish when I assign it directly to p.b so maybe that's the idea here.

With that in mind you could also get p.b and do insertions on it using ordinary string methods, then assign it back to p.b:

i = 12  # insertion point
original = p.b
s = 'this is the insert'
tail = original[i:]
head = original[:i]
new = head + s + tail
p.b = new

There's some difference regarding updating between assigning to p.b and p.v.b but I forget what it is. It's mentioned somewhere in the docs.  Edward will probably chime in here with more definitive information.

jkn

unread,
Jul 28, 2024, 10:40:49 AM7/28/24
to leo-editor
indeed, I could do "get current body text/append to it /set new body text". But I am trying to learn the way that Leo does it, ie. the 'cleanest' way.

Thomas Passin

unread,
Jul 28, 2024, 11:59:59 AM7/28/24
to leo-editor
The wrapper, w = c.frame.body.wrapper, is a member of c, not of the body.  When you select a node, w gets filled with that node's body text.  So you have to transfer that modified text back to the node's body before switching to a new node.

jkn

unread,
Jul 29, 2024, 3:37:29 PM7/29/24
to leo-editor

I would like to better understand the 'philosophy' here ... (eg. of the widget wrappers within Leo in general...), but I have something that will do for me now, thanks

    J^n
Reply all
Reply to author
Forward
0 new messages