Programatically remove entry from Atom's undo stack


#1

I already asked this in Stack Overflow, to no avail, so here am I :wink:

I know I can pack multiple changes into a single undo transaction using TextBuffer.transact() or TextEditor.transact(), but I can’t find how to just remove last entry (or entries) from the undo stack.

Is the only solution to access directly the historyProvider and mess with the undostack array? Frankly, right now I don’t know which side-effects this can have, but I don’t find anything in Atom API todo what I need.

Thanks a lot in advance! :slight_smile:


#2

Hello.

I use another mechanism to mark a recoverable undo position:


return false unless _editor = atom.workspace.getActiveTextEditor()
# Mark start position for 'undo'
_checkpoint = _editor.createCheckpoint()

# code

# Mark end position for 'undo'
_editor.groupChangesSinceCheckpoint(_checkpoint)

I am not 100% sure, but…
You may have some interest in looking at:
https://atom.io/docs/api/v1.21.2/TextBuffer#instance-revertToCheckpoint


#3

First of all @danPadric, thanks A LOT for your reply :slight_smile:

Second, I never consider using createCheckpoint() because when I read the docs for revertToCheckpoint() and saw that “Revert the buffer to the state it was”, my understanding was that it left the editor’s contents as they were at the moment the checkpoint was created, so I can’t use that to remove an undo position. I’ll have to check it anyway, because I think I can use this mechanism to achieve what I want (which is, more or less, to tell the editor “forget this change ever happened, this is here to stay, any undo has to be done from previous positions”, which I don’t think it’s even possible in Atom, even though it is possible in Vim (it was more or less my inspiration).

As for your solution, it may more or less work for me, I may try it if I can’t find a way of removing something from the undo stack without side effects.

Thanks!


#4

Thanks for your nice feedback.

I am currently using the checkpoint concept in my own codings called through init.coffee. This way I have multiple steps that is linked into “one”. When the user calls an undo task. All the tasks between the checkpoint calls are undone.


#5

I’ll keep you informed if I finally can use some solution based on packing undo entries. And again, thanks for your help. You made me look at the problem in a very different way!

And yes, I’m also using this code in init.coffee :wink:


#6

Sorry for the self reply, but I found a way of achieving what I want.

Using Editor.insertText(text, {undo: 'skip'}, or the same option for setTextInRange a text insertion can be removed from the undo stack.

@danPadric, maybe you’re interested in this!


#7

Thank you for sharing this possibility.
I have not before looked into the options.
Some of those could be handy.

I have found API description:
https://atom.io/docs/api/v1.21.2/TextEditor#instance-insertText
…and option description:
https://atom.io/docs/api/v1.21.2/Selection#instance-insertText

Why do you need to skip the undo ability? What is your use case?


#8

Well, @danPadric, my use case is probably uncommon. In some files I have a timestamp in a header, and I want it to be auto-updated when the file is saved. There’s even an Atom package for that, but it’s a very simple task and I thought it would be a great way of learning a bit of Atom’s programming.

Updating the text in the header was easy, but the problem was that the operation ended in the undo stack, obviously. So, if I made some change to the file and save it, and later I performed an undo operation, the first undone change was not that last change I made to the file but the updating of the timestamp in the header. Not something terrible, I could live with it, but skipping the undo stack was better. I could do that in Vim, for example, and I was interested in learning how to do it in Atom.


#9

You are a strange individual … no disrespect intended.
Perhaps there are no “normal” people in this world to begin with.
Just bunch of strange people to the left and to the right of what we call “normal”.

Most guys I know that uses Vim won’t use anything else.
You are using Vim Mode in Atom - right?

Interesting use case. I can see why you do it this way. Would love to see the code. Do you have it as a GIT somewhere?


#10

No disrespect taken @danPadric :wink:

I don’t use Vim Mode in Atom… because I still use Vim mostly. But I wanted to take a look at Atom for some reasons. Still not my main editor, that’s going to be Vim for long, I’m afraid, but I wanted to try and learn Atom. I love the package system, the fact that you can rewrite the entire editor, the looks, the autocompletion system, etc. But right now it’s too big, too slow to start and has quite a room to improve.

About the code, here it is (and yes, I prefer the regex like that instead of \d{4} or the like, it’s more visual for this particular usage). No GIT, sorry:

atom.workspace.observeTextEditors (editor) ->
    editor.getBuffer().onWillSave ->
        buffer = editor.getBuffer()
        regex = /Revision:\s*(\d\d\d\d-\d\d-\d\dT\d\d:\d\d:\d\d.\d\d\dZ)/g
        range = [[0, 0], [10, 0]]
        buffer.scanInRange regex, range, (match) ->
            scopes = editor.scopeDescriptorForBufferPosition(match.range.start).getScopesArray()
            return unless scopes.some (item) -> item.startsWith('comment.')
            timestamp = 'Revision: ' + new Date().toISOString()
            buffer.setTextInRange(match.range, timestamp, {undo:'skip'})
        return null
     

It’s a quick and dirty hack, that’s the reason I don’t get rid of the buffer var, which I think is not needed as scanInRange can also be used with Editor, the hardcoded range, etc. I’ll probably improve it with time.


#11

So, I had the idea to use Node’s fs module to edit the file. After a file is saved, Atom pays attention to changes to the file and saved TextBuffers will automatically update if you make a change to the file on disk. If you bypass Atom to make the edit, it can’t possibly put that action on the undo stack. However, when I go to test that idea, I make a change to a file in Atom, then add something to the file in Notepad++, but when I undo in Atom, what gets reverted is the N++ addition, so that’s a bust.