From 4f8dbd4544f4271c77176b08a155833a3c5d3c01 Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Tue, 12 Mar 2019 09:56:49 +0100 Subject: [PATCH] use a parent pointer instead of 2d array, #67872 --- .../client/src/cssMain.ts | 9 +++---- .../client/src/htmlMain.ts | 7 +++--- .../client/src/jsonMain.ts | 7 +++--- .../editor/contrib/smartSelect/smartSelect.ts | 3 ++- src/vs/vscode.proposed.d.ts | 5 ++-- .../api/node/extHostLanguageFeatures.ts | 9 +++++-- src/vs/workbench/api/node/extHostTypes.ts | 4 +++- .../api/extHostApiCommands.test.ts | 7 +++--- .../api/extHostLanguageFeatures.test.ts | 24 +++++++++++++++---- 9 files changed, 51 insertions(+), 24 deletions(-) diff --git a/extensions/css-language-features/client/src/cssMain.ts b/extensions/css-language-features/client/src/cssMain.ts index a7c4fac148d..8d8542f5a1e 100644 --- a/extensions/css-language-features/client/src/cssMain.ts +++ b/extensions/css-language-features/client/src/cssMain.ts @@ -81,16 +81,17 @@ export function activate(context: ExtensionContext) { documentSelector.forEach(selector => { context.subscriptions.push(languages.registerSelectionRangeProvider(selector, { - async provideSelectionRanges(document: TextDocument, positions: Position[]): Promise { + async provideSelectionRanges(document: TextDocument, positions: Position[]): Promise { const textDocument = client.code2ProtocolConverter.asTextDocumentIdentifier(document); const rawResult = await client.sendRequest('$/textDocument/selectionRanges', { textDocument, positions: positions.map(client.code2ProtocolConverter.asPosition) }); if (Array.isArray(rawResult)) { return rawResult.map(rawSelectionRanges => { - return rawSelectionRanges.map(selectionRange => { + return rawSelectionRanges.reduceRight((parent: SelectionRange | undefined, selectionRange: SelectionRange) => { return { - range: client.protocol2CodeConverter.asRange(selectionRange.range) + range: client.protocol2CodeConverter.asRange(selectionRange.range), + parent }; - }); + }, undefined)!; }); } return []; diff --git a/extensions/html-language-features/client/src/htmlMain.ts b/extensions/html-language-features/client/src/htmlMain.ts index efbfd2b3195..77799b561ba 100644 --- a/extensions/html-language-features/client/src/htmlMain.ts +++ b/extensions/html-language-features/client/src/htmlMain.ts @@ -90,16 +90,17 @@ export function activate(context: ExtensionContext) { documentSelector.forEach(selector => { context.subscriptions.push(languages.registerSelectionRangeProvider(selector, { - async provideSelectionRanges(document: TextDocument, positions: Position[]): Promise { + async provideSelectionRanges(document: TextDocument, positions: Position[]): Promise { const textDocument = client.code2ProtocolConverter.asTextDocumentIdentifier(document); const rawResult = await client.sendRequest('$/textDocument/selectionRanges', { textDocument, positions: positions.map(client.code2ProtocolConverter.asPosition) }); if (Array.isArray(rawResult)) { return rawResult.map(rawSelectionRanges => { - return rawSelectionRanges.map(selectionRange => { + return rawSelectionRanges.reduceRight((parent: SelectionRange | undefined, selectionRange: SelectionRange) => { return { range: client.protocol2CodeConverter.asRange(selectionRange.range), + parent }; - }); + }, undefined)!; }); } return []; diff --git a/extensions/json-language-features/client/src/jsonMain.ts b/extensions/json-language-features/client/src/jsonMain.ts index a5532004431..73a6f9bbf33 100644 --- a/extensions/json-language-features/client/src/jsonMain.ts +++ b/extensions/json-language-features/client/src/jsonMain.ts @@ -214,16 +214,17 @@ export function activate(context: ExtensionContext) { documentSelector.forEach(selector => { toDispose.push(languages.registerSelectionRangeProvider(selector, { - async provideSelectionRanges(document: TextDocument, positions: Position[]): Promise { + async provideSelectionRanges(document: TextDocument, positions: Position[]): Promise { const textDocument = client.code2ProtocolConverter.asTextDocumentIdentifier(document); const rawResult = await client.sendRequest('$/textDocument/selectionRanges', { textDocument, positions: positions.map(client.code2ProtocolConverter.asPosition) }); if (Array.isArray(rawResult)) { return rawResult.map(rawSelectionRanges => { - return rawSelectionRanges.map(selectionRange => { + return rawSelectionRanges.reduceRight((parent: SelectionRange | undefined, selectionRange: SelectionRange) => { return { range: client.protocol2CodeConverter.asRange(selectionRange.range), + parent, }; - }); + }, undefined)!; }); } return []; diff --git a/src/vs/editor/contrib/smartSelect/smartSelect.ts b/src/vs/editor/contrib/smartSelect/smartSelect.ts index 63e1579a348..f8edd2156ee 100644 --- a/src/vs/editor/contrib/smartSelect/smartSelect.ts +++ b/src/vs/editor/contrib/smartSelect/smartSelect.ts @@ -22,6 +22,7 @@ import { IDisposable, dispose } from 'vs/base/common/lifecycle'; import { WordSelectionRangeProvider } from 'vs/editor/contrib/smartSelect/wordSelections'; import { BracketSelectionRangeProvider } from 'vs/editor/contrib/smartSelect/bracketSelections'; import { CommandsRegistry } from 'vs/platform/commands/common/commands'; +import { onUnexpectedExternalError } from 'vs/base/common/errors'; class SelectionRanges { @@ -237,7 +238,7 @@ export function provideSelectionRanges(model: ITextModel, positions: Position[], } } } - })); + }, onUnexpectedExternalError)); } return Promise.all(work).then(() => { diff --git a/src/vs/vscode.proposed.d.ts b/src/vs/vscode.proposed.d.ts index 846714de7bc..e67cf1512f2 100644 --- a/src/vs/vscode.proposed.d.ts +++ b/src/vs/vscode.proposed.d.ts @@ -86,7 +86,8 @@ declare module 'vscode' { export class SelectionRange { range: Range; - constructor(range: Range); + parent?: SelectionRange; + constructor(range: Range, parent?: SelectionRange); } export interface SelectionRangeProvider { @@ -97,7 +98,7 @@ declare module 'vscode' { * * todo@joh */ - provideSelectionRanges(document: TextDocument, positions: Position[], token: CancellationToken): ProviderResult; + provideSelectionRanges(document: TextDocument, positions: Position[], token: CancellationToken): ProviderResult; } export namespace languages { diff --git a/src/vs/workbench/api/node/extHostLanguageFeatures.ts b/src/vs/workbench/api/node/extHostLanguageFeatures.ts index 5d902dd3def..19cf2adb014 100644 --- a/src/vs/workbench/api/node/extHostLanguageFeatures.ts +++ b/src/vs/workbench/api/node/extHostLanguageFeatures.ts @@ -944,14 +944,19 @@ class SelectionRangeAdapter { const oneResult: modes.SelectionRange[] = []; allResults.push(oneResult); - const oneProviderRanges = allProviderRanges[i]; let last: vscode.Position | vscode.Range = positions[i]; - for (const selectionRange of oneProviderRanges) { + let selectionRange = allProviderRanges[i]; + + while (true) { if (!selectionRange.range.contains(last)) { throw new Error('INVALID selection range, must contain the previous range'); } oneResult.push(typeConvert.SelectionRange.from(selectionRange)); + if (!selectionRange.parent) { + break; + } last = selectionRange.range; + selectionRange = selectionRange.parent; } } return allResults; diff --git a/src/vs/workbench/api/node/extHostTypes.ts b/src/vs/workbench/api/node/extHostTypes.ts index 76446d107e9..7edb9a9045c 100644 --- a/src/vs/workbench/api/node/extHostTypes.ts +++ b/src/vs/workbench/api/node/extHostTypes.ts @@ -1098,9 +1098,11 @@ CodeActionKind.SourceFixAll = CodeActionKind.Source.append('fixAll'); export class SelectionRange { range: Range; + parent?: SelectionRange; - constructor(range: Range) { + constructor(range: Range, parent?: SelectionRange) { this.range = range; + this.parent = parent; } } diff --git a/src/vs/workbench/test/electron-browser/api/extHostApiCommands.test.ts b/src/vs/workbench/test/electron-browser/api/extHostApiCommands.test.ts index fa2d483f30a..99ef6017284 100644 --- a/src/vs/workbench/test/electron-browser/api/extHostApiCommands.test.ts +++ b/src/vs/workbench/test/electron-browser/api/extHostApiCommands.test.ts @@ -799,10 +799,9 @@ suite('ExtHostLanguageFeatureCommands', function () { disposables.push(extHost.registerSelectionRangeProvider(nullExtensionDescription, defaultSelector, { provideSelectionRanges() { - return [[ - new types.SelectionRange(new types.Range(0, 10, 0, 18)), - new types.SelectionRange(new types.Range(0, 2, 0, 20)) - ]]; + return [ + new types.SelectionRange(new types.Range(0, 10, 0, 18), new types.SelectionRange(new types.Range(0, 2, 0, 20))), + ]; } })); diff --git a/src/vs/workbench/test/electron-browser/api/extHostLanguageFeatures.test.ts b/src/vs/workbench/test/electron-browser/api/extHostLanguageFeatures.test.ts index d2d9fc6f6c8..c25d55334b8 100644 --- a/src/vs/workbench/test/electron-browser/api/extHostLanguageFeatures.test.ts +++ b/src/vs/workbench/test/electron-browser/api/extHostLanguageFeatures.test.ts @@ -1104,10 +1104,9 @@ suite('ExtHostLanguageFeatures', function () { test('Selection Ranges, data conversion', async () => { disposables.push(extHost.registerSelectionRangeProvider(defaultExtension, defaultSelector, new class implements vscode.SelectionRangeProvider { provideSelectionRanges() { - return [[ - new types.SelectionRange(new types.Range(0, 10, 0, 18)), - new types.SelectionRange(new types.Range(0, 2, 0, 20)) - ]]; + return [ + new types.SelectionRange(new types.Range(0, 10, 0, 18), new types.SelectionRange(new types.Range(0, 2, 0, 20))), + ]; } })); @@ -1118,4 +1117,21 @@ suite('ExtHostLanguageFeatures', function () { assert.ok(ranges[0].length >= 2); }); }); + + test('Selection Ranges, bad data', async () => { + disposables.push(extHost.registerSelectionRangeProvider(defaultExtension, defaultSelector, new class implements vscode.SelectionRangeProvider { + provideSelectionRanges() { + return [ + new types.SelectionRange(new types.Range(0, 10, 0, 18), + new types.SelectionRange(new types.Range(0, 11, 0, 18))), + ]; + } + })); + + await rpcProtocol.sync(); + + provideSelectionRanges(model, [new Position(1, 17)], CancellationToken.None).then(ranges => { + assert.equal(ranges.length, 0); + }); + }); }); -- GitLab