UNPKG

text-buffer

Version:

A container for large mutable strings with annotated regions

503 lines (440 loc) 16.5 kB
(function() { var Emitter, Marker, MarkerIndex, MarkerLayer, Point, Range, SerializationVersion, clone, filterSet, intersectSet; clone = require("underscore-plus").clone; Emitter = require('event-kit').Emitter; Point = require("./point"); Range = require("./range"); Marker = require("./marker"); MarkerIndex = require("superstring").MarkerIndex; intersectSet = require("./set-helpers").intersectSet; SerializationVersion = 2; module.exports = MarkerLayer = (function() { MarkerLayer.deserialize = function(delegate, state) { var store; store = new MarkerLayer(delegate, 0); store.deserialize(state); return store; }; MarkerLayer.deserializeSnapshot = function(snapshot) { var layerId, markerId, markerSnapshot, markerSnapshots, result; result = {}; for (layerId in snapshot) { markerSnapshots = snapshot[layerId]; result[layerId] = {}; for (markerId in markerSnapshots) { markerSnapshot = markerSnapshots[markerId]; result[layerId][markerId] = clone(markerSnapshot); result[layerId][markerId].range = Range.fromObject(markerSnapshot.range); } } return result; }; /* Section: Lifecycle */ function MarkerLayer(delegate1, id3, options) { var ref, ref1, ref2; this.delegate = delegate1; this.id = id3; this.maintainHistory = (ref = options != null ? options.maintainHistory : void 0) != null ? ref : false; this.destroyInvalidatedMarkers = (ref1 = options != null ? options.destroyInvalidatedMarkers : void 0) != null ? ref1 : false; this.role = options != null ? options.role : void 0; if (this.role === "selections") { this.delegate.registerSelectionsMarkerLayer(this); } this.persistent = (ref2 = options != null ? options.persistent : void 0) != null ? ref2 : false; this.emitter = new Emitter; this.index = new MarkerIndex; this.markersById = {}; this.markersWithChangeListeners = new Set; this.markersWithDestroyListeners = new Set; this.displayMarkerLayers = new Set; this.destroyed = false; this.emitCreateMarkerEvents = false; } MarkerLayer.prototype.copy = function() { var copy, marker, markerId, ref, snapshot; copy = this.delegate.addMarkerLayer({ maintainHistory: this.maintainHistory, role: this.role }); ref = this.markersById; for (markerId in ref) { marker = ref[markerId]; snapshot = marker.getSnapshot(null); copy.createMarker(marker.getRange(), marker.getSnapshot()); } return copy; }; MarkerLayer.prototype.destroy = function() { if (this.destroyed) { return; } this.clear(); this.delegate.markerLayerDestroyed(this); this.displayMarkerLayers.forEach(function(displayMarkerLayer) { return displayMarkerLayer.destroy(); }); this.displayMarkerLayers.clear(); this.destroyed = true; this.emitter.emit('did-destroy'); return this.emitter.clear(); }; MarkerLayer.prototype.clear = function() { this.markersWithDestroyListeners.forEach(function(marker) { return marker.destroy(); }); this.markersWithDestroyListeners.clear(); this.markersById = {}; this.index = new MarkerIndex; this.displayMarkerLayers.forEach(function(layer) { return layer.didClearBufferMarkerLayer(); }); return this.delegate.markersUpdated(this); }; MarkerLayer.prototype.isDestroyed = function() { return this.destroyed; }; MarkerLayer.prototype.isAlive = function() { return !this.destroyed; }; /* Section: Querying */ MarkerLayer.prototype.getMarker = function(id) { return this.markersById[id]; }; MarkerLayer.prototype.getMarkers = function() { var id, marker, ref, results; ref = this.markersById; results = []; for (id in ref) { marker = ref[id]; results.push(marker); } return results; }; MarkerLayer.prototype.getMarkerCount = function() { return Object.keys(this.markersById).length; }; MarkerLayer.prototype.findMarkers = function(params) { var end, i, key, len, markerIds, position, ref, ref1, ref2, ref3, ref4, ref5, result, start, value; markerIds = null; ref = Object.keys(params); for (i = 0, len = ref.length; i < len; i++) { key = ref[i]; value = params[key]; switch (key) { case 'startPosition': markerIds = filterSet(markerIds, this.index.findStartingAt(Point.fromObject(value))); break; case 'endPosition': markerIds = filterSet(markerIds, this.index.findEndingAt(Point.fromObject(value))); break; case 'startsInRange': ref1 = Range.fromObject(value), start = ref1.start, end = ref1.end; markerIds = filterSet(markerIds, this.index.findStartingIn(start, end)); break; case 'endsInRange': ref2 = Range.fromObject(value), start = ref2.start, end = ref2.end; markerIds = filterSet(markerIds, this.index.findEndingIn(start, end)); break; case 'containsPoint': case 'containsPosition': position = Point.fromObject(value); markerIds = filterSet(markerIds, this.index.findContaining(position, position)); break; case 'containsRange': ref3 = Range.fromObject(value), start = ref3.start, end = ref3.end; markerIds = filterSet(markerIds, this.index.findContaining(start, end)); break; case 'intersectsRange': ref4 = Range.fromObject(value), start = ref4.start, end = ref4.end; markerIds = filterSet(markerIds, this.index.findIntersecting(start, end)); break; case 'startRow': markerIds = filterSet(markerIds, this.index.findStartingIn(Point(value, 0), Point(value, 2e308))); break; case 'endRow': markerIds = filterSet(markerIds, this.index.findEndingIn(Point(value, 0), Point(value, 2e308))); break; case 'intersectsRow': markerIds = filterSet(markerIds, this.index.findIntersecting(Point(value, 0), Point(value, 2e308))); break; case 'intersectsRowRange': markerIds = filterSet(markerIds, this.index.findIntersecting(Point(value[0], 0), Point(value[1], 2e308))); break; case 'containedInRange': ref5 = Range.fromObject(value), start = ref5.start, end = ref5.end; markerIds = filterSet(markerIds, this.index.findContainedIn(start, end)); break; default: continue; } delete params[key]; } if (markerIds == null) { markerIds = new Set(Object.keys(this.markersById)); } result = []; markerIds.forEach((function(_this) { return function(markerId) { var marker; marker = _this.markersById[markerId]; if (!marker.matchesParams(params)) { return; } return result.push(marker); }; })(this)); return result.sort(function(a, b) { return a.compare(b); }); }; MarkerLayer.prototype.getRole = function() { return this.role; }; /* Section: Marker creation */ MarkerLayer.prototype.markRange = function(range, options) { if (options == null) { options = {}; } return this.createMarker(this.delegate.clipRange(range), Marker.extractParams(options)); }; MarkerLayer.prototype.markPosition = function(position, options) { if (options == null) { options = {}; } position = this.delegate.clipPosition(position); options = Marker.extractParams(options); options.tailed = false; return this.createMarker(this.delegate.clipRange(new Range(position, position)), options); }; /* Section: Event subscription */ MarkerLayer.prototype.onDidUpdate = function(callback) { return this.emitter.on('did-update', callback); }; MarkerLayer.prototype.onDidCreateMarker = function(callback) { this.emitCreateMarkerEvents = true; return this.emitter.on('did-create-marker', callback); }; MarkerLayer.prototype.onDidDestroy = function(callback) { return this.emitter.on('did-destroy', callback); }; /* Section: Private - TextBuffer interface */ MarkerLayer.prototype.splice = function(start, oldExtent, newExtent) { var invalidated; invalidated = this.index.splice(start, oldExtent, newExtent); return invalidated.touch.forEach((function(_this) { return function(id) { var marker, ref; marker = _this.markersById[id]; if ((ref = invalidated[marker.getInvalidationStrategy()]) != null ? ref.has(id) : void 0) { if (_this.destroyInvalidatedMarkers) { return marker.destroy(); } else { return marker.valid = false; } } }; })(this)); }; MarkerLayer.prototype.restoreFromSnapshot = function(snapshots, alwaysCreate) { var existingMarkerIds, i, id, j, len, len1, marker, newMarker, range, results, snapshot, snapshotIds; if (snapshots == null) { return; } snapshotIds = Object.keys(snapshots); existingMarkerIds = Object.keys(this.markersById); for (i = 0, len = snapshotIds.length; i < len; i++) { id = snapshotIds[i]; snapshot = snapshots[id]; if (alwaysCreate) { this.createMarker(snapshot.range, snapshot, true); continue; } if (marker = this.markersById[id]) { marker.update(marker.getRange(), snapshot, true, true); } else { marker = snapshot.marker; if (marker) { this.markersById[marker.id] = marker; range = snapshot.range; this.index.insert(marker.id, range.start, range.end); marker.update(marker.getRange(), snapshot, true, true); if (this.emitCreateMarkerEvents) { this.emitter.emit('did-create-marker', marker); } } else { newMarker = this.createMarker(snapshot.range, snapshot, true); } } } results = []; for (j = 0, len1 = existingMarkerIds.length; j < len1; j++) { id = existingMarkerIds[j]; if ((marker = this.markersById[id]) && (snapshots[id] == null)) { results.push(marker.destroy(true)); } else { results.push(void 0); } } return results; }; MarkerLayer.prototype.createSnapshot = function() { var i, id, len, marker, ranges, ref, result; result = {}; ranges = this.index.dump(); ref = Object.keys(this.markersById); for (i = 0, len = ref.length; i < len; i++) { id = ref[i]; marker = this.markersById[id]; result[id] = marker.getSnapshot(Range.fromObject(ranges[id])); } return result; }; MarkerLayer.prototype.emitChangeEvents = function(snapshot) { return this.markersWithChangeListeners.forEach(function(marker) { var ref; if (!marker.isDestroyed()) { return marker.emitChangeEvent(snapshot != null ? (ref = snapshot[marker.id]) != null ? ref.range : void 0 : void 0, true, false); } }); }; MarkerLayer.prototype.serialize = function() { var i, id, len, marker, markersById, ranges, ref, snapshot; ranges = this.index.dump(); markersById = {}; ref = Object.keys(this.markersById); for (i = 0, len = ref.length; i < len; i++) { id = ref[i]; marker = this.markersById[id]; snapshot = marker.getSnapshot(Range.fromObject(ranges[id]), false); markersById[id] = snapshot; } return { id: this.id, maintainHistory: this.maintainHistory, role: this.role, persistent: this.persistent, markersById: markersById, version: SerializationVersion }; }; MarkerLayer.prototype.deserialize = function(state) { var id, markerState, range, ref; if (state.version !== SerializationVersion) { return; } this.id = state.id; this.maintainHistory = state.maintainHistory; this.role = state.role; if (this.role === "selections") { this.delegate.registerSelectionsMarkerLayer(this); } this.persistent = state.persistent; ref = state.markersById; for (id in ref) { markerState = ref[id]; range = Range.fromObject(markerState.range); delete markerState.range; this.addMarker(id, range, markerState); } }; /* Section: Private - Marker interface */ MarkerLayer.prototype.markerUpdated = function() { return this.delegate.markersUpdated(this); }; MarkerLayer.prototype.destroyMarker = function(marker, suppressMarkerLayerUpdateEvents) { if (suppressMarkerLayerUpdateEvents == null) { suppressMarkerLayerUpdateEvents = false; } if (this.markersById.hasOwnProperty(marker.id)) { delete this.markersById[marker.id]; this.index.remove(marker.id); this.markersWithChangeListeners["delete"](marker); this.markersWithDestroyListeners["delete"](marker); this.displayMarkerLayers.forEach(function(displayMarkerLayer) { return displayMarkerLayer.destroyMarker(marker.id); }); if (!suppressMarkerLayerUpdateEvents) { return this.delegate.markersUpdated(this); } } }; MarkerLayer.prototype.hasMarker = function(id) { return !this.destroyed && this.index.has(id); }; MarkerLayer.prototype.getMarkerRange = function(id) { return Range.fromObject(this.index.getRange(id)); }; MarkerLayer.prototype.getMarkerStartPosition = function(id) { return Point.fromObject(this.index.getStart(id)); }; MarkerLayer.prototype.getMarkerEndPosition = function(id) { return Point.fromObject(this.index.getEnd(id)); }; MarkerLayer.prototype.compareMarkers = function(id1, id2) { return this.index.compare(id1, id2); }; MarkerLayer.prototype.setMarkerRange = function(id, range) { var end, ref, start; ref = Range.fromObject(range), start = ref.start, end = ref.end; start = this.delegate.clipPosition(start); end = this.delegate.clipPosition(end); this.index.remove(id); return this.index.insert(id, start, end); }; MarkerLayer.prototype.setMarkerIsExclusive = function(id, exclusive) { return this.index.setExclusive(id, exclusive); }; MarkerLayer.prototype.createMarker = function(range, params, suppressMarkerLayerUpdateEvents) { var id, marker, ref; if (suppressMarkerLayerUpdateEvents == null) { suppressMarkerLayerUpdateEvents = false; } id = this.delegate.getNextMarkerId(); marker = this.addMarker(id, range, params); this.delegate.markerCreated(this, marker); if (!suppressMarkerLayerUpdateEvents) { this.delegate.markersUpdated(this); } marker.trackDestruction = (ref = this.trackDestructionInOnDidCreateMarkerCallbacks) != null ? ref : false; if (this.emitCreateMarkerEvents) { this.emitter.emit('did-create-marker', marker); } marker.trackDestruction = false; return marker; }; /* Section: Internal */ MarkerLayer.prototype.addMarker = function(id, range, params) { range = Range.fromObject(range); Point.assertValid(range.start); Point.assertValid(range.end); this.index.insert(id, range.start, range.end); return this.markersById[id] = new Marker(id, this, range, params); }; MarkerLayer.prototype.emitUpdateEvent = function() { return this.emitter.emit('did-update'); }; return MarkerLayer; })(); filterSet = function(set1, set2) { if (set1) { intersectSet(set1, set2); return set1; } else { return set2; } }; }).call(this);