mirror of
https://github.com/microsoft/TypeScript.git
synced 2026-02-15 03:23:08 -06:00
Move functions from 'types.ts' to 'utilities.ts'.
This commit is contained in:
parent
f218ce7684
commit
62dd12cb7a
@ -1637,245 +1637,10 @@ module ts {
|
||||
intersection(span: TextSpan): TextSpan;
|
||||
}
|
||||
|
||||
var textSpanConstructor = (function () {
|
||||
function textSpanConstructor(start: number, length: number) {
|
||||
if (start < 0) {
|
||||
throw new Error("start < 0");
|
||||
}
|
||||
if (length < 0) {
|
||||
throw new Error("start < 0");
|
||||
}
|
||||
this._start = start;
|
||||
this._length = length;
|
||||
}
|
||||
|
||||
textSpanConstructor.prototype = {
|
||||
toJSON(key: string) {
|
||||
return { start: this._start, length: this._length }
|
||||
},
|
||||
start() {
|
||||
return this._start
|
||||
},
|
||||
length() {
|
||||
return this._length
|
||||
},
|
||||
end() {
|
||||
return this._start + this._length
|
||||
},
|
||||
isEmpty() {
|
||||
return this._length === 0
|
||||
},
|
||||
containsPosition(position: number) {
|
||||
return position >= this._start && position < this.end()
|
||||
},
|
||||
containsTextSpan(span: TextSpan) {
|
||||
return span.start() >= this._start && span.end() <= this.end()
|
||||
},
|
||||
overlapsWith(span: TextSpan) {
|
||||
var overlapStart = Math.max(this._start, span.start());
|
||||
var overlapEnd = Math.min(this.end(), span.end());
|
||||
return overlapStart < overlapEnd;
|
||||
},
|
||||
overlap(span: TextSpan) {
|
||||
var overlapStart = Math.max(this._start, span.start());
|
||||
var overlapEnd = Math.min(this.end(), span.end());
|
||||
if (overlapStart < overlapEnd) {
|
||||
return createTextSpanFromBounds(overlapStart, overlapEnd);
|
||||
}
|
||||
return undefined;
|
||||
},
|
||||
intersectsWithTextSpan(span: TextSpan) {
|
||||
return span.start() <= this.end() && span.end() >= this._start
|
||||
},
|
||||
intersectsWith(start: number, length: number) {
|
||||
var end = start + length;
|
||||
return start <= this.end() && end >= this._start;
|
||||
},
|
||||
intersectsWithPosition(position: number) {
|
||||
return position <= this.end() && position >= this._start;
|
||||
},
|
||||
intersection(span: TextSpan) {
|
||||
var intersectStart = Math.max(this._start, span.start());
|
||||
var intersectEnd = Math.min(this.end(), span.end());
|
||||
if (intersectStart <= intersectEnd) {
|
||||
return createTextSpanFromBounds(intersectStart, intersectEnd);
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
};
|
||||
|
||||
return textSpanConstructor;
|
||||
})();
|
||||
|
||||
export function createTextSpan(start: number, length: number): TextSpan {
|
||||
return new (<any>textSpanConstructor)(start, length);
|
||||
}
|
||||
|
||||
export function createTextSpanFromBounds(start: number, end: number) {
|
||||
return createTextSpan(start, end - start);
|
||||
}
|
||||
|
||||
export interface TextChangeRange {
|
||||
span(): TextSpan;
|
||||
newLength(): number;
|
||||
newSpan(): TextSpan;
|
||||
isUnchanged(): boolean;
|
||||
}
|
||||
|
||||
var textChangeRangeConstructor = (function () {
|
||||
function textChangeRangeConstructor(span: TextSpan, newLength: number) {
|
||||
if (newLength < 0) {
|
||||
throw new Error("newLength < 0");
|
||||
}
|
||||
this._span = span;
|
||||
this._newLength = newLength;
|
||||
}
|
||||
|
||||
textChangeRangeConstructor.prototype = {
|
||||
span() {
|
||||
return this._span;
|
||||
},
|
||||
newLength() {
|
||||
return this._newLength;
|
||||
},
|
||||
newSpan() {
|
||||
return createTextSpan(this.span().start(), this.newLength());
|
||||
},
|
||||
isUnchanged() {
|
||||
return this.span().isEmpty() && this.newLength() === 0;
|
||||
}
|
||||
};
|
||||
|
||||
return textChangeRangeConstructor;
|
||||
})();
|
||||
|
||||
export function createTextChangeRange(span: TextSpan, newLength: number): TextChangeRange {
|
||||
return new (<any>textChangeRangeConstructor)(span, newLength);
|
||||
}
|
||||
|
||||
export var unchangedTextChangeRange = createTextChangeRange(createTextSpan(0, 0), 0);
|
||||
|
||||
/**
|
||||
* Called to merge all the changes that occurred across several versions of a script snapshot
|
||||
* into a single change. i.e. if a user keeps making successive edits to a script we will
|
||||
* have a text change from V1 to V2, V2 to V3, ..., Vn.
|
||||
*
|
||||
* This function will then merge those changes into a single change range valid between V1 and
|
||||
* Vn.
|
||||
*/
|
||||
export function collapseTextChangeRangesAcrossMultipleVersions(changes: TextChangeRange[]): TextChangeRange {
|
||||
if (changes.length === 0) {
|
||||
return unchangedTextChangeRange;
|
||||
}
|
||||
|
||||
if (changes.length === 1) {
|
||||
return changes[0];
|
||||
}
|
||||
|
||||
// We change from talking about { { oldStart, oldLength }, newLength } to { oldStart, oldEnd, newEnd }
|
||||
// as it makes things much easier to reason about.
|
||||
var change0 = changes[0];
|
||||
|
||||
var oldStartN = change0.span().start();
|
||||
var oldEndN = change0.span().end();
|
||||
var newEndN = oldStartN + change0.newLength();
|
||||
|
||||
for (var i = 1; i < changes.length; i++) {
|
||||
var nextChange = changes[i];
|
||||
|
||||
// Consider the following case:
|
||||
// i.e. two edits. The first represents the text change range { { 10, 50 }, 30 }. i.e. The span starting
|
||||
// at 10, with length 50 is reduced to length 30. The second represents the text change range { { 30, 30 }, 40 }.
|
||||
// i.e. the span starting at 30 with length 30 is increased to length 40.
|
||||
//
|
||||
// 0 10 20 30 40 50 60 70 80 90 100
|
||||
// -------------------------------------------------------------------------------------------------------
|
||||
// | /
|
||||
// | /----
|
||||
// T1 | /----
|
||||
// | /----
|
||||
// | /----
|
||||
// -------------------------------------------------------------------------------------------------------
|
||||
// | \
|
||||
// | \
|
||||
// T2 | \
|
||||
// | \
|
||||
// | \
|
||||
// -------------------------------------------------------------------------------------------------------
|
||||
//
|
||||
// Merging these turns out to not be too difficult. First, determining the new start of the change is trivial
|
||||
// it's just the min of the old and new starts. i.e.:
|
||||
//
|
||||
// 0 10 20 30 40 50 60 70 80 90 100
|
||||
// ------------------------------------------------------------*------------------------------------------
|
||||
// | /
|
||||
// | /----
|
||||
// T1 | /----
|
||||
// | /----
|
||||
// | /----
|
||||
// ----------------------------------------$-------------------$------------------------------------------
|
||||
// . | \
|
||||
// . | \
|
||||
// T2 . | \
|
||||
// . | \
|
||||
// . | \
|
||||
// ----------------------------------------------------------------------*--------------------------------
|
||||
//
|
||||
// (Note the dots represent the newly inferrred start.
|
||||
// Determining the new and old end is also pretty simple. Basically it boils down to paying attention to the
|
||||
// absolute positions at the asterixes, and the relative change between the dollar signs. Basically, we see
|
||||
// which if the two $'s precedes the other, and we move that one forward until they line up. in this case that
|
||||
// means:
|
||||
//
|
||||
// 0 10 20 30 40 50 60 70 80 90 100
|
||||
// --------------------------------------------------------------------------------*----------------------
|
||||
// | /
|
||||
// | /----
|
||||
// T1 | /----
|
||||
// | /----
|
||||
// | /----
|
||||
// ------------------------------------------------------------$------------------------------------------
|
||||
// . | \
|
||||
// . | \
|
||||
// T2 . | \
|
||||
// . | \
|
||||
// . | \
|
||||
// ----------------------------------------------------------------------*--------------------------------
|
||||
//
|
||||
// In other words (in this case), we're recognizing that the second edit happened after where the first edit
|
||||
// ended with a delta of 20 characters (60 - 40). Thus, if we go back in time to where the first edit started
|
||||
// that's the same as if we started at char 80 instead of 60.
|
||||
//
|
||||
// As it so happens, the same logic applies if the second edit precedes the first edit. In that case rahter
|
||||
// than pusing the first edit forward to match the second, we'll push the second edit forward to match the
|
||||
// first.
|
||||
//
|
||||
// In this case that means we have { oldStart: 10, oldEnd: 80, newEnd: 70 } or, in TextChangeRange
|
||||
// semantics: { { start: 10, length: 70 }, newLength: 60 }
|
||||
//
|
||||
// The math then works out as follows.
|
||||
// If we have { oldStart1, oldEnd1, newEnd1 } and { oldStart2, oldEnd2, newEnd2 } then we can compute the
|
||||
// final result like so:
|
||||
//
|
||||
// {
|
||||
// oldStart3: Min(oldStart1, oldStart2),
|
||||
// oldEnd3 : Max(oldEnd1, oldEnd1 + (oldEnd2 - newEnd1)),
|
||||
// newEnd3 : Max(newEnd2, newEnd2 + (newEnd1 - oldEnd2))
|
||||
// }
|
||||
|
||||
var oldStart1 = oldStartN;
|
||||
var oldEnd1 = oldEndN;
|
||||
var newEnd1 = newEndN;
|
||||
|
||||
var oldStart2 = nextChange.span().start();
|
||||
var oldEnd2 = nextChange.span().end();
|
||||
var newEnd2 = oldStart2 + nextChange.newLength();
|
||||
|
||||
oldStartN = Math.min(oldStart1, oldStart2);
|
||||
oldEndN = Math.max(oldEnd1, oldEnd1 + (oldEnd2 - newEnd1));
|
||||
newEndN = Math.max(newEnd2, newEnd2 + (newEnd1 - oldEnd2));
|
||||
}
|
||||
|
||||
return createTextChangeRange(createTextSpanFromBounds(oldStartN, oldEndN), /*newLength: */newEndN - oldStartN);
|
||||
}
|
||||
}
|
||||
|
||||
@ -708,6 +708,7 @@ module ts {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return undefined;
|
||||
}
|
||||
|
||||
@ -733,4 +734,238 @@ module ts {
|
||||
return false;
|
||||
}
|
||||
|
||||
var textSpanConstructor = (function () {
|
||||
function textSpanConstructor(start: number, length: number) {
|
||||
if (start < 0) {
|
||||
throw new Error("start < 0");
|
||||
}
|
||||
if (length < 0) {
|
||||
throw new Error("start < 0");
|
||||
}
|
||||
this._start = start;
|
||||
this._length = length;
|
||||
}
|
||||
|
||||
textSpanConstructor.prototype = {
|
||||
toJSON(key: string) {
|
||||
return { start: this._start, length: this._length }
|
||||
},
|
||||
start() {
|
||||
return this._start
|
||||
},
|
||||
length() {
|
||||
return this._length
|
||||
},
|
||||
end() {
|
||||
return this._start + this._length
|
||||
},
|
||||
isEmpty() {
|
||||
return this._length === 0
|
||||
},
|
||||
containsPosition(position: number) {
|
||||
return position >= this._start && position < this.end()
|
||||
},
|
||||
containsTextSpan(span: TextSpan) {
|
||||
return span.start() >= this._start && span.end() <= this.end()
|
||||
},
|
||||
overlapsWith(span: TextSpan) {
|
||||
var overlapStart = Math.max(this._start, span.start());
|
||||
var overlapEnd = Math.min(this.end(), span.end());
|
||||
return overlapStart < overlapEnd;
|
||||
},
|
||||
overlap(span: TextSpan) {
|
||||
var overlapStart = Math.max(this._start, span.start());
|
||||
var overlapEnd = Math.min(this.end(), span.end());
|
||||
if (overlapStart < overlapEnd) {
|
||||
return createTextSpanFromBounds(overlapStart, overlapEnd);
|
||||
}
|
||||
return undefined;
|
||||
},
|
||||
intersectsWithTextSpan(span: TextSpan) {
|
||||
return span.start() <= this.end() && span.end() >= this._start
|
||||
},
|
||||
intersectsWith(start: number, length: number) {
|
||||
var end = start + length;
|
||||
return start <= this.end() && end >= this._start;
|
||||
},
|
||||
intersectsWithPosition(position: number) {
|
||||
return position <= this.end() && position >= this._start;
|
||||
},
|
||||
intersection(span: TextSpan) {
|
||||
var intersectStart = Math.max(this._start, span.start());
|
||||
var intersectEnd = Math.min(this.end(), span.end());
|
||||
if (intersectStart <= intersectEnd) {
|
||||
return createTextSpanFromBounds(intersectStart, intersectEnd);
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
};
|
||||
|
||||
return textSpanConstructor;
|
||||
})();
|
||||
|
||||
export function createTextSpan(start: number, length: number): TextSpan {
|
||||
return new (<any>textSpanConstructor)(start, length);
|
||||
}
|
||||
|
||||
export function createTextSpanFromBounds(start: number, end: number) {
|
||||
return createTextSpan(start, end - start);
|
||||
}
|
||||
|
||||
var textChangeRangeConstructor = (function () {
|
||||
function textChangeRangeConstructor(span: TextSpan, newLength: number) {
|
||||
if (newLength < 0) {
|
||||
throw new Error("newLength < 0");
|
||||
}
|
||||
this._span = span;
|
||||
this._newLength = newLength;
|
||||
}
|
||||
|
||||
textChangeRangeConstructor.prototype = {
|
||||
span() {
|
||||
return this._span;
|
||||
},
|
||||
newLength() {
|
||||
return this._newLength;
|
||||
},
|
||||
newSpan() {
|
||||
return createTextSpan(this.span().start(), this.newLength());
|
||||
},
|
||||
isUnchanged() {
|
||||
return this.span().isEmpty() && this.newLength() === 0;
|
||||
}
|
||||
};
|
||||
|
||||
return textChangeRangeConstructor;
|
||||
})();
|
||||
|
||||
export function createTextChangeRange(span: TextSpan, newLength: number): TextChangeRange {
|
||||
return new (<any>textChangeRangeConstructor)(span, newLength);
|
||||
}
|
||||
|
||||
export var unchangedTextChangeRange = createTextChangeRange(createTextSpan(0, 0), 0);
|
||||
|
||||
/**
|
||||
* Called to merge all the changes that occurred across several versions of a script snapshot
|
||||
* into a single change. i.e. if a user keeps making successive edits to a script we will
|
||||
* have a text change from V1 to V2, V2 to V3, ..., Vn.
|
||||
*
|
||||
* This function will then merge those changes into a single change range valid between V1 and
|
||||
* Vn.
|
||||
*/
|
||||
export function collapseTextChangeRangesAcrossMultipleVersions(changes: TextChangeRange[]): TextChangeRange {
|
||||
if (changes.length === 0) {
|
||||
return unchangedTextChangeRange;
|
||||
}
|
||||
|
||||
if (changes.length === 1) {
|
||||
return changes[0];
|
||||
}
|
||||
|
||||
// We change from talking about { { oldStart, oldLength }, newLength } to { oldStart, oldEnd, newEnd }
|
||||
// as it makes things much easier to reason about.
|
||||
var change0 = changes[0];
|
||||
|
||||
var oldStartN = change0.span().start();
|
||||
var oldEndN = change0.span().end();
|
||||
var newEndN = oldStartN + change0.newLength();
|
||||
|
||||
for (var i = 1; i < changes.length; i++) {
|
||||
var nextChange = changes[i];
|
||||
|
||||
// Consider the following case:
|
||||
// i.e. two edits. The first represents the text change range { { 10, 50 }, 30 }. i.e. The span starting
|
||||
// at 10, with length 50 is reduced to length 30. The second represents the text change range { { 30, 30 }, 40 }.
|
||||
// i.e. the span starting at 30 with length 30 is increased to length 40.
|
||||
//
|
||||
// 0 10 20 30 40 50 60 70 80 90 100
|
||||
// -------------------------------------------------------------------------------------------------------
|
||||
// | /
|
||||
// | /----
|
||||
// T1 | /----
|
||||
// | /----
|
||||
// | /----
|
||||
// -------------------------------------------------------------------------------------------------------
|
||||
// | \
|
||||
// | \
|
||||
// T2 | \
|
||||
// | \
|
||||
// | \
|
||||
// -------------------------------------------------------------------------------------------------------
|
||||
//
|
||||
// Merging these turns out to not be too difficult. First, determining the new start of the change is trivial
|
||||
// it's just the min of the old and new starts. i.e.:
|
||||
//
|
||||
// 0 10 20 30 40 50 60 70 80 90 100
|
||||
// ------------------------------------------------------------*------------------------------------------
|
||||
// | /
|
||||
// | /----
|
||||
// T1 | /----
|
||||
// | /----
|
||||
// | /----
|
||||
// ----------------------------------------$-------------------$------------------------------------------
|
||||
// . | \
|
||||
// . | \
|
||||
// T2 . | \
|
||||
// . | \
|
||||
// . | \
|
||||
// ----------------------------------------------------------------------*--------------------------------
|
||||
//
|
||||
// (Note the dots represent the newly inferrred start.
|
||||
// Determining the new and old end is also pretty simple. Basically it boils down to paying attention to the
|
||||
// absolute positions at the asterixes, and the relative change between the dollar signs. Basically, we see
|
||||
// which if the two $'s precedes the other, and we move that one forward until they line up. in this case that
|
||||
// means:
|
||||
//
|
||||
// 0 10 20 30 40 50 60 70 80 90 100
|
||||
// --------------------------------------------------------------------------------*----------------------
|
||||
// | /
|
||||
// | /----
|
||||
// T1 | /----
|
||||
// | /----
|
||||
// | /----
|
||||
// ------------------------------------------------------------$------------------------------------------
|
||||
// . | \
|
||||
// . | \
|
||||
// T2 . | \
|
||||
// . | \
|
||||
// . | \
|
||||
// ----------------------------------------------------------------------*--------------------------------
|
||||
//
|
||||
// In other words (in this case), we're recognizing that the second edit happened after where the first edit
|
||||
// ended with a delta of 20 characters (60 - 40). Thus, if we go back in time to where the first edit started
|
||||
// that's the same as if we started at char 80 instead of 60.
|
||||
//
|
||||
// As it so happens, the same logic applies if the second edit precedes the first edit. In that case rahter
|
||||
// than pusing the first edit forward to match the second, we'll push the second edit forward to match the
|
||||
// first.
|
||||
//
|
||||
// In this case that means we have { oldStart: 10, oldEnd: 80, newEnd: 70 } or, in TextChangeRange
|
||||
// semantics: { { start: 10, length: 70 }, newLength: 60 }
|
||||
//
|
||||
// The math then works out as follows.
|
||||
// If we have { oldStart1, oldEnd1, newEnd1 } and { oldStart2, oldEnd2, newEnd2 } then we can compute the
|
||||
// final result like so:
|
||||
//
|
||||
// {
|
||||
// oldStart3: Min(oldStart1, oldStart2),
|
||||
// oldEnd3 : Max(oldEnd1, oldEnd1 + (oldEnd2 - newEnd1)),
|
||||
// newEnd3 : Max(newEnd2, newEnd2 + (newEnd1 - oldEnd2))
|
||||
// }
|
||||
|
||||
var oldStart1 = oldStartN;
|
||||
var oldEnd1 = oldEndN;
|
||||
var newEnd1 = newEndN;
|
||||
|
||||
var oldStart2 = nextChange.span().start();
|
||||
var oldEnd2 = nextChange.span().end();
|
||||
var newEnd2 = oldStart2 + nextChange.newLength();
|
||||
|
||||
oldStartN = Math.min(oldStart1, oldStart2);
|
||||
oldEndN = Math.max(oldEnd1, oldEnd1 + (oldEnd2 - newEnd1));
|
||||
newEndN = Math.max(newEnd2, newEnd2 + (newEnd1 - oldEnd2));
|
||||
}
|
||||
|
||||
return createTextChangeRange(createTextSpanFromBounds(oldStartN, oldEndN), /*newLength: */newEndN - oldStartN);
|
||||
}
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user