Sublime Forum

Redo inside of edit crashes sublime

#1

Calling view.run_command(‘redo’) inside of an edit in an on_modified callback (i.e. between view.begin_edit and view.end_edit), and then making a change and hitting undo twice crashes Sublime. I haven’t looked to see if it happens in more cases than this.

[code]class Redo(sublime_plugin.EventListener):
pending = 0

def on_modified(self, view):
if self.pending == 1:
return
self.pending = 1
try:
edit = view.begin_edit()
view.run_command(‘redo’)
finally:
view.end_edit(edit)
self.pending = 0 [/code]
Save this code as a plugin, edit a buffer, and hit undo twice.

I ran into this because I’m trying to add to a closed edit—i.e., when the user types something, I want to modify the buffer, but I want to do it in such a way that hitting undo once will undo both my changes and their changes. I tried to call “undo”, and then start an edit and call “redo” and make my changes before closing the edit, and that’s when I ran into this issue.

0 Likes

Plugin Api: on_modified should receive diffs
#2

Any ideas on how I can get around this? I’d really like to be able to add changes during the on_modified callback…

0 Likes

#3

Undo/redo inside of an edit is something that’s fundamentally not supported: if you were running a debug build, you’d hit an assert.

To be able to modify the buffer from within on_modified, and have it considered as part of the original edit, is going to require more API support. One option would be to add an on_pre_modified(view, edit) callback, where you’d have a chance to make any last minute changes before the action is committed. This would still be limited though, as you still wouldn’t know exactly what’s changed.

0 Likes

#4

Yeah, the only reason I want to call redo inside of the edit is because I can’t tell what’s changed.
Would it be possible to make edit objects more powerful? What if I could do something like this:

edit = sublime.Edit() #is there a reason edits are created from views? edit.insert(text_point,"hello world") edit.erase(region) view.apply_edit(edit) ... for edit in view.undo_stack(): print(edit.insertions()) #((text_point0, "string0"), (text_point1,"string1"), ...) print(edit.erasures()) #(sublime.Region object, sublime.Region object, ...) ... edit = view.undo_stack()-1] view.undo() edit.insert(text_point,"hi") #add an insertion to the edit view.apply_edit(edit)
or what have you. I sort of made up that API as I went along, but I like the idea of it. Then we could have plugins that interact with the undo stack—you could make a plugin that lists the different edits along with what changed so people can get a visual on their undo history. Or you could write a plugin that allows a branched undo stack like in e-texteditor. (or you could modify the top-most edit during an on_modified callback)

0 Likes

#5

Sublime Text 2 is all about a new application shell around the same editing core from Sublime Text 1. Sublime Text 3 (or 2.5? no idea yet) will be the same application shell, but with a new editing core. Among other things, this will allow plugins to determine exactly what was changed in a given edit.

I’ll spend some time looking if there’s an easy way to implement that functionality now, but if not, it’ll have to wait until after the stable version Sublime Text 2.

BTW, the reason Edit objects are specific to a view (well, a buffer really, but the buffer isn’t exposed directly), is that they exist to group modifications on the undo stack, and each buffer has its own undo stack.

0 Likes

#6

Thanks for checking to see if that information is easy to access. I’m curious—how does the undo stack actually work on the inside? Do you just keep track of insertions and deletions, or is it more complicated than that?

For now I’m working around the undo thing by wrapping undo and redo in some custom text commands and telling my plugin to ignore the next on_modified callback. It’s a little bit ugly but at least it works.

I guess it just seemed to me that edits could be kind of like regions: a region doesn’t actually have anything to do with a view, and depending on how you implement edits they wouldn’t necessarily have to have anything to do with a view until you actually applied the edit or whatever (kind of like the api I made up in my code example last post).

0 Likes