Skip to content

Commit

Permalink
Merge pull request #204800 from microsoft/aiday/showingPreviewInMulti…
Browse files Browse the repository at this point in the history
…DiffEditor

Show multi file diff editor from refactor preview
  • Loading branch information
aiday-mar authored Feb 16, 2024
2 parents ae7a786 + 0fd2b0c commit d9ef55a
Show file tree
Hide file tree
Showing 4 changed files with 115 additions and 51 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import { Disposable } from 'vs/base/common/lifecycle';
import { derived, derivedWithStore, observableValue, recomputeInitiallyAndOnChange } from 'vs/base/common/observable';
import { readHotReloadableExport } from 'vs/editor/browser/widget/diffEditor/utils';
import { IMultiDiffEditorModel } from 'vs/editor/browser/widget/multiDiffEditorWidget/model';
import { IMultiDiffEditorViewState, MultiDiffEditorWidgetImpl } from 'vs/editor/browser/widget/multiDiffEditorWidget/multiDiffEditorWidgetImpl';
import { IMultiDiffEditorViewState, IMultiDiffResource, MultiDiffEditorWidgetImpl } from 'vs/editor/browser/widget/multiDiffEditorWidget/multiDiffEditorWidgetImpl';
import { MultiDiffEditorViewModel } from './multiDiffEditorViewModel';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
import './colors';
Expand All @@ -19,6 +19,7 @@ import { URI } from 'vs/base/common/uri';
import { IDiffEditor } from 'vs/editor/common/editorCommon';
import { ICodeEditor } from 'vs/editor/browser/editorBrowser';
import { DiffEditorWidget } from 'vs/editor/browser/widget/diffEditor/diffEditorWidget';
import { Range } from 'vs/editor/common/core/range';

export class MultiDiffEditorWidget extends Disposable {
private readonly _dimension = observableValue<Dimension | undefined>(this, undefined);
Expand All @@ -45,6 +46,10 @@ export class MultiDiffEditorWidget extends Disposable {
this._register(recomputeInitiallyAndOnChange(this._widgetImpl));
}

public reveal(resource: IMultiDiffResource, range: Range): void {
this._widgetImpl.get().reveal(resource, range);
}

public createViewModel(model: IMultiDiffEditorModel): MultiDiffEditorViewModel {
return new MultiDiffEditorViewModel(model, this._instantiationService);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,9 @@ import { ISelection, Selection } from 'vs/editor/common/core/selection';
import { URI } from 'vs/base/common/uri';
import { ICodeEditor } from 'vs/editor/browser/editorBrowser';
import { IDiffEditor } from 'vs/editor/common/editorCommon';
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
import { Range } from 'vs/editor/common/core/range';
import { ITextEditorOptions } from 'vs/platform/editor/common/editor';

export class MultiDiffEditorWidgetImpl extends Disposable {
private readonly _elements = h('div.monaco-component.multiDiffEditor', [
Expand Down Expand Up @@ -104,6 +107,7 @@ export class MultiDiffEditorWidgetImpl extends Disposable {
private readonly _workbenchUIElementFactory: IWorkbenchUIElementFactory,
@IContextKeyService private readonly _parentContextKeyService: IContextKeyService,
@IInstantiationService private readonly _parentInstantiationService: IInstantiationService,
@IConfigurationService private readonly _configurationService: IConfigurationService,
) {
super();

Expand Down Expand Up @@ -186,6 +190,23 @@ export class MultiDiffEditorWidgetImpl extends Disposable {
this._scrollableElement.setScrollPosition({ scrollLeft: scrollState.left, scrollTop: scrollState.top });
}

// todo@aiday-mar need to reveal the range instead of just the start line number
public reveal(resource: IMultiDiffResource, range: Range): void {
const viewItems = this._viewItems.get();
let searchCallback: (item: VirtualizedViewItem) => boolean;
if ('original' in resource) {
searchCallback = (item) => item.viewModel.originalUri?.toString() === resource.original.toString();
} else {
searchCallback = (item) => item.viewModel.modifiedUri?.toString() === resource.modified.toString();
}
const index = viewItems.findIndex(searchCallback);
let scrollTop = (range.startLineNumber - 1) * this._configurationService.getValue<number>('editor.lineHeight');
for (let i = 0; i < index; i++) {
scrollTop += viewItems[i].contentHeight.get() + this._spaceBetweenPx;
}
this._scrollableElement.setScrollPosition({ scrollTop });
}

public getViewState(): IMultiDiffEditorViewState {
return {
scrollState: {
Expand Down Expand Up @@ -279,6 +300,19 @@ interface IMultiDiffDocState {
selections?: ISelection[];
}

export interface IMultiDiffEditorOptions extends ITextEditorOptions {
viewState?: IMultiDiffEditorOptionsViewState;
}

export interface IMultiDiffEditorOptionsViewState {
revealData?: {
resource: IMultiDiffResource;
range: Range;
};
}

export type IMultiDiffResource = { original: URI } | { modified: URI };

class VirtualizedViewItem extends Disposable {
private readonly _templateRef = this._register(disposableObservableValue<IReference<DiffEditorItemTemplate> | undefined>(this, undefined));

Expand Down
107 changes: 60 additions & 47 deletions src/vs/workbench/contrib/bulkEdit/browser/preview/bulkEditPane.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import { IThemeService } from 'vs/platform/theme/common/themeService';
import { localize } from 'vs/nls';
import { DisposableStore } from 'vs/base/common/lifecycle';
import { ACTIVE_GROUP, IEditorService, SIDE_GROUP } from 'vs/workbench/services/editor/common/editorService';
import { BulkEditPreviewProvider, BulkFileOperations, BulkFileOperationType } from 'vs/workbench/contrib/bulkEdit/browser/preview/bulkEditPreview';
import { BulkEditPreviewProvider, BulkFileOperation, BulkFileOperations, BulkFileOperationType } from 'vs/workbench/contrib/bulkEdit/browser/preview/bulkEditPreview';
import { ILabelService } from 'vs/platform/label/common/label';
import { ITextModelService } from 'vs/editor/common/services/resolverService';
import { URI } from 'vs/base/common/uri';
Expand All @@ -24,11 +24,9 @@ import { IContextKeyService, RawContextKey, IContextKey } from 'vs/platform/cont
import { IViewletViewOptions } from 'vs/workbench/browser/parts/views/viewsViewlet';
import { ResourceLabels, IResourceLabelsContainer } from 'vs/workbench/browser/labels';
import { IDialogService } from 'vs/platform/dialogs/common/dialogs';
import { basename, dirname } from 'vs/base/common/resources';
import { MenuId } from 'vs/platform/actions/common/actions';
import { ITreeContextMenuEvent } from 'vs/base/browser/ui/tree/tree';
import { CancellationToken } from 'vs/base/common/cancellation';
import { ITextEditorOptions } from 'vs/platform/editor/common/editor';
import type { IAsyncDataTreeViewState } from 'vs/base/browser/ui/tree/asyncDataTree';
import { IStorageService, StorageScope, StorageTarget } from 'vs/platform/storage/common/storage';
import { IViewDescriptorService } from 'vs/workbench/common/views';
Expand All @@ -38,6 +36,9 @@ import { ResourceEdit } from 'vs/editor/browser/services/bulkEditService';
import { ButtonBar } from 'vs/base/browser/ui/button/button';
import { defaultButtonStyles } from 'vs/platform/theme/browser/defaultStyles';
import { Mutable } from 'vs/base/common/types';
import { IResourceDiffEditorInput } from 'vs/workbench/common/editor';
import { Range } from 'vs/editor/common/core/range';
import { IMultiDiffEditorOptions } from 'vs/editor/browser/widget/multiDiffEditorWidget/multiDiffEditorWidgetImpl';

const enum State {
Data = 'data',
Expand Down Expand Up @@ -68,7 +69,8 @@ export class BulkEditPane extends ViewPane {
private _currentResolve?: (edit?: ResourceEdit[]) => void;
private _currentInput?: BulkFileOperations;
private _currentProvider?: BulkEditPreviewProvider;

private _fileOperations?: BulkFileOperation[];
private _resources?: IResourceDiffEditorInput[];

constructor(
options: IViewletViewOptions,
Expand Down Expand Up @@ -143,7 +145,7 @@ export class BulkEditPane extends ViewPane {
);

this._disposables.add(this._tree.onContextMenu(this._onContextMenu, this));
this._disposables.add(this._tree.onDidOpen(e => this._openElementAsEditor(e)));
this._disposables.add(this._tree.onDidOpen(e => this._openElementInMultiDiffEditor(e)));

// buttons
const buttonsContainer = document.createElement('div');
Expand Down Expand Up @@ -316,65 +318,76 @@ export class BulkEditPane extends ViewPane {
}
}

private async _openElementAsEditor(e: IOpenEvent<BulkEditElement | undefined>): Promise<void> {
private async _openElementInMultiDiffEditor(e: IOpenEvent<BulkEditElement | undefined>): Promise<void> {

const options: Mutable<ITextEditorOptions> = { ...e.editorOptions };
const fileOperations = this._currentInput?.fileOperations;
if (!fileOperations) {
return;
}
let fileElement: FileElement;
if (e.element instanceof TextEditElement) {
fileElement = e.element.parent;
options.selection = e.element.edit.textEdit.textEdit.range;

} else if (e.element instanceof FileElement) {
fileElement = e.element;
options.selection = e.element.edit.textEdits[0]?.textEdit.textEdit.range;

} else {
// invalid event
return;
}

const previewUri = this._currentProvider!.asPreviewUri(fileElement.edit.uri);

if (fileElement.edit.type & BulkFileOperationType.Delete) {
// delete -> show single editor
this._editorService.openEditor({
label: localize('edt.title.del', "{0} (delete, refactor preview)", basename(fileElement.edit.uri)),
resource: previewUri,
options
});

} else {
// rename, create, edits -> show diff editr
let leftResource: URI | undefined;
try {
(await this._textModelService.createModelReference(fileElement.edit.uri)).dispose();
leftResource = fileElement.edit.uri;
} catch {
leftResource = BulkEditPreviewProvider.emptyPreview;
const resources = await this._resolveResources(fileOperations);
const options: Mutable<IMultiDiffEditorOptions> = {
...e.editorOptions,
viewState: {
revealData: {
resource: { original: fileElement.edit.uri },
range: new Range(1, 1, 1, 1)
}
}
};
const multiDiffSource = URI.from({ scheme: 'refactor-preview' });
const label = 'Refactor Preview';
this._editorService.openEditor({
multiDiffSource,
resources,
label,
options,
description: label
}, e.sideBySide ? SIDE_GROUP : ACTIVE_GROUP);
}

let typeLabel: string | undefined;
if (fileElement.edit.type & BulkFileOperationType.Rename) {
typeLabel = localize('rename', "rename");
} else if (fileElement.edit.type & BulkFileOperationType.Create) {
typeLabel = localize('create', "create");
}
private async _resolveResources(fileOperations: BulkFileOperation[]): Promise<IResourceDiffEditorInput[]> {
if (this._fileOperations === fileOperations && this._resources) {
return this._resources;
}
const resources: IResourceDiffEditorInput[] = [];
for (const operation of fileOperations) {
const operationUri = operation.uri;
const previewUri = this._currentProvider!.asPreviewUri(operationUri);
// delete -> show single editor
if (operation.type & BulkFileOperationType.Delete) {
resources.push({
original: { resource: undefined },
modified: { resource: URI.revive(previewUri) }
});

let label: string;
if (typeLabel) {
label = localize('edt.title.2', "{0} ({1}, refactor preview)", basename(fileElement.edit.uri), typeLabel);
} else {
label = localize('edt.title.1', "{0} (refactor preview)", basename(fileElement.edit.uri));
// rename, create, edits -> show diff editr
let leftResource: URI | undefined;
try {
(await this._textModelService.createModelReference(operationUri)).dispose();
leftResource = operationUri;
} catch {
leftResource = BulkEditPreviewProvider.emptyPreview;
}
resources.push({
original: { resource: URI.revive(leftResource) },
modified: { resource: URI.revive(previewUri) }
});
}

this._editorService.openEditor({
original: { resource: leftResource },
modified: { resource: previewUri },
label,
description: this._labelService.getUriLabel(dirname(leftResource), { relative: true }),
options
}, e.sideBySide ? SIDE_GROUP : ACTIVE_GROUP);
}
this._fileOperations = fileOperations;
this._resources = resources;
return resources;
}

private _onContextMenu(e: ITreeContextMenuEvent<any>): void {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ import { CancellationToken } from 'vs/base/common/cancellation';
import { MultiDiffEditorWidget } from 'vs/editor/browser/widget/multiDiffEditorWidget/multiDiffEditorWidget';
import { IResourceLabel, IWorkbenchUIElementFactory } from 'vs/editor/browser/widget/multiDiffEditorWidget/workbenchUIElementFactory';
import { ITextResourceConfigurationService } from 'vs/editor/common/services/textResourceConfiguration';
import { IEditorOptions } from 'vs/platform/editor/common/editor';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
import { InstantiationService } from 'vs/platform/instantiation/common/instantiationService';
import { IStorageService } from 'vs/platform/storage/common/storage';
Expand All @@ -24,7 +23,7 @@ import { IEditorGroupsService } from 'vs/workbench/services/editor/common/editor
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
import { URI } from 'vs/base/common/uri';
import { MultiDiffEditorViewModel } from 'vs/editor/browser/widget/multiDiffEditorWidget/multiDiffEditorViewModel';
import { IMultiDiffEditorViewState } from 'vs/editor/browser/widget/multiDiffEditorWidget/multiDiffEditorWidgetImpl';
import { IMultiDiffEditorOptions, IMultiDiffEditorViewState } from 'vs/editor/browser/widget/multiDiffEditorWidget/multiDiffEditorWidgetImpl';
import { ICodeEditor } from 'vs/editor/browser/editorBrowser';
import { IDiffEditor } from 'vs/editor/common/editorCommon';

Expand Down Expand Up @@ -72,7 +71,7 @@ export class MultiDiffEditor extends AbstractEditorWithViewState<IMultiDiffEdito
}));
}

override async setInput(input: MultiDiffEditorInput, options: IEditorOptions | undefined, context: IEditorOpenContext, token: CancellationToken): Promise<void> {
override async setInput(input: MultiDiffEditorInput, options: IMultiDiffEditorOptions | undefined, context: IEditorOpenContext, token: CancellationToken): Promise<void> {
await super.setInput(input, options, context, token);
this._viewModel = await input.getViewModel();
this._multiDiffEditorWidget!.setViewModel(this._viewModel);
Expand All @@ -81,6 +80,19 @@ export class MultiDiffEditor extends AbstractEditorWithViewState<IMultiDiffEdito
if (viewState) {
this._multiDiffEditorWidget!.setViewState(viewState);
}
this._reveal(options);
}

override setOptions(options: IMultiDiffEditorOptions | undefined): void {
this._reveal(options);
}

private _reveal(options: IMultiDiffEditorOptions | undefined): void {
const viewState = options?.viewState;
if (!viewState || !viewState.revealData) {
return;
}
this._multiDiffEditorWidget?.reveal(viewState.revealData.resource, viewState.revealData.range);
}

override async clearInput(): Promise<void> {
Expand Down

0 comments on commit d9ef55a

Please sign in to comment.