simple-text-buffer
Version:
A version of Atom's text-buffer with marker layers and file support removed
968 lines (833 loc) • 31.6 kB
JavaScript
(function() {
var CompositeDisposable, Disposable, Emitter, History, MatchIterator, Patch, Point, Range, SearchCallbackArgument, SpanSkipList, TextBuffer, TransactionAbortedError, crypto, diff, newlineRegex, normalizePatchChanges, ref, ref1, spliceArray,
bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; },
extend = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; },
hasProp = {}.hasOwnProperty;
ref = require('event-kit'), Emitter = ref.Emitter, CompositeDisposable = ref.CompositeDisposable, Disposable = ref.Disposable;
SpanSkipList = require('span-skip-list');
diff = require('diff');
crypto = require('crypto');
Patch = require('atom-patch');
Point = require('./point');
Range = require('./range');
History = require('./history');
MatchIterator = require('./match-iterator');
ref1 = require('./helpers'), spliceArray = ref1.spliceArray, newlineRegex = ref1.newlineRegex, normalizePatchChanges = ref1.normalizePatchChanges;
SearchCallbackArgument = (function() {
Object.defineProperty(SearchCallbackArgument.prototype, "range", {
get: function() {
var endPosition, matchEndIndex, matchStartIndex, startPosition;
if (this.computedRange != null) {
return this.computedRange;
}
matchStartIndex = this.match.index;
matchEndIndex = matchStartIndex + this.matchText.length;
startPosition = this.buffer.positionForCharacterIndex(matchStartIndex + this.lengthDelta);
endPosition = this.buffer.positionForCharacterIndex(matchEndIndex + this.lengthDelta);
return this.computedRange = new Range(startPosition, endPosition);
},
set: function(range) {
return this.computedRange = range;
}
});
function SearchCallbackArgument(buffer1, match1, lengthDelta1) {
this.buffer = buffer1;
this.match = match1;
this.lengthDelta = lengthDelta1;
this.stop = bind(this.stop, this);
this.replace = bind(this.replace, this);
this.stopped = false;
this.replacementText = null;
this.matchText = this.match[0];
}
SearchCallbackArgument.prototype.getReplacementDelta = function() {
if (this.replacementText == null) {
return 0;
}
return this.replacementText.length - this.matchText.length;
};
SearchCallbackArgument.prototype.replace = function(text) {
this.replacementText = text;
return this.buffer.setTextInRange(this.range, this.replacementText);
};
SearchCallbackArgument.prototype.stop = function() {
return this.stopped = true;
};
SearchCallbackArgument.prototype.keepLooping = function() {
return this.stopped === false;
};
return SearchCallbackArgument;
})();
TransactionAbortedError = (function(superClass) {
extend(TransactionAbortedError, superClass);
function TransactionAbortedError() {
TransactionAbortedError.__super__.constructor.apply(this, arguments);
}
return TransactionAbortedError;
})(Error);
module.exports = TextBuffer = (function() {
TextBuffer.version = 5;
TextBuffer.Point = Point;
TextBuffer.Range = Range;
TextBuffer.Patch = require('./patch');
TextBuffer.newlineRegex = newlineRegex;
TextBuffer.prototype.cachedText = null;
TextBuffer.prototype.encoding = null;
TextBuffer.prototype.stoppedChangingDelay = 300;
TextBuffer.prototype.stoppedChangingTimeout = null;
TextBuffer.prototype.refcount = 0;
TextBuffer.prototype.backwardsScanChunkSize = 8000;
TextBuffer.prototype.defaultMaxUndoEntries = 10000;
TextBuffer.prototype.changeCount = 0;
/*
Section: Construction
*/
function TextBuffer(params) {
var maxUndoEntries, ref2, ref3, ref4, ref5, text;
this.eventIdCounter = 0;
if (typeof params === 'string') {
text = params;
}
this.emitter = new Emitter;
this.patchesSinceLastStoppedChangingEvent = [];
this.id = (ref2 = params != null ? params.id : void 0) != null ? ref2 : crypto.randomBytes(16).toString('hex');
this.lines = [''];
this.lineEndings = [''];
this.offsetIndex = new SpanSkipList('rows', 'characters');
this.setTextInRange([[0, 0], [0, 0]], (ref3 = text != null ? text : params != null ? params.text : void 0) != null ? ref3 : '', {
normalizeLineEndings: false
});
maxUndoEntries = (ref4 = params != null ? params.maxUndoEntries : void 0) != null ? ref4 : this.defaultMaxUndoEntries;
this.history = (ref5 = params != null ? params.history : void 0) != null ? ref5 : new History(this, maxUndoEntries);
this.setEncoding(params != null ? params.encoding : void 0);
this.setPreferredLineEnding(params != null ? params.preferredLineEnding : void 0);
this.transactCallDepth = 0;
}
TextBuffer.deserialize = function(params) {
var buffer;
if (params.version !== TextBuffer.prototype.version) {
return;
}
buffer = Object.create(TextBuffer.prototype);
params.history = History.deserialize(params.history, buffer);
TextBuffer.call(buffer, params);
return buffer;
};
TextBuffer.prototype.getId = function() {
return this.id;
};
TextBuffer.prototype.serialize = function(options) {
if (options == null) {
options = {};
}
return {
id: this.getId(),
text: this.getText(),
history: this.history.serialize(options),
encoding: this.getEncoding(),
preferredLineEnding: this.preferredLineEnding
};
};
/*
Section: Event Subscription
*/
TextBuffer.prototype.onWillChange = function(callback) {
return this.emitter.on('will-change', callback);
};
TextBuffer.prototype.onDidChange = function(callback) {
return this.emitter.on('did-change', callback);
};
TextBuffer.prototype.onDidChangeText = function(callback) {
return this.emitter.on('did-change-text', callback);
};
TextBuffer.prototype.preemptDidChange = function(callback) {
return this.emitter.preempt('did-change', callback);
};
TextBuffer.prototype.onDidStopChanging = function(callback) {
return this.emitter.on('did-stop-changing', callback);
};
TextBuffer.prototype.onDidChangeEncoding = function(callback) {
return this.emitter.on('did-change-encoding', callback);
};
TextBuffer.prototype.onDidDestroy = function(callback) {
return this.emitter.on('did-destroy', callback);
};
TextBuffer.prototype.getStoppedChangingDelay = function() {
return this.stoppedChangingDelay;
};
/*
Section: File Details
*/
TextBuffer.prototype.setEncoding = function(encoding) {
if (encoding == null) {
encoding = 'utf8';
}
if (encoding === this.getEncoding()) {
return;
}
this.encoding = encoding;
this.emitter.emit('did-change-encoding', encoding);
};
TextBuffer.prototype.getEncoding = function() {
return this.encoding;
};
TextBuffer.prototype.setPreferredLineEnding = function(preferredLineEnding) {
if (preferredLineEnding == null) {
preferredLineEnding = null;
}
return this.preferredLineEnding = preferredLineEnding;
};
TextBuffer.prototype.getPreferredLineEnding = function() {
return this.preferredLineEnding;
};
/*
Section: Reading Text
*/
TextBuffer.prototype.isEmpty = function() {
return this.getLastRow() === 0 && this.lineLengthForRow(0) === 0;
};
TextBuffer.prototype.getText = function() {
var i, ref2, row, text;
if (this.cachedText != null) {
return this.cachedText;
} else {
text = '';
for (row = i = 0, ref2 = this.getLastRow(); 0 <= ref2 ? i <= ref2 : i >= ref2; row = 0 <= ref2 ? ++i : --i) {
text += this.lineForRow(row) + this.lineEndingForRow(row);
}
return this.cachedText = text;
}
};
TextBuffer.prototype.getTextInRange = function(range) {
var endRow, i, line, ref2, ref3, row, startRow, text;
range = this.clipRange(Range.fromObject(range));
startRow = range.start.row;
endRow = range.end.row;
if (startRow === endRow) {
return this.lineForRow(startRow).slice(range.start.column, range.end.column);
} else {
text = '';
for (row = i = ref2 = startRow, ref3 = endRow; ref2 <= ref3 ? i <= ref3 : i >= ref3; row = ref2 <= ref3 ? ++i : --i) {
line = this.lineForRow(row);
if (row === startRow) {
text += line.slice(range.start.column);
} else if (row === endRow) {
text += line.slice(0, range.end.column);
continue;
} else {
text += line;
}
text += this.lineEndingForRow(row);
}
return text;
}
};
TextBuffer.prototype.getLines = function() {
return this.lines.slice();
};
TextBuffer.prototype.getLastLine = function() {
return this.lineForRow(this.getLastRow());
};
TextBuffer.prototype.lineForRow = function(row) {
return this.lines[row];
};
TextBuffer.prototype.lineEndingForRow = function(row) {
return this.lineEndings[row];
};
TextBuffer.prototype.lineLengthForRow = function(row) {
return this.lines[row].length;
};
TextBuffer.prototype.isRowBlank = function(row) {
return !/\S/.test(this.lineForRow(row));
};
TextBuffer.prototype.previousNonBlankRow = function(startRow) {
var i, ref2, row;
if (startRow === 0) {
return null;
}
startRow = Math.min(startRow, this.getLastRow());
for (row = i = ref2 = startRow - 1; ref2 <= 0 ? i <= 0 : i >= 0; row = ref2 <= 0 ? ++i : --i) {
if (!this.isRowBlank(row)) {
return row;
}
}
return null;
};
TextBuffer.prototype.nextNonBlankRow = function(startRow) {
var i, lastRow, ref2, ref3, row;
lastRow = this.getLastRow();
if (startRow < lastRow) {
for (row = i = ref2 = startRow + 1, ref3 = lastRow; ref2 <= ref3 ? i <= ref3 : i >= ref3; row = ref2 <= ref3 ? ++i : --i) {
if (!this.isRowBlank(row)) {
return row;
}
}
}
return null;
};
/*
Section: Mutating Text
*/
TextBuffer.prototype.setText = function(text) {
return this.setTextInRange(this.getRange(), text, {
normalizeLineEndings: false
});
};
TextBuffer.prototype.setTextViaDiff = function(text) {
var computeBufferColumn, currentText, endsWithNewline;
currentText = this.getText();
if (currentText === text) {
return;
}
endsWithNewline = function(str) {
return /[\r\n]+$/g.test(str);
};
computeBufferColumn = function(str) {
var newlineIndex;
newlineIndex = Math.max(str.lastIndexOf('\n'), str.lastIndexOf('\r'));
if (endsWithNewline(str)) {
return 0;
} else if (newlineIndex === -1) {
return str.length;
} else {
return str.length - newlineIndex - 1;
}
};
return this.transact((function(_this) {
return function() {
var change, changeOptions, column, currentPosition, endColumn, endRow, i, len, lineCount, lineDiff, ref2, ref3, row;
row = 0;
column = 0;
currentPosition = [0, 0];
lineDiff = diff.diffLines(currentText, text);
changeOptions = {
normalizeLineEndings: false
};
for (i = 0, len = lineDiff.length; i < len; i++) {
change = lineDiff[i];
lineCount = (ref2 = (ref3 = change.value.match(newlineRegex)) != null ? ref3.length : void 0) != null ? ref2 : 0;
currentPosition[0] = row;
currentPosition[1] = column;
if (change.added) {
row += lineCount;
column = computeBufferColumn(change.value);
_this.setTextInRange([currentPosition, currentPosition], change.value, changeOptions);
} else if (change.removed) {
endRow = row + lineCount;
endColumn = column + computeBufferColumn(change.value);
_this.setTextInRange([currentPosition, [endRow, endColumn]], '', changeOptions);
} else {
row += lineCount;
column = computeBufferColumn(change.value);
}
}
};
})(this));
};
TextBuffer.prototype.setTextInRange = function(range, newText, options) {
var change, newRange, normalizeLineEndings, oldRange, oldText, ref2, undo;
if (this.transactCallDepth === 0) {
return this.transact((function(_this) {
return function() {
return _this.setTextInRange(range, newText, options);
};
})(this));
}
if (options != null) {
normalizeLineEndings = options.normalizeLineEndings, undo = options.undo;
}
if (normalizeLineEndings == null) {
normalizeLineEndings = true;
}
oldRange = this.clipRange(range);
oldText = this.getTextInRange(oldRange);
newRange = Range.fromText(oldRange.start, newText);
change = {
newStart: oldRange.start,
oldExtent: oldRange.getExtent(),
newExtent: newRange.getExtent(),
oldText: oldText,
newText: newText,
normalizeLineEndings: normalizeLineEndings
};
if (undo !== 'skip') {
if ((ref2 = this.history) != null) {
ref2.pushChange(change);
}
}
this.applyChange(change);
return newRange;
};
TextBuffer.prototype.insert = function(position, text, options) {
return this.setTextInRange(new Range(position, position), text, options);
};
TextBuffer.prototype.append = function(text, options) {
return this.insert(this.getEndPosition(), text, options);
};
TextBuffer.prototype.applyChange = function(change) {
var changeEvent, endRow, ending, lastIndex, lastLine, lastLineEnding, line, lineEndings, lineStartIndex, lines, newExtent, newRange, newStart, newText, normalizeLineEndings, normalizedEnding, normalizedNewText, offsets, oldExtent, oldRange, oldText, prefix, ref2, result, rowCount, start, startRow, suffix;
newStart = change.newStart, oldExtent = change.oldExtent, newExtent = change.newExtent, oldText = change.oldText, newText = change.newText, normalizeLineEndings = change.normalizeLineEndings;
start = Point.fromObject(newStart);
oldRange = Range(start, start.traverse(oldExtent));
newRange = Range(start, start.traverse(newExtent));
oldRange.freeze();
newRange.freeze();
this.cachedText = null;
startRow = oldRange.start.row;
endRow = oldRange.end.row;
rowCount = endRow - startRow + 1;
if (normalizeLineEndings) {
normalizedEnding = (ref2 = this.preferredLineEnding) != null ? ref2 : this.lineEndingForRow(startRow);
if (!normalizedEnding) {
if (startRow > 0) {
normalizedEnding = this.lineEndingForRow(startRow - 1);
} else {
normalizedEnding = null;
}
}
}
lines = [];
lineEndings = [];
lineStartIndex = 0;
normalizedNewText = "";
while (result = newlineRegex.exec(newText)) {
line = newText.slice(lineStartIndex, result.index);
ending = normalizedEnding != null ? normalizedEnding : result[0];
lines.push(line);
lineEndings.push(ending);
normalizedNewText += line + ending;
lineStartIndex = newlineRegex.lastIndex;
}
lastLine = newText.slice(lineStartIndex);
lines.push(lastLine);
lineEndings.push('');
normalizedNewText += lastLine;
newText = normalizedNewText;
changeEvent = Object.freeze({
oldRange: oldRange,
newRange: newRange,
oldText: oldText,
newText: newText,
eventId: this.eventIdCounter++
});
this.emitter.emit('will-change', changeEvent);
prefix = this.lineForRow(startRow).slice(0, oldRange.start.column);
lines[0] = prefix + lines[0];
suffix = this.lineForRow(endRow).slice(oldRange.end.column);
lastIndex = lines.length - 1;
lines[lastIndex] += suffix;
lastLineEnding = this.lineEndingForRow(endRow);
if (lastLineEnding !== '' && (normalizedEnding != null)) {
lastLineEnding = normalizedEnding;
}
lineEndings[lastIndex] = lastLineEnding;
spliceArray(this.lines, startRow, rowCount, lines);
spliceArray(this.lineEndings, startRow, rowCount, lineEndings);
offsets = lines.map(function(line, index) {
return {
rows: 1,
characters: line.length + lineEndings[index].length
};
});
this.offsetIndex.spliceArray('rows', startRow, rowCount, offsets);
this.changeCount++;
return this.emitDidChangeEvent(changeEvent);
};
TextBuffer.prototype.emitDidChangeEvent = function(changeEvent) {
return this.emitter.emit('did-change', changeEvent);
};
TextBuffer.prototype["delete"] = function(range) {
return this.setTextInRange(range, '');
};
TextBuffer.prototype.deleteRow = function(row) {
return this.deleteRows(row, row);
};
TextBuffer.prototype.deleteRows = function(startRow, endRow) {
var endPoint, lastRow, ref2, startPoint;
lastRow = this.getLastRow();
if (startRow > endRow) {
ref2 = [endRow, startRow], startRow = ref2[0], endRow = ref2[1];
}
if (endRow < 0) {
return new Range(this.getFirstPosition(), this.getFirstPosition());
}
if (startRow > lastRow) {
return new Range(this.getEndPosition(), this.getEndPosition());
}
startRow = Math.max(0, startRow);
endRow = Math.min(lastRow, endRow);
if (endRow < lastRow) {
startPoint = new Point(startRow, 0);
endPoint = new Point(endRow + 1, 0);
} else {
if (startRow === 0) {
startPoint = new Point(startRow, 0);
} else {
startPoint = new Point(startRow - 1, this.lineLengthForRow(startRow - 1));
}
endPoint = new Point(endRow, this.lineLengthForRow(endRow));
}
return this["delete"](new Range(startPoint, endPoint));
};
/*
Section: History
*/
TextBuffer.prototype.undo = function() {
var change, i, len, pop, ref2;
if (pop = this.history.popUndoStack()) {
ref2 = pop.patch.getChanges();
for (i = 0, len = ref2.length; i < len; i++) {
change = ref2[i];
this.applyChange(change);
}
this.emitDidChangeTextEvent(pop.patch);
return true;
} else {
return false;
}
};
TextBuffer.prototype.redo = function() {
var change, i, len, pop, ref2;
if (pop = this.history.popRedoStack()) {
ref2 = pop.patch.getChanges();
for (i = 0, len = ref2.length; i < len; i++) {
change = ref2[i];
this.applyChange(change);
}
this.emitDidChangeTextEvent(pop.patch);
return true;
} else {
return false;
}
};
TextBuffer.prototype.transact = function(groupingInterval, fn) {
var checkpointBefore, compactedChanges, error1, exception, ref2, result;
if (typeof groupingInterval === 'function') {
fn = groupingInterval;
groupingInterval = 0;
}
checkpointBefore = this.history.createCheckpoint(true);
try {
this.transactCallDepth++;
result = fn();
} catch (error1) {
exception = error1;
this.revertToCheckpoint(checkpointBefore, true);
if (!(exception instanceof TransactionAbortedError)) {
throw exception;
}
return;
} finally {
this.transactCallDepth--;
}
compactedChanges = this.history.groupChangesSinceCheckpoint(checkpointBefore, true);
if ((ref2 = global.atom) != null) {
ref2.assert(compactedChanges, "groupChangesSinceCheckpoint() returned false.", (function(_this) {
return function(error) {
return error.metadata = {
history: _this.history.toString()
};
};
})(this));
}
this.history.applyGroupingInterval(groupingInterval);
this.history.enforceUndoStackSizeLimit();
if (compactedChanges) {
this.emitDidChangeTextEvent(compactedChanges);
}
return result;
};
TextBuffer.prototype.abortTransaction = function() {
throw new TransactionAbortedError("Transaction aborted.");
};
TextBuffer.prototype.clearUndoStack = function() {
return this.history.clearUndoStack();
};
TextBuffer.prototype.createCheckpoint = function() {
return this.history.createCheckpoint(false);
};
TextBuffer.prototype.revertToCheckpoint = function(checkpoint) {
var change, i, len, ref2, truncated;
if (truncated = this.history.truncateUndoStack(checkpoint)) {
ref2 = truncated.patch.getChanges();
for (i = 0, len = ref2.length; i < len; i++) {
change = ref2[i];
this.applyChange(change);
}
this.emitDidChangeTextEvent(truncated.patch);
return true;
} else {
return false;
}
};
TextBuffer.prototype.groupChangesSinceCheckpoint = function(checkpoint) {
return this.history.groupChangesSinceCheckpoint(checkpoint, false);
};
TextBuffer.prototype.getChangesSinceCheckpoint = function(checkpoint) {
var patch;
if (patch = this.history.getChangesSinceCheckpoint(checkpoint)) {
return normalizePatchChanges(patch.getChanges());
} else {
return [];
}
};
/*
Section: Search And Replace
*/
TextBuffer.prototype.scan = function(regex, iterator) {
return this.scanInRange(regex, this.getRange(), (function(_this) {
return function(result) {
result.lineText = _this.lineForRow(result.range.start.row);
result.lineTextOffset = 0;
return iterator(result);
};
})(this));
};
TextBuffer.prototype.backwardsScan = function(regex, iterator) {
return this.backwardsScanInRange(regex, this.getRange(), (function(_this) {
return function(result) {
result.lineText = _this.lineForRow(result.range.start.row);
result.lineTextOffset = 0;
return iterator(result);
};
})(this));
};
TextBuffer.prototype.scanInRange = function(regex, range, iterator, reverse) {
var callbackArgument, endIndex, flags, global, lengthDelta, match, matches, next, startIndex;
if (reverse == null) {
reverse = false;
}
range = this.clipRange(range);
global = regex.global;
flags = "gm";
if (regex.ignoreCase) {
flags += "i";
}
regex = new RegExp(regex.source, flags);
startIndex = this.characterIndexForPosition(range.start);
endIndex = this.characterIndexForPosition(range.end);
if (reverse) {
matches = new MatchIterator.Backwards(this.getText(), regex, startIndex, endIndex, this.backwardsScanChunkSize);
} else {
matches = new MatchIterator.Forwards(this.getText(), regex, startIndex, endIndex);
}
lengthDelta = 0;
while (!(next = matches.next()).done) {
match = next.value;
callbackArgument = new SearchCallbackArgument(this, match, lengthDelta);
iterator(callbackArgument);
if (!reverse) {
lengthDelta += callbackArgument.getReplacementDelta();
}
if (!(global && callbackArgument.keepLooping())) {
break;
}
}
};
TextBuffer.prototype.backwardsScanInRange = function(regex, range, iterator) {
return this.scanInRange(regex, range, iterator, true);
};
TextBuffer.prototype.replace = function(regex, replacementText) {
var replacements;
replacements = 0;
this.transact((function(_this) {
return function() {
return _this.scan(regex, function(arg) {
var matchText, replace;
matchText = arg.matchText, replace = arg.replace;
replace(matchText.replace(regex, replacementText));
return replacements++;
});
};
})(this));
return replacements;
};
/*
Section: Buffer Range Details
*/
TextBuffer.prototype.getRange = function() {
return new Range(this.getFirstPosition(), this.getEndPosition());
};
TextBuffer.prototype.getLineCount = function() {
return this.lines.length;
};
TextBuffer.prototype.getLastRow = function() {
return this.getLineCount() - 1;
};
TextBuffer.prototype.getFirstPosition = function() {
return new Point(0, 0);
};
TextBuffer.prototype.getEndPosition = function() {
var lastRow;
lastRow = this.getLastRow();
return new Point(lastRow, this.lineLengthForRow(lastRow));
};
TextBuffer.prototype.getMaxCharacterIndex = function() {
return this.offsetIndex.totalTo(Infinity, 'rows').characters;
};
TextBuffer.prototype.rangeForRow = function(row, includeNewline) {
row = Math.max(row, 0);
row = Math.min(row, this.getLastRow());
if (includeNewline && row < this.getLastRow()) {
return new Range(new Point(row, 0), new Point(row + 1, 0));
} else {
return new Range(new Point(row, 0), new Point(row, this.lineLengthForRow(row)));
}
};
TextBuffer.prototype.characterIndexForPosition = function(position) {
var characters, column, ref2, row;
ref2 = this.clipPosition(Point.fromObject(position)), row = ref2.row, column = ref2.column;
if (row < 0 || row > this.getLastRow() || column < 0 || column > this.lineLengthForRow(row)) {
throw new Error("Position " + position + " is invalid");
}
characters = this.offsetIndex.totalTo(row, 'rows').characters;
return characters + column;
};
TextBuffer.prototype.positionForCharacterIndex = function(offset) {
var characters, ref2, rows;
offset = Math.max(0, offset);
offset = Math.min(this.getMaxCharacterIndex(), offset);
ref2 = this.offsetIndex.totalTo(offset, 'characters'), rows = ref2.rows, characters = ref2.characters;
if (rows > this.getLastRow()) {
return this.getEndPosition();
} else {
return new Point(rows, offset - characters);
}
};
TextBuffer.prototype.clipRange = function(range) {
var end, start;
range = Range.fromObject(range);
start = this.clipPosition(range.start);
end = this.clipPosition(range.end);
if (range.start.isEqual(start) && range.end.isEqual(end)) {
return range;
} else {
return new Range(start, end);
}
};
TextBuffer.prototype.clipPosition = function(position, options) {
var column, row;
position = Point.fromObject(position);
Point.assertValid(position);
row = position.row, column = position.column;
if (row < 0) {
return this.getFirstPosition();
} else if (row > this.getLastRow()) {
return this.getEndPosition();
} else if (column < 0) {
return Point(row, 0);
} else if (column >= this.lineLengthForRow(row)) {
if ((options != null ? options.clipDirection : void 0) === 'forward' && row < this.getLastRow()) {
return Point(row + 1, 0);
} else {
return Point(row, this.lineLengthForRow(row));
}
} else {
return position;
}
};
/*
Section: Private Utility Methods
*/
TextBuffer.prototype.destroy = function() {
if (!this.destroyed) {
this.cancelStoppedChangingTimeout();
this.destroyed = true;
return this.emitter.emit('did-destroy');
}
};
TextBuffer.prototype.isAlive = function() {
return !this.destroyed;
};
TextBuffer.prototype.isDestroyed = function() {
return this.destroyed;
};
TextBuffer.prototype.isRetained = function() {
return this.refcount > 0;
};
TextBuffer.prototype.retain = function() {
this.refcount++;
return this;
};
TextBuffer.prototype.release = function() {
this.refcount--;
if (!this.isRetained()) {
this.destroy();
}
return this;
};
TextBuffer.prototype.emitDidChangeTextEvent = function(patch) {
if (this.transactCallDepth !== 0) {
return;
}
this.emitter.emit('did-change-text', {
changes: Object.freeze(normalizePatchChanges(patch.getChanges()))
});
this.patchesSinceLastStoppedChangingEvent.push(patch);
return this.scheduleDidStopChangingEvent();
};
TextBuffer.prototype.hasMultipleEditors = function() {
return this.refcount > 1;
};
TextBuffer.prototype.cancelStoppedChangingTimeout = function() {
if (this.stoppedChangingTimeout) {
return clearTimeout(this.stoppedChangingTimeout);
}
};
TextBuffer.prototype.scheduleDidStopChangingEvent = function() {
var stoppedChangingCallback;
this.cancelStoppedChangingTimeout();
stoppedChangingCallback = (function(_this) {
return function() {
_this.stoppedChangingTimeout = null;
_this.emitter.emit('did-stop-changing', {
changes: Object.freeze(normalizePatchChanges(Patch.compose(_this.patchesSinceLastStoppedChangingEvent).getChanges()))
});
return _this.patchesSinceLastStoppedChangingEvent = [];
};
})(this);
return this.stoppedChangingTimeout = setTimeout(stoppedChangingCallback, this.stoppedChangingDelay);
};
TextBuffer.prototype.logLines = function(start, end) {
var i, line, ref2, ref3, row;
if (start == null) {
start = 0;
}
if (end == null) {
end = this.getLastRow();
}
for (row = i = ref2 = start, ref3 = end; ref2 <= ref3 ? i <= ref3 : i >= ref3; row = ref2 <= ref3 ? ++i : --i) {
line = this.lineForRow(row);
console.log(row, line, line.length);
}
};
/*
Section: Private History Delegate Methods
*/
TextBuffer.prototype.invertChange = function(change) {
return Object.freeze({
oldRange: change.newRange,
newRange: change.oldRange,
oldText: change.newText,
newText: change.oldText
});
};
TextBuffer.prototype.serializeChange = function(change) {
return {
oldRange: change.oldRange.serialize(),
newRange: change.newRange.serialize(),
oldText: change.oldText,
newText: change.newText
};
};
TextBuffer.prototype.deserializeChange = function(change) {
return {
oldRange: Range.deserialize(change.oldRange),
newRange: Range.deserialize(change.newRange),
oldText: change.oldText,
newText: change.newText
};
};
return TextBuffer;
})();
}).call(this);