mirror of
https://github.com/atom/atom.git
synced 2026-01-24 22:38:20 -05:00
Radically simplify the definition of "modified" for buffers
Now, we maintain md5 signatures for the on-disk and in-memory contents of the buffer. Whenever either contents change, we recompute the signature and store it on the buffer. We can tell if the buffer is modified by comparing these signatures. When the disk contents change, we compare the memory and disk signatures *before* recomputing the disk signature to determine whether to update the buffer or mark it as a conflict.
This commit is contained in:
@@ -77,7 +77,7 @@ describe 'Buffer', ->
|
||||
waitsFor "buffer path change", ->
|
||||
eventHandler.callCount > 0
|
||||
|
||||
describe "when the buffer's file is modified (via another process)", ->
|
||||
describe "when the buffer's on-disk contents change (via another process writing to its file)", ->
|
||||
path = null
|
||||
beforeEach ->
|
||||
path = "/tmp/tmp.txt"
|
||||
@@ -98,8 +98,8 @@ describe 'Buffer', ->
|
||||
runs ->
|
||||
expect(changeHandler).not.toHaveBeenCalled()
|
||||
|
||||
describe "when the buffer is unmodified", ->
|
||||
it "triggers 'change' event and buffer remains unmodified", ->
|
||||
describe "when the buffer's memory contents are the same as the *previous* disk contents", ->
|
||||
it "changes the memory contents of the buffer to match the new disk contents and triggers a 'change' event", ->
|
||||
changeHandler = jasmine.createSpy('changeHandler')
|
||||
buffer.on 'change', changeHandler
|
||||
fs.write(path, "second")
|
||||
@@ -116,8 +116,8 @@ describe 'Buffer', ->
|
||||
expect(event.newText).toBe "second"
|
||||
expect(buffer.isModified()).toBeFalsy()
|
||||
|
||||
describe "when the buffer is modified", ->
|
||||
it "sets modifiedOnDisk to be true", ->
|
||||
describe "when the buffer's memory contents differ from the *previous* disk contents", ->
|
||||
it "leaves the buffer in a modified state (does not update its memory contents)", ->
|
||||
fileChangeHandler = jasmine.createSpy('fileChange')
|
||||
buffer.file.on 'contents-change', fileChangeHandler
|
||||
|
||||
@@ -129,7 +129,7 @@ describe 'Buffer', ->
|
||||
fileChangeHandler.callCount > 0
|
||||
|
||||
runs ->
|
||||
expect(buffer.isModifiedOnDisk()).toBeTruthy()
|
||||
expect(buffer.isModified()).toBeTruthy()
|
||||
|
||||
describe "when the buffer's file is deleted (via another process)", ->
|
||||
it "no longer has a path", ->
|
||||
@@ -342,14 +342,13 @@ describe 'Buffer', ->
|
||||
expect(-> buffer.save()).toThrow()
|
||||
|
||||
describe "reload()", ->
|
||||
it "loads text from disk are sets @modified and @modifiedOnDisk to false", ->
|
||||
buffer.modified = true
|
||||
buffer.modifiedOnDisk = true
|
||||
it "reloads current text from disk and clears any conflicts", ->
|
||||
buffer.setText("abc")
|
||||
buffer.conflict = true
|
||||
|
||||
buffer.reload()
|
||||
expect(buffer.modifed).toBeFalsy()
|
||||
expect(buffer.modifiedOnDisk).toBeFalsy()
|
||||
expect(buffer.isModified()).toBeFalsy()
|
||||
expect(buffer.isInConflict()).toBeFalsy()
|
||||
expect(buffer.getText()).toBe(fileContents)
|
||||
|
||||
describe ".saveAs(path)", ->
|
||||
|
||||
@@ -155,6 +155,7 @@ describe "Editor", ->
|
||||
it "closes active edit session and loads next edit session", ->
|
||||
editor.edit(rootView.project.buildEditSessionForPath())
|
||||
editSession = editor.activeEditSession
|
||||
spyOn(editSession.buffer, 'isModified').andReturn false
|
||||
spyOn(editSession, 'destroy').andCallThrough()
|
||||
spyOn(editor, "remove").andCallThrough()
|
||||
editor.trigger "core:close"
|
||||
|
||||
@@ -8,14 +8,15 @@ UndoManager = require 'undo-manager'
|
||||
BufferChangeOperation = require 'buffer-change-operation'
|
||||
Anchor = require 'anchor'
|
||||
AnchorRange = require 'anchor-range'
|
||||
{hex_md5} = require 'md5'
|
||||
|
||||
module.exports =
|
||||
class Buffer
|
||||
@idCounter = 1
|
||||
undoManager: null
|
||||
modified: null
|
||||
contentOnDisk: null
|
||||
modifiedOnDisk: null
|
||||
diskContentSignature: null
|
||||
memoryContentSignature: null
|
||||
conflict: false
|
||||
lines: null
|
||||
file: null
|
||||
anchors: null
|
||||
@@ -31,13 +32,19 @@ class Buffer
|
||||
if path
|
||||
throw "Path '#{path}' does not exist" unless fs.exists(path)
|
||||
@setPath(path)
|
||||
@contentOnDisk = fs.read(@getPath())
|
||||
@setText(@contentOnDisk)
|
||||
@setText(fs.read(@getPath()))
|
||||
@computeDiskContentSignature()
|
||||
else
|
||||
@setText('')
|
||||
|
||||
@computeMemoryContentSignature()
|
||||
@undoManager = new UndoManager(this)
|
||||
@modified = false
|
||||
|
||||
computeDiskContentSignature: ->
|
||||
@diskContentSignature = fs.md5ForPath(@getPath())
|
||||
|
||||
computeMemoryContentSignature: ->
|
||||
@memoryContentSignature = hex_md5(@getText())
|
||||
|
||||
destroy: ->
|
||||
throw new Error("Destroying buffer twice with path '#{@getPath()}'") if @destroyed
|
||||
@@ -57,10 +64,12 @@ class Buffer
|
||||
subscribeToFile: ->
|
||||
@file.on "contents-change", =>
|
||||
if @isModified()
|
||||
@modifiedOnDisk = true
|
||||
@conflict = true
|
||||
@computeDiskContentSignature()
|
||||
@trigger "contents-change-on-disk"
|
||||
else
|
||||
@setText(fs.read(@file.getPath()))
|
||||
@modified = false
|
||||
@computeDiskContentSignature()
|
||||
|
||||
@file.on "remove", =>
|
||||
@file = null
|
||||
@@ -70,10 +79,7 @@ class Buffer
|
||||
@trigger "path-change", this
|
||||
|
||||
reload: ->
|
||||
@contentOnDisk = fs.read(@getPath())
|
||||
@setText(@contentOnDisk)
|
||||
@modified = false
|
||||
@modifiedOnDisk = false
|
||||
@setText(fs.read(@getPath()))
|
||||
|
||||
getBaseName: ->
|
||||
@file?.getBaseName()
|
||||
@@ -87,13 +93,7 @@ class Buffer
|
||||
@file?.off()
|
||||
@file = new File(path)
|
||||
@subscribeToFile()
|
||||
@file.on "contents-change", =>
|
||||
if @isModified()
|
||||
@modifiedOnDisk = true
|
||||
@trigger "contents-change-on-disk"
|
||||
else
|
||||
@setText(fs.read(@file.getPath()))
|
||||
@modified = false
|
||||
|
||||
@trigger "path-change", this
|
||||
|
||||
getExtension: ->
|
||||
@@ -209,7 +209,8 @@ class Buffer
|
||||
|
||||
replaceLines: (startRow, endRow, newLines) ->
|
||||
@lines[startRow..endRow] = newLines
|
||||
@modified = true
|
||||
@computeMemoryContentSignature()
|
||||
@conflict = false unless @isModified()
|
||||
|
||||
pushOperation: (operation, editSession) ->
|
||||
if @undoManager
|
||||
@@ -235,23 +236,14 @@ class Buffer
|
||||
@trigger 'before-save'
|
||||
fs.write path, @getText()
|
||||
@file?.updateMd5()
|
||||
@modified = false
|
||||
@modifiedOnDisk = false
|
||||
@setPath(path)
|
||||
@contentOnDisk = @getText()
|
||||
@computeDiskContentSignature()
|
||||
@trigger 'after-save'
|
||||
|
||||
isInConflict: ->
|
||||
@isModified() and @isModifiedOnDisk()
|
||||
|
||||
isModifiedOnDisk: ->
|
||||
@modifiedOnDisk
|
||||
|
||||
isModified: ->
|
||||
@modified
|
||||
@memoryContentSignature != @diskContentSignature
|
||||
|
||||
contentDifferentOnDisk: ->
|
||||
@contentOnDisk != @getText()
|
||||
isInConflict: -> @conflict
|
||||
|
||||
getAnchors: -> new Array(@anchors...)
|
||||
|
||||
|
||||
@@ -41,7 +41,7 @@ class StatusBar extends View
|
||||
@updateBufferModifiedText()
|
||||
|
||||
updateBufferModifiedText: ->
|
||||
if @buffer.isModified() and @buffer.contentDifferentOnDisk()
|
||||
if @buffer.isModified()
|
||||
@bufferModified.text('*')
|
||||
else
|
||||
@bufferModified.text('')
|
||||
|
||||
Reference in New Issue
Block a user