Diff editing performance is poor

Where does the bug appear (feature/product)?

Cursor IDE

Describe the Bug

Inline diff editing performance is poor.

I’ve got a file that has some pending changes (on the order of 50?), I would like to go through and edit them.

Each change (undo / apply action) takes about 20 seconds to apply on my M1 Macbook Pro.

Steps to Reproduce

Make a file, have more than a couple pending changes, try to edit one.

Expected Behavior

You should be able to edit changes at the monitor refresh rate.

Operating System

MacOS

Current Cursor Version (Menu → About Cursor → Copy)

Version: 1.7.39
VSCode Version: 1.99.3
Commit: a9c77ceae65b77ff772d6adfe05f24d8ebcb2790
Date: 2025-10-08T00:33:20.352Z
Electron: 34.5.8
Chromium: 132.0.6834.210
Node.js: 20.19.1
V8: 13.2.152.41-electron.0
OS: Darwin arm64 24.6.0

Additional Information

Taking a flamechart, the removedLinesZoneWidget component is a primary cause. The styles are recalculated on the order of a thousand times, with style mutations followed immediately by reads that trigger a reflow. Reads and writes should be grouped so that each batch of changes causes ideally, a single reflow.

But zooming out, updatePosition is being called with identical lineNumber and column values. Shouldn’t this bail out if they’re identical?

The method below, updateInnerChanges, does a conceptually similar check when cursor.diffs.useCharacterLevelDiffs is enabled, but comparing the JSON stringified values is pretty suboptimal, it’s a known type?

In the inlineDiffController, in getZoneWidgets you’ve got quadratic(? e and t seem to be basically the same size) scaling loops checking equality that should be linear. Iterate over the second zoneWidgets argument (t when minified), build a Map<typeof t[number].id, typeof t>, then once you’ve calculated ${r.removedLinesOriginalRange.startLineNumber}-${r.removedLinesOriginalRange.endLineNumberExclusive}, check the map. Linear scaling, 60 checks instead of 3300?

Does this stop you from using Cursor

Yes - Cursor is unusable

To me and I’m sure many others, the primary feature of Cursor is the state management of AI edits, the ability to ask for changes, have the IDE keep track of pending ones, at which point they can be applied, edited or undone. It’s the primary differentiator against the terminal based systems, and the “killer feature” of Cursor. It not working doesn’t just prevent me from using the IDE, it makes me reconsider whether this IDE is worth using. It’s the kind of feature where its performance should be automatically integration tested before release. It falling over with frankly pretty small work-loads is disappointing.

This is a really detailed bug report - thanks for the flamechart analysis and specific performance bottlenecks you’ve identified. The 20 second delays for diff operations with ~50 changes is definitely not the kind of performance we want in Cursor.

We haven’t seen many reports on this, and our diff functionality has been around for a while, so I’d be surprised if there has been any regression in performance here. However, with the wide array of devices and setups our users run Cursor on, there may be an issue here we haven’t seen before.

Firstly, can you open the Activity Monitor, find Cursor in the list and check what shows under the Kind header. It should read Apple but if you see Intel, it means you may be running the wrong version of Cursor and will see much worse performance. Given the depth of your investigation, I would guess this isn’t the case, but just want to confirm as it’s easily done!

Secondly, we often see standalone reports like this when there is some other software or extension that is interfering.
Can you try running cursor --disable-extensions and see if you can recreate the same performance issues? If you can, this does suggest an issue within Cursor itself, but if not, you may have an extension installed that is contributing to the poor performance - potentially triggering the recalculations that might not happen on a clean Cursor installation.

Finally, sometimes things can get corrupted or out of sync under the hood. In this case, a reinstall of Cursor may help. Deleting and installing from cursor.com can ensure you are on the latest version, but you can also try running sudo rm -rf ~/Library/Application\ Support/Cursor, followed by rm -f ~/.cursor.json in the Terminal to clear the apps data, which does persist by default between app uninstalls. Note that this will delete your conversation history, installed extensions and any other config you have inside Cursor, so ensure you have your rules, extensions and other data backed up.

I have logged this internally for our client performance team to look into, but let me know if the above helps in any way.

I’m on an M1 Max Macbook Pro with 64gb ram, I’d assume that’s pretty common.

Yeah, I pulled version 1.0.0 of cursor and the same codepath is there. Maybe not many people have more than a few dozen separate diffs at once, and if they do, they just hit ‘accept all’?

Nah it’s running natively (but good call, Rosetta has caught me out before with other Electron apps!)

Version: 1.7.44
VSCode Version: 1.99.3
Commit: 9d178a4■■■89981b62546448bb32920a8219a5d0
Date: 2025-10-10T15:43:37.500Z
Electron: 34.5.8
Chromium: 132.0.6834.210
Node.js: 20.19.1
V8: 13.2.152.41-electron.0
OS: Darwin arm64 24.6.0

Yeah it’s very repeatable, unrelated to extensions.

I grabbed a typical 1000 line file from my repo, got the LLM to make a tiny change, then induced 149 other changes that got caught up by the diff system, the end result being 150 distinct “red line, green line, some untouched lines”.

In prod Cursor, hitting ‘undo’ on one causes it to lock up for at least 5 minutes (I killed the process after that).

Monkey patching the removedLinesZoneWidget component:

updatePosition(e) {
  this._position = e
  this.showWidget()
}

to

updatePosition(e) {
  if (e.lineNumber !== this._position.lineNumber && e.column !== this._position.column) {  
    this._position = e
    this.showWidget() 
  }
}

Helps significantly, with the same setup (as in reloading and seeing the exact same diffs) it takes ~170ms to hit undo on one.

I didn’t try this, but it looks like the application detects corruption pretty well anyway, it throws this up when I’ve patched the JS!

image

This topic was automatically closed 22 days after the last reply. New replies are no longer allowed.