diff --git a/src/services/formatting/references.ts b/src/services/formatting/references.ts
index 9f4b7e37436..3d19b33d821 100644
--- a/src/services/formatting/references.ts
+++ b/src/services/formatting/references.ts
@@ -13,7 +13,6 @@
// limitations under the License.
//
-///
///
///
///
diff --git a/src/services/services.ts b/src/services/services.ts
index 980b7ecda3d..e31d2b42ee5 100644
--- a/src/services/services.ts
+++ b/src/services/services.ts
@@ -4,7 +4,6 @@
///
///
-///
///
///
///
@@ -933,6 +932,301 @@ module ts {
dispose(): void;
}
+ export class TextSpan {
+ private _start: number;
+ private _length: number;
+
+ /**
+ * Creates a TextSpan instance beginning with the position Start and having the Length
+ * specified with length.
+ */
+ constructor(start: number, length: number) {
+ Debug.assert(start >= 0, "start");
+ Debug.assert(length >= 0, "length");
+
+ this._start = start;
+ this._length = length;
+ }
+
+ public toJSON(key: any): any {
+ return { start: this._start, length: this._length };
+ }
+
+ public start(): number {
+ return this._start;
+ }
+
+ public length(): number {
+ return this._length;
+ }
+
+ public end(): number {
+ return this._start + this._length;
+ }
+
+ public isEmpty(): boolean {
+ return this._length === 0;
+ }
+
+ /**
+ * Determines whether the position lies within the span. Returns true if the position is greater than or equal to Start and strictly less
+ * than End, otherwise false.
+ * @param position The position to check.
+ */
+ public containsPosition(position: number): boolean {
+ return position >= this._start && position < this.end();
+ }
+
+ /**
+ * Determines whether span falls completely within this span. Returns true if the specified span falls completely within this span, otherwise false.
+ * @param span The span to check.
+ */
+ public containsTextSpan(span: TextSpan): boolean {
+ return span._start >= this._start && span.end() <= this.end();
+ }
+
+ /**
+ * Determines whether the given span overlaps this span. Two spans are considered to overlap
+ * if they have positions in common and neither is empty. Empty spans do not overlap with any
+ * other span. Returns true if the spans overlap, false otherwise.
+ * @param span The span to check.
+ */
+ public overlapsWith(span: TextSpan): boolean {
+ var overlapStart = Math.max(this._start, span._start);
+ var overlapEnd = Math.min(this.end(), span.end());
+
+ return overlapStart < overlapEnd;
+ }
+
+ /**
+ * Returns the overlap with the given span, or undefined if there is no overlap.
+ * @param span The span to check.
+ */
+ public overlap(span: TextSpan): TextSpan {
+ var overlapStart = Math.max(this._start, span._start);
+ var overlapEnd = Math.min(this.end(), span.end());
+
+ if (overlapStart < overlapEnd) {
+ return TextSpan.fromBounds(overlapStart, overlapEnd);
+ }
+
+ return undefined;
+ }
+
+ /**
+ * Determines whether span intersects this span. Two spans are considered to
+ * intersect if they have positions in common or the end of one span
+ * coincides with the start of the other span. Returns true if the spans intersect, false otherwise.
+ * @param The span to check.
+ */
+ public intersectsWithTextSpan(span: TextSpan): boolean {
+ return span._start <= this.end() && span.end() >= this._start;
+ }
+
+ public intersectsWith(start: number, length: number): boolean {
+ var end = start + length;
+ return start <= this.end() && end >= this._start;
+ }
+
+ /**
+ * Determines whether the given position intersects this span.
+ * A position is considered to intersect if it is between the start and
+ * end positions (inclusive) of this span. Returns true if the position intersects, false otherwise.
+ * @param position The position to check.
+ */
+ public intersectsWithPosition(position: number): boolean {
+ return position <= this.end() && position >= this._start;
+ }
+
+ /**
+ * Returns the intersection with the given span, or undefined if there is no intersection.
+ * @param span The span to check.
+ */
+ public intersection(span: TextSpan): TextSpan {
+ var intersectStart = Math.max(this._start, span._start);
+ var intersectEnd = Math.min(this.end(), span.end());
+
+ if (intersectStart <= intersectEnd) {
+ return TextSpan.fromBounds(intersectStart, intersectEnd);
+ }
+
+ return undefined;
+ }
+
+ /**
+ * Creates a new TextSpan from the given start and end positions
+ * as opposed to a position and length.
+ */
+ public static fromBounds(start: number, end: number): TextSpan {
+ Debug.assert(start >= 0);
+ Debug.assert(end - start >= 0);
+ return new TextSpan(start, end - start);
+ }
+ }
+
+ export class TextChangeRange {
+ public static unchanged = new TextChangeRange(new TextSpan(0, 0), 0);
+
+ private _span: TextSpan;
+ private _newLength: number;
+
+ /**
+ * Initializes a new instance of TextChangeRange.
+ */
+ constructor(span: TextSpan, newLength: number) {
+ Debug.assert(newLength >= 0, "newLength");
+
+ this._span = span;
+ this._newLength = newLength;
+ }
+
+ /**
+ * The span of text before the edit which is being changed
+ */
+ public span(): TextSpan {
+ return this._span;
+ }
+
+ /**
+ * Width of the span after the edit. A 0 here would represent a delete
+ */
+ public newLength(): number {
+ return this._newLength;
+ }
+
+ public newSpan(): TextSpan {
+ return new TextSpan(this.span().start(), this.newLength());
+ }
+
+ public isUnchanged(): boolean {
+ return this.span().isEmpty() && this.newLength() === 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.
+ */
+ public static collapseChangesAcrossMultipleVersions(changes: TextChangeRange[]): TextChangeRange {
+ if (changes.length === 0) {
+ return TextChangeRange.unchanged;
+ }
+
+ 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 new TextChangeRange(TextSpan.fromBounds(oldStartN, oldEndN), /*newLength: */newEndN - oldStartN);
+ }
+ }
+
export interface ClassifiedSpan {
textSpan: TextSpan;
classificationType: string; // ClassificationTypeNames
diff --git a/src/services/text.ts b/src/services/text.ts
deleted file mode 100644
index fd768785dea..00000000000
--- a/src/services/text.ts
+++ /dev/null
@@ -1,296 +0,0 @@
-module ts {
- export class TextSpan {
- private _start: number;
- private _length: number;
-
- /**
- * Creates a TextSpan instance beginning with the position Start and having the Length
- * specified with length.
- */
- constructor(start: number, length: number) {
- Debug.assert(start >= 0, "start");
- Debug.assert(length >= 0, "length");
-
- this._start = start;
- this._length = length;
- }
-
- public toJSON(key: any): any {
- return { start: this._start, length: this._length };
- }
-
- public start(): number {
- return this._start;
- }
-
- public length(): number {
- return this._length;
- }
-
- public end(): number {
- return this._start + this._length;
- }
-
- public isEmpty(): boolean {
- return this._length === 0;
- }
-
- /**
- * Determines whether the position lies within the span. Returns true if the position is greater than or equal to Start and strictly less
- * than End, otherwise false.
- * @param position The position to check.
- */
- public containsPosition(position: number): boolean {
- return position >= this._start && position < this.end();
- }
-
- /**
- * Determines whether span falls completely within this span. Returns true if the specified span falls completely within this span, otherwise false.
- * @param span The span to check.
- */
- public containsTextSpan(span: TextSpan): boolean {
- return span._start >= this._start && span.end() <= this.end();
- }
-
- /**
- * Determines whether the given span overlaps this span. Two spans are considered to overlap
- * if they have positions in common and neither is empty. Empty spans do not overlap with any
- * other span. Returns true if the spans overlap, false otherwise.
- * @param span The span to check.
- */
- public overlapsWith(span: TextSpan): boolean {
- var overlapStart = Math.max(this._start, span._start);
- var overlapEnd = Math.min(this.end(), span.end());
-
- return overlapStart < overlapEnd;
- }
-
- /**
- * Returns the overlap with the given span, or undefined if there is no overlap.
- * @param span The span to check.
- */
- public overlap(span: TextSpan): TextSpan {
- var overlapStart = Math.max(this._start, span._start);
- var overlapEnd = Math.min(this.end(), span.end());
-
- if (overlapStart < overlapEnd) {
- return TextSpan.fromBounds(overlapStart, overlapEnd);
- }
-
- return undefined;
- }
-
- /**
- * Determines whether span intersects this span. Two spans are considered to
- * intersect if they have positions in common or the end of one span
- * coincides with the start of the other span. Returns true if the spans intersect, false otherwise.
- * @param The span to check.
- */
- public intersectsWithTextSpan(span: TextSpan): boolean {
- return span._start <= this.end() && span.end() >= this._start;
- }
-
- public intersectsWith(start: number, length: number): boolean {
- var end = start + length;
- return start <= this.end() && end >= this._start;
- }
-
- /**
- * Determines whether the given position intersects this span.
- * A position is considered to intersect if it is between the start and
- * end positions (inclusive) of this span. Returns true if the position intersects, false otherwise.
- * @param position The position to check.
- */
- public intersectsWithPosition(position: number): boolean {
- return position <= this.end() && position >= this._start;
- }
-
- /**
- * Returns the intersection with the given span, or undefined if there is no intersection.
- * @param span The span to check.
- */
- public intersection(span: TextSpan): TextSpan {
- var intersectStart = Math.max(this._start, span._start);
- var intersectEnd = Math.min(this.end(), span.end());
-
- if (intersectStart <= intersectEnd) {
- return TextSpan.fromBounds(intersectStart, intersectEnd);
- }
-
- return undefined;
- }
-
- /**
- * Creates a new TextSpan from the given start and end positions
- * as opposed to a position and length.
- */
- public static fromBounds(start: number, end: number): TextSpan {
- Debug.assert(start >= 0);
- Debug.assert(end - start >= 0);
- return new TextSpan(start, end - start);
- }
- }
-
- export class TextChangeRange {
- public static unchanged = new TextChangeRange(new TextSpan(0, 0), 0);
-
- private _span: TextSpan;
- private _newLength: number;
-
- /**
- * Initializes a new instance of TextChangeRange.
- */
- constructor(span: TextSpan, newLength: number) {
- Debug.assert(newLength >= 0, "newLength");
-
- this._span = span;
- this._newLength = newLength;
- }
-
- /**
- * The span of text before the edit which is being changed
- */
- public span(): TextSpan {
- return this._span;
- }
-
- /**
- * Width of the span after the edit. A 0 here would represent a delete
- */
- public newLength(): number {
- return this._newLength;
- }
-
- public newSpan(): TextSpan {
- return new TextSpan(this.span().start(), this.newLength());
- }
-
- public isUnchanged(): boolean {
- return this.span().isEmpty() && this.newLength() === 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.
- */
- public static collapseChangesAcrossMultipleVersions(changes: TextChangeRange[]): TextChangeRange {
- if (changes.length === 0) {
- return TextChangeRange.unchanged;
- }
-
- 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 new TextChangeRange(TextSpan.fromBounds(oldStartN, oldEndN), /*newLength: */newEndN - oldStartN);
- }
- }
-}
\ No newline at end of file