Skip to content

Reflect External File Changes #2075

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 16 commits into
base: main
Choose a base branch
from

Conversation

thecoolwinter
Copy link
Collaborator

@thecoolwinter thecoolwinter commented Jun 27, 2025

Description

Implements reflecting external changes in open files. If a file has no unsaved changes, and is notified that the contents changed, it reloads the contents. NSDocument already handles asking the user if they want to overwrite the contents of the file or use the disk version if the user attempts to save to a file that has been updated since they edited the file.

When a successful reload happens, the CodeFileDocument will also register a new undo frame with the new contents. This allows the user to undo changes that are reflected in the editor.

When a file is updated externally and there are no open editors, the cached undo stack is cleared.

Detailed changes:

  • Override CodeFileDocument.presentedItemDidChange to handle notifications about file changes.
    • If the file's current modification date != the last recorded one, we assume it has been changed on disk.
    • If isDocumentEdited is false, we block the calling thread and reload the document.
  • In CodeFileDocument.read, we check to see if the file has already been read into the NSTextStorage object.
    • If it has, we replace the contents with the new contents. This will be reflected in any open editors. Replacing the object would lose any subscribers (like the text view and syntax highlighting).
    • We also register the undo frame here.
  • Centralized the code that loads CodeFileDocuments into CEWorkspaceFile. Previously it was in a few different places.
  • Added UndoManagerRestoration to receive file system events. It uses these to invalidate undo stacks where necessary.
  • Updated CodeFileView to use the file document's object ID as SwiftUI's identifier. This fixed a bug where a document was sometimes 'cached' by the document controller and meant SwiftUI didn't load up a new view for the new document. This ID is stable while a file is open in an editor.
  • Fixed ~3 memory leaks related to CodeFileDocument that were causing the file to not reload when it was closed and opened again.
    • The changes to EditorLayout+StateRestoration.swift are all related to this.
    • Any changes where I just added a [weak codeFile] are similarly related.

Related Issues

Checklist

  • I read and understood the contributing guide as well as the code of conduct
  • The issues this PR addresses are related to each other
  • My changes generate no new warnings
  • My code builds and runs on my machine
  • My changes are all related to the related issue above
  • I documented my code

Screenshots

Demo of new behavior. I first undo modifications to the open file, then make some modifications. The changes are added to the current undo stack. I cause a lint again and then undo all the changes and close the file. I then make more external changes (invalidating the undo stack) and open the file, where Command-Z no longer has any effect because of the changes that happened while the file wasn't opened.

CodeEdit.-.Reflect.External.Changes.Demo.Long.mp4

@thecoolwinter thecoolwinter mentioned this pull request Jul 3, 2025
6 tasks
thecoolwinter added a commit that referenced this pull request Jul 10, 2025
### Description

Implements editor restoration, helping ease the user experience for longer editing tasks spanning multiple files. Users expect opened tabs to retain the scroll position, cursors, and undo stack. To facilitate this, we receive a stream of state updates from the editor and save them to a SQLite DB. When a file is opened again, the state is restored from that DB.

Ideally this is transparent to the user. However, there is one very slight UX flaw that this doesn't address: highlighting. When a user restores an editor there can be a flash as the highlighter works to do syntax highlighting on the newly opened editor. Some potential future directions:
- The text storage object that outlives editors does retain color information, if we could avoid wiping that color information when an editor is loaded we could avoid that slight delay.
- To do that, we need to store that state with the storage object somehow. Either through a custom text attribute (could be finicky) or maybe by subclassing NSTextStorage and adding a flag.

> [!NOTE]
> This includes a mechanism for sharing undo stacks for editors during a workspace's lifetime. As @austincondiff mentioned on discord, it should add a undo frame when a file is updated externally. This PR notably does not include that change. I'll be adding it in #2075 

### Related Issues

* closes #2057 

### Checklist

- [x] I read and understood the [contributing guide](https://github.com/CodeEditApp/CodeEdit/blob/main/CONTRIBUTING.md) as well as the [code of conduct](https://github.com/CodeEditApp/CodeEdit/blob/main/CODE_OF_CONDUCT.md)
- [x] The issues this PR addresses are related to each other
- [x] My changes generate no new warnings
- [x] My code builds and runs on my machine
- [x] My changes are all related to the related issue above
- [x] I documented my code

### Screenshots


https://github.com/user-attachments/assets/6a9ff5ea-743e-4183-83c9-b774915b0c35
@thecoolwinter thecoolwinter marked this pull request as ready for review July 11, 2025 17:09
Copy link
Collaborator

@austincondiff austincondiff left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wow, this all looks really good. Nice work!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

✨ Reflect External File Updates in Open Files
2 participants