From 8004fec2ceebc69c2dad06c61990bb47c8cd8daf Mon Sep 17 00:00:00 2001 From: Armando Aguirre Date: Wed, 18 Oct 2017 14:48:06 -0700 Subject: [PATCH] Addressed PR comments: added simplified/full version, changed design --- src/harness/harnessLanguageService.ts | 4 +-- src/server/client.ts | 19 ++++++++++-- src/server/protocol.ts | 4 +++ src/server/session.ts | 31 ++++++++++--------- src/services/goToDefinition.ts | 17 +++++++++- src/services/services.ts | 13 ++------ src/services/shims.ts | 13 ++++++++ .../reference/api/tsserverlibrary.d.ts | 8 +++-- 8 files changed, 76 insertions(+), 33 deletions(-) diff --git a/src/harness/harnessLanguageService.ts b/src/harness/harnessLanguageService.ts index 2ec40a8981d..9740d493662 100644 --- a/src/harness/harnessLanguageService.ts +++ b/src/harness/harnessLanguageService.ts @@ -432,8 +432,8 @@ namespace Harness.LanguageService { getDefinitionAtPosition(fileName: string, position: number): ts.DefinitionInfo[] { return unwrapJSONCallResult(this.shim.getDefinitionAtPosition(fileName, position)); } - getDefinitionAndBoundSpan(): ts.DefinitionInfoAndBoundSpan { - throw new Error("Not supported on the shim."); + getDefinitionAndBoundSpan(fileName: string, position: number): ts.DefinitionInfoAndBoundSpan { + return unwrapJSONCallResult(this.shim.getDefinitionAndBoundSpan(fileName, position)); } getTypeDefinitionAtPosition(fileName: string, position: number): ts.DefinitionInfo[] { return unwrapJSONCallResult(this.shim.getTypeDefinitionAtPosition(fileName, position)); diff --git a/src/server/client.ts b/src/server/client.ts index 0fe5f48ed31..c0208d74903 100644 --- a/src/server/client.ts +++ b/src/server/client.ts @@ -268,8 +268,23 @@ namespace ts.server { })); } - getDefinitionAndBoundSpan(_fileName: string, _position: number): DefinitionInfoAndBoundSpan { - return notImplemented(); + getDefinitionAndBoundSpan(fileName: string, position: number): DefinitionInfoAndBoundSpan { + const args: protocol.FileLocationRequestArgs = this.createFileLocationRequestArgs(fileName, position); + + const request = this.processRequest(CommandNames.DefinitionAndBoundSpan, args); + const response = this.processResponse(request); + + return { + definitions: response.body.definitions.map(entry => ({ + containerKind: ScriptElementKind.unknown, + containerName: "", + fileName: entry.file, + textSpan: this.decodeSpan(entry), + kind: ScriptElementKind.unknown, + name: "" + })), + textSpan: this.decodeSpan(response.body.textSpan, request.arguments.file) + }; } getTypeDefinitionAtPosition(fileName: string, position: number): DefinitionInfo[] { diff --git a/src/server/protocol.ts b/src/server/protocol.ts index 327c351ba6f..21b090548ff 100644 --- a/src/server/protocol.ts +++ b/src/server/protocol.ts @@ -703,6 +703,10 @@ namespace ts.server.protocol { body?: FileSpan[]; } + export interface DefinitionInfoAndBoundSpanReponse extends Response { + body?: DefinitionInfoAndBoundSpan; + } + /** * Definition response message. Gives text range for definition. */ diff --git a/src/server/session.ts b/src/server/session.ts index 54ac3082c18..fb37bf55408 100644 --- a/src/server/session.ts +++ b/src/server/session.ts @@ -601,7 +601,7 @@ namespace ts.server { } if (simplifiedResult) { - return this.getSimplifiedDefinition(definitions, project); + return this.getSimplifiedDefinitions(definitions, project); } else { return definitions; @@ -624,28 +624,29 @@ namespace ts.server { if (simplifiedResult) { return { - definitions: this.getSimplifiedDefinition(definitionAndBoundSpan.definitions, project), - textSpan: this.getSimplifiedTextSpan(definitionAndBoundSpan.textSpan, scriptInfo) + definitions: this.getSimplifiedDefinitions(definitionAndBoundSpan.definitions, project), + textSpan: this.getSimplifiedTextSpan(scriptInfo, definitionAndBoundSpan.textSpan) }; } return definitionAndBoundSpan; } - private getSimplifiedDefinition(definitions: ReadonlyArray, project: Project): ReadonlyArray { - return definitions.map(def => { - const defScriptInfo = project.getScriptInfo(def.fileName); - const simplifiedTextSpan = this.getSimplifiedTextSpan(def.textSpan, defScriptInfo); - - return { - file: def.fileName, - start: simplifiedTextSpan.start, - end: simplifiedTextSpan.end - }; - }); + private getSimplifiedDefinitions(definitions: ReadonlyArray, project: Project): ReadonlyArray { + return definitions.map(def => this.getSimplifiedFileSpan(def.fileName, def.textSpan, project)); } - private getSimplifiedTextSpan(textSpan: TextSpan, scriptInfo: ScriptInfo): protocol.TextSpan { + private getSimplifiedFileSpan(fileName: string, textSpan: TextSpan, project: Project): protocol.FileSpan { + const scriptInfo = project.getScriptInfo(fileName); + const simplifiedTextSpan = this.getSimplifiedTextSpan(scriptInfo, textSpan); + + return { + file: fileName, + ...simplifiedTextSpan + }; + } + + private getSimplifiedTextSpan(scriptInfo: ScriptInfo, textSpan: TextSpan): protocol.TextSpan { return { start: scriptInfo.positionToLineOffset(textSpan.start), end: scriptInfo.positionToLineOffset(textSpanEnd(textSpan)) diff --git a/src/services/goToDefinition.ts b/src/services/goToDefinition.ts index cb2be7d484c..158d6d6ac6f 100644 --- a/src/services/goToDefinition.ts +++ b/src/services/goToDefinition.ts @@ -88,7 +88,7 @@ namespace ts.GoToDefinition { // } // bar(({pr/*goto*/op1})=>{}); if (isPropertyName(node) && isBindingElement(node.parent) && isObjectBindingPattern(node.parent.parent) && - (node === (node.parent.propertyName || node.parent.name))) { + (node === (node.parent.propertyName || node.parent.name))) { const type = typeChecker.getTypeAtLocation(node.parent.parent); if (type) { const propSymbols = getPropertySymbolsFromType(type, node); @@ -149,6 +149,21 @@ namespace ts.GoToDefinition { return getDefinitionFromSymbol(typeChecker, type.symbol, node); } + export function getDefinitionAndBoundSpan(program: Program, sourceFile: SourceFile, position: number): DefinitionInfoAndBoundSpan { + const definitions = getDefinitionAtPosition(program, sourceFile, position); + + if (!definitions || definitions.length === 0) { + return undefined; + } + + // TODO: Add textSpan for triple slash references (file and type). + + const node = getTouchingPropertyName(sourceFile, position, /*includeJsDocComment*/ true); + const textSpan = createTextSpan(node.getStart(), node.getWidth()); + + return { definitions, textSpan }; + } + // Go to the original declaration for cases: // // (1) when the aliased symbol was declared in the location(parent). diff --git a/src/services/services.ts b/src/services/services.ts index f2702082470..90ff50e45d0 100644 --- a/src/services/services.ts +++ b/src/services/services.ts @@ -1412,17 +1412,8 @@ namespace ts { } function getDefinitionAndBoundSpan(fileName: string, position: number): DefinitionInfoAndBoundSpan { - const definitions = getDefinitionAtPosition(fileName, position); - - if (!definitions) { - return undefined; - } - - const sourceFile = getValidSourceFile(fileName); - const node = getTouchingPropertyName(sourceFile, position, /*includeJsDocComment*/ true); - const textSpan = createTextSpan(node.getStart(), node.getWidth()); - - return { definitions, textSpan }; + synchronizeHostData(); + return GoToDefinition.getDefinitionAndBoundSpan(program, getValidSourceFile(fileName), position); } function getTypeDefinitionAtPosition(fileName: string, position: number): DefinitionInfo[] { diff --git a/src/services/shims.ts b/src/services/shims.ts index 9d4baccc3c4..f97628d6388 100644 --- a/src/services/shims.ts +++ b/src/services/shims.ts @@ -170,6 +170,8 @@ namespace ts { */ getDefinitionAtPosition(fileName: string, position: number): string; + getDefinitionAndBoundSpan(fileName: string, position: number): string; + /** * Returns a JSON-encoded value of the type: * { fileName: string; textSpan: { start: number; length: number}; kind: string; name: string; containerKind: string; containerName: string } @@ -772,6 +774,17 @@ namespace ts { ); } + /** + * Computes the definition location and file for the symbol + * at the requested position. + */ + public getDefinitionAndBoundSpan(fileName: string, position: number): string { + return this.forwardJSONCall( + `getDefinitionAndBoundSpan('${fileName}', ${position})`, + () => this.languageService.getDefinitionAndBoundSpan(fileName, position) + ); + } + /// GOTO Type /** diff --git a/tests/baselines/reference/api/tsserverlibrary.d.ts b/tests/baselines/reference/api/tsserverlibrary.d.ts index b69b44e98a0..306f15e9521 100644 --- a/tests/baselines/reference/api/tsserverlibrary.d.ts +++ b/tests/baselines/reference/api/tsserverlibrary.d.ts @@ -5313,6 +5313,9 @@ declare namespace ts.server.protocol { interface DefinitionResponse extends Response { body?: FileSpan[]; } + interface DefinitionInfoAndBoundSpanReponse extends Response { + body?: DefinitionInfoAndBoundSpan; + } /** * Definition response message. Gives text range for definition. */ @@ -6865,8 +6868,9 @@ declare namespace ts.server { private getDiagnosticsWorker(args, isSemantic, selector, includeLinePosition); private getDefinition(args, simplifiedResult); private getDefinitionAndBoundSpan(args, simplifiedResult); - private getSimplifiedDefinition(definitions, project); - private getSimplifiedTextSpan(textSpan, scriptInfo); + private getSimplifiedDefinitions(definitions, project); + private getSimplifiedFileSpan(fileName, textSpan, project); + private getSimplifiedTextSpan(scriptInfo, textSpan); private getTypeDefinition(args); private getImplementation(args, simplifiedResult); private getOccurrences(args);