diff --git a/build/lib/stylelint/vscode-known-variables.json b/build/lib/stylelint/vscode-known-variables.json index 42103c21ff9..b5759f027db 100644 --- a/build/lib/stylelint/vscode-known-variables.json +++ b/build/lib/stylelint/vscode-known-variables.json @@ -100,6 +100,7 @@ "--vscode-diffEditor-removedLineBackground", "--vscode-diffEditor-removedTextBackground", "--vscode-diffEditor-removedTextBorder", + "--vscode-diffEditor-unchangedCodeBackground", "--vscode-diffEditor-unchangedRegionBackground", "--vscode-diffEditor-unchangedRegionForeground", "--vscode-diffEditorGutter-insertedLineBackground", diff --git a/scripts/playground-server.ts b/scripts/playground-server.ts index abeb8230a45..9468087409f 100644 --- a/scripts/playground-server.ts +++ b/scripts/playground-server.ts @@ -235,10 +235,10 @@ function handleGetFileChangesRequest(watcher: DirWatcher, fileServer: FileServer function makeLoaderJsHotReloadable(loaderJsCode: string, fileChangesUrl: URL): string { loaderJsCode = loaderJsCode.replace( /constructor\(env, scriptLoader, defineFunc, requireFunc, loaderAvailableTimestamp = 0\) {/, - '$&globalThis.$$globalModuleManager = this;' + '$&globalThis.___globalModuleManager = this;' ); - const $$globalModuleManager: any = undefined; + const ___globalModuleManager: any = undefined; // This code will be appended to loader.js function $watchChanges(fileChangesUrl: string) { @@ -266,24 +266,26 @@ function makeLoaderJsHotReloadable(loaderJsCode: string, fileChangesUrl: URL): s const data = JSON.parse(line); let handled = false; if (data.changedPath.endsWith('.css')) { - console.log('css changed', data.changedPath); - const styleSheet = [...document.querySelectorAll(`link[rel='stylesheet']`)].find((l: any) => new URL(l.href, document.location.href).pathname.endsWith(data.changedPath)) as any; - if (styleSheet) { - styleSheet.href = styleSheet.href.replace(/\?.*/, '') + '?' + Date.now(); + if (typeof document !== 'undefined') { + console.log('css changed', data.changedPath); + const styleSheet = [...document.querySelectorAll(`link[rel='stylesheet']`)].find((l: any) => new URL(l.href, document.location.href).pathname.endsWith(data.changedPath)) as any; + if (styleSheet) { + styleSheet.href = styleSheet.href.replace(/\?.*/, '') + '?' + Date.now(); + } } handled = true; } else if (data.changedPath.endsWith('.js') && data.moduleId) { console.log('js changed', data.changedPath); - const moduleId = $$globalModuleManager._moduleIdProvider.getModuleId(data.moduleId); - if ($$globalModuleManager._modules2[moduleId]) { - const srcUrl = $$globalModuleManager._config.moduleIdToPaths(data.moduleId); + const moduleId = ___globalModuleManager._moduleIdProvider.getModuleId(data.moduleId); + if (___globalModuleManager._modules2[moduleId]) { + const srcUrl = ___globalModuleManager._config.moduleIdToPaths(data.moduleId); const newSrc = await (await fetch(srcUrl)).text(); (new Function('define', newSrc))(function (deps, callback) { - const oldModule = $$globalModuleManager._modules2[moduleId]; - delete $$globalModuleManager._modules2[moduleId]; + const oldModule = ___globalModuleManager._modules2[moduleId]; + delete ___globalModuleManager._modules2[moduleId]; - $$globalModuleManager.defineModule(data.moduleId, deps, callback); - const newModule = $$globalModuleManager._modules2[moduleId]; + ___globalModuleManager.defineModule(data.moduleId, deps, callback); + const newModule = ___globalModuleManager._modules2[moduleId]; const oldExports = { ...oldModule.exports }; Object.assign(oldModule.exports, newModule.exports); diff --git a/src/vs/editor/browser/widget/diffEditorWidget2/diffEditorWidget2.ts b/src/vs/editor/browser/widget/diffEditorWidget2/diffEditorWidget2.ts index dbf7424e020..42826c91b74 100644 --- a/src/vs/editor/browser/widget/diffEditorWidget2/diffEditorWidget2.ts +++ b/src/vs/editor/browser/widget/diffEditorWidget2/diffEditorWidget2.ts @@ -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) => { diff --git a/src/vs/editor/browser/widget/diffEditorWidget2/diffModel.ts b/src/vs/editor/browser/widget/diffEditorWidget2/diffModel.ts index 18cf0148357..f79d78dea25 100644 --- a/src/vs/editor/browser/widget/diffEditorWidget2/diffModel.ts +++ b/src/vs/editor/browser/widget/diffEditorWidget2/diffModel.ts @@ -31,8 +31,19 @@ export class DiffModel extends Disposable implements IDiffEditorViewModel { 'unchangedRegion', { regions: [], originalDecorationIds: [], modifiedDecorationIds: [] } ); - public readonly unchangedRegions: IObservable = derived('unchangedRegions', r => - this._hideUnchangedRegions.read(r) ? this._unchangedRegions.read(r).regions : [] + public readonly unchangedRegions: IObservable = derived('unchangedRegions', r => { + if (this.hideUnchangedRegions.read(r)) { + return this._unchangedRegions.read(r).regions; + } else { + // Reset state + transaction(tx => { + for (const r of this._unchangedRegions.get().regions) { + r.setState(0, 0, tx); + } + }); + return []; + } + } ); public readonly syncedMovedTexts = observableValue('syncedMovedText', undefined); @@ -41,7 +52,7 @@ export class DiffModel extends Disposable implements IDiffEditorViewModel { public readonly model: IDiffEditorModel, ignoreTrimWhitespace: IObservable, maxComputationTimeMs: IObservable, - private readonly _hideUnchangedRegions: IObservable, + public readonly hideUnchangedRegions: IObservable, private readonly _showMoves: IObservable, documentDiffProvider: IDocumentDiffProvider, ) { @@ -74,7 +85,7 @@ export class DiffModel extends Disposable implements IDiffEditorViewModel { } const textEdits = TextEditInfo.fromModelContentChanges(e.changes); - const result = applyModifiedEdits(this._lastDiff!, textEdits, model.original, model.modified); + const result = applyOriginalEdits(this._lastDiff!, textEdits, model.original, model.modified); if (result) { this._lastDiff = result; this._diff.set(DiffState.fromDiffResult(this._lastDiff), undefined); @@ -171,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)) { @@ -181,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)) { @@ -251,8 +268,10 @@ export class UnchangedRegion { let modStart = mapping.modifiedRange.startLineNumber; let length = mapping.originalRange.length; - if (origStart === 1 && length > minContext + minHiddenLineCount) { - length -= minContext; + if (origStart === 1 && modStart === 1 && length > minContext + minHiddenLineCount) { + if (length < originalLineCount) { + length -= minContext; + } result.push(new UnchangedRegion(origStart, modStart, length, 0, 0)); } else if (origStart + length === originalLineCount + 1 && length > minContext + minHiddenLineCount) { origStart += minContext; diff --git a/src/vs/editor/browser/widget/diffEditorWidget2/lineAlignment.ts b/src/vs/editor/browser/widget/diffEditorWidget2/lineAlignment.ts index e39b72f3e62..add49794ab2 100644 --- a/src/vs/editor/browser/widget/diffEditorWidget2/lineAlignment.ts +++ b/src/vs/editor/browser/widget/diffEditorWidget2/lineAlignment.ts @@ -335,8 +335,21 @@ export class ViewZoneManager extends Disposable { scrollState.restore(this._modifiedEditor); })); - this._register(this._originalEditor.onDidScrollChange(e => { this._modifiedEditor.setScrollLeft(e.scrollLeft); })); - this._register(this._modifiedEditor.onDidScrollChange(e => { this._originalEditor.setScrollLeft(e.scrollLeft); })); + let ignoreChange = false; + this._register(this._originalEditor.onDidScrollChange(e => { + if (e.scrollLeftChanged && !ignoreChange) { + ignoreChange = true; + this._modifiedEditor.setScrollLeft(e.scrollLeft); + ignoreChange = false; + } + })); + this._register(this._modifiedEditor.onDidScrollChange(e => { + if (e.scrollLeftChanged && !ignoreChange) { + ignoreChange = true; + this._originalEditor.setScrollLeft(e.scrollLeft); + ignoreChange = false; + } + })); this._originalScrollTop = observableFromEvent(this._originalEditor.onDidScrollChange, () => this._originalEditor.getScrollTop()); this._modifiedScrollTop = observableFromEvent(this._modifiedEditor.onDidScrollChange, () => this._modifiedEditor.getScrollTop()); diff --git a/src/vs/editor/browser/widget/diffEditorWidget2/style.css b/src/vs/editor/browser/widget/diffEditorWidget2/style.css index 6797d4f7291..64f4d9e9c7f 100644 --- a/src/vs/editor/browser/widget/diffEditorWidget2/style.css +++ b/src/vs/editor/browser/widget/diffEditorWidget2/style.css @@ -8,7 +8,8 @@ } .diff-hidden-lines { - transform: translate(0px, -8px); + height: 0px; /* The children each have a fixed height, the transform confuses the browser */ + transform: translate(0px, -10px); font-size: 13px; line-height: 14px; } @@ -35,6 +36,19 @@ transform: translate(0px, -6px); } +.diff-unchanged-lines { + 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); diff --git a/src/vs/editor/browser/widget/diffEditorWidget2/unchangedRanges.ts b/src/vs/editor/browser/widget/diffEditorWidget2/unchangedRanges.ts index 498d34fd71e..5b1a8c5f879 100644 --- a/src/vs/editor/browser/widget/diffEditorWidget2/unchangedRanges.ts +++ b/src/vs/editor/browser/widget/diffEditorWidget2/unchangedRanges.ts @@ -13,8 +13,10 @@ import { isDefined } from 'vs/base/common/types'; import { ICodeEditor, IViewZone } from 'vs/editor/browser/editorBrowser'; import { CodeEditorWidget } from 'vs/editor/browser/widget/codeEditorWidget'; import { DiffModel, UnchangedRegion } from 'vs/editor/browser/widget/diffEditorWidget2/diffModel'; -import { PlaceholderViewZone, ViewZoneOverlayWidget, applyStyle, applyViewZones } from 'vs/editor/browser/widget/diffEditorWidget2/utils'; +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 { private _isUpdatingViewZones = false; @@ -29,45 +31,51 @@ 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; } { const d = derived('hiddenOriginalRangeStart', reader => r.getHiddenOriginalRange(reader).startLineNumber - 1); - const origVz = new PlaceholderViewZone(d, 30); + const origVz = new PlaceholderViewZone(d, 24); origViewZones.push(origVz); store.add(new CollapsedCodeOverlayWidget(this._originalEditor, origVz, r, !sideBySide)); } { const d = derived('hiddenModifiedRangeStart', reader => r.getHiddenModifiedRange(reader).startLineNumber - 1); - const modViewZone = new PlaceholderViewZone(d, 30); + const modViewZone = new PlaceholderViewZone(d, 24); modViewZones.push(modViewZone); store.add(new CollapsedCodeOverlayWidget(this._modifiedEditor, modViewZone, r, false)); } @@ -76,28 +84,50 @@ export class UnchangedRangesFeature extends Disposable { return { origViewZones, modViewZones, }; }); + + const unchangedLinesDecoration: IModelDecorationOptions = { + description: 'unchanged lines', + className: 'diff-unchanged-lines', + isWholeLine: true, + }; + + this._register(applyObservableDecorations(this._originalEditor, derived('decorations', (reader) => { + const curUnchangedRegions = unchangedRegions.read(reader); + return curUnchangedRegions.map(r => ({ + range: r.originalRange.toInclusiveRange()!, + options: unchangedLinesDecoration, + })); + }))); + + this._register(applyObservableDecorations(this._modifiedEditor, derived('decorations', (reader) => { + const curUnchangedRegions = unchangedRegions.read(reader); + return curUnchangedRegions.map(r => ({ + range: r.modifiedRange.toInclusiveRange()!, + options: unchangedLinesDecoration, + })); + }))); + this._register(applyViewZones(this._originalEditor, viewZones.map(v => v.origViewZones), v => this._isUpdatingViewZones = v)); 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)); })); } } class CollapsedCodeOverlayWidget extends ViewZoneOverlayWidget { private readonly _nodes = h('div.diff-hidden-lines', [ - h('div.top@top', { title: 'Show more above' }), + h('div.top@top', { title: 'Click or drag to show more above' }), h('div.center@content', { style: { display: 'flex' } }, [ h('div@first', { style: { display: 'flex', justifyContent: 'center', alignItems: 'center' } }, [$('a', { title: 'Show all', role: 'button', onclick: () => { this._unchangedRegion.showAll(undefined); } }, ...renderLabelWithIcons('$(unfold)'))] ), h('div@others', { style: { display: 'flex', justifyContent: 'center', alignItems: 'center' } }), ]), - h('div.bottom@bottom', { title: 'Show more below', role: 'button' }), + h('div.bottom@bottom', { title: 'Click or drag to show more below', role: 'button' }), ]); constructor( @@ -123,6 +153,9 @@ class CollapsedCodeOverlayWidget extends ViewZoneOverlayWidget { const editor = this._editor; this._register(addDisposableListener(this._nodes.top, 'mousedown', e => { + if (e.button !== 0) { + return; + } this._nodes.top.classList.toggle('dragging', true); this._nodes.root.classList.toggle('dragging', true); e.preventDefault(); @@ -154,7 +187,9 @@ class CollapsedCodeOverlayWidget extends ViewZoneOverlayWidget { })); this._register(addDisposableListener(this._nodes.bottom, 'mousedown', e => { - + if (e.button !== 0) { + return; + } this._nodes.bottom.classList.toggle('dragging', true); this._nodes.root.classList.toggle('dragging', true); e.preventDefault(); @@ -176,12 +211,17 @@ class CollapsedCodeOverlayWidget extends ViewZoneOverlayWidget { }); const mouseUpListener = addDisposableListener(document.body, 'mouseup', e => { + this._unchangedRegion.isDragged.set(false, undefined); + if (!didMove) { + const top = editor.getTopForLineNumber(this._unchangedRegion.modifiedRange.endLineNumberExclusive); + this._unchangedRegion.showMoreBelow(20, undefined); + const top2 = editor.getTopForLineNumber(this._unchangedRegion.modifiedRange.endLineNumberExclusive); + editor.setScrollTop(editor.getScrollTop() + (top2 - top)); } this._nodes.bottom.classList.toggle('dragging', false); this._nodes.root.classList.toggle('dragging', false); - this._unchangedRegion.isDragged.set(false, undefined); mouseMoveListener.dispose(); mouseUpListener.dispose(); }); diff --git a/src/vs/editor/browser/widget/diffEditorWidget2/utils.ts b/src/vs/editor/browser/widget/diffEditorWidget2/utils.ts index 8dab9276ba8..6968264f3ac 100644 --- a/src/vs/editor/browser/widget/diffEditorWidget2/utils.ts +++ b/src/vs/editor/browser/widget/diffEditorWidget2/utils.ts @@ -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 | undefined }>) { diff --git a/src/vs/editor/common/viewModel.ts b/src/vs/editor/common/viewModel.ts index bedb93e902b..ff08d5fa24b 100644 --- a/src/vs/editor/common/viewModel.ts +++ b/src/vs/editor/common/viewModel.ts @@ -210,7 +210,11 @@ export interface ICoordinatesConverter { validateViewRange(viewRange: Range, expectedModelRange: Range): Range; // Model -> View conversion and related methods - convertModelPositionToViewPosition(modelPosition: Position, affinity?: PositionAffinity, allowZeroLineNumber?: boolean): Position; + /** + * @param allowZeroLineNumber Should it return 0 when there are hidden lines at the top and the position is in the hidden area? + * @param belowHiddenRanges When the model position is in a hidden area, should it return the first view position after or before? + */ + convertModelPositionToViewPosition(modelPosition: Position, affinity?: PositionAffinity, allowZeroLineNumber?: boolean, belowHiddenRanges?: boolean): Position; /** * @param affinity Only has an effect if the range is empty. */ diff --git a/src/vs/editor/common/viewModel/viewModelDecorations.ts b/src/vs/editor/common/viewModel/viewModelDecorations.ts index 239637ff916..4725c903073 100644 --- a/src/vs/editor/common/viewModel/viewModelDecorations.ts +++ b/src/vs/editor/common/viewModel/viewModelDecorations.ts @@ -82,7 +82,7 @@ export class ViewModelDecorations implements IDisposable { const options = modelDecoration.options; let viewRange: Range; if (options.isWholeLine) { - const start = this._coordinatesConverter.convertModelPositionToViewPosition(new Position(modelRange.startLineNumber, 1), PositionAffinity.Left); + const start = this._coordinatesConverter.convertModelPositionToViewPosition(new Position(modelRange.startLineNumber, 1), PositionAffinity.Left, false, true); const end = this._coordinatesConverter.convertModelPositionToViewPosition(new Position(modelRange.endLineNumber, this.model.getLineMaxColumn(modelRange.endLineNumber)), PositionAffinity.Right); viewRange = new Range(start.lineNumber, start.column, end.lineNumber, end.column); } else { diff --git a/src/vs/editor/common/viewModel/viewModelLines.ts b/src/vs/editor/common/viewModel/viewModelLines.ts index 487bbaa919e..c9fb7f3f662 100644 --- a/src/vs/editor/common/viewModel/viewModelLines.ts +++ b/src/vs/editor/common/viewModel/viewModelLines.ts @@ -830,16 +830,23 @@ export class ViewModelLinesFromProjectedModel implements IViewModelLines { return new Range(start.lineNumber, start.column, end.lineNumber, end.column); } - public convertModelPositionToViewPosition(_modelLineNumber: number, _modelColumn: number, affinity: PositionAffinity = PositionAffinity.None, allowZeroLineNumber: boolean = false): Position { + public convertModelPositionToViewPosition(_modelLineNumber: number, _modelColumn: number, affinity: PositionAffinity = PositionAffinity.None, allowZeroLineNumber: boolean = false, belowHiddenRanges: boolean = false): Position { const validPosition = this.model.validatePosition(new Position(_modelLineNumber, _modelColumn)); const inputLineNumber = validPosition.lineNumber; const inputColumn = validPosition.column; let lineIndex = inputLineNumber - 1, lineIndexChanged = false; - while (lineIndex > 0 && !this.modelLineProjections[lineIndex].isVisible()) { - lineIndex--; - lineIndexChanged = true; + if (belowHiddenRanges) { + while (lineIndex < this.modelLineProjections.length && !this.modelLineProjections[lineIndex].isVisible()) { + lineIndex++; + lineIndexChanged = true; + } + } else { + while (lineIndex > 0 && !this.modelLineProjections[lineIndex].isVisible()) { + lineIndex--; + lineIndexChanged = true; + } } if (lineIndex === 0 && !this.modelLineProjections[lineIndex].isVisible()) { // Could not reach a real line @@ -851,7 +858,11 @@ export class ViewModelLinesFromProjectedModel implements IViewModelLines { let r: Position; if (lineIndexChanged) { - r = this.modelLineProjections[lineIndex].getViewPositionOfModelPosition(deltaLineNumber, this.model.getLineMaxColumn(lineIndex + 1), affinity); + if (belowHiddenRanges) { + r = this.modelLineProjections[lineIndex].getViewPositionOfModelPosition(deltaLineNumber, 1, affinity); + } else { + r = this.modelLineProjections[lineIndex].getViewPositionOfModelPosition(deltaLineNumber, this.model.getLineMaxColumn(lineIndex + 1), affinity); + } } else { r = this.modelLineProjections[inputLineNumber - 1].getViewPositionOfModelPosition(deltaLineNumber, inputColumn, affinity); } @@ -1071,8 +1082,8 @@ class CoordinatesConverter implements ICoordinatesConverter { // Model -> View conversion and related methods - public convertModelPositionToViewPosition(modelPosition: Position, affinity?: PositionAffinity, allowZero?: boolean): Position { - return this._lines.convertModelPositionToViewPosition(modelPosition.lineNumber, modelPosition.column, affinity, allowZero); + public convertModelPositionToViewPosition(modelPosition: Position, affinity?: PositionAffinity, allowZero?: boolean, belowHiddenRanges?: boolean): Position { + return this._lines.convertModelPositionToViewPosition(modelPosition.lineNumber, modelPosition.column, affinity, allowZero, belowHiddenRanges); } public convertModelRangeToViewRange(modelRange: Range, affinity?: PositionAffinity): Range { diff --git a/src/vs/platform/theme/common/colorRegistry.ts b/src/vs/platform/theme/common/colorRegistry.ts index d8e84bd0e01..f4cce8875a7 100644 --- a/src/vs/platform/theme/common/colorRegistry.ts +++ b/src/vs/platform/theme/common/colorRegistry.ts @@ -424,8 +424,9 @@ export const diffRemovedOutline = registerColor('diffEditor.removedTextBorder', export const diffBorder = registerColor('diffEditor.border', { dark: null, light: null, hcDark: contrastBorder, hcLight: contrastBorder }, nls.localize('diffEditorBorder', 'Border color between the two text editors.')); export const diffDiagonalFill = registerColor('diffEditor.diagonalFill', { dark: '#cccccc33', light: '#22222233', hcDark: null, hcLight: null }, nls.localize('diffDiagonalFill', "Color of the diff editor's diagonal fill. The diagonal fill is used in side-by-side diff views.")); -export const diffUnchangedRegionBackground = registerColor('diffEditor.unchangedRegionBackground', { dark: '#3e3e3e', light: '#e4e4e4', hcDark: null, hcLight: null }, nls.localize('diffEditor.unchangedRegionBackground', "The background color of unchanged blocks in diff editor.")); -export const diffUnchangedRegionForeground = registerColor('diffEditor.unchangedRegionForeground', { dark: '#a3a2a2', light: '#4d4c4c', hcDark: null, hcLight: null }, nls.localize('diffEditor.unchangedRegionForeground', "The foreground color of unchanged blocks in diff editor.")); +export const diffUnchangedRegionBackground = registerColor('diffEditor.unchangedRegionBackground', { dark: '#3e3e3e', light: '#e4e4e4', hcDark: null, hcLight: null }, nls.localize('diffEditor.unchangedRegionBackground', "The background color of unchanged blocks in the diff editor.")); +export const diffUnchangedRegionForeground = registerColor('diffEditor.unchangedRegionForeground', { dark: '#a3a2a2', light: '#4d4c4c', hcDark: null, hcLight: null }, nls.localize('diffEditor.unchangedRegionForeground', "The foreground color of unchanged blocks in the diff editor.")); +export const diffUnchangedTextBackground = registerColor('diffEditor.unchangedCodeBackground', { dark: '#74747429', light: '#b8b8b829', hcDark: null, hcLight: null }, nls.localize('diffEditor.unchangedCodeBackground', "The background color of unchanged code in the diff editor.")); /** * List and tree colors