-
-
Notifications
You must be signed in to change notification settings - Fork 1
Promote “deleted” into its own state #12
Description
Have you checked for existing feature requests?
- Completed
Summary
The buffer can be in any of several states that we care about:
- modified means that the current contents of the buffer differ from what is on disk. This state will be removed the next time the contents of the buffer are written to disk.
- conflicted means that the contents on disk changed after the buffer entered the “modified” state, and still do not match what is currently on disk. Like “modified” above, this state resolves itself once the contents of the buffer are written to disk.
- deleted means that the buffer used to be backed by a file, but the file has since been removed. This state resolves itself once the contents of the buffer are written to disk (whether at the previous file name or some other file name).
These do not map neatly to an enum. “Conflicted” is a subset of “modified,” but “deleted” should not necessarily be. “Conflicted” and “deleted” happen to be mutually exclusive. Each is a trait that can exist somewhat independently of the others.
Right now, after a buffer's file is deleted, it will enter the “modified” state and stay that way until it's saved to disk again. That's because any buffer without a backing file is considered to be modified, and it means “deleted” is a subset of “modified” the same way “conflicted” is. But that's not necessarily the behavior we want. For one thing, it means that you get prompted to save the file when you try to close it.
The behavior we want
Let's work backwards from how VS Code handles deleted files, then decide the best way to get there.
- Suppose I've got
foo.txtopen in an editor. - I save the file to disk and keep it open in VS Code.
- A few seconds later, some other program deletes
foo.txt. - VS Code keeps
foo.txtin view, but marks it as having entered the “deleted” state. The tab label turns red and introduces astrikethrougheffect. - I can instantly close the tab without being prompted to save, since the buffer was not considered to be modified at the moment the file was deleted.
This is what we want to happen in Pulsar, more or less. But consider this similar scenario:
- Suppose I've got
foo.txtopen in an editor. - I make some modifications but do not save them.
- A few seconds later, some other program deletes
foo.txt. - VS Code keeps
foo.txtin view, but marks it as having entered the “deleted” state. The tab label turns red and introduces astrikethrougheffect. - When I try to close the tab, I am prompted to save my changes, since the buffer was in the modified state at the moment the file was deleted.
Option 1
This option changes the definition of “modified” to conform to the behavior we want:
- All buffers that never had backing files are considered to be modified until they are saved to disk.
- All buffers that did have backing files, but do no longer, initially persist their “modified” status even after the file is deleted…
- …until and unless the buffer changes again, at which point the buffer will enter the “modified” state permanently until the file is saved to disk once more.
Pros: this carves out the ability to close the tab without being prompted to do so, and does not require that we modify any Pulsar code to do it.
Cons: there might be unforeseen consequences to changing the definition of “modified” in this way.
Option 2
This option keeps the existing definition of “modified,” but changes the criteria we use to decide whether to prompt the user to save.
- All buffers that do not currently have backing files are considered to be modified until they are saved to disk.
- Buffers that did have backing files, but do no longer, enter a “deleted” state; they also expose a similar concept to “modified” but call it something like… uh… let's say “unrealized.” If a file is “unrealized,” it means that the file's buffer was deleted while the buffer was in a modified state.
- If the buffer changes again while in the “deleted” state, it also enters the “unrealized” state — in order to signal that the current state of the buffer involves changes that were not able to be written to disk before the backing file was deleted.
TextEditormakes itsshouldPromptToSavelogic more nuanced; it checksisModified()for most buffers, but instead checksisUnrealized()if the buffer is in the “deleted” state. It uses that as the source of truth to decide whether it should prompt the user to save.
Which is better?
Option 1 is simpler and is what I'll start with. It also produces the side effects we want — for instance, the difference between an X and a circle in the tab bar.
If it causes too many regressions, I'll reluctantly pursue option 2.
What benefits does this feature provide?
The ability to distinguish between “deleted after modification” and “deleted while unmodified” and to have the UI behave differently in these two scenarios.
Any alternatives?
If we want this feature and want it to behave similarly to how it behaves in VSCode, then the main options are the two that I list above. I am open to other ideas if folks have them.
Other examples:
No response