Join Line Above


#1

Hey guys,

I’m trying to define a new command for joining the current line with the line above. So far, I have made it work as expected with the following code:

atom.commands.add 'atom-text-editor', 'custom:join-line-above', (e) ->
    return unless editor = atom.workspace.getActiveTextEditor()
    editor.moveUp()
    editor.joinLines()

However, one issue arises: when undoing the command, I have to press ctrl+z twice because atom recognizes the last action as two commands, instead of just one.

Does anyone know how to handle this?

Thanks!


#2

The way to handle this is with editor.transact(). This code works for me with only one undo required to reverse it:

atom.commands.add 'atom-text-editor', 'custom:join-line-above', (e) ->
    return unless editor = atom.workspace.getActiveTextEditor()
    editor.transact ->
        editor.moveUp()
        editor.joinLines()

#3

Hello.

The following should help you out.

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

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

NOTE: _ is used above as prefix for temporary tags.


#4

Thanks! This worked perfectly :smiley:


#5

This solution is for packages that are too complicated to comfortably fit the operation inside an anonymous function in the transact() call. If you have a package of sufficient complexity, you might not know everything that goes into each transaction, but if your package knows when the transaction is finished, you can have it decide when to create the group.

For example, I would not want to nest more than two layers deep inside transact(). I only nest deeper than two levels past the inside of the primary function (in this case, the anonymous function generated for atom.commands.add()) if I’m doing complicated loops, and even then I try to avoid it if I can (comprehensions are really freaking useful for this, in Python/CS). If the operation involves defining its own functions, then it’s just going to get harder to read the deeper you go and the manual checkpoint functions become very useful. In that case, you treat them like constructor() and destroy() methods, as the begin and end steps of your package’s execution.


#6

…well you taught me something -> transact(). Thank you.

For future reference: Description => transact([groupingInterval], fn)


#7

I just figured it out, myself. I hadn’t explored that part of the API previously.


#8

always the scholar? :smiley: :+1:
Sample code pieces with those API descriptions would be most helpful.


#9

Great trick!!! Thanks. I’m now also using it to Toggle comments both ways.