Secure your code as it's written. Use Snyk Code to scan source code in minutes - no build needed - and fix issues immediately.
it('does not fire duplicate change events when multiple changes happen on disk', async done => {
const changeEvents = []
buffer.onWillChange(() => changeEvents.push('will-change'))
buffer.onDidChange((event) => changeEvents.push('did-change'))
// We debounce file system change events to avoid redundant loads. But
// for large files, another file system change event may occur *after* the
// debounce interval but *before* the previous load has completed. In
// that scenario, we still want to avoid emitting redundant change events.
//
// This test simulates the buffer taking a long time to load and diff by
// first reading the file's current contents (copying them to a temp file),
// then waiting for a period of time longer than the debounce interval,
// and then performing the actual load.
const originalLoad = buffer.buffer.load
spyOn(NativeTextBuffer.prototype, 'load').and.callFake(function (pathToLoad, ...args) {
const pathToLoadCopy = temp.openSync('atom').path
fs.writeFileSync(pathToLoadCopy, fs.readFileSync(pathToLoad))
return timeoutPromise(buffer.fileChangeDelay + 100)
.then(() => originalLoad.call(this, pathToLoadCopy, ...args))
})
fs.writeFileSync(filePath, 'a')
fs.writeFileSync(filePath, 'ab')
setTimeout(() => {
fs.writeFileSync(filePath, 'abc')
fs.writeFileSync(filePath, 'abcd')
setTimeout(() => {
fs.writeFileSync(filePath, 'abcde')
fs.writeFileSync(filePath, 'abcdef')
}, buffer.fileChangeDelay + 50)
}, buffer.fileChangeDelay + 50)
// Indent guides on sequences of blank lines are affected by the content of
// adjacent lines.
if (this.showIndentGuides) {
while (startRow > 0) {
if (this.buffer.lineLengthForRow(startRow - 1) > 0) break
startRow--
}
while (newEndRow < this.buffer.getLastRow()) {
if (this.buffer.lineLengthForRow(newEndRow + 1) > 0) break
oldEndRow++
newEndRow++
}
}
const combinedChanges = new Patch()
this.indexedBufferRowCount += newEndRow - oldEndRow
const {start, oldExtent, newExtent} = this.updateSpatialIndex(startRow, oldEndRow + 1, newEndRow + 1, Infinity)
combinedChanges.splice(start, oldExtent, newExtent)
for (let bufferRange of this.textDecorationLayer.getInvalidatedRanges()) {
bufferRange = Range.fromObject(bufferRange)
this.populateSpatialIndexIfNeeded(bufferRange.end.row + 1, Infinity)
const startBufferRow = this.findBoundaryPrecedingBufferRow(bufferRange.start.row)
const endBufferRow = this.findBoundaryFollowingBufferRow(bufferRange.end.row + 1)
const startRow = this.translateBufferPositionWithSpatialIndex(Point(startBufferRow, 0), 'backward').row
const endRow = this.translateBufferPositionWithSpatialIndex(Point(endBufferRow, 0), 'backward').row
const extent = Point(endRow - startRow, 0)
spliceArray(this.cachedScreenLines, startRow, extent.row, new Array(extent.row))
combinedChanges.splice(Point(startRow, 0), extent, extent)
}
const {Emitter, CompositeDisposable} = require('event-kit')
const {File} = require('pathwatcher')
const diff = require('diff')
const _ = require('underscore-plus')
const path = require('path')
const crypto = require('crypto')
const mkdirp = require('mkdirp')
const superstring = require('superstring')
const NativeTextBuffer = superstring.TextBuffer
const Point = require('./point')
const Range = require('./range')
const DefaultHistoryProvider = require('./default-history-provider')
const NullLanguageMode = require('./null-language-mode')
const Marker = require('./marker')
const MarkerLayer = require('./marker-layer')
const DisplayLayer = require('./display-layer')
const {spliceArray, newlineRegex, patchFromChanges, normalizePatchChanges, extentForText, debounce} = require('./helpers')
const {traverse, traversal} = require('./point-helpers')
const Grim = require('grim')
// Extended: A mutable text container with undo/redo support and the ability to
// annotate logical regions in the text.
//
// ## Observing Changes
//
constructor (decorations, buffer, random) {
this.buffer = buffer
this.random = random
this.nextMarkerId = MAX_BUILT_IN_SCOPE_ID + 1
this.markerIndex = new MarkerIndex()
this.classNamesByScopeId = new Map()
this.emitter = new Emitter()
this.invalidatedRanges = []
if (this.buffer) {
this.buffer.onDidChange(() => {
for (const invalidatedRange of this.invalidatedRanges) {
this.emitHighlightingChangeEvent(invalidatedRange)
}
this.invalidatedRanges = []
})
}
for (let value of decorations) {
const className = value[0]
const [rangeStart, rangeEnd] = Array.from(value[1])
exports.patchFromChanges = function (changes) {
const patch = new Patch()
for (let i = 0; i < changes.length; i++) {
const {oldStart, oldEnd, oldText, newStart, newEnd, newText} = changes[i]
const oldExtent = traversal(oldEnd, oldStart)
const newExtent = traversal(newEnd, newStart)
patch.splice(newStart, oldExtent, newExtent, oldText, newText)
}
return patch
}
this.foldsMarkerLayer = params.foldsMarkerLayer || buffer.addMarkerLayer({
maintainHistory: false,
persistent: true,
destroyInvalidatedMarkers: true
})
this.foldIdCounter = params.foldIdCounter || 1
if (params.spatialIndex) {
this.spatialIndex = params.spatialIndex
this.tabCounts = params.tabCounts
this.screenLineLengths = params.screenLineLengths
this.rightmostScreenPosition = params.rightmostScreenPosition
this.indexedBufferRowCount = params.indexedBufferRowCount
} else {
this.spatialIndex = new Patch({mergeAdjacentHunks: false})
this.tabCounts = []
this.screenLineLengths = []
this.rightmostScreenPosition = Point(0, 0)
this.indexedBufferRowCount = 0
}
}
beforeEach(() => {
const save = NativeTextBuffer.prototype.save
spyOn(NativeTextBuffer.prototype, 'save').and.callFake(function (destination, encoding) {
if (destination === filePath) {
return Promise.reject(Object.assign(new Error('Permission denied'), {code: 'EACCES'}))
}
return save.call(this, destination, encoding)
})
})