Implements "No Changes"

This commit is contained in:
Henning Dieterichs
2023-06-19 18:32:49 +02:00
parent c22bb0ec64
commit 813a36e903
5 changed files with 57 additions and 28 deletions

View File

@@ -2,7 +2,7 @@
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { h } from 'vs/base/browser/dom';
import { $, h } from 'vs/base/browser/dom';
import { IBoundarySashes } from 'vs/base/browser/ui/sash/sash';
import { findLast } from 'vs/base/common/arrays';
import { onUnexpectedError } from 'vs/base/common/errors';
@@ -25,7 +25,7 @@ import { ViewZoneManager } from 'vs/editor/browser/widget/diffEditorWidget2/line
import { MovedBlocksLinesPart } from 'vs/editor/browser/widget/diffEditorWidget2/movedBlocksLines';
import { OverviewRulerPart } from 'vs/editor/browser/widget/diffEditorWidget2/overviewRulerPart';
import { UnchangedRangesFeature } from 'vs/editor/browser/widget/diffEditorWidget2/unchangedRanges';
import { ObservableElementSizeObserver, applyObservableDecorations, deepMerge, readHotReloadableExport } from 'vs/editor/browser/widget/diffEditorWidget2/utils';
import { ObservableElementSizeObserver, applyObservableDecorations, applyStyle, deepMerge, readHotReloadableExport } from 'vs/editor/browser/widget/diffEditorWidget2/utils';
import { WorkerBasedDocumentDiffProvider } from 'vs/editor/browser/widget/workerBasedDocumentDiffProvider';
import { EditorOptions, IDiffEditorOptions, IEditorOptions, ValidDiffEditorBaseOptions, clampedFloat, clampedInt, boolean as validateBooleanOption, stringSet as validateStringSetOption } from 'vs/editor/common/config/editorOptions';
import { IDimension } from 'vs/editor/common/core/dimension';
@@ -68,6 +68,7 @@ const diffEditorDefaultOptions: ValidDiffEditorBaseOptions = {
export class DiffEditorWidget2 extends DelegatingEditor implements IDiffEditor {
private readonly elements = h('div.monaco-diff-editor.side-by-side', { style: { position: 'relative', height: '100%' } }, [
h('div.noModificationsOverlay@overlay', { style: { position: 'absolute', height: '100%', visibility: 'hidden', } }, [$('span', {}, 'No Changes')]),
h('div.editor.original@original', { style: { position: 'absolute', height: '100%' } }),
h('div.editor.modified@modified', { style: { position: 'absolute', height: '100%' } }),
]);
@@ -190,6 +191,11 @@ export class DiffEditorWidget2 extends DelegatingEditor implements IDiffEditor {
this._originalEditor,
this._modifiedEditor,
));
this._register(applyStyle(this.elements.overlay, {
width: this._layoutInfo.map((i, r) => i.originalEditor.width + (this._options.read(r).renderSideBySide ? 0 : i.modifiedEditor.width)),
visibility: this._diffModel.map((m, r) => (m && m.hideUnchangedRegions.read(r) && m.diff.read(r)?.mappings.length === 0) ? 'visible' : 'hidden'),
}));
}
private readonly _layoutInfo = derived('modifiedEditorLayoutInfo', (reader) => {

View File

@@ -32,7 +32,7 @@ export class DiffModel extends Disposable implements IDiffEditorViewModel {
{ regions: [], originalDecorationIds: [], modifiedDecorationIds: [] }
);
public readonly unchangedRegions: IObservable<UnchangedRegion[]> = derived('unchangedRegions', r => {
if (this._hideUnchangedRegions.read(r)) {
if (this.hideUnchangedRegions.read(r)) {
return this._unchangedRegions.read(r).regions;
} else {
// Reset state
@@ -52,7 +52,7 @@ export class DiffModel extends Disposable implements IDiffEditorViewModel {
public readonly model: IDiffEditorModel,
ignoreTrimWhitespace: IObservable<boolean>,
maxComputationTimeMs: IObservable<number>,
private readonly _hideUnchangedRegions: IObservable<boolean>,
public readonly hideUnchangedRegions: IObservable<boolean>,
private readonly _showMoves: IObservable<boolean>,
documentDiffProvider: IDocumentDiffProvider,
) {
@@ -182,6 +182,9 @@ export class DiffModel extends Disposable implements IDiffEditorViewModel {
}
public ensureModifiedLineIsVisible(lineNumber: number, tx: ITransaction): void {
if (this.diff.get()?.mappings.length === 0) {
return;
}
const unchangedRegions = this._unchangedRegions.get().regions;
for (const r of unchangedRegions) {
if (r.getHiddenModifiedRange(undefined).contains(lineNumber)) {
@@ -192,6 +195,9 @@ export class DiffModel extends Disposable implements IDiffEditorViewModel {
}
public ensureOriginalLineIsVisible(lineNumber: number, tx: ITransaction): void {
if (this.diff.get()?.mappings.length === 0) {
return;
}
const unchangedRegions = this._unchangedRegions.get().regions;
for (const r of unchangedRegions) {
if (r.getHiddenOriginalRange(undefined).contains(lineNumber)) {

View File

@@ -40,6 +40,15 @@
background: var(--vscode-diffEditor-unchangedCodeBackground);
}
.noModificationsOverlay {
z-index: 1;
background: var(--vscode-editor-background);
display: flex;
justify-content: center;
align-items: center;
}
.diff-hidden-lines .center {
background: var(--vscode-diffEditor-unchangedRegionBackground);

View File

@@ -15,6 +15,7 @@ import { CodeEditorWidget } from 'vs/editor/browser/widget/codeEditorWidget';
import { DiffModel, UnchangedRegion } from 'vs/editor/browser/widget/diffEditorWidget2/diffModel';
import { PlaceholderViewZone, ViewZoneOverlayWidget, applyObservableDecorations, applyStyle, applyViewZones } from 'vs/editor/browser/widget/diffEditorWidget2/utils';
import { EditorOption } from 'vs/editor/common/config/editorOptions';
import { CursorChangeReason } from 'vs/editor/common/cursorEvents';
import { IModelDecorationOptions, IModelDeltaDecoration } from 'vs/editor/common/model';
export class UnchangedRangesFeature extends Disposable {
@@ -30,32 +31,38 @@ export class UnchangedRangesFeature extends Disposable {
super();
this._register(this._originalEditor.onDidChangeCursorPosition(e => {
const m = this._diffModel.get();
transaction(tx => {
for (const s of this._originalEditor.getSelections() || []) {
m?.ensureOriginalLineIsVisible(s.getStartPosition().lineNumber, tx);
m?.ensureOriginalLineIsVisible(s.getEndPosition().lineNumber, tx);
}
});
if (e.reason === CursorChangeReason.Explicit) {
const m = this._diffModel.get();
transaction(tx => {
for (const s of this._originalEditor.getSelections() || []) {
m?.ensureOriginalLineIsVisible(s.getStartPosition().lineNumber, tx);
m?.ensureOriginalLineIsVisible(s.getEndPosition().lineNumber, tx);
}
});
}
}));
this._register(this._modifiedEditor.onDidChangeCursorPosition(e => {
const m = this._diffModel.get();
transaction(tx => {
for (const s of this._modifiedEditor.getSelections() || []) {
m?.ensureModifiedLineIsVisible(s.getStartPosition().lineNumber, tx);
m?.ensureModifiedLineIsVisible(s.getEndPosition().lineNumber, tx);
}
});
if (e.reason === CursorChangeReason.Explicit) {
const m = this._diffModel.get();
transaction(tx => {
for (const s of this._modifiedEditor.getSelections() || []) {
m?.ensureModifiedLineIsVisible(s.getStartPosition().lineNumber, tx);
m?.ensureModifiedLineIsVisible(s.getEndPosition().lineNumber, tx);
}
});
}
}));
const unchangedRegions = this._diffModel.map((m, reader) => m?.diff.read(reader)?.mappings.length === 0 ? [] : m?.unchangedRegions.read(reader) ?? []);
const viewZones = derivedWithStore('view zones', (reader, store) => {
const origViewZones: IViewZone[] = [];
const modViewZones: IViewZone[] = [];
const sideBySide = this._sideBySide.read(reader);
const unchangedRegions = this._diffModel.read(reader)?.unchangedRegions.read(reader) ?? [];
for (const r of unchangedRegions) {
const curUnchangedRegions = unchangedRegions.read(reader);
for (const r of curUnchangedRegions) {
if (r.shouldHideControls(reader)) {
continue;
}
@@ -85,16 +92,16 @@ export class UnchangedRangesFeature extends Disposable {
};
this._register(applyObservableDecorations(this._originalEditor, derived('decorations', (reader) => {
const unchangedRegions = this._diffModel.read(reader)?.unchangedRegions.read(reader) ?? [];
return unchangedRegions.map<IModelDeltaDecoration>(r => ({
const curUnchangedRegions = unchangedRegions.read(reader);
return curUnchangedRegions.map<IModelDeltaDecoration>(r => ({
range: r.originalRange.toInclusiveRange()!,
options: unchangedLinesDecoration,
}));
})));
this._register(applyObservableDecorations(this._modifiedEditor, derived('decorations', (reader) => {
const unchangedRegions = this._diffModel.read(reader)?.unchangedRegions.read(reader) ?? [];
return unchangedRegions.map<IModelDeltaDecoration>(r => ({
const curUnchangedRegions = unchangedRegions.read(reader);
return curUnchangedRegions.map<IModelDeltaDecoration>(r => ({
range: r.modifiedRange.toInclusiveRange()!,
options: unchangedLinesDecoration,
}));
@@ -104,10 +111,9 @@ export class UnchangedRangesFeature extends Disposable {
this._register(applyViewZones(this._modifiedEditor, viewZones.map(v => v.modViewZones), v => this._isUpdatingViewZones = v));
this._register(autorunWithStore2('update folded unchanged regions', (reader, store) => {
const unchangedRegions = this._diffModel.read(reader)?.unchangedRegions.read(reader) ?? [];
this._originalEditor.setHiddenAreas(unchangedRegions.map(r => r.getHiddenOriginalRange(reader).toInclusiveRange()).filter(isDefined));
this._modifiedEditor.setHiddenAreas(unchangedRegions.map(r => r.getHiddenModifiedRange(reader).toInclusiveRange()).filter(isDefined));
const curUnchangedRegions = unchangedRegions.read(reader);
this._originalEditor.setHiddenAreas(curUnchangedRegions.map(r => r.getHiddenOriginalRange(reader).toInclusiveRange()).filter(isDefined));
this._modifiedEditor.setHiddenAreas(curUnchangedRegions.map(r => r.getHiddenModifiedRange(reader).toInclusiveRange()).filter(isDefined));
}));
}
}

View File

@@ -264,6 +264,8 @@ export interface CSSStyle {
height: number | string;
width: number | string;
top: number | string;
visibility: 'visible' | 'hidden' | 'collapse';
display: 'block' | 'inline' | 'inline-block' | 'flex' | 'none';
}
export function applyStyle(domNode: HTMLElement, style: Partial<{ [TKey in keyof CSSStyle]: CSSStyle[TKey] | IObservable<CSSStyle[TKey] | undefined> | undefined }>) {