Command to switch adjacent blocks

I’m trying to make a command to switch adjacent blocks, but I just don’t have a good enough understanding of the data model to know how I’m supposed to do this.

  // Move current block "up"
  bind("Shift-Mod-k", function(state: EditorState, dispatch?: any) {
    let $cursor: ResolvedPos = (state.selection as any).$cursor

    if (!$cursor) return false

    /**
     * paragraph: (grandparent)
     *  text:     (parent)
     *   abcdef 
     */
    let blockRP = state.doc.resolve($cursor.pos - $cursor.parentOffset - 1)

    let isFirstBlock = blockRP.parentOffset === 0

    if (isFirstBlock) return false

    if (dispatch) {
      let blockNode = blockRP.doc.nodeAt(blockRP.pos)
      let copy = blockNode.copy(blockNode.content)

      let prevTextRP = blockRP.doc.resolve(blockRP.pos - 1)
      let prevBlockRP = prevTextRP.doc.resolve(prevTextRP.pos - prevTextRP.parentOffset)

      let tr = state.tr
      tr.delete(blockRP.pos + 1, blockRP.pos + blockNode.nodeSize)
      tr.insert(prevBlockRP.pos, copy)
      dispatch(tr)
    }
    return true
  })

This code does manage to switch the two blocks, but it has unwanted side effects.

It inserts extra empty paragraphs both before and after the two blocks in question, and sets the selection to be in the last of the newly created paragraphs.

Sep-22-2017 15-57-02

I’ve been struggling with this for a couple hours. Although I have a basic understanding of the data model, I just don’t have a good enough understanding of how I can work with it. Any help would be greatly appreciated.

I figured it out. I was deleting blockPR.pos + 1 which was removing the text but leaving an empty paragraph at the end. And I was inserting the copy one spot too far forward which was splitting the start of the paragraph.

tr.delete(blockRP.pos, blockRP.pos + blockNode.nodeSize)
tr.insert(prevBlockRP.pos - 1, copy)
dispatch(tr)

While this kind of worked, I decided to set aside this feature. This problem is significantly more complicated then I initially thought. Switching paragraphs isn’t bad, but when you start having nodes of different types interacting things get weird.