mirror of
https://github.com/microsoft/TypeScript.git
synced 2026-02-17 01:55:50 -06:00
Initial entrypoint in SourceFile for the LS to call to peform incremental parsing.
Right now the entrypoint just causes a full parse to happen. But the LS code is cleaned up to take advantage of it appropriately.
This commit is contained in:
parent
aea499e572
commit
5bd49fec1d
@ -1034,10 +1034,13 @@ module ts {
|
||||
|
||||
export function createSourceFile(filename: string, sourceText: string, languageVersion: ScriptTarget, setParentNodes = false): SourceFile {
|
||||
var parsingContext: ParsingContext;
|
||||
var identifiers: Map<string> = {};
|
||||
var identifiers: Map<string>;
|
||||
var identifierCount = 0;
|
||||
var nodeCount = 0;
|
||||
var lineStarts: number[];
|
||||
var syntacticDiagnostics: Diagnostic[];
|
||||
var scanner: Scanner;
|
||||
var token: SyntaxKind;
|
||||
|
||||
// Flags that dictate what parsing context we're in. For example:
|
||||
// Whether or not we are in strict parsing mode. All that changes in strict parsing mode is
|
||||
@ -1085,7 +1088,7 @@ module ts {
|
||||
// Note: it should not be necessary to save/restore these flags during speculative/lookahead
|
||||
// parsing. These context flags are naturally stored and restored through normal recursive
|
||||
// descent parsing and unwinding.
|
||||
var contextFlags: ParserContextFlags = 0;
|
||||
var contextFlags: ParserContextFlags;
|
||||
|
||||
// Whether or not we've had a parse error since creating the last AST node. If we have
|
||||
// encountered an error, it will be stored on the next AST node we create. Parse errors
|
||||
@ -1114,48 +1117,69 @@ module ts {
|
||||
//
|
||||
// Note: any errors at the end of the file that do not precede a regular node, should get
|
||||
// attached to the EOF token.
|
||||
var parseErrorBeforeNextFinishedNode = false;
|
||||
var parseErrorBeforeNextFinishedNode: boolean;
|
||||
|
||||
var sourceFile = <SourceFile>createNode(SyntaxKind.SourceFile, 0);
|
||||
if (fileExtensionIs(filename, ".d.ts")) {
|
||||
sourceFile.flags = NodeFlags.DeclarationFile;
|
||||
}
|
||||
sourceFile.end = sourceText.length;
|
||||
sourceFile.filename = normalizePath(filename);
|
||||
sourceFile.text = sourceText;
|
||||
var sourceFile: SourceFile;
|
||||
|
||||
sourceFile.getLineAndCharacterFromPosition = getLineAndCharacterFromSourcePosition;
|
||||
sourceFile.getPositionFromLineAndCharacter = getPositionFromSourceLineAndCharacter;
|
||||
sourceFile.getLineStarts = getLineStarts;
|
||||
sourceFile.getSyntacticDiagnostics = getSyntacticDiagnostics;
|
||||
return parseSourceFile(sourceText, /*textChangeRange:*/ undefined, setParentNodes);
|
||||
|
||||
sourceFile.referenceDiagnostics = [];
|
||||
sourceFile.parseDiagnostics = [];
|
||||
sourceFile.grammarDiagnostics = [];
|
||||
sourceFile.semanticDiagnostics = [];
|
||||
function parseSourceFile(text: string, textChangeRange: TextChangeRange, setParentNodes: boolean): SourceFile {
|
||||
// Set our initial state before parsing.
|
||||
sourceText = text;
|
||||
parsingContext = 0;
|
||||
identifiers = {};
|
||||
lineStarts = undefined;
|
||||
syntacticDiagnostics = undefined;
|
||||
contextFlags = 0;
|
||||
parseErrorBeforeNextFinishedNode = false;
|
||||
|
||||
processReferenceComments();
|
||||
sourceFile = <SourceFile>createNode(SyntaxKind.SourceFile, 0);
|
||||
sourceFile.referenceDiagnostics = [];
|
||||
sourceFile.parseDiagnostics = [];
|
||||
sourceFile.grammarDiagnostics = [];
|
||||
sourceFile.semanticDiagnostics = [];
|
||||
|
||||
// Create and prime the scanner before parsing the source elements.
|
||||
var scanner = createScanner(languageVersion, /*skipTrivia*/ true, sourceText, scanError);
|
||||
var token = nextToken();
|
||||
// Create and prime the scanner before parsing the source elements.
|
||||
scanner = createScanner(languageVersion, /*skipTrivia*/ true, sourceText, scanError);
|
||||
token = nextToken();
|
||||
|
||||
sourceFile.statements = parseList(ParsingContext.SourceElements, /*checkForStrictMode*/ true, parseSourceElement);
|
||||
Debug.assert(token === SyntaxKind.EndOfFileToken);
|
||||
sourceFile.endOfFileToken = parseTokenNode();
|
||||
sourceFile.flags = fileExtensionIs(filename, ".d.ts") ? NodeFlags.DeclarationFile : 0;
|
||||
sourceFile.end = sourceText.length;
|
||||
sourceFile.filename = normalizePath(filename);
|
||||
sourceFile.text = sourceText;
|
||||
|
||||
sourceFile.externalModuleIndicator = getExternalModuleIndicator();
|
||||
sourceFile.getLineAndCharacterFromPosition = getLineAndCharacterFromSourcePosition;
|
||||
sourceFile.getPositionFromLineAndCharacter = getPositionFromSourceLineAndCharacter;
|
||||
sourceFile.getLineStarts = getLineStarts;
|
||||
sourceFile.getSyntacticDiagnostics = getSyntacticDiagnostics;
|
||||
sourceFile.update = update;
|
||||
|
||||
sourceFile.nodeCount = nodeCount;
|
||||
sourceFile.identifierCount = identifierCount;
|
||||
sourceFile.languageVersion = languageVersion;
|
||||
sourceFile.identifiers = identifiers;
|
||||
processReferenceComments(sourceFile);
|
||||
|
||||
if (setParentNodes) {
|
||||
fixupParentReferences(sourceFile);
|
||||
sourceFile.statements = parseList(ParsingContext.SourceElements, /*checkForStrictMode*/ true, parseSourceElement);
|
||||
Debug.assert(token === SyntaxKind.EndOfFileToken);
|
||||
sourceFile.endOfFileToken = parseTokenNode();
|
||||
|
||||
setExternalModuleIndicator(sourceFile);
|
||||
|
||||
sourceFile.nodeCount = nodeCount;
|
||||
sourceFile.identifierCount = identifierCount;
|
||||
sourceFile.languageVersion = languageVersion;
|
||||
sourceFile.identifiers = identifiers;
|
||||
|
||||
if (setParentNodes) {
|
||||
fixupParentReferences(sourceFile);
|
||||
}
|
||||
|
||||
return sourceFile;
|
||||
}
|
||||
|
||||
function update(newText: string, textChangeRange: TextChangeRange) {
|
||||
// Don't pass along the text change range for now. We'll pass it along once incremental
|
||||
// parsing is enabled.
|
||||
return parseSourceFile(newText, /*textChangeRange:*/ undefined, /*setNodeParents*/ true);
|
||||
}
|
||||
|
||||
return sourceFile;
|
||||
|
||||
function setContextFlag(val: Boolean, flag: ParserContextFlags) {
|
||||
if (val) {
|
||||
@ -4467,7 +4491,7 @@ module ts {
|
||||
: parseStatement();
|
||||
}
|
||||
|
||||
function processReferenceComments(): void {
|
||||
function processReferenceComments(sourceFile: SourceFile): void {
|
||||
var triviaScanner = createScanner(languageVersion, /*skipTrivia*/false, sourceText);
|
||||
var referencedFiles: FileReference[] = [];
|
||||
var amdDependencies: string[] = [];
|
||||
@ -4523,16 +4547,15 @@ module ts {
|
||||
sourceFile.amdModuleName = amdModuleName;
|
||||
}
|
||||
|
||||
function getExternalModuleIndicator() {
|
||||
return forEach(sourceFile.statements, node =>
|
||||
function setExternalModuleIndicator(sourceFile: SourceFile) {
|
||||
sourceFile.externalModuleIndicator = forEach(sourceFile.statements, node =>
|
||||
node.flags & NodeFlags.Export
|
||||
|| node.kind === SyntaxKind.ImportDeclaration && (<ImportDeclaration>node).moduleReference.kind === SyntaxKind.ExternalModuleReference
|
||||
|| node.kind === SyntaxKind.ExportAssignment
|
||||
? node
|
||||
: undefined);
|
||||
? node
|
||||
: undefined);
|
||||
}
|
||||
|
||||
var syntacticDiagnostics: Diagnostic[];
|
||||
function getSyntacticDiagnostics() {
|
||||
if (syntacticDiagnostics === undefined) {
|
||||
if (sourceFile.parseDiagnostics.length > 0) {
|
||||
|
||||
@ -866,9 +866,20 @@ module ts {
|
||||
|
||||
filename: string;
|
||||
text: string;
|
||||
|
||||
getLineAndCharacterFromPosition(position: number): LineAndCharacter;
|
||||
getPositionFromLineAndCharacter(line: number, character: number): number;
|
||||
getLineStarts(): number[];
|
||||
|
||||
// Updates this source file to represent the 'newText' passed in. The 'textChangeRange'
|
||||
// parameter indicates what changed between the 'text' that this SourceFile has and the
|
||||
// 'newText'.
|
||||
//
|
||||
// Note: this function mutates nodes from this SourceFile. That means any existing nodes
|
||||
// from this SourceFile that are being held onto may change as a result (including
|
||||
// becoming detached from any SourceFile).
|
||||
update(newText: string, textChangeRange: TextChangeRange): SourceFile;
|
||||
|
||||
amdDependencies: string[];
|
||||
amdModuleName: string;
|
||||
referencedFiles: FileReference[];
|
||||
@ -1435,7 +1446,6 @@ module ts {
|
||||
character: number;
|
||||
}
|
||||
|
||||
|
||||
export const enum ScriptTarget {
|
||||
ES3,
|
||||
ES5,
|
||||
@ -1607,4 +1617,26 @@ module ts {
|
||||
useCaseSensitiveFileNames(): boolean;
|
||||
getNewLine(): string;
|
||||
}
|
||||
|
||||
export interface TextChangeRange {
|
||||
span(): TextSpan;
|
||||
newLength(): number;
|
||||
newSpan(): TextSpan;
|
||||
isUnchanged(): boolean;
|
||||
}
|
||||
|
||||
export interface TextSpan {
|
||||
start(): number;
|
||||
length(): number;
|
||||
end(): number;
|
||||
isEmpty(): boolean;
|
||||
containsPosition(position: number): boolean;
|
||||
containsTextSpan(span: TextSpan): boolean;
|
||||
overlapsWith(span: TextSpan): boolean;
|
||||
overlap(span: TextSpan): TextSpan;
|
||||
intersectsWithTextSpan(span: TextSpan): boolean;
|
||||
intersectsWith(start: number, length: number): boolean;
|
||||
intersectsWithPosition(position: number): boolean;
|
||||
intersection(span: TextSpan): TextSpan;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1755,14 +1755,14 @@ module FourSlash {
|
||||
|
||||
public verifySemanticClassifications(expected: { classificationType: string; text: string }[]) {
|
||||
var actual = this.languageService.getSemanticClassifications(this.activeFile.fileName,
|
||||
new ts.TextSpan(0, this.activeFile.content.length));
|
||||
new ts.TextSpanObject(0, this.activeFile.content.length));
|
||||
|
||||
this.verifyClassifications(expected, actual);
|
||||
}
|
||||
|
||||
public verifySyntacticClassifications(expected: { classificationType: string; text: string }[]) {
|
||||
var actual = this.languageService.getSyntacticClassifications(this.activeFile.fileName,
|
||||
new ts.TextSpan(0, this.activeFile.content.length));
|
||||
new ts.TextSpanObject(0, this.activeFile.content.length));
|
||||
|
||||
this.verifyClassifications(expected, actual);
|
||||
}
|
||||
@ -1796,7 +1796,7 @@ module FourSlash {
|
||||
for (var i = 0; i < spans.length; i++) {
|
||||
var expectedSpan = spans[i];
|
||||
var actualComment = actual[i];
|
||||
var actualCommentSpan = new ts.TextSpan(actualComment.position, actualComment.message.length);
|
||||
var actualCommentSpan = new ts.TextSpanObject(actualComment.position, actualComment.message.length);
|
||||
|
||||
if (expectedSpan.start !== actualCommentSpan.start() || expectedSpan.end !== actualCommentSpan.end()) {
|
||||
this.raiseError('verifyOutliningSpans failed - span ' + (i + 1) + ' expected: (' + expectedSpan.start + ',' + expectedSpan.end + '), actual: (' + actualCommentSpan.start() + ',' + actualCommentSpan.end() + ')');
|
||||
|
||||
@ -32,8 +32,8 @@ module Harness.LanguageService {
|
||||
// Store edit range + new length of script
|
||||
this.editRanges.push({
|
||||
length: this.content.length,
|
||||
textChangeRange: new ts.TextChangeRange(
|
||||
ts.TextSpan.fromBounds(minChar, limChar), newText.length)
|
||||
textChangeRange: new ts.TextChangeRangeObject(
|
||||
ts.TextSpanObject.fromBounds(minChar, limChar), newText.length)
|
||||
});
|
||||
|
||||
// Update version #
|
||||
@ -43,14 +43,14 @@ module Harness.LanguageService {
|
||||
public getTextChangeRangeBetweenVersions(startVersion: number, endVersion: number): ts.TextChangeRange {
|
||||
if (startVersion === endVersion) {
|
||||
// No edits!
|
||||
return ts.TextChangeRange.unchanged;
|
||||
return ts.TextChangeRangeObject.unchanged;
|
||||
}
|
||||
|
||||
var initialEditRangeIndex = this.editRanges.length - (this.version - startVersion);
|
||||
var lastEditRangeIndex = this.editRanges.length - (this.version - endVersion);
|
||||
|
||||
var entries = this.editRanges.slice(initialEditRangeIndex, lastEditRangeIndex);
|
||||
return ts.TextChangeRange.collapseChangesAcrossMultipleVersions(entries.map(e => e.textChangeRange));
|
||||
return ts.TextChangeRangeObject.collapseChangesAcrossMultipleVersions(entries.map(e => e.textChangeRange));
|
||||
}
|
||||
}
|
||||
|
||||
@ -126,7 +126,7 @@ module Harness.LanguageService {
|
||||
isOpen: boolean,
|
||||
textChangeRange: ts.TextChangeRange
|
||||
): ts.SourceFile {
|
||||
return document.update(scriptSnapshot, version, isOpen, textChangeRange);
|
||||
return ts.updateLanguageServiceSourceFile(document, scriptSnapshot, version, isOpen, textChangeRange);
|
||||
}
|
||||
|
||||
public releaseDocument(fileName: string, compilationSettings: ts.CompilerOptions): void {
|
||||
|
||||
@ -38,7 +38,7 @@ module ts.BreakpointResolver {
|
||||
return spanInNode(tokenAtLocation);
|
||||
|
||||
function textSpan(startNode: Node, endNode?: Node) {
|
||||
return TextSpan.fromBounds(startNode.getStart(), (endNode || startNode).getEnd());
|
||||
return TextSpanObject.fromBounds(startNode.getStart(), (endNode || startNode).getEnd());
|
||||
}
|
||||
|
||||
function spanInNodeIfStartsOnSameLine(node: Node, otherwiseOnNode?: Node): TextSpan {
|
||||
|
||||
@ -868,7 +868,7 @@ module ts.formatting {
|
||||
}
|
||||
|
||||
function newTextChange(start: number, len: number, newText: string): TextChange {
|
||||
return { span: new TextSpan(start, len), newText }
|
||||
return { span: new TextSpanObject(start, len), newText }
|
||||
}
|
||||
|
||||
function recordDelete(start: number, len: number) {
|
||||
|
||||
@ -16,7 +16,7 @@
|
||||
///<reference path='references.ts' />
|
||||
|
||||
module ts.formatting {
|
||||
export class TokenSpan extends TextSpan {
|
||||
export class TokenSpan extends TextSpanObject {
|
||||
constructor(public kind: SyntaxKind, start: number, length: number) {
|
||||
super(start, length);
|
||||
}
|
||||
|
||||
@ -462,8 +462,8 @@ module ts.NavigationBar {
|
||||
|
||||
function getNodeSpan(node: Node) {
|
||||
return node.kind === SyntaxKind.SourceFile
|
||||
? TextSpan.fromBounds(node.getFullStart(), node.getEnd())
|
||||
: TextSpan.fromBounds(node.getStart(), node.getEnd());
|
||||
? TextSpanObject.fromBounds(node.getFullStart(), node.getEnd())
|
||||
: TextSpanObject.fromBounds(node.getStart(), node.getEnd());
|
||||
}
|
||||
|
||||
function getTextOfNode(node: Node): string {
|
||||
|
||||
@ -38,8 +38,8 @@ module ts {
|
||||
function addOutliningSpan(hintSpanNode: Node, startElement: Node, endElement: Node, autoCollapse: boolean) {
|
||||
if (hintSpanNode && startElement && endElement) {
|
||||
var span: OutliningSpan = {
|
||||
textSpan: TextSpan.fromBounds(startElement.pos, endElement.end),
|
||||
hintSpan: TextSpan.fromBounds(hintSpanNode.getStart(), hintSpanNode.end),
|
||||
textSpan: TextSpanObject.fromBounds(startElement.pos, endElement.end),
|
||||
hintSpan: TextSpanObject.fromBounds(hintSpanNode.getStart(), hintSpanNode.end),
|
||||
bannerText: collapseText,
|
||||
autoCollapse: autoCollapse
|
||||
};
|
||||
@ -88,7 +88,7 @@ module ts {
|
||||
else {
|
||||
// Block was a standalone block. In this case we want to only collapse
|
||||
// the span of the block, independent of any parent span.
|
||||
var span = TextSpan.fromBounds(n.getStart(), n.end);
|
||||
var span = TextSpanObject.fromBounds(n.getStart(), n.end);
|
||||
elements.push({
|
||||
textSpan: span,
|
||||
hintSpan: span,
|
||||
|
||||
@ -61,10 +61,9 @@ module ts {
|
||||
export interface SourceFile {
|
||||
isOpen: boolean;
|
||||
version: string;
|
||||
scriptSnapshot: IScriptSnapshot;
|
||||
|
||||
getScriptSnapshot(): IScriptSnapshot;
|
||||
getNamedDeclarations(): Declaration[];
|
||||
update(scriptSnapshot: IScriptSnapshot, version: string, isOpen: boolean, textChangeRange: TextChangeRange): SourceFile;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -724,6 +723,7 @@ module ts {
|
||||
public _declarationBrand: any;
|
||||
public filename: string;
|
||||
public text: string;
|
||||
public scriptSnapshot: IScriptSnapshot;
|
||||
|
||||
public statements: NodeArray<Statement>;
|
||||
public endOfFileToken: Node;
|
||||
@ -734,6 +734,7 @@ module ts {
|
||||
public getPositionFromLineAndCharacter: (line: number, character: number) => number;
|
||||
public getLineStarts: () => number[];
|
||||
public getSyntacticDiagnostics: () => Diagnostic[];
|
||||
public update: (newText: string, textChangeRange: TextChangeRange) => SourceFile;
|
||||
|
||||
public amdDependencies: string[];
|
||||
public amdModuleName: string;
|
||||
@ -754,13 +755,8 @@ module ts {
|
||||
public languageVersion: ScriptTarget;
|
||||
public identifiers: Map<string>;
|
||||
|
||||
private scriptSnapshot: IScriptSnapshot;
|
||||
private namedDeclarations: Declaration[];
|
||||
|
||||
public getScriptSnapshot(): IScriptSnapshot {
|
||||
return this.scriptSnapshot;
|
||||
}
|
||||
|
||||
public getNamedDeclarations() {
|
||||
if (!this.namedDeclarations) {
|
||||
var sourceFile = this;
|
||||
@ -846,35 +842,6 @@ module ts {
|
||||
|
||||
return this.namedDeclarations;
|
||||
}
|
||||
|
||||
public update(scriptSnapshot: IScriptSnapshot, version: string, isOpen: boolean, textChangeRange: TextChangeRange): SourceFile {
|
||||
if (textChangeRange && Debug.shouldAssert(AssertionLevel.Normal)) {
|
||||
var oldText = this.scriptSnapshot;
|
||||
var newText = scriptSnapshot;
|
||||
|
||||
Debug.assert((oldText.getLength() - textChangeRange.span().length() + textChangeRange.newLength()) === newText.getLength());
|
||||
|
||||
if (Debug.shouldAssert(AssertionLevel.VeryAggressive)) {
|
||||
var oldTextPrefix = oldText.getText(0, textChangeRange.span().start());
|
||||
var newTextPrefix = newText.getText(0, textChangeRange.span().start());
|
||||
Debug.assert(oldTextPrefix === newTextPrefix);
|
||||
|
||||
var oldTextSuffix = oldText.getText(textChangeRange.span().end(), oldText.getLength());
|
||||
var newTextSuffix = newText.getText(textChangeRange.newSpan().end(), newText.getLength());
|
||||
Debug.assert(oldTextSuffix === newTextSuffix);
|
||||
}
|
||||
}
|
||||
|
||||
return SourceFileObject.createSourceFileObject(this.filename, scriptSnapshot, this.languageVersion, version, isOpen);
|
||||
}
|
||||
|
||||
public static createSourceFileObject(filename: string, scriptSnapshot: IScriptSnapshot, languageVersion: ScriptTarget, version: string, isOpen: boolean) {
|
||||
var newSourceFile = <SourceFileObject><any>createSourceFile(filename, scriptSnapshot.getText(0, scriptSnapshot.getLength()), languageVersion, /*setParentNodes:*/ true);
|
||||
newSourceFile.version = version;
|
||||
newSourceFile.isOpen = isOpen;
|
||||
newSourceFile.scriptSnapshot = scriptSnapshot;
|
||||
return newSourceFile;
|
||||
}
|
||||
}
|
||||
|
||||
export interface Logger {
|
||||
@ -1646,7 +1613,7 @@ module ts {
|
||||
public getChangeRange(filename: string, lastKnownVersion: string, oldScriptSnapshot: IScriptSnapshot): TextChangeRange {
|
||||
var currentVersion = this.getVersion(filename);
|
||||
if (lastKnownVersion === currentVersion) {
|
||||
return TextChangeRange.unchanged; // "No changes"
|
||||
return TextChangeRangeObject.unchanged; // "No changes"
|
||||
}
|
||||
|
||||
var scriptSnapshot = this.getScriptSnapshot(filename);
|
||||
@ -1679,25 +1646,17 @@ module ts {
|
||||
var scriptSnapshot = this.hostCache.getScriptSnapshot(filename);
|
||||
|
||||
var start = new Date().getTime();
|
||||
sourceFile = createLanguageServiceSourceFile(filename, scriptSnapshot, getDefaultCompilerOptions(), version, /*isOpen*/ true);
|
||||
sourceFile = createLanguageServiceSourceFile(filename, scriptSnapshot, ScriptTarget.Latest, version, /*isOpen*/ true, /*setNodeParents;*/ true);
|
||||
this.host.log("SyntaxTreeCache.Initialize: createSourceFile: " + (new Date().getTime() - start));
|
||||
|
||||
var start = new Date().getTime();
|
||||
this.host.log("SyntaxTreeCache.Initialize: fixupParentRefs : " + (new Date().getTime() - start));
|
||||
}
|
||||
else if (this.currentFileVersion !== version) {
|
||||
var scriptSnapshot = this.hostCache.getScriptSnapshot(filename);
|
||||
|
||||
var editRange = this.hostCache.getChangeRange(filename, this.currentFileVersion, this.currentSourceFile.getScriptSnapshot());
|
||||
var editRange = this.hostCache.getChangeRange(filename, this.currentFileVersion, this.currentSourceFile.scriptSnapshot);
|
||||
|
||||
var start = new Date().getTime();
|
||||
sourceFile = !editRange
|
||||
? createLanguageServiceSourceFile(filename, scriptSnapshot, getDefaultCompilerOptions(), version, /*isOpen*/ true)
|
||||
: this.currentSourceFile.update(scriptSnapshot, version, /*isOpen*/ true, editRange);
|
||||
sourceFile = updateLanguageServiceSourceFile(this.currentSourceFile, scriptSnapshot, version, /*isOpen*/ true, editRange);
|
||||
this.host.log("SyntaxTreeCache.Initialize: updateSourceFile: " + (new Date().getTime() - start));
|
||||
|
||||
var start = new Date().getTime();
|
||||
this.host.log("SyntaxTreeCache.Initialize: fixupParentRefs : " + (new Date().getTime() - start));
|
||||
}
|
||||
|
||||
if (sourceFile) {
|
||||
@ -1714,12 +1673,52 @@ module ts {
|
||||
}
|
||||
|
||||
public getCurrentScriptSnapshot(filename: string): IScriptSnapshot {
|
||||
return this.getCurrentSourceFile(filename).getScriptSnapshot();
|
||||
return this.getCurrentSourceFile(filename).scriptSnapshot;
|
||||
}
|
||||
}
|
||||
|
||||
export function createLanguageServiceSourceFile(filename: string, scriptSnapshot: IScriptSnapshot, settings: CompilerOptions, version: string, isOpen: boolean): SourceFile {
|
||||
return SourceFileObject.createSourceFileObject(filename, scriptSnapshot, settings.target, version, isOpen);
|
||||
function setSourceFileFields(sourceFile: SourceFile, scriptSnapshot: IScriptSnapshot, version: string, isOpen: boolean) {
|
||||
sourceFile.version = version;
|
||||
sourceFile.isOpen = isOpen;
|
||||
sourceFile.scriptSnapshot = scriptSnapshot;
|
||||
}
|
||||
|
||||
export function createLanguageServiceSourceFile(filename: string, scriptSnapshot: IScriptSnapshot, scriptTarget: ScriptTarget, version: string, isOpen: boolean, setNodeParents: boolean): SourceFile {
|
||||
var sourceFile = createSourceFile(filename, scriptSnapshot.getText(0, scriptSnapshot.getLength()), scriptTarget, setNodeParents);
|
||||
setSourceFileFields(sourceFile, scriptSnapshot, version, isOpen);
|
||||
return sourceFile;
|
||||
}
|
||||
|
||||
export function updateLanguageServiceSourceFile(sourceFile: SourceFile, scriptSnapshot: IScriptSnapshot, version: string, isOpen: boolean, textChangeRange: TextChangeRange): SourceFile {
|
||||
if (textChangeRange && Debug.shouldAssert(AssertionLevel.Normal)) {
|
||||
var oldText = sourceFile.scriptSnapshot;
|
||||
var newText = scriptSnapshot;
|
||||
|
||||
Debug.assert((oldText.getLength() - textChangeRange.span().length() + textChangeRange.newLength()) === newText.getLength());
|
||||
|
||||
if (Debug.shouldAssert(AssertionLevel.VeryAggressive)) {
|
||||
var oldTextPrefix = oldText.getText(0, textChangeRange.span().start());
|
||||
var newTextPrefix = newText.getText(0, textChangeRange.span().start());
|
||||
Debug.assert(oldTextPrefix === newTextPrefix);
|
||||
|
||||
var oldTextSuffix = oldText.getText(textChangeRange.span().end(), oldText.getLength());
|
||||
var newTextSuffix = newText.getText(textChangeRange.newSpan().end(), newText.getLength());
|
||||
Debug.assert(oldTextSuffix === newTextSuffix);
|
||||
}
|
||||
}
|
||||
|
||||
// If we were given a text change range, and our version or open-ness changed, then
|
||||
// incrementally parse this file.
|
||||
if (textChangeRange) {
|
||||
if (version !== sourceFile.version || isOpen != sourceFile.isOpen) {
|
||||
var newSourceFile = sourceFile.update(scriptSnapshot.getText(0, scriptSnapshot.getLength()), textChangeRange);
|
||||
setSourceFileFields(newSourceFile, scriptSnapshot, version, isOpen);
|
||||
return newSourceFile;
|
||||
}
|
||||
}
|
||||
|
||||
// Otherwise, just create a new source file.
|
||||
return createLanguageServiceSourceFile(sourceFile.filename, scriptSnapshot, sourceFile.languageVersion, version, isOpen, /*setNodeParents:*/ true);
|
||||
}
|
||||
|
||||
export function createDocumentRegistry(): DocumentRegistry {
|
||||
@ -1769,7 +1768,7 @@ module ts {
|
||||
var bucket = getBucketForCompilationSettings(compilationSettings, /*createIfMissing*/ true);
|
||||
var entry = lookUp(bucket, filename);
|
||||
if (!entry) {
|
||||
var sourceFile = createLanguageServiceSourceFile(filename, scriptSnapshot, compilationSettings, version, isOpen);
|
||||
var sourceFile = createLanguageServiceSourceFile(filename, scriptSnapshot, compilationSettings.target, version, isOpen, /*setNodeParents:*/ false);
|
||||
|
||||
bucket[filename] = entry = {
|
||||
sourceFile: sourceFile,
|
||||
@ -1797,11 +1796,7 @@ module ts {
|
||||
var entry = lookUp(bucket, filename);
|
||||
Debug.assert(entry !== undefined);
|
||||
|
||||
if (entry.sourceFile.isOpen === isOpen && entry.sourceFile.version === version) {
|
||||
return entry.sourceFile;
|
||||
}
|
||||
|
||||
entry.sourceFile = entry.sourceFile.update(scriptSnapshot, version, isOpen, textChangeRange);
|
||||
entry.sourceFile = updateLanguageServiceSourceFile(entry.sourceFile, scriptSnapshot, version, isOpen, textChangeRange);
|
||||
return entry.sourceFile;
|
||||
}
|
||||
|
||||
@ -2225,7 +2220,7 @@ module ts {
|
||||
// new text buffer).
|
||||
var textChangeRange: TextChangeRange = null;
|
||||
if (sourceFile.isOpen && isOpen) {
|
||||
textChangeRange = hostCache.getChangeRange(filename, sourceFile.version, sourceFile.getScriptSnapshot());
|
||||
textChangeRange = hostCache.getChangeRange(filename, sourceFile.version, sourceFile.scriptSnapshot);
|
||||
}
|
||||
|
||||
sourceFile = documentRegistry.updateDocument(sourceFile, filename, compilationSettings, scriptSnapshot, version, isOpen, textChangeRange);
|
||||
@ -3223,7 +3218,7 @@ module ts {
|
||||
return {
|
||||
kind: ScriptElementKind.unknown,
|
||||
kindModifiers: ScriptElementKindModifier.none,
|
||||
textSpan: new TextSpan(node.getStart(), node.getWidth()),
|
||||
textSpan: new TextSpanObject(node.getStart(), node.getWidth()),
|
||||
displayParts: typeToDisplayParts(typeInfoResolver, type, getContainerNode(node)),
|
||||
documentation: type.symbol ? type.symbol.getDocumentationComment() : undefined
|
||||
};
|
||||
@ -3237,7 +3232,7 @@ module ts {
|
||||
return {
|
||||
kind: displayPartsDocumentationsAndKind.symbolKind,
|
||||
kindModifiers: getSymbolModifiers(symbol),
|
||||
textSpan: new TextSpan(node.getStart(), node.getWidth()),
|
||||
textSpan: new TextSpanObject(node.getStart(), node.getWidth()),
|
||||
displayParts: displayPartsDocumentationsAndKind.displayParts,
|
||||
documentation: displayPartsDocumentationsAndKind.documentation
|
||||
};
|
||||
@ -3248,7 +3243,7 @@ module ts {
|
||||
function getDefinitionInfo(node: Node, symbolKind: string, symbolName: string, containerName: string): DefinitionInfo {
|
||||
return {
|
||||
fileName: node.getSourceFile().filename,
|
||||
textSpan: TextSpan.fromBounds(node.getStart(), node.getEnd()),
|
||||
textSpan: TextSpanObject.fromBounds(node.getStart(), node.getEnd()),
|
||||
kind: symbolKind,
|
||||
name: symbolName,
|
||||
containerKind: undefined,
|
||||
@ -3325,7 +3320,7 @@ module ts {
|
||||
if (referenceFile) {
|
||||
return [{
|
||||
fileName: referenceFile.filename,
|
||||
textSpan: TextSpan.fromBounds(0, 0),
|
||||
textSpan: TextSpanObject.fromBounds(0, 0),
|
||||
kind: ScriptElementKind.scriptElement,
|
||||
name: comment.filename,
|
||||
containerName: undefined,
|
||||
@ -3516,7 +3511,7 @@ module ts {
|
||||
if (shouldHighlightNextKeyword) {
|
||||
result.push({
|
||||
fileName: filename,
|
||||
textSpan: TextSpan.fromBounds(elseKeyword.getStart(), ifKeyword.end),
|
||||
textSpan: TextSpanObject.fromBounds(elseKeyword.getStart(), ifKeyword.end),
|
||||
isWriteAccess: false
|
||||
});
|
||||
i++; // skip the next keyword
|
||||
@ -4208,7 +4203,7 @@ module ts {
|
||||
(findInComments && isInComment(position))) {
|
||||
result.push({
|
||||
fileName: sourceFile.filename,
|
||||
textSpan: new TextSpan(position, searchText.length),
|
||||
textSpan: new TextSpanObject(position, searchText.length),
|
||||
isWriteAccess: false
|
||||
});
|
||||
}
|
||||
@ -4591,7 +4586,7 @@ module ts {
|
||||
|
||||
return {
|
||||
fileName: node.getSourceFile().filename,
|
||||
textSpan: TextSpan.fromBounds(start, end),
|
||||
textSpan: TextSpanObject.fromBounds(start, end),
|
||||
isWriteAccess: isWriteAccess(node)
|
||||
};
|
||||
}
|
||||
@ -4647,7 +4642,7 @@ module ts {
|
||||
kindModifiers: getNodeModifiers(declaration),
|
||||
matchKind: MatchKind[matchKind],
|
||||
fileName: filename,
|
||||
textSpan: TextSpan.fromBounds(declaration.getStart(), declaration.getEnd()),
|
||||
textSpan: TextSpanObject.fromBounds(declaration.getStart(), declaration.getEnd()),
|
||||
// TODO(jfreeman): What should be the containerName when the container has a computed name?
|
||||
containerName: container && container.name ? (<Identifier>container.name).text : "",
|
||||
containerKind: container && container.name ? getNodeKind(container) : ""
|
||||
@ -4924,7 +4919,7 @@ module ts {
|
||||
}
|
||||
}
|
||||
|
||||
return TextSpan.fromBounds(nodeForStartPos.getStart(), node.getEnd());
|
||||
return TextSpanObject.fromBounds(nodeForStartPos.getStart(), node.getEnd());
|
||||
}
|
||||
|
||||
function getBreakpointStatementAtPosition(filename: string, position: number) {
|
||||
@ -5001,7 +4996,7 @@ module ts {
|
||||
var type = classifySymbol(symbol, getMeaningFromLocation(node));
|
||||
if (type) {
|
||||
result.push({
|
||||
textSpan: new TextSpan(node.getStart(), node.getWidth()),
|
||||
textSpan: new TextSpanObject(node.getStart(), node.getWidth()),
|
||||
classificationType: type
|
||||
});
|
||||
}
|
||||
@ -5027,7 +5022,7 @@ module ts {
|
||||
var width = comment.end - comment.pos;
|
||||
if (span.intersectsWith(comment.pos, width)) {
|
||||
result.push({
|
||||
textSpan: new TextSpan(comment.pos, width),
|
||||
textSpan: new TextSpanObject(comment.pos, width),
|
||||
classificationType: ClassificationTypeNames.comment
|
||||
});
|
||||
}
|
||||
@ -5040,7 +5035,7 @@ module ts {
|
||||
var type = classifyTokenType(token);
|
||||
if (type) {
|
||||
result.push({
|
||||
textSpan: new TextSpan(token.getStart(), token.getWidth()),
|
||||
textSpan: new TextSpanObject(token.getStart(), token.getWidth()),
|
||||
classificationType: type
|
||||
});
|
||||
}
|
||||
@ -5168,8 +5163,8 @@ module ts {
|
||||
var current = childNodes[i];
|
||||
|
||||
if (current.kind === matchKind) {
|
||||
var range1 = new TextSpan(token.getStart(sourceFile), token.getWidth(sourceFile));
|
||||
var range2 = new TextSpan(current.getStart(sourceFile), current.getWidth(sourceFile));
|
||||
var range1 = new TextSpanObject(token.getStart(sourceFile), token.getWidth(sourceFile));
|
||||
var range2 = new TextSpanObject(current.getStart(sourceFile), current.getWidth(sourceFile));
|
||||
|
||||
// We want to order the braces when we return the result.
|
||||
if (range1.start() < range2.start()) {
|
||||
@ -5420,7 +5415,7 @@ module ts {
|
||||
if (kind) {
|
||||
return getRenameInfo(symbol.name, typeInfoResolver.getFullyQualifiedName(symbol), kind,
|
||||
getSymbolModifiers(symbol),
|
||||
new TextSpan(node.getStart(), node.getWidth()));
|
||||
new TextSpanObject(node.getStart(), node.getWidth()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -328,8 +328,8 @@ module ts {
|
||||
}
|
||||
|
||||
var decoded: { span: { start: number; length: number; }; newLength: number; } = JSON.parse(encoded);
|
||||
return new TextChangeRange(
|
||||
new TextSpan(decoded.span.start, decoded.span.length), decoded.newLength);
|
||||
return new TextChangeRangeObject(
|
||||
new TextSpanObject(decoded.span.start, decoded.span.length), decoded.newLength);
|
||||
}
|
||||
}
|
||||
|
||||
@ -510,7 +510,7 @@ module ts {
|
||||
return this.forwardJSONCall(
|
||||
"getSyntacticClassifications('" + fileName + "', " + start + ", " + length + ")",
|
||||
() => {
|
||||
var classifications = this.languageService.getSyntacticClassifications(fileName, new TextSpan(start, length));
|
||||
var classifications = this.languageService.getSyntacticClassifications(fileName, new TextSpanObject(start, length));
|
||||
return classifications;
|
||||
});
|
||||
}
|
||||
@ -519,7 +519,7 @@ module ts {
|
||||
return this.forwardJSONCall(
|
||||
"getSemanticClassifications('" + fileName + "', " + start + ", " + length + ")",
|
||||
() => {
|
||||
var classifications = this.languageService.getSemanticClassifications(fileName, new TextSpan(start, length));
|
||||
var classifications = this.languageService.getSemanticClassifications(fileName, new TextSpanObject(start, length));
|
||||
return classifications;
|
||||
});
|
||||
}
|
||||
|
||||
@ -367,7 +367,7 @@ module ts.SignatureHelp {
|
||||
// but not including parentheses)
|
||||
var applicableSpanStart = argumentsList.getFullStart();
|
||||
var applicableSpanEnd = skipTrivia(sourceFile.text, argumentsList.getEnd(), /*stopAfterLineBreak*/ false);
|
||||
return new TextSpan(applicableSpanStart, applicableSpanEnd - applicableSpanStart);
|
||||
return new TextSpanObject(applicableSpanStart, applicableSpanEnd - applicableSpanStart);
|
||||
}
|
||||
|
||||
function getApplicableSpanForTaggedTemplate(taggedTemplate: TaggedTemplateExpression): TextSpan {
|
||||
@ -391,7 +391,7 @@ module ts.SignatureHelp {
|
||||
}
|
||||
}
|
||||
|
||||
return new TextSpan(applicableSpanStart, applicableSpanEnd - applicableSpanStart);
|
||||
return new TextSpanObject(applicableSpanStart, applicableSpanEnd - applicableSpanStart);
|
||||
}
|
||||
|
||||
function getContainingArgumentInfo(node: Node): ArgumentListInfo {
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
module ts {
|
||||
export class TextSpan {
|
||||
export class TextSpanObject {
|
||||
private _start: number;
|
||||
private _length: number;
|
||||
|
||||
@ -49,7 +49,7 @@ module ts {
|
||||
* @param span The span to check.
|
||||
*/
|
||||
public containsTextSpan(span: TextSpan): boolean {
|
||||
return span._start >= this._start && span.end() <= this.end();
|
||||
return span.start() >= this._start && span.end() <= this.end();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -59,7 +59,7 @@ module ts {
|
||||
* @param span The span to check.
|
||||
*/
|
||||
public overlapsWith(span: TextSpan): boolean {
|
||||
var overlapStart = Math.max(this._start, span._start);
|
||||
var overlapStart = Math.max(this._start, span.start());
|
||||
var overlapEnd = Math.min(this.end(), span.end());
|
||||
|
||||
return overlapStart < overlapEnd;
|
||||
@ -70,11 +70,11 @@ module ts {
|
||||
* @param span The span to check.
|
||||
*/
|
||||
public overlap(span: TextSpan): TextSpan {
|
||||
var overlapStart = Math.max(this._start, span._start);
|
||||
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 TextSpanObject.fromBounds(overlapStart, overlapEnd);
|
||||
}
|
||||
|
||||
return undefined;
|
||||
@ -87,7 +87,7 @@ module ts {
|
||||
* @param The span to check.
|
||||
*/
|
||||
public intersectsWithTextSpan(span: TextSpan): boolean {
|
||||
return span._start <= this.end() && span.end() >= this._start;
|
||||
return span.start() <= this.end() && span.end() >= this._start;
|
||||
}
|
||||
|
||||
public intersectsWith(start: number, length: number): boolean {
|
||||
@ -110,11 +110,11 @@ module ts {
|
||||
* @param span The span to check.
|
||||
*/
|
||||
public intersection(span: TextSpan): TextSpan {
|
||||
var intersectStart = Math.max(this._start, span._start);
|
||||
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 TextSpanObject.fromBounds(intersectStart, intersectEnd);
|
||||
}
|
||||
|
||||
return undefined;
|
||||
@ -127,12 +127,12 @@ module ts {
|
||||
public static fromBounds(start: number, end: number): TextSpan {
|
||||
Debug.assert(start >= 0);
|
||||
Debug.assert(end - start >= 0);
|
||||
return new TextSpan(start, end - start);
|
||||
return new TextSpanObject(start, end - start);
|
||||
}
|
||||
}
|
||||
|
||||
export class TextChangeRange {
|
||||
public static unchanged = new TextChangeRange(new TextSpan(0, 0), 0);
|
||||
export class TextChangeRangeObject implements TextChangeRange {
|
||||
public static unchanged = new TextChangeRangeObject(new TextSpanObject(0, 0), 0);
|
||||
|
||||
private _span: TextSpan;
|
||||
private _newLength: number;
|
||||
@ -162,7 +162,7 @@ module ts {
|
||||
}
|
||||
|
||||
public newSpan(): TextSpan {
|
||||
return new TextSpan(this.span().start(), this.newLength());
|
||||
return new TextSpanObject(this.span().start(), this.newLength());
|
||||
}
|
||||
|
||||
public isUnchanged(): boolean {
|
||||
@ -179,7 +179,7 @@ module ts {
|
||||
*/
|
||||
public static collapseChangesAcrossMultipleVersions(changes: TextChangeRange[]): TextChangeRange {
|
||||
if (changes.length === 0) {
|
||||
return TextChangeRange.unchanged;
|
||||
return TextChangeRangeObject.unchanged;
|
||||
}
|
||||
|
||||
if (changes.length === 1) {
|
||||
@ -290,7 +290,7 @@ module ts {
|
||||
newEndN = Math.max(newEnd2, newEnd2 + (newEnd1 - oldEnd2));
|
||||
}
|
||||
|
||||
return new TextChangeRange(TextSpan.fromBounds(oldStartN, oldEndN), /*newLength: */newEndN - oldStartN);
|
||||
return new TextChangeRangeObject(TextSpanObject.fromBounds(oldStartN, oldEndN), /*newLength: */newEndN - oldStartN);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -6,7 +6,7 @@ module ts {
|
||||
var contents = text.getText(0, text.getLength());
|
||||
var newContents = contents.substr(0, start) + newText + contents.substring(start + length);
|
||||
|
||||
return { text: ScriptSnapshot.fromString(newContents), textChangeRange: new TextChangeRange(new TextSpan(start, length), newText.length) }
|
||||
return { text: ScriptSnapshot.fromString(newContents), textChangeRange: new TextChangeRangeObject(new TextSpanObject(start, length), newText.length) }
|
||||
}
|
||||
|
||||
function withInsert(text: IScriptSnapshot, start: number, newText: string): { text: IScriptSnapshot; textChangeRange: TextChangeRange; } {
|
||||
@ -18,10 +18,7 @@ module ts {
|
||||
}
|
||||
|
||||
function createTree(text: IScriptSnapshot, version: string) {
|
||||
var options: CompilerOptions = {};
|
||||
options.target = ScriptTarget.ES5;
|
||||
|
||||
return createLanguageServiceSourceFile(/*fileName:*/ "", text, options, version, /*isOpen:*/ true)
|
||||
return createLanguageServiceSourceFile(/*fileName:*/ "", text, ScriptTarget.Latest, version, /*isOpen:*/ true, /*setNodeParents:*/ true)
|
||||
}
|
||||
|
||||
// NOTE: 'reusedElements' is the expected count of elements reused from the old tree to the new
|
||||
@ -38,7 +35,7 @@ module ts {
|
||||
Utils.assertInvariants(newTree, /*parent:*/ undefined);
|
||||
|
||||
// Create a tree for the new text, in an incremental fashion.
|
||||
var incrementalNewTree = oldTree.update(newText, oldTree.version + ".", /*isOpen:*/ true, textChangeRange);
|
||||
var incrementalNewTree = updateLanguageServiceSourceFile(oldTree, newText, oldTree.version + ".", /*isOpen:*/ true, textChangeRange);
|
||||
Utils.assertInvariants(incrementalNewTree, /*parent:*/ undefined);
|
||||
|
||||
// We should get the same tree when doign a full or incremental parse.
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user