Skip to content

Commit

Permalink
Merge pull request #88428 from microsoft/joh/bulkEditPreview
Browse files Browse the repository at this point in the history
Preview workspace edits
  • Loading branch information
jrieken authored Jan 13, 2020
2 parents 528202e + 175ee80 commit 17d6b13
Show file tree
Hide file tree
Showing 17 changed files with 1,345 additions and 134 deletions.
4 changes: 4 additions & 0 deletions build/lib/i18n.resources.json
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,10 @@
"name": "vs/workbench/api/common",
"project": "vscode-workbench"
},
{
"name": "vs/workbench/contrib/bulkEdit",
"project": "vscode-workbench"
},
{
"name": "vs/workbench/contrib/cli",
"project": "vscode-workbench"
Expand Down
7 changes: 6 additions & 1 deletion src/vs/base/browser/ui/highlightedlabel/highlightedLabel.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import { escape } from 'vs/base/common/strings';
export interface IHighlight {
start: number;
end: number;
extraClasses?: string;
}

export class HighlightedLabel {
Expand Down Expand Up @@ -69,7 +70,11 @@ export class HighlightedLabel {
htmlContent += '</span>';
pos = highlight.end;
}
htmlContent += '<span class="highlight">';
if (highlight.extraClasses) {
htmlContent += `<span class="highlight ${highlight.extraClasses}">`;
} else {
htmlContent += `<span class="highlight">`;
}
const substring = this.text.substring(highlight.start, highlight.end);
htmlContent += this.supportCodicons ? renderCodicons(escape(substring)) : escape(substring);
htmlContent += '</span>';
Expand Down
4 changes: 2 additions & 2 deletions src/vs/base/common/map.ts
Original file line number Diff line number Diff line change
Expand Up @@ -454,8 +454,8 @@ export class ResourceMap<T> {
return this.map.delete(this.toKey(resource));
}

forEach(clb: (value: T) => void): void {
this.map.forEach(clb);
forEach(clb: (value: T, key: URI) => void): void {
this.map.forEach((value, index) => clb(value, URI.parse(index)));
}

values(): T[] {
Expand Down
8 changes: 7 additions & 1 deletion src/vs/editor/browser/services/bulkEditService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,22 +7,28 @@ import { ICodeEditor } from 'vs/editor/browser/editorBrowser';
import { WorkspaceEdit } from 'vs/editor/common/modes';
import { createDecorator } from 'vs/platform/instantiation/common/instantiation';
import { IProgress, IProgressStep } from 'vs/platform/progress/common/progress';
import { IDisposable } from 'vs/base/common/lifecycle';

export const IBulkEditService = createDecorator<IBulkEditService>('IWorkspaceEditService');


export interface IBulkEditOptions {
editor?: ICodeEditor;
progress?: IProgress<IProgressStep>;
showPreview?: boolean;
label?: string;
}

export interface IBulkEditResult {
ariaSummary: string;
}

export type IBulkEditPreviewHandler = (edit: WorkspaceEdit, options?: IBulkEditOptions) => Promise<WorkspaceEdit>;

export interface IBulkEditService {
_serviceBrand: undefined;

setPreviewHandler(handler: IBulkEditPreviewHandler): IDisposable;

apply(edit: WorkspaceEdit, options?: IBulkEditOptions): Promise<IBulkEditResult>;
}

60 changes: 39 additions & 21 deletions src/vs/editor/contrib/rename/rename.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,14 @@
import * as nls from 'vs/nls';
import { illegalArgument, onUnexpectedError } from 'vs/base/common/errors';
import { KeyMod, KeyCode } from 'vs/base/common/keyCodes';
import { IContextKeyService, ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey';
import { ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey';
import { IEditorProgressService } from 'vs/platform/progress/common/progress';
import { registerEditorAction, registerEditorContribution, ServicesAccessor, EditorAction, EditorCommand, registerEditorCommand, registerDefaultLanguageCommand } from 'vs/editor/browser/editorExtensions';
import { IEditorContribution } from 'vs/editor/common/editorCommon';
import { ITextModel } from 'vs/editor/common/model';
import { EditorContextKeys } from 'vs/editor/common/editorContextKeys';
import { ICodeEditor } from 'vs/editor/browser/editorBrowser';
import { RenameInputField, CONTEXT_RENAME_INPUT_VISIBLE } from './renameInputField';
import { IThemeService } from 'vs/platform/theme/common/themeService';
import { WorkspaceEdit, RenameProviderRegistry, RenameProvider, RenameLocation, Rejection } from 'vs/editor/common/modes';
import { Position, IPosition } from 'vs/editor/common/core/position';
import { alert } from 'vs/base/browser/ui/aria/aria';
Expand All @@ -30,6 +29,8 @@ import { CancellationToken, CancellationTokenSource } from 'vs/base/common/cance
import { DisposableStore } from 'vs/base/common/lifecycle';
import { IdleValue, raceCancellation } from 'vs/base/common/async';
import { withNullAsUndefined } from 'vs/base/common/types';
import { ILogService } from 'vs/platform/log/common/log';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';

class RenameSkeleton {

Expand Down Expand Up @@ -109,13 +110,13 @@ class RenameController implements IEditorContribution {

constructor(
private readonly editor: ICodeEditor,
@IInstantiationService private readonly _instaService: IInstantiationService,
@INotificationService private readonly _notificationService: INotificationService,
@IBulkEditService private readonly _bulkEditService: IBulkEditService,
@IEditorProgressService private readonly _progressService: IEditorProgressService,
@IContextKeyService private readonly _contextKeyService: IContextKeyService,
@IThemeService private readonly _themeService: IThemeService,
@ILogService private readonly _logService: ILogService,
) {
this._renameInputField = this._dispoableStore.add(new IdleValue(() => this._dispoableStore.add(new RenameInputField(this.editor, this._themeService, this._contextKeyService))));
this._renameInputField = this._dispoableStore.add(new IdleValue(() => this._dispoableStore.add(this._instaService.createInstance(RenameInputField, this.editor, ['acceptRenameInput', 'acceptRenameInputWithPreview']))));
}

dispose(): void {
Expand Down Expand Up @@ -174,19 +175,19 @@ class RenameController implements IEditorContribution {
selectionEnd = Math.min(loc.range.endColumn, selection.endColumn) - loc.range.startColumn;
}

const newNameOrFocusFlag = await this._renameInputField.getValue().getInput(loc.range, loc.text, selectionStart, selectionEnd);
const inputFieldResult = await this._renameInputField.getValue().getInput(loc.range, loc.text, selectionStart, selectionEnd);


if (typeof newNameOrFocusFlag === 'boolean') {
if (newNameOrFocusFlag) {
// no result, only hint to focus the editor or not
if (typeof inputFieldResult === 'boolean') {
if (inputFieldResult) {
this.editor.focus();
}
return undefined;
}

this.editor.focus();

const renameOperation = raceCancellation(skeleton.provideRenameEdits(newNameOrFocusFlag, 0, [], this._cts.token), this._cts.token).then(async renameResult => {
const renameOperation = raceCancellation(skeleton.provideRenameEdits(inputFieldResult.newName, 0, [], this._cts.token), this._cts.token).then(async renameResult => {

if (!renameResult || !this.editor.hasModel()) {
return;
Expand All @@ -197,25 +198,31 @@ class RenameController implements IEditorContribution {
return;
}

const editResult = await this._bulkEditService.apply(renameResult, { editor: this.editor });

// alert
if (editResult.ariaSummary) {
alert(nls.localize('aria', "Successfully renamed '{0}' to '{1}'. Summary: {2}", loc!.text, newNameOrFocusFlag, editResult.ariaSummary));
}
this._bulkEditService.apply(renameResult, {
editor: this.editor,
showPreview: inputFieldResult.wantsPreview,
label: nls.localize('label', "Renaming '{0}'", loc?.text)
}).then(result => {
if (result.ariaSummary) {
alert(nls.localize('aria', "Successfully renamed '{0}' to '{1}'. Summary: {2}", loc!.text, inputFieldResult.newName, result.ariaSummary));
}
}).catch(err => {
this._notificationService.error(nls.localize('rename.failedApply', "Rename failed to apply edits"));
this._logService.error(err);
});

}, err => {
this._notificationService.error(nls.localize('rename.failed', "Rename failed to execute."));
return Promise.reject(err);
this._notificationService.error(nls.localize('rename.failed', "Rename failed to compute edits"));
this._logService.error(err);
});

this._progressService.showWhile(renameOperation, 250);
return renameOperation;

}

acceptRenameInput(): void {
this._renameInputField.getValue().acceptInput();
acceptRenameInput(wantsPreview: boolean): void {
this._renameInputField.getValue().acceptInput(wantsPreview);
}

cancelRenameInput(): void {
Expand Down Expand Up @@ -282,14 +289,25 @@ const RenameCommand = EditorCommand.bindToContribution<RenameController>(RenameC
registerEditorCommand(new RenameCommand({
id: 'acceptRenameInput',
precondition: CONTEXT_RENAME_INPUT_VISIBLE,
handler: x => x.acceptRenameInput(),
handler: x => x.acceptRenameInput(false),
kbOpts: {
weight: KeybindingWeight.EditorContrib + 99,
kbExpr: EditorContextKeys.focus,
primary: KeyCode.Enter
}
}));

registerEditorCommand(new RenameCommand({
id: 'acceptRenameInputWithPreview',
precondition: CONTEXT_RENAME_INPUT_VISIBLE,
handler: x => x.acceptRenameInput(true),
kbOpts: {
weight: KeybindingWeight.EditorContrib + 99,
kbExpr: EditorContextKeys.focus,
primary: KeyMod.Shift + KeyCode.Enter
}
}));

registerEditorCommand(new RenameCommand({
id: 'cancelRenameInput',
precondition: CONTEXT_RENAME_INPUT_VISIBLE,
Expand Down
2 changes: 2 additions & 0 deletions src/vs/editor/contrib/rename/renameInputField.css
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,10 @@
.monaco-editor .rename-box {
z-index: 100;
color: inherit;
padding: 4px;
}

.monaco-editor .rename-box .rename-input {
padding: 4px;
width: calc(100% - 8px);
}
Loading

0 comments on commit 17d6b13

Please sign in to comment.