move text defintions to services.ts

This commit is contained in:
Mohamed Hegazy 2014-12-06 09:10:16 -08:00 committed by Daniel Rosenwasser
parent 4deea66c1c
commit 0d9b2c8725
3 changed files with 295 additions and 298 deletions

View File

@ -13,7 +13,6 @@
// limitations under the License.
//
///<reference path='..\text.ts' />
///<reference path='..\services.ts' />
///<reference path='formattingContext.ts' />
///<reference path='formattingRequestKind.ts' />

View File

@ -4,7 +4,6 @@
/// <reference path="..\compiler\parser.ts"/>
/// <reference path="..\compiler\checker.ts"/>
/// <reference path='text.ts' />
/// <reference path='outliningElementsCollector.ts' />
/// <reference path='navigationBar.ts' />
/// <reference path='breakpoints.ts' />
@ -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

View File

@ -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);
}
}
}