diff --git a/src/vs/editor/common/modes.ts b/src/vs/editor/common/modes.ts index 86c0b612d25..e27b7ce7530 100644 --- a/src/vs/editor/common/modes.ts +++ b/src/vs/editor/common/modes.ts @@ -521,26 +521,18 @@ export interface IConfigurationSupport { configure(options:any):TPromise; } + export interface IResourceEdit { resource: URI; - range?: editorCommon.IRange; + range: editorCommon.IRange; newText: string; } - -export interface IRenameResult { - currentName: string; +export interface WorkspaceEdit { edits: IResourceEdit[]; rejectReason?: string; } - -/** - * Interface used to support renaming of symbols - */ -export interface IRenameSupport { - - filter?: string[]; - - rename(resource: URI, position: editorCommon.IPosition, newName: string): TPromise; +export interface RenameProvider { + provideRenameEdits(model:editorCommon.IReadOnlyModel, position:editorCommon.IEditorPosition, newName: string, token: CancellationToken): WorkspaceEdit | Thenable; } export interface ICommand { @@ -691,7 +683,7 @@ export interface IRichEditSupport { export const ReferenceProviderRegistry = new LanguageFeatureRegistry(); -export const RenameRegistry = new LanguageFeatureRegistry(); +export const RenameProviderRegistry = new LanguageFeatureRegistry(); export const SuggestRegistry = new LanguageFeatureRegistry(); diff --git a/src/vs/editor/common/modes/supports.ts b/src/vs/editor/common/modes/supports.ts index 3bfbe3299de..ad60086e7c6 100644 --- a/src/vs/editor/common/modes/supports.ts +++ b/src/vs/editor/common/modes/supports.ts @@ -71,42 +71,6 @@ export function handleEvent(context:modes.ILineContext, offset:number, runner return runner(nestedMode, newCtx, offset - firstTokenCharacterOffset); } -/** - * Returns {{true}} if the line token at the specified - * offset matches one of the provided types. Matching - * happens on a substring start from the end, unless - * anywhereInToken is set to true in which case matches - * happen on a substring at any position. - */ -export function isLineToken(context:modes.ILineContext, offset:number, types:string[], anywhereInToken:boolean = false):boolean { - - if (!Array.isArray(types) || types.length === 0) { - return false; - } - - if (context.getLineContent().length <= offset) { - return false; - } - - var tokenIdx = context.findIndexOfOffset(offset); - var type = context.getTokenType(tokenIdx); - - for (var i = 0, len = types.length; i < len; i++) { - if (anywhereInToken) { - if (type.indexOf(types[i]) >= 0) { - return true; - } - } - else { - if (strings.endsWith(type, types[i])) { - return true; - } - } - } - - return false; -} - export class FilteredLineContext implements modes.ILineContext { public modeTransitions: ModeTransition[]; diff --git a/src/vs/editor/contrib/rename/browser/rename.ts b/src/vs/editor/contrib/rename/browser/rename.ts index 1f25fd5f4ac..e50cf0b6cb5 100644 --- a/src/vs/editor/contrib/rename/browser/rename.ts +++ b/src/vs/editor/contrib/rename/browser/rename.ts @@ -18,8 +18,7 @@ import {EditorAction} from 'vs/editor/common/editorAction'; import {Behaviour} from 'vs/editor/common/editorActionEnablement'; import {IEditorActionDescriptorData, IRange} from 'vs/editor/common/editorCommon'; import {CommonEditorRegistry, ContextKey, EditorActionDescriptor} from 'vs/editor/common/editorCommonExtensions'; -import {isLineToken} from 'vs/editor/common/modes/supports'; -import {RenameRegistry} from 'vs/editor/common/modes'; +import {RenameProviderRegistry} from 'vs/editor/common/modes'; import {BulkEdit, createBulkEdit} from 'vs/editor/common/services/bulkEdit'; import {ICodeEditor} from 'vs/editor/browser/editorBrowser'; import {rename} from '../common/rename'; @@ -58,28 +57,11 @@ export class RenameAction extends EditorAction { } public isSupported(): boolean { - return RenameRegistry.has(this.editor.getModel()) && !this.editor.getModel().hasEditableRange() && super.isSupported(); + return RenameProviderRegistry.has(this.editor.getModel()) && !this.editor.getModel().hasEditableRange() && super.isSupported(); } public getEnablementState(): boolean { - - let model = this.editor.getModel(); - let position = this.editor.getSelection().getStartPosition(); - let lineContext = model.getLineContext(position.lineNumber); - - return RenameRegistry.ordered(model).some(support => { - if (!support.filter) { - return true; - } - if (isLineToken(lineContext, position.column - 1, support.filter)) { - return true; - } - - if (position.column > 1 && isLineToken(lineContext, position.column - 2, support.filter)) { - // in case we are in between two tokens - return true; - } - }); + return RenameProviderRegistry.has(this.editor.getModel()); } public run(event?: any): TPromise { diff --git a/src/vs/editor/contrib/rename/common/rename.ts b/src/vs/editor/contrib/rename/common/rename.ts index e82800a4cf0..013cbc7d6d7 100644 --- a/src/vs/editor/contrib/rename/common/rename.ts +++ b/src/vs/editor/contrib/rename/common/rename.ts @@ -6,24 +6,25 @@ 'use strict'; import {localize} from 'vs/nls'; -import {sequence} from 'vs/base/common/async'; +import {sequence, asWinJsPromise} from 'vs/base/common/async'; import {illegalArgument} from 'vs/base/common/errors'; import {TPromise} from 'vs/base/common/winjs.base'; -import {IReadOnlyModel, IPosition} from 'vs/editor/common/editorCommon'; +import {IReadOnlyModel, IEditorPosition} from 'vs/editor/common/editorCommon'; import {CommonEditorRegistry} from 'vs/editor/common/editorCommonExtensions'; -import {IRenameResult, RenameRegistry} from 'vs/editor/common/modes'; +import {WorkspaceEdit, RenameProviderRegistry} from 'vs/editor/common/modes'; -export function rename(model: IReadOnlyModel, position: IPosition, newName: string): TPromise { +export function rename(model: IReadOnlyModel, position: IEditorPosition, newName: string): TPromise { - const supports = RenameRegistry.ordered(model); - const resource = model.getAssociatedResource(); + const supports = RenameProviderRegistry.ordered(model); const rejects: string[] = []; let hasResult = false; const factory = supports.map(support => { return () => { if (!hasResult) { - return support.rename(resource, position, newName).then(result => { + return asWinJsPromise((token) => { + return support.provideRenameEdits(model, position, newName, token); + }).then(result => { if (!result) { // ignore } else if (!result.rejectReason) { @@ -37,17 +38,15 @@ export function rename(model: IReadOnlyModel, position: IPosition, newName: stri }; }); - return sequence(factory).then(values => { + return sequence(factory).then((values): WorkspaceEdit => { let result = values[0]; if (rejects.length > 0) { - return { - currentName: undefined, + return { edits: undefined, rejectReason: rejects.join('\n') }; } else if (!result) { - return { - currentName: undefined, + return { edits: undefined, rejectReason: localize('no result', "No result.") }; diff --git a/src/vs/workbench/api/node/extHostApiCommands.ts b/src/vs/workbench/api/node/extHostApiCommands.ts index 4d7d5b966cc..79944234de4 100644 --- a/src/vs/workbench/api/node/extHostApiCommands.ts +++ b/src/vs/workbench/api/node/extHostApiCommands.ts @@ -285,7 +285,7 @@ class ExtHostApiCommands { position: position && typeConverters.fromPosition(position), newName }; - return this._commands.executeCommand('_executeDocumentRenameProvider', args).then(value => { + return this._commands.executeCommand('_executeDocumentRenameProvider', args).then(value => { if (!value) { return; } diff --git a/src/vs/workbench/api/node/extHostLanguageFeatures.ts b/src/vs/workbench/api/node/extHostLanguageFeatures.ts index a0126244f6e..4b63f539aae 100644 --- a/src/vs/workbench/api/node/extHostLanguageFeatures.ts +++ b/src/vs/workbench/api/node/extHostLanguageFeatures.ts @@ -415,7 +415,7 @@ class NavigateTypeAdapter implements INavigateTypesSupport { } } -class RenameAdapter implements modes.IRenameSupport { +class RenameAdapter { private _documents: ExtHostModelService; private _provider: vscode.RenameProvider; @@ -425,7 +425,7 @@ class RenameAdapter implements modes.IRenameSupport { this._provider = provider; } - rename(resource: URI, position: IPosition, newName: string): TPromise { + provideRenameEdits(resource: URI, position: IPosition, newName: string): TPromise { let doc = this._documents.getDocumentData(resource).document; let pos = TypeConverters.toPosition(position); @@ -436,8 +436,7 @@ class RenameAdapter implements modes.IRenameSupport { return; } - let result = { - currentName: undefined, + let result = { edits: [] }; @@ -454,8 +453,7 @@ class RenameAdapter implements modes.IRenameSupport { return result; }, err => { if (typeof err === 'string') { - return { - currentName: undefined, + return { edits: undefined, rejectReason: err }; @@ -792,8 +790,8 @@ export class ExtHostLanguageFeatures { return this._createDisposable(handle); } - $rename(handle: number, resource: URI, position: IPosition, newName: string): TPromise { - return this._withAdapter(handle, RenameAdapter, adapter => adapter.rename(resource, position, newName)); + $provideRenameEdits(handle: number, resource: URI, position: IPosition, newName: string): TPromise { + return this._withAdapter(handle, RenameAdapter, adapter => adapter.provideRenameEdits(resource, position, newName)); } // --- suggestion @@ -975,9 +973,9 @@ export class MainThreadLanguageFeatures { // --- rename $registerRenameSupport(handle: number, selector: vscode.DocumentSelector): TPromise { - this._registrations[handle] = modes.RenameRegistry.register(selector, { - rename: (resource: URI, position: IPosition, newName: string): TPromise => { - return this._proxy.$rename(handle, resource, position, newName); + this._registrations[handle] = modes.RenameProviderRegistry.register(selector, { + provideRenameEdits: (model:IReadOnlyModel, position:IEditorPosition, newName: string, token: CancellationToken): Thenable => { + return wireCancellationToken(token, this._proxy.$provideRenameEdits(handle, model.getAssociatedResource(), position, newName)); } }); return undefined; diff --git a/src/vs/workbench/test/node/api/extHostLanguageFeatures.test.ts b/src/vs/workbench/test/node/api/extHostLanguageFeatures.test.ts index 921f4910668..63f7b44b044 100644 --- a/src/vs/workbench/test/node/api/extHostLanguageFeatures.test.ts +++ b/src/vs/workbench/test/node/api/extHostLanguageFeatures.test.ts @@ -650,7 +650,7 @@ suite('ExtHostLanguageFeatures', function() { return threadService.sync().then(() => { - return rename(model, { lineNumber: 1, column: 1 }, 'newName').then(value => { + return rename(model, new EditorPosition(1, 1), 'newName').then(value => { throw new Error(''); }, err => { // expected @@ -676,7 +676,7 @@ suite('ExtHostLanguageFeatures', function() { return threadService.sync().then(() => { - return rename(model, { lineNumber: 1, column: 1 }, 'newName').then(value => { + return rename(model, new EditorPosition(1, 1), 'newName').then(value => { assert.equal(value.edits.length, 1); }); }); @@ -701,7 +701,7 @@ suite('ExtHostLanguageFeatures', function() { return threadService.sync().then(() => { - return rename(model, { lineNumber: 1, column: 1 }, 'newName').then(value => { + return rename(model, new EditorPosition(1, 1), 'newName').then(value => { assert.equal(value.edits.length, 2); // least relevant renamer }); });