From d8936fd2906c66c294420e35f1dce654eeac6a13 Mon Sep 17 00:00:00 2001 From: Andrew Branch Date: Thu, 18 Apr 2019 16:23:06 -0700 Subject: [PATCH] Rename to be smarter --- src/harness/client.ts | 2 +- src/harness/harnessLanguageService.ts | 4 +- src/server/session.ts | 8 +-- src/services/services.ts | 6 +-- src/services/shims.ts | 8 +-- .../{selectionRange.ts => smartSelection.ts} | 4 +- src/services/tsconfig.json | 2 +- src/services/types.ts | 2 +- .../unittests/tsserver/selectionRange.ts | 54 +++++++++---------- .../reference/api/tsserverlibrary.d.ts | 24 ++++++++- tests/baselines/reference/api/typescript.d.ts | 5 ++ .../TypeScript-Node-Starter | 2 +- .../user/create-react-app/create-react-app | 2 +- tests/cases/user/prettier/prettier | 2 +- 14 files changed, 76 insertions(+), 49 deletions(-) rename src/services/{selectionRange.ts => smartSelection.ts} (97%) diff --git a/src/harness/client.ts b/src/harness/client.ts index bb9e674bbc6..d223f9f5fe3 100644 --- a/src/harness/client.ts +++ b/src/harness/client.ts @@ -424,7 +424,7 @@ namespace ts.server { return renameInfo; } - getSelectionRange() { + getSmartSelectionRange() { return notImplemented(); } diff --git a/src/harness/harnessLanguageService.ts b/src/harness/harnessLanguageService.ts index fff02e5b94a..03ccbb5d6de 100644 --- a/src/harness/harnessLanguageService.ts +++ b/src/harness/harnessLanguageService.ts @@ -472,8 +472,8 @@ namespace Harness.LanguageService { getRenameInfo(fileName: string, position: number, options?: ts.RenameInfoOptions): ts.RenameInfo { return unwrapJSONCallResult(this.shim.getRenameInfo(fileName, position, options)); } - getSelectionRange(fileName: string, position: number): ts.SelectionRange { - return unwrapJSONCallResult(this.shim.getSelectionRange(fileName, position)); + getSmartSelectionRange(fileName: string, position: number): ts.SelectionRange { + return unwrapJSONCallResult(this.shim.getSmartSelectionRange(fileName, position)); } findRenameLocations(fileName: string, position: number, findInStrings: boolean, findInComments: boolean, providePrefixAndSuffixTextForRename?: boolean): ts.RenameLocation[] { return unwrapJSONCallResult(this.shim.findRenameLocations(fileName, position, findInStrings, findInComments, providePrefixAndSuffixTextForRename)); diff --git a/src/server/session.ts b/src/server/session.ts index 261356f2cd0..2e9d6948b1a 100644 --- a/src/server/session.ts +++ b/src/server/session.ts @@ -2059,14 +2059,14 @@ namespace ts.server { this.projectService.configurePlugin(args); } - private getSelectionRange(args: protocol.SelectionRangeRequestArgs, simplifiedResult: boolean) { + private getSmartSelectionRange(args: protocol.SelectionRangeRequestArgs, simplifiedResult: boolean) { const { locations } = args; const { file, languageService } = this.getFileAndLanguageServiceForSyntacticOperation(args); const scriptInfo = Debug.assertDefined(this.projectService.getScriptInfo(file)); return map(locations, location => { const pos = this.getPosition(location, scriptInfo); - const selectionRange = languageService.getSelectionRange(file, pos); + const selectionRange = languageService.getSmartSelectionRange(file, pos); return simplifiedResult ? this.mapSelectionRange(selectionRange, scriptInfo) : selectionRange; }); } @@ -2438,10 +2438,10 @@ namespace ts.server { return this.notRequired(); }, [CommandNames.SelectionRange]: (request: protocol.SelectionRangeRequest) => { - return this.requiredResponse(this.getSelectionRange(request.arguments, /*simplifiedResult*/ true)); + return this.requiredResponse(this.getSmartSelectionRange(request.arguments, /*simplifiedResult*/ true)); }, [CommandNames.SelectionRangeFull]: (request: protocol.SelectionRangeRequest) => { - return this.requiredResponse(this.getSelectionRange(request.arguments, /*simplifiedResult*/ false)); + return this.requiredResponse(this.getSmartSelectionRange(request.arguments, /*simplifiedResult*/ false)); }, }); diff --git a/src/services/services.ts b/src/services/services.ts index 721777c2bad..64fe3bca664 100644 --- a/src/services/services.ts +++ b/src/services/services.ts @@ -2087,8 +2087,8 @@ namespace ts { }; } - function getSelectionRange(fileName: string, position: number): SelectionRange { - return SelectionRange.getSelectionRange(position, syntaxTreeCache.getCurrentSourceFile(fileName)); + function getSmartSelectionRange(fileName: string, position: number): SelectionRange { + return SmartSelectionRange.getSmartSelectionRange(position, syntaxTreeCache.getCurrentSourceFile(fileName)); } function getApplicableRefactors(fileName: string, positionOrRange: number | TextRange, preferences: UserPreferences = emptyOptions): ApplicableRefactorInfo[] { @@ -2138,7 +2138,7 @@ namespace ts { getBreakpointStatementAtPosition, getNavigateToItems, getRenameInfo, - getSelectionRange, + getSmartSelectionRange, findRenameLocations, getNavigationBarItems, getNavigationTree, diff --git a/src/services/shims.ts b/src/services/shims.ts index 3f3b3c2bef6..e914a4acd42 100644 --- a/src/services/shims.ts +++ b/src/services/shims.ts @@ -165,7 +165,7 @@ namespace ts { * { canRename: boolean, localizedErrorMessage: string, displayName: string, fullDisplayName: string, kind: string, kindModifiers: string, triggerSpan: { start; length } } */ getRenameInfo(fileName: string, position: number, options?: RenameInfoOptions): string; - getSelectionRange(fileName: string, position: number): string; + getSmartSelectionRange(fileName: string, position: number): string; /** * Returns a JSON-encoded value of the type: @@ -839,10 +839,10 @@ namespace ts { ); } - public getSelectionRange(fileName: string, position: number): string { + public getSmartSelectionRange(fileName: string, position: number): string { return this.forwardJSONCall( - `getSelectionRange('${fileName}', ${position})`, - () => this.languageService.getSelectionRange(fileName, position) + `getSmartSelectionRange('${fileName}', ${position})`, + () => this.languageService.getSmartSelectionRange(fileName, position) ); } diff --git a/src/services/selectionRange.ts b/src/services/smartSelection.ts similarity index 97% rename from src/services/selectionRange.ts rename to src/services/smartSelection.ts index 0ec0641a8a2..ba2ec60e9c5 100644 --- a/src/services/selectionRange.ts +++ b/src/services/smartSelection.ts @@ -1,6 +1,6 @@ /* @internal */ -namespace ts.SelectionRange { - export function getSelectionRange(pos: number, sourceFile: SourceFile): SelectionRange { +namespace ts.SmartSelectionRange { + export function getSmartSelectionRange(pos: number, sourceFile: SourceFile): SelectionRange { let selectionRange: SelectionRange = { textSpan: createTextSpanFromBounds(sourceFile.getFullStart(), sourceFile.getEnd()) }; diff --git a/src/services/tsconfig.json b/src/services/tsconfig.json index a456fbb957f..d5977ee46bf 100644 --- a/src/services/tsconfig.json +++ b/src/services/tsconfig.json @@ -28,7 +28,7 @@ "patternMatcher.ts", "preProcess.ts", "rename.ts", - "selectionRange.ts", + "smartSelection.ts", "signatureHelp.ts", "sourcemaps.ts", "suggestionDiagnostics.ts", diff --git a/src/services/types.ts b/src/services/types.ts index d3c9de0f332..4e784e8160b 100644 --- a/src/services/types.ts +++ b/src/services/types.ts @@ -297,7 +297,7 @@ namespace ts { getRenameInfo(fileName: string, position: number, options?: RenameInfoOptions): RenameInfo; findRenameLocations(fileName: string, position: number, findInStrings: boolean, findInComments: boolean, providePrefixAndSuffixTextForRename?: boolean): ReadonlyArray | undefined; - getSelectionRange(fileName: string, position: number): SelectionRange; + getSmartSelectionRange(fileName: string, position: number): SelectionRange; getDefinitionAtPosition(fileName: string, position: number): ReadonlyArray | undefined; getDefinitionAndBoundSpan(fileName: string, position: number): DefinitionInfoAndBoundSpan | undefined; diff --git a/src/testRunner/unittests/tsserver/selectionRange.ts b/src/testRunner/unittests/tsserver/selectionRange.ts index 7940edcdebb..5d4113d3f97 100644 --- a/src/testRunner/unittests/tsserver/selectionRange.ts +++ b/src/testRunner/unittests/tsserver/selectionRange.ts @@ -4,7 +4,7 @@ namespace ts.projectSystem { const host = createServerHost([file, libFile]); const session = createSession(host); openFilesForSession([file], session); - return function getSelectionRange(locations: protocol.SelectionRangeRequestArgs["locations"]) { + return function getSmartSelectionRange(locations: protocol.SelectionRangeRequestArgs["locations"]) { return executeSessionRequest( session, CommandNames.SelectionRange, @@ -14,7 +14,7 @@ namespace ts.projectSystem { describe("unittests:: tsserver:: selectionRange", () => { it("works for simple JavaScript", () => { - const getSelectionRange = setup("/file.js", ` + const getSmartSelectionRange = setup("/file.js", ` class Foo { bar(a, b) { if (a === b) { @@ -24,7 +24,7 @@ class Foo { } }`); - const locations = getSelectionRange([ + const locations = getSmartSelectionRange([ { line: 4, offset: 13, @@ -87,14 +87,14 @@ class Foo { }); it("works for simple TypeScript", () => { - const getSelectionRange = setup("/file.ts", ` + const getSmartSelectionRange = setup("/file.ts", ` export interface IService { _serviceBrand: any; open(host: number, data: any): Promise; bar(): void }`); - const locations = getSelectionRange([ + const locations = getSmartSelectionRange([ { line: 5, offset: 12 }, // ho/**/st { line: 6, offset: 16 }, // void/**/ ]); @@ -136,10 +136,10 @@ export interface IService { }); it("works for complex TypeScript", () => { - const getSelectionRange = setup("/file.ts", ` + const getSmartSelectionRange = setup("/file.ts", ` type X = IsExactlyAny

extends true ? T : ({ [K in keyof P]: IsExactlyAny extends true ? K extends keyof T ? T[K] : P[K] : P[K]; } & Pick>) `); - const locations = getSelectionRange([ + const locations = getSmartSelectionRange([ { line: 2, offset: 133, @@ -195,13 +195,13 @@ type X = IsExactlyAny

extends true ? T : ({ [K in keyof P]: IsExactlyAn }); it("works for object types", () => { - const getSelectionRange = setup("/file.js", ` + const getSmartSelectionRange = setup("/file.js", ` type X = { foo?: string; readonly bar: { x: number }; meh }`); - const locations = getSelectionRange([ + const locations = getSmartSelectionRange([ { line: 3, offset: 5 }, { line: 4, offset: 5 }, { line: 4, offset: 14 }, @@ -285,8 +285,8 @@ type X = { it("works for string literals and template strings", () => { // tslint:disable-next-line:no-invalid-template-strings - const getSelectionRange = setup("/file.ts", "`a b ${\n 'c'\n} d`"); - const locations = getSelectionRange([ + const getSmartSelectionRange = setup("/file.ts", "`a b ${\n 'c'\n} d`"); + const locations = getSmartSelectionRange([ { line: 2, offset: 4 }, { line: 1, offset: 4 }, ]); @@ -327,13 +327,13 @@ type X = { }); it("works for ES2015 import lists", () => { - const getSelectionRange = setup("/file.ts", ` + const getSmartSelectionRange = setup("/file.ts", ` import { x as y, z } from './z'; import { b } from './'; console.log(1);`); - const locations = getSelectionRange([{ line: 2, offset: 10 }]); + const locations = getSmartSelectionRange([{ line: 2, offset: 10 }]); assert.deepEqual(locations, [ { textSpan: { // x @@ -367,10 +367,10 @@ console.log(1);`); }); it("works for complex mapped types", () => { - const getSelectionRange = setup("/file.ts", ` + const getSmartSelectionRange = setup("/file.ts", ` type M = { -readonly [K in keyof any]-?: any };`); - const locations = getSelectionRange([ + const locations = getSmartSelectionRange([ { line: 2, offset: 12 }, // -readonly { line: 2, offset: 14 }, // eadonly { line: 2, offset: 22 }, // [ @@ -476,10 +476,10 @@ type M = { -readonly [K in keyof any]-?: any };`); }); it("works for parameters", () => { - const getSelectionRange = setup("/file.ts", ` + const getSmartSelectionRange = setup("/file.ts", ` function f(p, q?, ...r: any[] = []) {}`); - const locations = getSelectionRange([ + const locations = getSmartSelectionRange([ { line: 2, offset: 12 }, // p { line: 2, offset: 15 }, // q { line: 2, offset: 19 }, // ... @@ -537,9 +537,9 @@ function f(p, q?, ...r: any[] = []) {}`); }); it("works for binding elements", () => { - const getSelectionRange = setup("/file.ts", ` + const getSmartSelectionRange = setup("/file.ts", ` const { x, y: a, ...zs = {} } = {};`); - const locations = getSelectionRange([ + const locations = getSmartSelectionRange([ { line: 2, offset: 9 }, // x { line: 2, offset: 15 }, // a { line: 2, offset: 21 }, // zs @@ -578,12 +578,12 @@ const { x, y: a, ...zs = {} } = {};`); }); it("consumes all whitespace in a multi-line function parameter list", () => { - const getSelectionRange = setup("/file.ts", ` + const getSmartSelectionRange = setup("/file.ts", ` function f( a, b ) {}`); - const locations = getSelectionRange([{ line: 4, offset: 5 }]); // b + const locations = getSmartSelectionRange([{ line: 4, offset: 5 }]); // b assert.deepEqual(locations, [{ textSpan: { // b start: { line: 4, offset: 5 }, @@ -604,8 +604,8 @@ function f( }); it("snaps to nodes directly behind the cursor instead of trivia ahead of the cursor", () => { - const getSelectionRange = setup("/file.ts", `let x: string`); - const locations = getSelectionRange([{ line: 1, offset: 4 }]); + const getSmartSelectionRange = setup("/file.ts", `let x: string`); + const locations = getSmartSelectionRange([{ line: 1, offset: 4 }]); assert.deepEqual(locations![0].textSpan, { start: { line: 1, offset: 1 }, end: { line: 1, offset: 4 }, @@ -613,7 +613,7 @@ function f( }); it("creates a stop for JSDoc ranges", () => { - const getSelectionRange = setup("/file.js", "" + + const getSmartSelectionRange = setup("/file.js", "" + `// Not a JSDoc comment /** * @param {number} x The number to square @@ -621,7 +621,7 @@ function f( function square(x) { return x * x; }`); - const locations = getSelectionRange([{ line: 5, offset: 10 }]); // square(x) + const locations = getSmartSelectionRange([{ line: 5, offset: 10 }]); // square(x) assert.deepEqual(locations, [{ textSpan: { // square start: { line: 5 , offset: 10 }, @@ -641,8 +641,8 @@ function square(x) { }); it("skips lone VariableDeclarations in a declaration list", () => { - const getSelectionRange = setup("/file.ts", `const x = 3;`); - const locations = getSelectionRange([{ line: 1, offset: 7 }]); // x + const getSmartSelectionRange = setup("/file.ts", `const x = 3;`); + const locations = getSmartSelectionRange([{ line: 1, offset: 7 }]); // x assert.deepEqual(locations, [{ textSpan: { start: { line: 1, offset: 7 }, diff --git a/tests/baselines/reference/api/tsserverlibrary.d.ts b/tests/baselines/reference/api/tsserverlibrary.d.ts index 1b4acd88ebf..0cf9780593d 100644 --- a/tests/baselines/reference/api/tsserverlibrary.d.ts +++ b/tests/baselines/reference/api/tsserverlibrary.d.ts @@ -4788,6 +4788,7 @@ declare namespace ts { getSignatureHelpItems(fileName: string, position: number, options: SignatureHelpItemsOptions | undefined): SignatureHelpItems | undefined; getRenameInfo(fileName: string, position: number, options?: RenameInfoOptions): RenameInfo; findRenameLocations(fileName: string, position: number, findInStrings: boolean, findInComments: boolean, providePrefixAndSuffixTextForRename?: boolean): ReadonlyArray | undefined; + getSmartSelectionRange(fileName: string, position: number): SelectionRange; getDefinitionAtPosition(fileName: string, position: number): ReadonlyArray | undefined; getDefinitionAndBoundSpan(fileName: string, position: number): DefinitionInfoAndBoundSpan | undefined; getTypeDefinitionAtPosition(fileName: string, position: number): ReadonlyArray | undefined; @@ -5239,6 +5240,10 @@ declare namespace ts { displayParts: SymbolDisplayPart[]; isOptional: boolean; } + interface SelectionRange { + textSpan: TextSpan; + parent?: SelectionRange; + } /** * Represents a single signature to show in signature help. * The id is used for subsequent calls into the language service to ask questions about the @@ -5790,7 +5795,8 @@ declare namespace ts.server.protocol { GetEditsForRefactor = "getEditsForRefactor", OrganizeImports = "organizeImports", GetEditsForFileRename = "getEditsForFileRename", - ConfigurePlugin = "configurePlugin" + ConfigurePlugin = "configurePlugin", + SelectionRange = "selectionRange", } /** * A TypeScript Server message @@ -6753,6 +6759,20 @@ declare namespace ts.server.protocol { } interface ConfigurePluginResponse extends Response { } + interface SelectionRangeRequest extends FileRequest { + command: CommandTypes.SelectionRange; + arguments: SelectionRangeRequestArgs; + } + interface SelectionRangeRequestArgs extends FileRequestArgs { + locations: Location[]; + } + interface SelectionRangeResponse extends Response { + body?: SelectionRange[]; + } + interface SelectionRange { + textSpan: TextSpan; + parent?: SelectionRange; + } /** * Information found in an "open" request. */ @@ -9026,6 +9046,8 @@ declare namespace ts.server { private getBraceMatching; private getDiagnosticsForProject; private configurePlugin; + private getSmartSelectionRange; + private mapSelectionRange; getCanonicalFileName(fileName: string): string; exit(): void; private notRequired; diff --git a/tests/baselines/reference/api/typescript.d.ts b/tests/baselines/reference/api/typescript.d.ts index c25e1d733c0..db24e19b3d8 100644 --- a/tests/baselines/reference/api/typescript.d.ts +++ b/tests/baselines/reference/api/typescript.d.ts @@ -4788,6 +4788,7 @@ declare namespace ts { getSignatureHelpItems(fileName: string, position: number, options: SignatureHelpItemsOptions | undefined): SignatureHelpItems | undefined; getRenameInfo(fileName: string, position: number, options?: RenameInfoOptions): RenameInfo; findRenameLocations(fileName: string, position: number, findInStrings: boolean, findInComments: boolean, providePrefixAndSuffixTextForRename?: boolean): ReadonlyArray | undefined; + getSmartSelectionRange(fileName: string, position: number): SelectionRange; getDefinitionAtPosition(fileName: string, position: number): ReadonlyArray | undefined; getDefinitionAndBoundSpan(fileName: string, position: number): DefinitionInfoAndBoundSpan | undefined; getTypeDefinitionAtPosition(fileName: string, position: number): ReadonlyArray | undefined; @@ -5239,6 +5240,10 @@ declare namespace ts { displayParts: SymbolDisplayPart[]; isOptional: boolean; } + interface SelectionRange { + textSpan: TextSpan; + parent?: SelectionRange; + } /** * Represents a single signature to show in signature help. * The id is used for subsequent calls into the language service to ask questions about the diff --git a/tests/cases/user/TypeScript-Node-Starter/TypeScript-Node-Starter b/tests/cases/user/TypeScript-Node-Starter/TypeScript-Node-Starter index 40bdb4eadab..46971a84547 160000 --- a/tests/cases/user/TypeScript-Node-Starter/TypeScript-Node-Starter +++ b/tests/cases/user/TypeScript-Node-Starter/TypeScript-Node-Starter @@ -1 +1 @@ -Subproject commit 40bdb4eadabc9fbed7d83e3f26817a931c0763b6 +Subproject commit 46971a8454761f1a11d8fde4d96ff8d29bc4e754 diff --git a/tests/cases/user/create-react-app/create-react-app b/tests/cases/user/create-react-app/create-react-app index 1a61db58d43..9514cb88ab9 160000 --- a/tests/cases/user/create-react-app/create-react-app +++ b/tests/cases/user/create-react-app/create-react-app @@ -1 +1 @@ -Subproject commit 1a61db58d434d33603f20e73ca643ec83c561b73 +Subproject commit 9514cb88ab92fec7f5df2914702ef23a62c0a249 diff --git a/tests/cases/user/prettier/prettier b/tests/cases/user/prettier/prettier index 1e471a00796..0b07e108333 160000 --- a/tests/cases/user/prettier/prettier +++ b/tests/cases/user/prettier/prettier @@ -1 +1 @@ -Subproject commit 1e471a007968b7490563b91ed6909ae6046f3fe8 +Subproject commit 0b07e1083339e28a8239df3f5245f530cc4fd7f8