Distinguish User Input Updates

Ran into a case where a simple EditorView.updateListener wasn’t sufficient, as I needed to know if the document had changed due to direct user input in that specific CodeMirror instance, not due to other extensions or an external source changing the document.

Passing along this little helper I wrote to check for user events that change the doc:

// Check if a ViewUpdate contains User Events
function isViewUpdateFromUserInput(viewUpdate) {
  // Make sure document has changed, ensuring user events like selections don't count.
  if (viewUpdate.docChanged) {
    // Check transactions for any that are direct user input, not changes from Y.js or another extension.
    for (const transaction of viewUpdate.transactions) {
      // Not using Transaction.isUserEvent because that only checks for a specific User event type ( "input", "delete", etc.). Checking the annotation directly allows for any type of user event.
      const userEventType = transaction.annotation(Transaction.userEvent);
      if (userEventType) return userEventType;
    }
  }

  return false;
}

Basic Usage:

const state = EditorState.create({
  doc: await fileDoc.getValue(),
  extensions: [
     ...
     EditorView.updateListener.of(function (viewUpdate) {
       const userEvent = isViewUpdateFromUserInput(viewUpdate);
       if (userEvent) { ... }
     })
  ]
});

Hopefully that’s helpful to someone. If there’s a better or simpler approach to determining a user input event, I’m all ears!

3 Likes