Skip to content

Commit

Permalink
allow to return range or range and placeholder, #7340
Browse files Browse the repository at this point in the history
  • Loading branch information
jrieken committed Apr 17, 2018
1 parent 523abdc commit 8c1e3a7
Show file tree
Hide file tree
Showing 9 changed files with 60 additions and 34 deletions.
7 changes: 6 additions & 1 deletion src/vs/editor/common/modes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -929,9 +929,14 @@ export interface WorkspaceEdit {
rejectReason?: string; // TODO@joh, move to rename
}

export interface RenameLocation {
range: IRange;
text: string;
}

export interface RenameProvider {
provideRenameEdits(model: model.ITextModel, position: Position, newName: string, token: CancellationToken): WorkspaceEdit | Thenable<WorkspaceEdit>;
resolveRenameLocation?(model: model.ITextModel, position: Position, token: CancellationToken): IRange | Thenable<IRange>;
resolveRenameLocation?(model: model.ITextModel, position: Position, token: CancellationToken): RenameLocation | Thenable<RenameLocation>;
}


Expand Down
40 changes: 21 additions & 19 deletions src/vs/editor/contrib/rename/rename.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,10 @@ 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 { asWinJsPromise } from 'vs/base/common/async';
import { WorkspaceEdit, RenameProviderRegistry, RenameProvider } from 'vs/editor/common/modes';
import { WorkspaceEdit, RenameProviderRegistry, RenameProvider, RenameLocation } from 'vs/editor/common/modes';
import { Position } from 'vs/editor/common/core/position';
import { alert } from 'vs/base/browser/ui/aria/aria';
import { Range, IRange } from 'vs/editor/common/core/range';
import { Range } from 'vs/editor/common/core/range';
import { MessageController } from 'vs/editor/contrib/message/messageController';
import { EditorState, CodeEditorStateFlag } from 'vs/editor/browser/core/editorState';
import { KeybindingsRegistry } from 'vs/platform/keybinding/common/keybindingsRegistry';
Expand All @@ -47,23 +47,26 @@ class RenameSkeleton {
return this._provider.length > 0;
}

async resolveRenameLocation(): TPromise<IRange> {
async resolveRenameLocation(): TPromise<RenameLocation> {

let [provider] = this._provider;
let range: IRange;
let res: RenameLocation;

if (provider.resolveRenameLocation) {
range = await asWinJsPromise(token => provider.resolveRenameLocation(this.model, this.position, token));
res = await asWinJsPromise(token => provider.resolveRenameLocation(this.model, this.position, token));
}

if (!range) {
if (!res) {
let word = this.model.getWordAtPosition(this.position);
if (word) {
range = new Range(this.position.lineNumber, word.startColumn, this.position.lineNumber, word.endColumn);
res = {
range: new Range(this.position.lineNumber, word.startColumn, this.position.lineNumber, word.endColumn),
text: word.word
};
}
}

return range;
return res;
}

async provideRenameEdits(newName: string, i: number = 0, rejects: string[] = [], position: Position = this.position): TPromise<WorkspaceEdit> {
Expand Down Expand Up @@ -131,30 +134,29 @@ class RenameController implements IEditorContribution {
const position = this.editor.getPosition();
const skeleton = new RenameSkeleton(this.editor.getModel(), position);

let range: IRange;
let loc: RenameLocation;
try {
range = await skeleton.resolveRenameLocation();
loc = await skeleton.resolveRenameLocation();
} catch (e) {
MessageController.get(this.editor).showMessage(e, position);
return undefined;
}

if (!range) {
if (!loc) {
return undefined;
}

let text = this.editor.getModel().getValueInRange(range);
let selection = this.editor.getSelection();
let selectionStart = 0;
let selectionEnd = text.length;
let selectionEnd = loc.text.length;

if (!selection.isEmpty() && selection.startLineNumber === selection.endLineNumber) {
selectionStart = Math.max(0, selection.startColumn - range.startColumn);
selectionEnd = Math.min(range.endColumn, selection.endColumn) - range.startColumn;
if (!Range.isEmpty(selection) && !Range.spansMultipleLines(selection) && Range.containsRange(loc.range, selection)) {
selectionStart = Math.max(0, selection.startColumn - loc.range.startColumn);
selectionEnd = Math.min(loc.range.endColumn, selection.endColumn) - loc.range.startColumn;
}

this._renameInputVisible.set(true);
return this._renameInputField.getInput(Range.lift(range), text, selectionStart, selectionEnd).then(newNameOrFocusFlag => {
return this._renameInputField.getInput(loc.range, loc.text, selectionStart, selectionEnd).then(newNameOrFocusFlag => {
this._renameInputVisible.reset();

if (typeof newNameOrFocusFlag === 'boolean') {
Expand All @@ -169,7 +171,7 @@ class RenameController implements IEditorContribution {
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 = skeleton.provideRenameEdits(newNameOrFocusFlag, 0, [], Range.lift(range).getStartPosition()).then(result => {
const renameOperation = skeleton.provideRenameEdits(newNameOrFocusFlag, 0, [], Range.lift(loc.range).getStartPosition()).then(result => {
if (result.rejectReason) {
if (state.validate(this.editor)) {
MessageController.get(this.editor).showMessage(result.rejectReason, this.editor.getPosition());
Expand All @@ -185,7 +187,7 @@ class RenameController implements IEditorContribution {
this.editor.setSelection(selection);
}
// alert
alert(nls.localize('aria', "Successfully renamed '{0}' to '{1}'. Summary: {2}", text, newNameOrFocusFlag, edit.ariaMessage()));
alert(nls.localize('aria', "Successfully renamed '{0}' to '{1}'. Summary: {2}", loc.text, newNameOrFocusFlag, edit.ariaMessage()));
});

}, err => {
Expand Down
4 changes: 2 additions & 2 deletions src/vs/editor/contrib/rename/renameInputField.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import 'vs/css!./renameInputField';
import { localize } from 'vs/nls';
import { IDisposable, dispose } from 'vs/base/common/lifecycle';
import { TPromise } from 'vs/base/common/winjs.base';
import { Range } from 'vs/editor/common/core/range';
import { Range, IRange } from 'vs/editor/common/core/range';
import { ContentWidgetPositionPreference, ICodeEditor, IContentWidget, IContentWidgetPosition } from 'vs/editor/browser/editorBrowser';
import { IThemeService, ITheme } from 'vs/platform/theme/common/themeService';
import { inputBackground, inputBorder, inputForeground, widgetShadow } from 'vs/platform/theme/common/colorRegistry';
Expand Down Expand Up @@ -123,7 +123,7 @@ export default class RenameInputField implements IContentWidget, IDisposable {
}
}

public getInput(where: Range, value: string, selectionStart: number, selectionEnd: number): TPromise<string | boolean> {
public getInput(where: IRange, value: string, selectionStart: number, selectionEnd: number): TPromise<string | boolean> {

this._position = new Position(where.startLineNumber, where.startColumn);
this._inputField.value = value;
Expand Down
7 changes: 6 additions & 1 deletion src/vs/monaco.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5016,9 +5016,14 @@ declare namespace monaco.languages {
rejectReason?: string;
}

export interface RenameLocation {
range: IRange;
text: string;
}

export interface RenameProvider {
provideRenameEdits(model: editor.ITextModel, position: Position, newName: string, token: CancellationToken): WorkspaceEdit | Thenable<WorkspaceEdit>;
resolveRenameLocation?(model: editor.ITextModel, position: Position, token: CancellationToken): IRange | Thenable<IRange>;
resolveRenameLocation?(model: editor.ITextModel, position: Position, token: CancellationToken): RenameLocation | Thenable<RenameLocation>;
}

export interface Command {
Expand Down
2 changes: 1 addition & 1 deletion src/vs/vscode.proposed.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -503,7 +503,7 @@ declare module 'vscode' {
* @param token A cancellation token.
* @return The range of the identifier that is to be renamed. The lack of a result can signaled by returning `undefined` or `null`.
*/
resolveRenameLocation?(document: TextDocument, position: Position, token: CancellationToken): ProviderResult<Range>;
resolveRenameLocation?(document: TextDocument, position: Position, token: CancellationToken): ProviderResult<Range | { range: Range, placeholder: string }>;

}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import { WorkspaceSymbolProviderRegistry, IWorkspaceSymbolProvider } from 'vs/wo
import { wireCancellationToken } from 'vs/base/common/async';
import { CancellationToken } from 'vs/base/common/cancellation';
import { Position as EditorPosition } from 'vs/editor/common/core/position';
import { Range as EditorRange, IRange } from 'vs/editor/common/core/range';
import { Range as EditorRange } from 'vs/editor/common/core/range';
import { ExtHostContext, MainThreadLanguageFeaturesShape, ExtHostLanguageFeaturesShape, MainContext, IExtHostContext, ISerializedLanguageConfiguration, ISerializedRegExp, ISerializedIndentationRule, ISerializedOnEnterRule, LocationDto, SymbolInformationDto, CodeActionDto, reviveWorkspaceEditDto, ISerializedDocumentFilter } from '../node/extHost.protocol';
import { LanguageConfigurationRegistry } from 'vs/editor/common/modes/languageConfigurationRegistry';
import { LanguageConfiguration, IndentationRule, OnEnterRule } from 'vs/editor/common/modes/languageConfiguration';
Expand Down Expand Up @@ -258,7 +258,7 @@ export class MainThreadLanguageFeatures implements MainThreadLanguageFeaturesSha
return wireCancellationToken(token, this._proxy.$provideRenameEdits(handle, model.uri, position, newName)).then(reviveWorkspaceEditDto);
},
resolveRenameLocation: supportResolveLocation
? (model: ITextModel, position: EditorPosition, token: CancellationToken): Thenable<IRange> => wireCancellationToken(token, this._proxy.$resolveRenameLocation(handle, model.uri, position))
? (model: ITextModel, position: EditorPosition, token: CancellationToken): Thenable<modes.RenameLocation> => wireCancellationToken(token, this._proxy.$resolveRenameLocation(handle, model.uri, position))
: undefined
});
}
Expand Down
2 changes: 1 addition & 1 deletion src/vs/workbench/api/node/extHost.protocol.ts
Original file line number Diff line number Diff line change
Expand Up @@ -710,7 +710,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>;
$resolveRenameLocation(handle: number, resource: UriComponents, position: IPosition): TPromise<IRange>;
$resolveRenameLocation(handle: number, resource: UriComponents, position: IPosition): TPromise<modes.RenameLocation>;
$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;
Expand Down
26 changes: 20 additions & 6 deletions src/vs/workbench/api/node/extHostLanguageFeatures.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import { regExpLeadsToEndlessLoop } from 'vs/base/common/strings';
import { IPosition } from 'vs/editor/common/core/position';
import { IRange } from 'vs/editor/common/core/range';
import { isFalsyOrEmpty } from 'vs/base/common/arrays';
import { isObject } from 'vs/base/common/types';

// --- adapter

Expand Down Expand Up @@ -506,23 +507,36 @@ class RenameAdapter {
});
}

resolveRenameLocation(resource: URI, position: IPosition): TPromise<IRange> {
resolveRenameLocation(resource: URI, position: IPosition): TPromise<modes.RenameLocation> {
if (typeof this._provider.resolveRenameLocation !== 'function') {
return TPromise.as(undefined);
}

let doc = this._documents.getDocumentData(resource).document;
let pos = TypeConverters.toPosition(position);

return asWinJsPromise(token => this._provider.resolveRenameLocation(doc, pos, token)).then(range => {
return asWinJsPromise(token => this._provider.resolveRenameLocation(doc, pos, token)).then(rangeOrLocation => {

let range: vscode.Range;
let text: string;
if (Range.isRange(rangeOrLocation)) {
range = rangeOrLocation;
text = doc.getText(rangeOrLocation);

} else if (isObject(rangeOrLocation)) {
range = rangeOrLocation.range;
text = rangeOrLocation.placeholder;
}

if (!range) {
return undefined;
}
if (range && (!range.isSingleLine || range.start.line !== pos.line)) {
console.warn('INVALID rename context, range must be single line and on the same line');

if (!range.contains(pos)) {
console.warn('INVALID rename location: range must contain position');
return undefined;
}
return TypeConverters.fromRange(range);
return { range: TypeConverters.fromRange(range), text };
});
}
}
Expand Down Expand Up @@ -1088,7 +1102,7 @@ export class ExtHostLanguageFeatures implements ExtHostLanguageFeaturesShape {
return this._withAdapter(handle, RenameAdapter, adapter => adapter.provideRenameEdits(URI.revive(resource), position, newName));
}

$resolveRenameLocation(handle: number, resource: URI, position: IPosition): TPromise<IRange> {
$resolveRenameLocation(handle: number, resource: URI, position: IPosition): TPromise<modes.RenameLocation> {
return this._withAdapter(handle, RenameAdapter, adapter => adapter.resolveRenameLocation(resource, position));
}

Expand Down
2 changes: 1 addition & 1 deletion src/vs/workbench/api/node/extHostTypes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -208,7 +208,7 @@ export class Position {

export class Range {

static isRange(thing: any): thing is Range {
static isRange(thing: any): thing is vscode.Range {
if (thing instanceof Range) {
return true;
}
Expand Down

0 comments on commit 8c1e3a7

Please sign in to comment.