mirror of
https://github.com/microsoft/vscode.git
synced 2026-05-02 22:41:31 +01:00
adopt feedback for #109923
This commit is contained in:
@@ -824,12 +824,27 @@ export interface DocumentHighlightProvider {
|
||||
*/
|
||||
export interface OnTypeRenameProvider {
|
||||
|
||||
wordPattern?: RegExp;
|
||||
|
||||
/**
|
||||
* Provide a list of ranges that can be live-renamed together.
|
||||
*/
|
||||
provideOnTypeRenameRanges(model: model.ITextModel, position: Position, token: CancellationToken): ProviderResult<{ ranges: IRange[]; wordPattern?: RegExp; }>;
|
||||
provideOnTypeRenameRanges(model: model.ITextModel, position: Position, token: CancellationToken): ProviderResult<OnTypeRenameRanges>;
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents a list of ranges that can be renamed together along with a word pattern to describe valid range contents.
|
||||
*/
|
||||
export interface OnTypeRenameRanges {
|
||||
/**
|
||||
* A list of ranges that can be renamed together. The ranges must have
|
||||
* identical length and contain identical text content. The ranges cannot overlap
|
||||
*/
|
||||
ranges: IRange[];
|
||||
|
||||
/**
|
||||
* An optional word pattern that describes valid contents for the given ranges.
|
||||
* If no pattern is provided, the language configuration's word pattern will be used.
|
||||
*/
|
||||
wordPattern?: RegExp;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -15,7 +15,7 @@ import { Position, IPosition } from 'vs/editor/common/core/position';
|
||||
import { ITextModel, IModelDeltaDecoration, TrackedRangeStickiness, IIdentifiedSingleEditOperation } from 'vs/editor/common/model';
|
||||
import { CancellationToken } from 'vs/base/common/cancellation';
|
||||
import { IRange, Range } from 'vs/editor/common/core/range';
|
||||
import { OnTypeRenameProviderRegistry } from 'vs/editor/common/modes';
|
||||
import { OnTypeRenameProviderRegistry, OnTypeRenameRanges } from 'vs/editor/common/modes';
|
||||
import { first, createCancelablePromise, CancelablePromise, Delayer } from 'vs/base/common/async';
|
||||
import { ModelDecorationOptions } from 'vs/editor/common/model/textModel';
|
||||
import { ContextKeyExpr, RawContextKey, IContextKeyService, IContextKey } from 'vs/platform/contextkey/common/contextkey';
|
||||
@@ -419,33 +419,19 @@ registerEditorCommand(new OnTypeRenameCommand({
|
||||
}));
|
||||
|
||||
|
||||
export function getOnTypeRenameRanges(model: ITextModel, position: Position, token: CancellationToken): Promise<{
|
||||
ranges: IRange[],
|
||||
wordPattern?: RegExp
|
||||
} | undefined | null> {
|
||||
function getOnTypeRenameRanges(model: ITextModel, position: Position, token: CancellationToken): Promise<OnTypeRenameRanges | undefined | null> {
|
||||
const orderedByScore = OnTypeRenameProviderRegistry.ordered(model);
|
||||
|
||||
// in order of score ask the occurrences provider
|
||||
// in order of score ask the on type rename provider
|
||||
// until someone response with a good result
|
||||
// (good = none empty array)
|
||||
return first<{
|
||||
ranges: IRange[],
|
||||
wordPattern?: RegExp
|
||||
} | undefined>(orderedByScore.map(provider => () => {
|
||||
return Promise.resolve(provider.provideOnTypeRenameRanges(model, position, token)).then((res) => {
|
||||
if (!res) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
return {
|
||||
ranges: res.ranges,
|
||||
wordPattern: res.wordPattern || provider.wordPattern
|
||||
};
|
||||
}, (err) => {
|
||||
onUnexpectedExternalError(err);
|
||||
// (good = not null)
|
||||
return first<OnTypeRenameRanges | undefined | null>(orderedByScore.map(provider => async () => {
|
||||
try {
|
||||
return await provider.provideOnTypeRenameRanges(model, position, token);
|
||||
} catch (e) {
|
||||
onUnexpectedExternalError(e);
|
||||
return undefined;
|
||||
});
|
||||
|
||||
}
|
||||
}), result => !!result && arrays.isNonEmptyArray(result?.ranges));
|
||||
}
|
||||
|
||||
|
||||
@@ -16,6 +16,7 @@ import { createTextModel } from 'vs/editor/test/common/editorTestUtils';
|
||||
import { CoreEditingCommands } from 'vs/editor/browser/controller/coreCommands';
|
||||
import { ITextModel } from 'vs/editor/common/model';
|
||||
import { USUAL_WORD_SEPARATORS } from 'vs/editor/common/model/wordHelper';
|
||||
import { LanguageConfigurationRegistry } from 'vs/editor/common/modes/languageConfigurationRegistry';
|
||||
|
||||
const mockFile = URI.parse('test:somefile.ttt');
|
||||
const mockFileSelector = { scheme: 'test' };
|
||||
@@ -29,6 +30,11 @@ interface TestEditor {
|
||||
redo(): void;
|
||||
}
|
||||
|
||||
const languageIdentifier = new modes.LanguageIdentifier('onTypeRenameTestLangage', 74);
|
||||
LanguageConfigurationRegistry.register(languageIdentifier, {
|
||||
wordPattern: /[a-zA-Z]+/
|
||||
});
|
||||
|
||||
suite('On type rename', () => {
|
||||
const disposables = new DisposableStore();
|
||||
|
||||
@@ -42,8 +48,8 @@ suite('On type rename', () => {
|
||||
|
||||
function createMockEditor(text: string | string[]): ITestCodeEditor {
|
||||
const model = typeof text === 'string'
|
||||
? createTextModel(text, undefined, undefined, mockFile)
|
||||
: createTextModel(text.join('\n'), undefined, undefined, mockFile);
|
||||
? createTextModel(text, undefined, languageIdentifier, mockFile)
|
||||
: createTextModel(text.join('\n'), undefined, languageIdentifier, mockFile);
|
||||
|
||||
const editor = createTestCodeEditor({ model });
|
||||
disposables.add(model);
|
||||
@@ -55,18 +61,16 @@ suite('On type rename', () => {
|
||||
|
||||
function testCase(
|
||||
name: string,
|
||||
initialState: { text: string | string[], responseWordPattern?: RegExp, providerWordPattern?: RegExp },
|
||||
initialState: { text: string | string[], responseWordPattern?: RegExp },
|
||||
operations: (editor: TestEditor) => Promise<void>,
|
||||
expectedEndText: string | string[]
|
||||
) {
|
||||
test(name, async () => {
|
||||
disposables.add(modes.OnTypeRenameProviderRegistry.register(mockFileSelector, {
|
||||
wordPattern: initialState.providerWordPattern,
|
||||
provideOnTypeRenameRanges(model: ITextModel, pos: IPosition) {
|
||||
const wordAtPos = model.getWordAtPosition(pos);
|
||||
if (wordAtPos) {
|
||||
const matches = model.findMatches(wordAtPos.word, false, false, true, USUAL_WORD_SEPARATORS, false);
|
||||
assert.ok(matches.length > 0);
|
||||
return { ranges: matches.map(m => m.range), wordPattern: initialState.responseWordPattern };
|
||||
}
|
||||
return { ranges: [], wordPattern: initialState.responseWordPattern };
|
||||
@@ -299,7 +303,7 @@ suite('On type rename', () => {
|
||||
|
||||
const state3 = {
|
||||
...state,
|
||||
providerWordPattern: /[a-yA-Y]+/
|
||||
responseWordPattern: /[a-yA-Y]+/
|
||||
};
|
||||
|
||||
testCase('Breakout with stop pattern - insert', state3, async (editor) => {
|
||||
@@ -334,7 +338,6 @@ suite('On type rename', () => {
|
||||
|
||||
const state4 = {
|
||||
...state,
|
||||
providerWordPattern: /[a-yA-Y]+/,
|
||||
responseWordPattern: /[a-eA-E]+/
|
||||
};
|
||||
|
||||
|
||||
22
src/vs/monaco.d.ts
vendored
22
src/vs/monaco.d.ts
vendored
@@ -5829,14 +5829,26 @@ declare namespace monaco.languages {
|
||||
* the live-rename feature.
|
||||
*/
|
||||
export interface OnTypeRenameProvider {
|
||||
wordPattern?: RegExp;
|
||||
/**
|
||||
* Provide a list of ranges that can be live-renamed together.
|
||||
*/
|
||||
provideOnTypeRenameRanges(model: editor.ITextModel, position: Position, token: CancellationToken): ProviderResult<{
|
||||
ranges: IRange[];
|
||||
wordPattern?: RegExp;
|
||||
}>;
|
||||
provideOnTypeRenameRanges(model: editor.ITextModel, position: Position, token: CancellationToken): ProviderResult<OnTypeRenameRanges>;
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents a list of ranges that can be renamed together along with a word pattern to describe valid range contents.
|
||||
*/
|
||||
export interface OnTypeRenameRanges {
|
||||
/**
|
||||
* A list of ranges that can be renamed together. The ranges must have
|
||||
* identical length and contain identical text content. The ranges cannot overlap.
|
||||
*/
|
||||
ranges: IRange[];
|
||||
/**
|
||||
* An optional word pattern that describes valid contents for the given ranges.
|
||||
* If no pattern is provided, the language configuration's word pattern will be used.
|
||||
*/
|
||||
wordPattern?: RegExp;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
36
src/vs/vscode.proposed.d.ts
vendored
36
src/vs/vscode.proposed.d.ts
vendored
@@ -1115,19 +1115,17 @@ declare module 'vscode' {
|
||||
export interface OnTypeRenameProvider {
|
||||
/**
|
||||
* For a given position in a document, returns the range of the symbol at the position and all ranges
|
||||
* that have the same content and can be renamed together. Optionally a result specific word pattern can be returned as well
|
||||
* that describes valid contents. A rename to one of the ranges can be applied to all other ranges if the new content
|
||||
* matches the word pattern.
|
||||
* If no result-specific word pattern is provided, the word pattern defined when registering the provider is used.
|
||||
* that have the same content and can be renamed together. Optionally a word pattern can be returned
|
||||
* to describe valid contents. A rename to one of the ranges can be applied to all other ranges if the new content
|
||||
* is valid.
|
||||
* If no result-specific word pattern is provided, the word pattern from the language configuration is used.
|
||||
*
|
||||
* @param document The document in which the provider was invoked.
|
||||
* @param position The position at which the provider was invoked.
|
||||
* @param token A cancellation token.
|
||||
* @return A list of ranges that can be renamed together. The ranges must have
|
||||
* identical length and contain identical text content. The ranges cannot overlap. Optionally a word pattern
|
||||
* that overrides the word pattern defined when registering the provider can be provided.
|
||||
* @return A list of ranges that can be renamed together
|
||||
*/
|
||||
provideOnTypeRenameRanges(document: TextDocument, position: Position, token: CancellationToken): ProviderResult<{ ranges: Range[]; wordPattern?: RegExp; }>;
|
||||
provideOnTypeRenameRanges(document: TextDocument, position: Position, token: CancellationToken): ProviderResult<OnTypeRenameRanges>;
|
||||
}
|
||||
|
||||
namespace languages {
|
||||
@@ -1140,10 +1138,28 @@ declare module 'vscode' {
|
||||
*
|
||||
* @param selector A selector that defines the documents this provider is applicable to.
|
||||
* @param provider An 'on type' rename provider.
|
||||
* @param wordPattern A word pattern to describes valid contents of renamed ranges.
|
||||
* @return A [disposable](#Disposable) that unregisters this provider when being disposed.
|
||||
*/
|
||||
export function registerOnTypeRenameProvider(selector: DocumentSelector, provider: OnTypeRenameProvider, wordPattern?: RegExp): Disposable;
|
||||
export function registerOnTypeRenameProvider(selector: DocumentSelector, provider: OnTypeRenameProvider): Disposable;
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents a list of ranges that can be renamed together along with a word pattern to describe valid range contents.
|
||||
*/
|
||||
export class OnTypeRenameRanges {
|
||||
constructor(ranges: Range[], wordPattern?: RegExp);
|
||||
|
||||
/**
|
||||
* A list of ranges that can be renamed together. The ranges must have
|
||||
* identical length and contain identical text content. The ranges cannot overlap.
|
||||
*/
|
||||
readonly ranges: Range[];
|
||||
|
||||
/**
|
||||
* An optional word pattern that describes valid contents for the given ranges.
|
||||
* If no pattern is provided, the language configuration's word pattern will be used.
|
||||
*/
|
||||
readonly wordPattern?: RegExp;
|
||||
}
|
||||
|
||||
//#endregion
|
||||
|
||||
@@ -262,11 +262,9 @@ export class MainThreadLanguageFeatures implements MainThreadLanguageFeaturesSha
|
||||
|
||||
// --- on type rename
|
||||
|
||||
$registerOnTypeRenameProvider(handle: number, selector: IDocumentFilterDto[], wordPattern?: IRegExpDto): void {
|
||||
const revivedWordPattern = wordPattern ? MainThreadLanguageFeatures._reviveRegExp(wordPattern) : undefined;
|
||||
$registerOnTypeRenameProvider(handle: number, selector: IDocumentFilterDto[]): void {
|
||||
this._registrations.set(handle, modes.OnTypeRenameProviderRegistry.register(selector, <modes.OnTypeRenameProvider>{
|
||||
wordPattern: revivedWordPattern,
|
||||
provideOnTypeRenameRanges: async (model: ITextModel, position: EditorPosition, token: CancellationToken): Promise<{ ranges: IRange[]; wordPattern?: RegExp; } | undefined> => {
|
||||
provideOnTypeRenameRanges: async (model: ITextModel, position: EditorPosition, token: CancellationToken): Promise<modes.OnTypeRenameRanges | undefined> => {
|
||||
const res = await this._proxy.$provideOnTypeRenameRanges(handle, model.uri, position, token);
|
||||
if (res) {
|
||||
return {
|
||||
|
||||
@@ -397,9 +397,9 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I
|
||||
registerDocumentHighlightProvider(selector: vscode.DocumentSelector, provider: vscode.DocumentHighlightProvider): vscode.Disposable {
|
||||
return extHostLanguageFeatures.registerDocumentHighlightProvider(extension, checkSelector(selector), provider);
|
||||
},
|
||||
registerOnTypeRenameProvider(selector: vscode.DocumentSelector, provider: vscode.OnTypeRenameProvider, stopPattern?: RegExp): vscode.Disposable {
|
||||
registerOnTypeRenameProvider(selector: vscode.DocumentSelector, provider: vscode.OnTypeRenameProvider): vscode.Disposable {
|
||||
checkProposedApiEnabled(extension);
|
||||
return extHostLanguageFeatures.registerOnTypeRenameProvider(extension, checkSelector(selector), provider, stopPattern);
|
||||
return extHostLanguageFeatures.registerOnTypeRenameProvider(extension, checkSelector(selector), provider);
|
||||
},
|
||||
registerReferenceProvider(selector: vscode.DocumentSelector, provider: vscode.ReferenceProvider): vscode.Disposable {
|
||||
return extHostLanguageFeatures.registerReferenceProvider(extension, checkSelector(selector), provider);
|
||||
@@ -1197,6 +1197,7 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I
|
||||
NotebookEditorRevealType: extHostTypes.NotebookEditorRevealType,
|
||||
NotebookCellOutput: extHostTypes.NotebookCellOutput,
|
||||
NotebookCellOutputItem: extHostTypes.NotebookCellOutputItem,
|
||||
OnTypeRenameRanges: extHostTypes.OnTypeRenameRanges
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
@@ -384,7 +384,7 @@ export interface MainThreadLanguageFeaturesShape extends IDisposable {
|
||||
$registerHoverProvider(handle: number, selector: IDocumentFilterDto[]): void;
|
||||
$registerEvaluatableExpressionProvider(handle: number, selector: IDocumentFilterDto[]): void;
|
||||
$registerDocumentHighlightProvider(handle: number, selector: IDocumentFilterDto[]): void;
|
||||
$registerOnTypeRenameProvider(handle: number, selector: IDocumentFilterDto[], stopPattern: IRegExpDto | undefined): void;
|
||||
$registerOnTypeRenameProvider(handle: number, selector: IDocumentFilterDto[]): void;
|
||||
$registerReferenceSupport(handle: number, selector: IDocumentFilterDto[]): void;
|
||||
$registerQuickFixSupport(handle: number, selector: IDocumentFilterDto[], metadata: ICodeActionProviderMetadataDto, displayName: string, supportsResolve: boolean): void;
|
||||
$registerDocumentFormattingSupport(handle: number, selector: IDocumentFilterDto[], extensionId: ExtensionIdentifier, displayName: string): void;
|
||||
@@ -1395,6 +1395,11 @@ export interface ILanguageWordDefinitionDto {
|
||||
regexFlags: string
|
||||
}
|
||||
|
||||
export interface IOnTypeRenameRangesDto {
|
||||
ranges: IRange[];
|
||||
wordPattern?: IRegExpDto;
|
||||
}
|
||||
|
||||
export interface ExtHostLanguageFeaturesShape {
|
||||
$provideDocumentSymbols(handle: number, resource: UriComponents, token: CancellationToken): Promise<modes.DocumentSymbol[] | undefined>;
|
||||
$provideCodeLenses(handle: number, resource: UriComponents, token: CancellationToken): Promise<ICodeLensListDto | undefined>;
|
||||
@@ -1407,7 +1412,7 @@ export interface ExtHostLanguageFeaturesShape {
|
||||
$provideHover(handle: number, resource: UriComponents, position: IPosition, token: CancellationToken): Promise<modes.Hover | undefined>;
|
||||
$provideEvaluatableExpression(handle: number, resource: UriComponents, position: IPosition, token: CancellationToken): Promise<modes.EvaluatableExpression | undefined>;
|
||||
$provideDocumentHighlights(handle: number, resource: UriComponents, position: IPosition, token: CancellationToken): Promise<modes.DocumentHighlight[] | undefined>;
|
||||
$provideOnTypeRenameRanges(handle: number, resource: UriComponents, position: IPosition, token: CancellationToken): Promise<{ ranges: IRange[]; wordPattern?: IRegExpDto; } | undefined>;
|
||||
$provideOnTypeRenameRanges(handle: number, resource: UriComponents, position: IPosition, token: CancellationToken): Promise<IOnTypeRenameRangesDto | undefined>;
|
||||
$provideReferences(handle: number, resource: UriComponents, position: IPosition, context: modes.ReferenceContext, token: CancellationToken): Promise<ILocationDto[] | undefined>;
|
||||
$provideCodeActions(handle: number, resource: UriComponents, rangeOrSelection: IRange | ISelection, context: modes.CodeActionContext, token: CancellationToken): Promise<ICodeActionListDto | undefined>;
|
||||
$resolveCodeAction(handle: number, id: ChainedCacheId, token: CancellationToken): Promise<IWorkspaceEditDto | undefined>;
|
||||
|
||||
@@ -317,7 +317,7 @@ class OnTypeRenameAdapter {
|
||||
private readonly _provider: vscode.OnTypeRenameProvider
|
||||
) { }
|
||||
|
||||
provideOnTypeRenameRanges(resource: URI, position: IPosition, token: CancellationToken): Promise<{ ranges: IRange[]; wordPattern?: RegExp; } | undefined> {
|
||||
provideOnTypeRenameRanges(resource: URI, position: IPosition, token: CancellationToken): Promise<modes.OnTypeRenameRanges | undefined> {
|
||||
|
||||
const doc = this._documents.getDocument(resource);
|
||||
const pos = typeConvert.Position.to(position);
|
||||
@@ -1564,14 +1564,13 @@ export class ExtHostLanguageFeatures implements extHostProtocol.ExtHostLanguageF
|
||||
|
||||
// --- on type rename
|
||||
|
||||
registerOnTypeRenameProvider(extension: IExtensionDescription, selector: vscode.DocumentSelector, provider: vscode.OnTypeRenameProvider, wordPattern?: RegExp): vscode.Disposable {
|
||||
registerOnTypeRenameProvider(extension: IExtensionDescription, selector: vscode.DocumentSelector, provider: vscode.OnTypeRenameProvider): vscode.Disposable {
|
||||
const handle = this._addNewAdapter(new OnTypeRenameAdapter(this._documents, provider), extension);
|
||||
const serializedWordPattern = wordPattern ? ExtHostLanguageFeatures._serializeRegExp(wordPattern) : undefined;
|
||||
this._proxy.$registerOnTypeRenameProvider(handle, this._transformDocumentSelector(selector), serializedWordPattern);
|
||||
this._proxy.$registerOnTypeRenameProvider(handle, this._transformDocumentSelector(selector));
|
||||
return this._createDisposable(handle);
|
||||
}
|
||||
|
||||
$provideOnTypeRenameRanges(handle: number, resource: UriComponents, position: IPosition, token: CancellationToken): Promise<{ ranges: IRange[]; wordPattern?: extHostProtocol.IRegExpDto; } | undefined> {
|
||||
$provideOnTypeRenameRanges(handle: number, resource: UriComponents, position: IPosition, token: CancellationToken): Promise<extHostProtocol.IOnTypeRenameRangesDto | undefined> {
|
||||
return this._withAdapter(handle, OnTypeRenameAdapter, async adapter => {
|
||||
const res = await adapter.provideOnTypeRenameRanges(URI.revive(resource), position, token);
|
||||
if (res) {
|
||||
|
||||
@@ -2891,3 +2891,9 @@ export enum StandardTokenType {
|
||||
String = 2,
|
||||
RegEx = 4
|
||||
}
|
||||
|
||||
|
||||
export class OnTypeRenameRanges {
|
||||
constructor(public readonly ranges: Range[], public readonly wordPattern?: RegExp) {
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user