Skip to content

Commit 05aa611

Browse files
Proof of concept for better handling of deleted state
1 parent 863a74c commit 05aa611

1 file changed

Lines changed: 33 additions & 2 deletions

File tree

src/text-buffer.js

Lines changed: 33 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,15 @@ class TextBuffer {
102102
this.cachedHasAstral = null
103103
this._emittedWillChangeEvent = false
104104

105+
// Whether a buffer has ever had a backing file, whether or not it exists
106+
// now.
107+
this.didHaveFileOnDisk = false
108+
109+
// When a buffer's backing file is deleted while the file is unmodified,
110+
// this trait flips to `true`… and then flips back to `false` if any
111+
// further edits are made.
112+
this.retainsUnmodifiedTraitAfterDeletion = false
113+
105114
this.setEncoding(params.encoding)
106115
this.setPreferredLineEnding(params.preferredLineEnding)
107116

@@ -524,15 +533,32 @@ class TextBuffer {
524533
//
525534
// Returns a {Boolean}.
526535
isModified () {
536+
if (this.isDeleted()) {
537+
// We typically consider a deleted file to be modified… unless it was
538+
// unmodified at the time of deletion and has not been modified since.
539+
return !this.retainsUnmodifiedTraitAfterDeletion
540+
}
527541
if (this.file) {
528542
return !this.file.existsSync() || this.buffer.isModified()
529543
} else {
530544
return this.buffer.getLength() > 0
531545
}
532546
}
533547

534-
// Public: Determine if the in-memory contents of the buffer conflict with the
535-
// on-disk contents of its associated file.
548+
// Public: Determine if the buffer is in a deleted state — meaning that it
549+
// was previously backed by a file on disk, but is no longer.
550+
isDeleted () {
551+
let hasNoFile = !this.file || !this.file.existsSync()
552+
return hasNoFile && this.didHaveFileOnDisk
553+
}
554+
555+
// Public: Determine if the in-memory contents of the buffer conflict with
556+
// the on-disk contents of its associated file.
557+
//
558+
// This happens if the contents of a buffer’s backing file change while the
559+
// editor has uncommitted changes. Those uncommitted changes build upon a
560+
// state that is now stale; if those changes were committed to disk, it could
561+
// clobber the changes made by the external program.
536562
//
537563
// Returns a {Boolean}.
538564
isInConflict () {
@@ -845,6 +871,7 @@ class TextBuffer {
845871
if (undo != null) {
846872
Grim.deprecate('The `undo` option is deprecated. Call groupLastChanges() on the TextBuffer afterward instead.')
847873
}
874+
this.retainsUnmodifiedTraitAfterDeletion = false
848875

849876
if (this.transactCallDepth === 0) {
850877
const newRange = this.transact(() => this.setTextInRange(range, newText, {normalizeLineEndings}))
@@ -1929,6 +1956,7 @@ class TextBuffer {
19291956

19301957
try {
19311958
await this.buffer.save(destination, this.getEncoding())
1959+
this.didHaveFileOnDisk = true
19321960
} catch (error) {
19331961
if (error.code !== 'EACCES' || destination !== filePath) throw error
19341962

@@ -2101,6 +2129,8 @@ class TextBuffer {
21012129
Grim.deprecate('The .load instance method is deprecated. Create a loaded buffer using TextBuffer.load(filePath) instead.')
21022130
}
21032131

2132+
this.didHaveFileOnDisk = true
2133+
21042134
const source = this.file instanceof File
21052135
? this.file.getPath()
21062136
: this.file.createReadStream()
@@ -2295,6 +2325,7 @@ class TextBuffer {
22952325
if (this.file.onDidDelete) {
22962326
this.fileSubscriptions.add(this.file.onDidDelete(() => {
22972327
const modified = this.buffer.isModified()
2328+
this.retainsUnmodifiedTraitAfterDeletion = !modified
22982329
this.emitter.emit('did-delete')
22992330
if (!modified && this.shouldDestroyOnFileDelete()) {
23002331
return this.destroy()

0 commit comments

Comments
 (0)