outline position when deleting a clone

66 views
Skip to first unread message

HansBKK

unread,
Dec 17, 2011, 8:11:39 PM12/17/11
to leo-e...@googlegroups.com
It appears that when I delete a clone from a given position in the outline, the cursor location in the outline pane jumps to that of another instance of the node whose clone was deleted. In many cases this is light-years away from the current working location, and it seems that often that location has collapsed, requiring a start-from-scratch navigation effort to get back to delete the next clone (rinse cycle repeat).

I would have expected as a general principle the outline location to remain stable unless I explicitly change it, even if it is for some reason necessary for the body pane focus to remain in the node whose clone is being deleted. That would require a mouse click to continue in the working location, but would be much better than the current state of affairs.

Please let me know if I'm doing something wrong, or if not I guess it's a wishlist, and in the meantime, any workaround suggestions would be welcome.

Brian Theado

unread,
Dec 17, 2011, 10:20:18 PM12/17/11
to leo-e...@googlegroups.com
On Sat, Dec 17, 2011 at 8:11 PM, HansBKK <han...@gmail.com> wrote:
> It appears that when I delete a clone from a given position in the outline,
> the cursor location in the outline pane jumps to that of another instance of
> the node whose clone was deleted.

I haven't seen this behavior before. Are you able to duplicate it for
a simple test case in a brand new outline? I'm not. If you can't
duplicate it in a new outline either, then I wonder what is different
between your complicated outline and the brand new one. If you can
duplicate it even for a simple test case, then I wonder what is
different between your setup and mine.

Here is a script I whipped up to ensure you and I are trying the same
thing in for the simple test case. To use it, just open a new
outline, paste the following text into the default node and hit Ctrl-b
(or Edit -> Execute Script) to execute the script.

######### start script
# Make aliases for less typing
mb = c.executeMinibufferCommand
cp = c.currentPosition

mb('insert-child')
cp().h = 'deep clone'
mb('insert-child')
cp().h = 'sub1'
mb('insert-child')
cp().h = 'the clone'
mb('clone-node')
mb('move-outline-left')
mb('move-outline-left')
mb('move-outline-up')
mb('insert-node')
cp().h = "selection should be here after deleting top level clone"
mb('move-outline-up')
mb('goto-next-sibling')
g.es('deleting toplevel clone: "%s"' % cp().h)
mb('delete-node')
g.es('selected node after clone delete: "%s"' % cp().h)
########## end script

The output I saw in my log pane was this:
deleting toplevel clone: "the clone"
selected node after clone delete: "selection should be here after
deleting top level clone"

Another reason I shared this script is to illustrate how easy it can
be to write scripts. What I've written is very similar to what you
might have come up with for an AutoHotKey script.

Brian

HansBKK

unread,
Dec 18, 2011, 12:34:19 AM12/18/11
to leo-e...@googlegroups.com
Thanks so much for taking so much time, and you're absolutely right, with a small & simple outline like this I see everything works as it should.

One "not real" example is when you have multiple clones of the same node together, this triggers a jump down to the "original".

I will try to get to the bottom of the problem in my yes much larger and more complex setup and if possible come up with a similarly simple test case to illustrate my findings. Or report back what screwing thing the nut behind the wheel was doing to cause the problem 8-)

Double-plus thanks also for your efforts to nudge me towards Python scripting - I'll also try to make time to see if I can figure out how your sample script works.

I find the very short ?variables? ?commands? like "c" and "h" and "g.es" a bit intimidating - are these generic Python, or defined by Leo's code? Any pointers to any English-language resources to help me understand these would also be most appreciated.

Pretty off-topic, so feel free to ignore, but one of my TEFL tutoring students is interested in doing more IT oriented learning with me, so if I can persuade his 'rents maybe that will help me get on track with some baby steps - he's only ten but very bright. This looks like a possible starting point - http://www.manning.com/sande/ any other ideas for learning resources welcome.

HansBKK

unread,
Dec 18, 2011, 2:00:29 AM12/18/11
to leo-e...@googlegroups.com
OK, found one example pretty quickly - delete the sub2 node and I believe your cursor will jump to the bottom-most instance of the clone just above.

I'm speculating this might be an artifact of the move to the "one-node" world of cloning, Leo is able to get the outline position of the node it wants to jump to, but rather than jumping to that outline position it's using its gnx?

I don't know if the fact that my "A" master tree (using @shadow files) is at the bottom, with all the "B" @no-sent trees are above, is relevant or not. . .
Clipboard01.png

HansBKK

unread,
Dec 18, 2011, 3:28:43 AM12/18/11
to leo-e...@googlegroups.com
Little bit more systematically, trying to work out a "rule" for the behaviour.

I thought this was it:

The problem comes when deleting a cloned node in a "foreign tree" whose immediate "node above" (not necessarily parent) is a clone which has another instance in a lower tree.

But deleting 2B in tree 3 triggers it, but doing so in tree 2 does not.

Anyway, simple enough example to show the issue exists?

Clipboard02.png

Brian Theado

unread,
Dec 18, 2011, 9:34:23 AM12/18/11
to leo-e...@googlegroups.com
On Sun, Dec 18, 2011 at 3:28 AM, HansBKK <han...@gmail.com> wrote:
[...]

> The problem comes when deleting a cloned node in a "foreign tree" whose
> immediate "node above" (not necessarily parent) is a clone which has another
> instance in a lower tree.
>
> But deleting 2B in tree 3 triggers it, but doing so in tree 2 does not.
>
> Anyway, simple enough example to show the issue exists?

This kind of simple is definitely useful, but somehow I wasn't able to
reproduce.

I wrote a script to duplicate your screenshot. Comment out the last 3
lines to verify I have the outline structure the same as you. When I
run the full script, the output to the log pane is:

selected node after clone delete: "2a"
parent of selected node: "3"

Here is the script:


########### Begin script


# Make aliases for less typing
mb = c.executeMinibufferCommand
cp = c.currentPosition

mb('insert-child')
mb('insert-child')

cp().h = '1'
mb('insert-child')
cp().h = '1a'
mb('clone-node')
mb('insert-node')
cp().h = '2'
mb('goto-prev-sibling')
mb('move-outline-down')
mb('move-outline-right')
mb('goto-prev-node')
mb('move-outline-left')
mb('insert-child')
cp().h = '2b'
mb('goto-prev-node')
mb('insert-child')
cp().h = '2a'
mb('goto-prev-node')
mb('insert-child')
cp().h = '3'
mb('goto-next-node')
mb('clone-node')
mb('move-outline-up')
mb('move-outline-right')
mb('goto-next-node'); mb('goto-next-node')
mb('clone-node')
mb('move-outline-up'); mb('move-outline-up')
mb('goto-next-node'); mb('goto-next-node')
mb('goto-next-node')
mb('clone-node')
mb('move-outline-up'); mb('move-outline-up')
mb('move-outline-up')
mb('move-outline-up'); mb('move-outline-up')
mb('goto-prev-node')
mb('move-outline-left')

# Tree is now setup except expansion level doesn't match
# the screenshot, so expand the nodes to match
mb('goto-prev-visible')
mb('expand-or-go-right')
mb('goto-prev-visible')
mb('expand-or-go-right')

# Goto the 3.2b node
mb('goto-next-sibling'); mb('goto-next-sibling')
mb('goto-next-node'); mb('goto-next-node')
mb('goto-next-node')

# Delete 3.2b and display the selected node to the log


mb('delete-node')
g.es('selected node after clone delete: "%s"' % cp().h)

g.es('parent of selected node: "%s"' % cp().parent().h)
############## end script

Brian

Brian Theado

unread,
Dec 18, 2011, 9:41:07 AM12/18/11
to leo-e...@googlegroups.com
On Sun, Dec 18, 2011 at 12:34 AM, HansBKK <han...@gmail.com> wrote:
> I find the very short ?variables? ?commands? like "c" and "h" and "g.es" a
> bit intimidating - are these generic Python, or defined by Leo's code? Any
> pointers to any English-language resources to help me understand these would
> also be most appreciated.

http://webpages.charter.net/edreamleo/scripting.html

>
> Pretty off-topic, so feel free to ignore, but one of my TEFL tutoring
> students is interested in doing more IT oriented learning with me, so if I
> can persuade his 'rents maybe that will help me get on track with some baby
> steps - he's only ten but very bright. This looks like a possible starting
> point - http://www.manning.com/sande/ any other ideas for learning resources
> welcome.

I haven't personally used this, but:

http://learnpythonthehardway.org/book/

Brian

Edward K. Ream

unread,
Dec 18, 2011, 11:46:26 AM12/18/11
to leo-e...@googlegroups.com
On Sun, Dec 18, 2011 at 12:34 AM, HansBKK <han...@gmail.com> wrote:

> I find the very short ?variables? ?commands? like "c" and "h" and "g.es" a
> bit intimidating - are these generic Python, or defined by Leo's code?

These are conventions used throughout Leo. For a more complete list,
see the top-level "Code" node in leoPy.leo.

I strongly prefer the shortest possible names for commonly used
objects, and the clearest possible names for less commonly used
objects. This will not change.

g is globally bound to the leoGlobals module. g.es isn't a
convention, it is a reference to the es function in leoGlobals.py For
more details, see Leo's scripting chapter:

http://webpages.charter.net/edreamleo/scripting.html

Also note that Leo's execute script command pre-defines c, g and p.
This simple convention make Leo's scripting environment exceedingly
powerful.

Edward

HansBKK

unread,
Dec 18, 2011, 7:28:12 PM12/18/11
to leo-e...@googlegroups.com
Thanks a lot for the reply Edward, I took a look at that page, but given my current level of (not)understanding, it (and even some of your message) was like:

http://www.theamericanresident.com/wp-content/uploads/2011/02/ginger.jpg

But I hope to get there one day, thanks for the encouragement. . .

HansBKK

unread,
Dec 18, 2011, 7:37:24 PM12/18/11
to leo-e...@googlegroups.com
Letting your script delete the node gives the expected (correct) result.

Deleting the same node **manually** (rt-click delete) gives me the jumping behaviour, in this case to the top location.

Same with the one just above it (either of the 2's within the 3 tree, in any order)

Leo 4.9.1 devel, build 4867, 2011-12-05 06:57:18 -0500
Python 2.7.2, qt version 4.7.4
Windows 6, 1, 7601, 2, Service Pack 1

Brian Theado

unread,
Dec 18, 2011, 8:37:26 PM12/18/11
to leo-e...@googlegroups.com
On Sun, Dec 18, 2011 at 7:37 PM, HansBKK <han...@gmail.com> wrote:
> Letting your script delete the node gives the expected (correct) result.
>
> Deleting the same node **manually** (rt-click delete) gives me the jumping
> behaviour, in this case to the top location.

Finally I'm able to duplicate the issue. Just like you said only when
deleting via right click menu. Deleting via minibuffer command
doesn't exhibit the issue.

So there must be some difference between the minibuffer and picking
via the menu which is making the difference. Nice job figuring that
out.

I've reduced the script to the minimal amount needed to duplicate the
problem. However, I don't know how to simulate right-click menu in a
script, so that last step must be done manually.


# Make aliases for less typing
mb = c.executeMinibufferCommand
cp = c.currentPosition

mb('insert-child')
mb('insert-child')
cp().h = '1'
mb('insert-child')
cp().h = '1a'
mb('clone-node')
mb('insert-node')
cp().h = '2'
mb('goto-prev-sibling')
mb('move-outline-down')
mb('move-outline-right')

mb('insert-node')
cp().h = '2a'
mb('goto-parent')
mb('move-outline-left')

# The outline is setup, now select '2a'


mb('goto-next-node')
mb('goto-next-node')

# Delete 2a and display the selected node to the log
# Executing 'delete-node' via minibuffer command does
# not replicate the problem. Only deleting via
# right click menu exhibits the problem. I'm not sure
# how to simulate right-click menu in script
#g.es('selected node before clone delete: "%s"' % cp().h)
#mb('delete-node')
#g.es('selected node after clone delete: "%s"' % cp().h)
#g.es('parent of selected node: "%s"' % cp().parent().h)

HansBKK

unread,
Dec 18, 2011, 10:41:33 PM12/18/11
to leo-e...@googlegroups.com
Although I would have preferred it just be a fixable glitch with my personal setup, it's good to know I'm not crazy. If others haven't noticed this before, obviously not a high-priority issue, but it brings up a couple of points that might be of more general interest.

As a workaround I'm considering keybinding the delete-node command (suggested keystrokes welcome), but of course that would be dangerous. Is there a way to make it work safely - on nodes which have at least one clone remaining? Not only to prevent data-loss from old-fuddy-brainfarts, but accidental wrong-key-presses. . .

I'm **not** asking anyone to write a custom script for me please (just in case someone was going to 8-), but suggesting that if it isn't possible now, perhaps a delete-safely command would be a useful wishlist?

Terry Brown

unread,
Dec 18, 2011, 11:33:55 PM12/18/11
to leo-e...@googlegroups.com
On Sun, 18 Dec 2011 16:37:24 -0800 (PST)
HansBKK <han...@gmail.com> wrote:

> Letting your script delete the node gives the expected (correct) result.
>
> Deleting the same node **manually** (rt-click delete) gives me the jumping
> behaviour, in this case to the top location.

The right-click delete is different code, unlike the other deleted
commands, it can delete multiple selected nodes at once. I.e. click a
node in the tree, shift-click another node to select all nodes between,
or ctrl-click various separate nodes.

These (potentially) multi-level deletes can get very complicated in
terms of what's left and what's gone afterwards, say you have

A
B
C
D
E
F
G
H

select B, D, and F, then delete them all, where should the cursor go?
It's not clear where it was to start with, given that there were three
selected nodes.

I wonder if the code also has trouble knowing which clone was the one
selected.

Anyway, if you want more predictable results with single node
deletions, use Ctrl-X or bind something to the delete-node command.

Cheers -Terry

HansBKK

unread,
Dec 19, 2011, 2:50:56 AM12/19/11
to leo-e...@googlegroups.com, terry_...@yahoo.com


On Monday, December 19, 2011 11:33:55 AM UTC+7, Terry wrote:

These (potentially) multi-level deletes can get very complicated in
terms of what's left and what's gone afterwards, say you have

A
   B
      C
      D
   E
      F
   G
H

select B, D, and F, then delete them all, where should the cursor go?

I'm afraid my answer as a human user is "at least somewhere in the same neighborhood as where I thought my cursor was".

Personally if I were multi-selecting across different branches, I'd use delete-marked - now that I know to keeping my marks clear for such temporary working operations.

If it's really difficult to make this happen and few people are experiencing the behaviour as a problem I can understand it not getting fixed for now, but it is an issue from a UX POV - logged it to launchpad.

Brian Theado

unread,
Dec 19, 2011, 10:37:12 PM12/19/11
to leo-e...@googlegroups.com
On Sun, Dec 18, 2011 at 11:33 PM, Terry Brown <terry_...@yahoo.com> wrote:
> The right-click delete is different code, unlike the other deleted
> commands, it can delete multiple selected nodes at once.  I.e. click a
> node in the tree, shift-click another node to select all nodes between,
> or ctrl-click various separate nodes.
>
> These (potentially) multi-level deletes can get very complicated in
> terms of what's left and what's gone afterwards[...]

I wasn't aware of the multi-select functionality.

Does it make sense to change contextmenu.py to fall back to the core
code when there is just a single node selected (untested--but you get
the idea?):

if len(pl) == 1:
c.deleteOutline()
return

That way the behavior will always be the same when there is a single
node selected no matter how the command is executed.

> Anyway, if you want more predictable results with single node
> deletions, use Ctrl-X or bind something to the delete-node command.

While poking around I notice another workaround option is to use
@settings to add another entry to the context menu:

@settings
@data contextmenu_commands

The in the body put something like:

delete-node Simple Delete

Then for predictable results choose "Simple Delete" from the context
menu rather than "Delete". I didn't see a way for "@data
contextmenu_commands" to override other context menu entries (i.e. to
replace the existing "Delete" menu entry)

Brian

HansBKK

unread,
Dec 20, 2011, 1:42:24 AM12/20/11
to leo-e...@googlegroups.com
On Tuesday, December 20, 2011 10:37:12 AM UTC+7, btheado wrote:

    I wasn't aware of the multi-select functionality.

Nor was I, I guess the fact that cloning requires marking nodes first caused me to assume same for deletes.

Actually now that I think about it, I haven't had a need for bulk deletes yet, I guess because I'm still so tentative about my data. . .



>    While poking around I notice another workaround option is to use @settings to add another entry to the context menu:


Very cool, works a treat thanks!

 

>    I didn't see a way for "@data contextmenu_commands" to override other context menu entries (i.e. to replace the existing "Delete" menu entry)

Too bad, would be nice.

Now that I think about it (I can hear the groans), that would also be a straightforward way (maybe?) to handle all the mouse-driven events, in learning about
  - active_path.py
  - act-on-node
  - @url vs @mime, bookmarks etc

it seems there needs to be an easy standardized way to control what happens when the user left-clicks (single vs double, "new" vs when already selected) as well as the right-click context menu.

With the same facility and clarity that keybindings do now.

There could be a global default for a given event, then more specific actions defined for specific @types, maybe even user-defined new ones, tied into commands and scripts.


Right now, if you select multiple nodes and right-click, some of the options offered operate on all nodes selected, but others only on one at a time.

Others only appear in the first place if you have a single node selected.

I'm not complaining about this, just pointing out that there does seem to be a need to rationalize this area of the UI.

To simplify things, perhaps have the user-added context options only show when single nodes are selected, as for example happens with "open containing folder" - such a facility might also provide the basis for overriding Terry's multiple-delete code with the regular command in that context.

Did a little further digging and found these enlightening
  https://groups.google.com/forum/#!topic/leo-editor/em3Jn8GguYw/discussion
  https://groups.google.com/d/msg/leo-editor/-xheznGVc9c/ZTJdwtyLZa4J

I think I tend to agree with Edward about prefering to just not deal with multiple selected nodes, the ability to mark nodes and their specifically targeted commands seems much safer.

Not to mention the value of setting things up so you can just keep your hands on the keyboard. . .

Terry Brown

unread,
Dec 20, 2011, 8:36:36 AM12/20/11
to leo-e...@googlegroups.com
On Mon, 19 Dec 2011 22:37:12 -0500
Brian Theado <brian....@gmail.com> wrote:

> if len(pl) == 1:
> c.deleteOutline()
> return

Seems reasonable, I'll try and do that, if you don't / haven't
already :)

Cheers -Terry

Terry Brown

unread,
Jan 2, 2012, 4:13:48 PM1/2/12
to leo-e...@googlegroups.com
On Mon, 19 Dec 2011 22:37:12 -0500
Brian Theado <brian....@gmail.com> wrote:

> I wasn't aware of the multi-select functionality.
>
> Does it make sense to change contextmenu.py to fall back to the core
> code when there is just a single node selected (untested--but you get
> the idea?):
>
> if len(pl) == 1:
> c.deleteOutline()
> return
>
> That way the behavior will always be the same when there is a single
> node selected no matter how the command is executed.

Done at 4907

Cheers -Terry

HansBKK

unread,
Jan 3, 2012, 1:53:40 AM1/3/12
to leo-e...@googlegroups.com, terry_...@yahoo.com
I went to test on my minimal sample file, but I'm afraid the "latest" at the nightly builds page:

http://www.greygreen.org/leo/leo-editor-latest.zip

is "stuck" at 4904, dated 12-28

maybe still pulling from trunk2?

HansBKK

unread,
Jan 3, 2012, 3:39:33 AM1/3/12
to leo-e...@googlegroups.com, terry_...@yahoo.com

As reported here, I'm not sure what version I'm actually testing with, but it seems AFAICT this issue is now fixed, so  thanks, looks like I can get rid of the "Simple delete" script customization.

Are these issues from above worth adding as a wishlist item or further discussion?

>>It seems there needs to be an easy standardized way to control what happens when the user left-clicks (single vs double, "new" vs when already selected) as well as the right-click context menu.

Terry Brown

unread,
Jan 3, 2012, 10:51:20 AM1/3/12
to leo-e...@googlegroups.com
On Mon, 2 Jan 2012 22:53:40 -0800 (PST)
HansBKK <han...@gmail.com> wrote:

> I went to test on my minimal sample file, but I'm afraid the "latest" at
> the nightly builds page:
>
> http://www.greygreen.org/leo/leo-editor-latest.zip
>
> is "stuck" at 4904, dated 12-28

Looks ok to me now, Tue Jan 3 15:51:01 UTC 2012

rev. 4907

Cheers -Terry

Terry Brown

unread,
Jan 3, 2012, 11:05:49 AM1/3/12
to leo-e...@googlegroups.com
On Tue, 3 Jan 2012 00:39:33 -0800 (PST)
HansBKK <han...@gmail.com> wrote:

> Are these issues from above worth adding as a wishlist item or further
> discussion?
>
> >>It seems there needs to be an easy standardized way to control what
> happens when the user left-clicks (single vs double, "new" vs when already
> selected) as well as the right-click context menu.

These things have been discussed before, I think searching for "act on
node" or actonnode or something might turn up one relevant thread.

There are perhaps three different issues here, so some thinning is
required before you could file a wishlist item:

- how do you decide which plugin gets to say what single-click and
double-click do?

- Leo has very little support for multi-node operations / multi-node
selection, basically the few commands from the contextmenu.py plugin

- I don't think it's possible to support single and double click
actions without using a timer, which Edward doesn't want, which I
understand, as they do scary things to code execution pathways

Cheers -Terry

HansBKK

unread,
Jan 3, 2012, 6:38:06 PM1/3/12
to leo-e...@googlegroups.com, terry_...@yahoo.com
Responded in a new thread
Reply all
Reply to author
Forward
0 new messages