提交 9b363e8e 编写于 作者: J Johannes Rieken

cleanup rename-flow, #7340

上级 78a2f08d
......@@ -919,7 +919,7 @@ export interface WorkspaceEdit {
export interface RenameInformation {
range: IRange;
text?: string;
text: string;
}
export interface RenameProvider {
......
......@@ -6,7 +6,7 @@
'use strict';
import * as nls from 'vs/nls';
import { isPromiseCanceledError, illegalArgument, onUnexpectedExternalError } from 'vs/base/common/errors';
import { isPromiseCanceledError, illegalArgument } from 'vs/base/common/errors';
import { KeyMod, KeyCode } from 'vs/base/common/keyCodes';
import { TPromise } from 'vs/base/common/winjs.base';
import { IFileService } from 'vs/platform/files/common/files';
......@@ -22,8 +22,8 @@ import RenameInputField from './renameInputField';
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, RenameInformation } from 'vs/editor/common/modes';
import { asWinJsPromise } from 'vs/base/common/async';
import { WorkspaceEdit, RenameProviderRegistry, RenameInformation, RenameProvider } 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';
......@@ -32,69 +32,62 @@ import { EditorState, CodeEditorStateFlag } from 'vs/editor/browser/core/editorS
import { KeybindingsRegistry } from 'vs/platform/keybinding/common/keybindingsRegistry';
import { INotificationService } from 'vs/platform/notification/common/notification';
class RenameSkeleton {
export function rename(model: ITextModel, position: Position, newName: string): TPromise<WorkspaceEdit> {
private _provider: RenameProvider[];
const supports = RenameProviderRegistry.ordered(model);
const rejects: string[] = [];
let hasResult = false;
const factory = supports.map(support => {
return (): TPromise<WorkspaceEdit> => {
if (!hasResult) {
return asWinJsPromise((token) => {
return support.provideRenameEdits(model, position, newName, token);
}).then(result => {
if (!result) {
// ignore
} else if (!result.rejectReason) {
hasResult = true;
return result;
} else {
rejects.push(result.rejectReason);
}
return undefined;
});
constructor(
readonly model: ITextModel,
readonly position: Position
) {
this._provider = RenameProviderRegistry.ordered(model);
}
hasProvider() {
return this._provider.length > 0;
}
async resolveRenameInformation(): TPromise<RenameInformation> {
let [provider] = this._provider;
let information: RenameInformation;
if (provider.resolveInitialRenameValue) {
information = await asWinJsPromise(token => provider.resolveInitialRenameValue(this.model, this.position, token));
}
if (!information) {
let word = this.model.getWordAtPosition(this.position);
if (word) {
information = {
range: new Range(this.position.lineNumber, word.startColumn, this.position.lineNumber, word.endColumn),
text: word.word
};
}
return undefined;
};
});
}
return sequence(factory).then((values): WorkspaceEdit => {
let result = values[0];
if (rejects.length > 0) {
return {
edits: undefined,
rejectReason: rejects.join('\n')
};
} else if (!result) {
return {
return information;
}
async rename(newName: string): TPromise<WorkspaceEdit> {
let [provider] = this._provider;
let result = await asWinJsPromise((token) => provider.provideRenameEdits(this.model, this.position, newName, token));
if (!result) {
result = {
edits: undefined,
rejectReason: nls.localize('no result', "No result.")
};
} else {
return result;
}
});
return result;
}
}
// TODO@joh
// merge this into above function to make we always
// use the same provider for resolving and renamin
function resolveInitialRenameValue(model: ITextModel, position: Position): TPromise<RenameInformation> {
const [first] = RenameProviderRegistry.ordered(model);
if (!first || typeof first.resolveInitialRenameValue !== 'function') {
return TPromise.as(null);
}
//Use first rename provider so that we always use the same for resolving the location and for the actual rename
return asWinJsPromise(token => first.resolveInitialRenameValue(model, position, token)).then(result => {
return !result ? undefined : result;
}, err => {
onUnexpectedExternalError(err);
return TPromise.wrapError<RenameInformation>(new Error('provider failed'));
});
export function rename(model: ITextModel, position: Position, newName: string): TPromise<WorkspaceEdit> {
return new RenameSkeleton(model, position).rename(newName);
}
// --- register actions and commands
const CONTEXT_RENAME_INPUT_VISIBLE = new RawContextKey<boolean>('renameInputVisible', false);
......@@ -132,70 +125,32 @@ class RenameController implements IEditorContribution {
}
public async run(): TPromise<void> {
const selection = this.editor.getSelection();
let lineNumber = selection.startLineNumber,
selectionStart = 0,
selectionEnd = 0,
wordRange: Range,
word: string;
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
);
const skeleton = new RenameSkeleton(this.editor.getModel(), this.editor.getPosition());
let initialValue = await skeleton.resolveRenameInformation();
if (!initialValue) {
return undefined;
}
else {
const wordAtPosition = this.editor.getModel().getWordAtPosition(selection.getStartPosition());
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;
}
let selection = this.editor.getSelection();
let selectionStart = 0;
let selectionEnd = initialValue.text.length;
wordRange = new Range(
lineNumber,
wordAtPosition.startColumn,
lineNumber,
wordAtPosition.endColumn
);
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;
}
this._renameInputVisible.set(true);
return this._renameInputField.getInput(wordRange, word, selectionStart, selectionEnd).then(newName => {
return this._renameInputField.getInput(Range.lift(initialValue.range), initialValue.text, selectionStart, selectionEnd).then(newName => {
this._renameInputVisible.reset();
this.editor.focus();
const edit = new BulkEdit(this.editor, null, this._textModelResolverService, this._fileService);
const state = new EditorState(this.editor, CodeEditorStateFlag.Position | CodeEditorStateFlag.Value | CodeEditorStateFlag.Selection | CodeEditorStateFlag.Scroll);
const renameOperation = rename(this.editor.getModel(), this.editor.getPosition(), newName).then(result => {
const renameOperation = skeleton.rename(newName).then(result => {
if (result.rejectReason) {
if (state.validate(this.editor)) {
MessageController.get(this.editor).showMessage(result.rejectReason, this.editor.getPosition());
......@@ -211,7 +166,7 @@ class RenameController implements IEditorContribution {
this.editor.setSelection(selection);
}
// alert
alert(nls.localize('aria', "Successfully renamed '{0}' to '{1}'. Summary: {2}", word, newName, edit.ariaMessage()));
alert(nls.localize('aria', "Successfully renamed '{0}' to '{1}'. Summary: {2}", initialValue.text, newName, edit.ariaMessage()));
});
}, err => {
......
......@@ -4966,7 +4966,7 @@ declare module monaco.languages {
export interface RenameInformation {
range: IRange;
text?: string;
text: string;
}
export interface RenameProvider {
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册