未验证 提交 86b8fb26 编写于 作者: J Johannes Rieken 提交者: GitHub

Merge pull request #37691 from Krzysztof-Cieslak/resolveInitialRenameValue

Resolve initial rename value
......@@ -856,8 +856,14 @@ export interface WorkspaceEdit {
rejectReason?: string; // TODO@joh, move to rename
}
export interface RenameInitialValue {
range: IRange;
text?: string;
}
export interface RenameProvider {
provideRenameEdits(model: model.ITextModel, position: Position, newName: string, token: CancellationToken): WorkspaceEdit | Thenable<WorkspaceEdit>;
resolveInitialRenameValue?(model: model.ITextModel, position: Position, token: CancellationToken): RenameInitialValue | Thenable<RenameInitialValue>;
}
......
......@@ -6,7 +6,7 @@
'use strict';
import * as nls from 'vs/nls';
import { isPromiseCanceledError, illegalArgument } from 'vs/base/common/errors';
import { isPromiseCanceledError, illegalArgument, onUnexpectedExternalError } from 'vs/base/common/errors';
import { KeyMod, KeyCode } from 'vs/base/common/keyCodes';
import Severity from 'vs/base/common/severity';
import { TPromise } from 'vs/base/common/winjs.base';
......@@ -25,7 +25,7 @@ import { ITextModelService } from 'vs/editor/common/services/resolverService';
import { optional } from 'vs/platform/instantiation/common/instantiation';
import { IThemeService } from 'vs/platform/theme/common/themeService';
import { sequence, asWinJsPromise } from 'vs/base/common/async';
import { WorkspaceEdit, RenameProviderRegistry } from 'vs/editor/common/modes';
import { WorkspaceEdit, RenameProviderRegistry, RenameInitialValue } from 'vs/editor/common/modes';
import { Position } from 'vs/editor/common/core/position';
import { alert } from 'vs/base/browser/ui/aria/aria';
import { Range } from 'vs/editor/common/core/range';
......@@ -79,6 +79,19 @@ export function rename(model: ITextModel, position: Position, newName: string):
});
}
function resolveInitialRenameValue(model: ITextModel, position: Position): TPromise<RenameInitialValue> {
const supports = RenameProviderRegistry.ordered(model);
return asWinJsPromise((token) =>
supports.length > 0
? supports[0].resolveInitialRenameValue(model, position, token) //Use first rename provider so that we always use the same for resolving the location and for the actual rename
: undefined
).then(result => {
return !result ? undefined : result;
}, err => {
onUnexpectedExternalError(err);
return TPromise.wrapError<RenameInitialValue>(new Error('provider failed'));
});
}
// --- register actions and commands
......@@ -116,34 +129,64 @@ class RenameController implements IEditorContribution {
return RenameController.ID;
}
public run(): TPromise<void> {
public async run(): TPromise<void> {
const selection = this.editor.getSelection();
let lineNumber = selection.startLineNumber,
selectionStart = 0,
selectionEnd = 0,
wordRange: Range,
word: string;
const selection = this.editor.getSelection(),
word = this.editor.getModel().getWordAtPosition(selection.getStartPosition());
let initialValue = await resolveInitialRenameValue(this.editor.getModel(), this.editor.getPosition());
if(initialValue) {
lineNumber = initialValue.range.startLineNumber;
if(initialValue.text) {
word = initialValue.text;
}
else {
word = this.editor.getModel().getValueInRange(initialValue.range);
}
selectionEnd = word.length;
if (!selection.isEmpty() && selection.startLineNumber === selection.endLineNumber) {
selectionStart = Math.max(0, selection.startColumn - initialValue.range.startColumn);
selectionEnd = Math.min(initialValue.range.endColumn, selection.endColumn) - initialValue.range.startColumn;
}
wordRange = new Range(
lineNumber,
initialValue.range.startColumn,
lineNumber,
initialValue.range.endColumn
);
if (!word) {
return undefined;
}
else {
const wordAtPosition = this.editor.getModel().getWordAtPosition(selection.getStartPosition());
let lineNumber = selection.startLineNumber,
selectionStart = 0,
selectionEnd = word.word.length,
wordRange: Range;
wordRange = new Range(
lineNumber,
word.startColumn,
lineNumber,
word.endColumn
);
if (!selection.isEmpty() && selection.startLineNumber === selection.endLineNumber) {
selectionStart = Math.max(0, selection.startColumn - word.startColumn);
selectionEnd = Math.min(word.endColumn, selection.endColumn) - word.startColumn;
if (!wordAtPosition) {
return undefined;
}
word = wordAtPosition.word;
selectionEnd = word.length;
if (!selection.isEmpty() && selection.startLineNumber === selection.endLineNumber) {
selectionStart = Math.max(0, selection.startColumn - wordAtPosition.startColumn);
selectionEnd = Math.min(wordAtPosition.endColumn, selection.endColumn) - wordAtPosition.startColumn;
}
wordRange = new Range(
lineNumber,
wordAtPosition.startColumn,
lineNumber,
wordAtPosition.endColumn
);
}
this._renameInputVisible.set(true);
return this._renameInputField.getInput(wordRange, word.word, selectionStart, selectionEnd).then(newName => {
return this._renameInputField.getInput(wordRange, word, selectionStart, selectionEnd).then(newName => {
this._renameInputVisible.reset();
this.editor.focus();
......@@ -166,7 +209,7 @@ class RenameController implements IEditorContribution {
this.editor.setSelection(selection);
}
// alert
alert(nls.localize('aria', "Successfully renamed '{0}' to '{1}'. Summary: {2}", word.word, newName, edit.ariaMessage()));
alert(nls.localize('aria', "Successfully renamed '{0}' to '{1}'. Summary: {2}", word, newName, edit.ariaMessage()));
});
}, err => {
......
......@@ -4956,8 +4956,14 @@ declare module monaco.languages {
rejectReason?: string;
}
export interface RenameInitialValue {
range: IRange;
text?: string;
}
export interface RenameProvider {
provideRenameEdits(model: editor.ITextModel, position: Position, newName: string, token: CancellationToken): WorkspaceEdit | Thenable<WorkspaceEdit>;
resolveInitialRenameValue?(model: editor.ITextModel, position: Position, token: CancellationToken): RenameInitialValue | Thenable<RenameInitialValue>;
}
export interface Command {
......
......@@ -2664,6 +2664,11 @@ declare module 'vscode' {
appendVariable(name: string, defaultValue: string | ((snippet: SnippetString) => any)): SnippetString;
}
export interface RenameInitialValue {
range: Range
text?: string
}
/**
* The rename provider interface defines the contract between extensions and
* the [rename](https://code.visualstudio.com/docs/editor/editingevolved#_rename-symbol)-feature.
......@@ -2682,6 +2687,8 @@ declare module 'vscode' {
* signaled by returning `undefined` or `null`.
*/
provideRenameEdits(document: TextDocument, position: Position, newName: string, token: CancellationToken): ProviderResult<WorkspaceEdit>;
resolveInitialRenameValue?(document: TextDocument, position: Position, token: CancellationToken): ProviderResult<RenameInitialValue>;
}
/**
......
......@@ -251,10 +251,14 @@ export class MainThreadLanguageFeatures implements MainThreadLanguageFeaturesSha
// --- rename
$registerRenameSupport(handle: number, selector: vscode.DocumentSelector): void {
$registerRenameSupport(handle: number, selector: vscode.DocumentSelector, supportsResolveInitialValues: boolean): void {
this._registrations[handle] = modes.RenameProviderRegistry.register(toLanguageSelector(selector), <modes.RenameProvider>{
provideRenameEdits: (model: ITextModel, position: EditorPosition, newName: string, token: CancellationToken): Thenable<modes.WorkspaceEdit> => {
return wireCancellationToken(token, this._proxy.$provideRenameEdits(handle, model.uri, position, newName)).then(reviveWorkspaceEditDto);
},
resolveInitialRenameValue: supportsResolveInitialValues
? (model: ITextModel, position: EditorPosition, token: CancellationToken): Thenable<modes.RenameInitialValue> => wireCancellationToken(token, this._proxy.$resolveInitialRenameValue(handle, model.uri, position))
: undefined
}
});
}
......
......@@ -277,7 +277,7 @@ export interface MainThreadLanguageFeaturesShape extends IDisposable {
$registerRangeFormattingSupport(handle: number, selector: vscode.DocumentSelector): void;
$registerOnTypeFormattingSupport(handle: number, selector: vscode.DocumentSelector, autoFormatTriggerCharacters: string[]): void;
$registerNavigateTypeSupport(handle: number): void;
$registerRenameSupport(handle: number, selector: vscode.DocumentSelector): void;
$registerRenameSupport(handle: number, selector: vscode.DocumentSelector, supportsResolveInitialValues: boolean): void;
$registerSuggestSupport(handle: number, selector: vscode.DocumentSelector, triggerCharacters: string[], supportsResolveDetails: boolean): void;
$registerSignatureHelpProvider(handle: number, selector: vscode.DocumentSelector, triggerCharacter: string[]): void;
$registerDocumentLinkProvider(handle: number, selector: vscode.DocumentSelector): void;
......@@ -669,6 +669,7 @@ export interface ExtHostLanguageFeaturesShape {
$resolveWorkspaceSymbol(handle: number, symbol: SymbolInformationDto): TPromise<SymbolInformationDto>;
$releaseWorkspaceSymbols(handle: number, id: number): void;
$provideRenameEdits(handle: number, resource: UriComponents, position: IPosition, newName: string): TPromise<WorkspaceEditDto>;
$resolveInitialRenameValue(handle: number, resource: UriComponents, position: IPosition): TPromise<modes.RenameInitialValue>;
$provideCompletionItems(handle: number, resource: UriComponents, position: IPosition, context: modes.SuggestContext): TPromise<SuggestResultDto>;
$resolveCompletionItem(handle: number, resource: UriComponents, position: IPosition, suggestion: modes.ISuggestion): TPromise<modes.ISuggestion>;
$releaseCompletionItems(handle: number, id: number): void;
......
......@@ -470,6 +470,10 @@ class NavigateTypeAdapter {
class RenameAdapter {
static supportsResolving(provider: vscode.RenameProvider): boolean {
return typeof provider.resolveInitialRenameValue === 'function';
}
private _documents: ExtHostDocuments;
private _provider: vscode.RenameProvider;
......@@ -505,6 +509,22 @@ class RenameAdapter {
}
});
}
resolveInitialRenameValue(resource: URI, position: IPosition) : TPromise<modes.RenameInitialValue> {
if (typeof this._provider.resolveInitialRenameValue !== 'function') {
return TPromise.as(undefined);
}
let doc = this._documents.getDocumentData(resource).document;
let pos = TypeConverters.toPosition(position);
return asWinJsPromise(token => this._provider.resolveInitialRenameValue(doc, pos, token)).then((value) => {
return <modes.RenameInitialValue> {
range: TypeConverters.fromRange(value.range),
text: value.text
};
});
}
}
......@@ -1010,7 +1030,7 @@ export class ExtHostLanguageFeatures implements ExtHostLanguageFeaturesShape {
registerRenameProvider(selector: vscode.DocumentSelector, provider: vscode.RenameProvider): vscode.Disposable {
const handle = this._addNewAdapter(new RenameAdapter(this._documents, provider));
this._proxy.$registerRenameSupport(handle, selector);
this._proxy.$registerRenameSupport(handle, selector, RenameAdapter.supportsResolving(provider));
return this._createDisposable(handle);
}
......@@ -1018,6 +1038,10 @@ export class ExtHostLanguageFeatures implements ExtHostLanguageFeaturesShape {
return this._withAdapter(handle, RenameAdapter, adapter => adapter.provideRenameEdits(URI.revive(resource), position, newName));
}
$resolveInitialRenameValue(handle: number, resource: URI, position: IPosition): TPromise<modes.RenameInitialValue> {
return this._withAdapter(handle, RenameAdapter, adapter => adapter.resolveInitialRenameValue(resource, position));
}
// --- suggestion
registerCompletionItemProvider(selector: vscode.DocumentSelector, provider: vscode.CompletionItemProvider, triggerCharacters: string[]): vscode.Disposable {
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册