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
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
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
> 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
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)
> 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
These (potentially) multi-level deletes can get very complicated in
terms of what's left and what's gone afterwards, say you haveA
B
C
D
E
F
G
Hselect B, D, and F, then delete them all, where should the cursor go?
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
> if len(pl) == 1:
> c.deleteOutline()
> return
Seems reasonable, I'll try and do that, if you don't / haven't
already :)
Cheers -Terry
> 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
> 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
> 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