UNPKG

monaco-editor

Version:
292 lines (291 loc) • 15.6 kB
/*--------------------------------------------------------------------------------------------- * Copyright (c) Microsoft Corporation. All rights reserved. * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) { var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d; if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc); else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r; return c > 3 && r && Object.defineProperty(target, key, r), r; }; var __param = (this && this.__param) || function (paramIndex, decorator) { return function (target, key) { decorator(target, key, paramIndex); } }; import { getWindow, h, scheduleAtNextAnimationFrame } from '../../../../base/browser/dom.js'; import { SmoothScrollableElement } from '../../../../base/browser/ui/scrollbar/scrollableElement.js'; import { findFirstMaxBy } from '../../../../base/common/arraysFind.js'; import { Disposable, toDisposable } from '../../../../base/common/lifecycle.js'; import { autorun, autorunWithStore, derived, derivedObservableWithCache, derivedWithStore, observableFromEvent, observableValue } from '../../../../base/common/observable.js'; import { disposableObservableValue, globalTransaction, transaction } from '../../../../base/common/observableInternal/base.js'; import { Scrollable } from '../../../../base/common/scrollable.js'; import './style.css'; import { ObservableElementSizeObserver } from '../diffEditor/utils.js'; import { OffsetRange } from '../../../common/core/offsetRange.js'; import { IInstantiationService } from '../../../../platform/instantiation/common/instantiation.js'; import { DiffEditorItemTemplate, TemplateData } from './diffEditorItemTemplate.js'; import { ObjectPool } from './objectPool.js'; import { IContextKeyService } from '../../../../platform/contextkey/common/contextkey.js'; import { ServiceCollection } from '../../../../platform/instantiation/common/serviceCollection.js'; import { EditorContextKeys } from '../../../common/editorContextKeys.js'; import { Selection } from '../../../common/core/selection.js'; let MultiDiffEditorWidgetImpl = class MultiDiffEditorWidgetImpl extends Disposable { constructor(_element, _dimension, _viewModel, _workbenchUIElementFactory, _parentContextKeyService, _parentInstantiationService) { super(); this._element = _element; this._dimension = _dimension; this._viewModel = _viewModel; this._workbenchUIElementFactory = _workbenchUIElementFactory; this._parentContextKeyService = _parentContextKeyService; this._parentInstantiationService = _parentInstantiationService; this._elements = h('div.monaco-component.multiDiffEditor', [ h('div@content', { style: { overflow: 'hidden', } }), h('div.monaco-editor@overflowWidgetsDomNode', {}), ]); this._sizeObserver = this._register(new ObservableElementSizeObserver(this._element, undefined)); this._objectPool = this._register(new ObjectPool((data) => { const template = this._instantiationService.createInstance(DiffEditorItemTemplate, this._elements.content, this._elements.overflowWidgetsDomNode, this._workbenchUIElementFactory); template.setData(data); return template; })); this._scrollable = this._register(new Scrollable({ forceIntegerValues: false, scheduleAtNextAnimationFrame: (cb) => scheduleAtNextAnimationFrame(getWindow(this._element), cb), smoothScrollDuration: 100, })); this._scrollableElement = this._register(new SmoothScrollableElement(this._elements.root, { vertical: 1 /* ScrollbarVisibility.Auto */, horizontal: 1 /* ScrollbarVisibility.Auto */, useShadows: false, }, this._scrollable)); this.scrollTop = observableFromEvent(this._scrollableElement.onScroll, () => /** @description scrollTop */ this._scrollableElement.getScrollPosition().scrollTop); this.scrollLeft = observableFromEvent(this._scrollableElement.onScroll, () => /** @description scrollLeft */ this._scrollableElement.getScrollPosition().scrollLeft); this._viewItems = derivedWithStore(this, (reader, store) => { const vm = this._viewModel.read(reader); if (!vm) { return []; } const items = vm.items.read(reader); return items.map(d => { var _a; const item = store.add(new VirtualizedViewItem(d, this._objectPool, this.scrollLeft)); const data = (_a = this._lastDocStates) === null || _a === void 0 ? void 0 : _a[item.getKey()]; if (data) { transaction(tx => { item.setViewState(data, tx); }); } return item; }); }); this._spaceBetweenPx = 10; this._totalHeight = this._viewItems.map(this, (items, reader) => items.reduce((r, i) => r + i.contentHeight.read(reader) + this._spaceBetweenPx, 0)); this.activeDiffItem = derived(this, reader => this._viewItems.read(reader).find(i => { var _a; return (_a = i.template.read(reader)) === null || _a === void 0 ? void 0 : _a.isFocused.read(reader); })); this.lastActiveDiffItem = derivedObservableWithCache((reader, lastValue) => { var _a; return (_a = this.activeDiffItem.read(reader)) !== null && _a !== void 0 ? _a : lastValue; }); this._contextKeyService = this._register(this._parentContextKeyService.createScoped(this._element)); this._instantiationService = this._parentInstantiationService.createChild(new ServiceCollection([IContextKeyService, this._contextKeyService])); /** This accounts for documents that are not loaded yet. */ this._lastDocStates = {}; this._contextKeyService.createKey(EditorContextKeys.inMultiDiffEditor.key, true); this._register(autorunWithStore((reader, store) => { const viewModel = this._viewModel.read(reader); if (viewModel && viewModel.contextKeys) { for (const [key, value] of Object.entries(viewModel.contextKeys)) { const contextKey = this._contextKeyService.createKey(key, undefined); contextKey.set(value); store.add(toDisposable(() => contextKey.reset())); } } })); const ctxAllCollapsed = this._parentContextKeyService.createKey(EditorContextKeys.multiDiffEditorAllCollapsed.key, false); this._register(autorun((reader) => { const viewModel = this._viewModel.read(reader); if (viewModel) { const allCollapsed = viewModel.items.read(reader).every(item => item.collapsed.read(reader)); ctxAllCollapsed.set(allCollapsed); } })); this._register(autorun((reader) => { const lastActiveDiffItem = this.lastActiveDiffItem.read(reader); transaction(tx => { var _a; (_a = this._viewModel.read(reader)) === null || _a === void 0 ? void 0 : _a.activeDiffItem.set(lastActiveDiffItem === null || lastActiveDiffItem === void 0 ? void 0 : lastActiveDiffItem.viewModel, tx); }); })); this._register(autorun((reader) => { /** @description Update widget dimension */ const dimension = this._dimension.read(reader); this._sizeObserver.observe(dimension); })); this._elements.content.style.position = 'relative'; this._register(autorun((reader) => { /** @description Update scroll dimensions */ const height = this._sizeObserver.height.read(reader); this._elements.root.style.height = `${height}px`; const totalHeight = this._totalHeight.read(reader); this._elements.content.style.height = `${totalHeight}px`; const width = this._sizeObserver.width.read(reader); let scrollWidth = width; const viewItems = this._viewItems.read(reader); const max = findFirstMaxBy(viewItems, i => i.maxScroll.read(reader).maxScroll); if (max) { const maxScroll = max.maxScroll.read(reader); scrollWidth = width + maxScroll.maxScroll; } this._scrollableElement.setScrollDimensions({ width: width, height: height, scrollHeight: totalHeight, scrollWidth, }); })); _element.replaceChildren(this._scrollableElement.getDomNode()); this._register(toDisposable(() => { _element.replaceChildren(); })); this._register(this._register(autorun(reader => { /** @description Render all */ globalTransaction(tx => { this.render(reader); }); }))); } render(reader) { const scrollTop = this.scrollTop.read(reader); let contentScrollOffsetToScrollOffset = 0; let itemHeightSumBefore = 0; let itemContentHeightSumBefore = 0; const viewPortHeight = this._sizeObserver.height.read(reader); const contentViewPort = OffsetRange.ofStartAndLength(scrollTop, viewPortHeight); const width = this._sizeObserver.width.read(reader); for (const v of this._viewItems.read(reader)) { const itemContentHeight = v.contentHeight.read(reader); const itemHeight = Math.min(itemContentHeight, viewPortHeight); const itemRange = OffsetRange.ofStartAndLength(itemHeightSumBefore, itemHeight); const itemContentRange = OffsetRange.ofStartAndLength(itemContentHeightSumBefore, itemContentHeight); if (itemContentRange.isBefore(contentViewPort)) { contentScrollOffsetToScrollOffset -= itemContentHeight - itemHeight; v.hide(); } else if (itemContentRange.isAfter(contentViewPort)) { v.hide(); } else { const scroll = Math.max(0, Math.min(contentViewPort.start - itemContentRange.start, itemContentHeight - itemHeight)); contentScrollOffsetToScrollOffset -= scroll; const viewPort = OffsetRange.ofStartAndLength(scrollTop + contentScrollOffsetToScrollOffset, viewPortHeight); v.render(itemRange, scroll, width, viewPort); } itemHeightSumBefore += itemHeight + this._spaceBetweenPx; itemContentHeightSumBefore += itemContentHeight + this._spaceBetweenPx; } this._elements.content.style.transform = `translateY(${-(scrollTop + contentScrollOffsetToScrollOffset)}px)`; } }; MultiDiffEditorWidgetImpl = __decorate([ __param(4, IContextKeyService), __param(5, IInstantiationService) ], MultiDiffEditorWidgetImpl); export { MultiDiffEditorWidgetImpl }; class VirtualizedViewItem extends Disposable { constructor(viewModel, _objectPool, _scrollLeft) { super(); this.viewModel = viewModel; this._objectPool = _objectPool; this._scrollLeft = _scrollLeft; this._templateRef = this._register(disposableObservableValue(this, undefined)); this.contentHeight = derived(this, reader => { var _a, _b, _c; return (_c = (_b = (_a = this._templateRef.read(reader)) === null || _a === void 0 ? void 0 : _a.object.contentHeight) === null || _b === void 0 ? void 0 : _b.read(reader)) !== null && _c !== void 0 ? _c : this.viewModel.lastTemplateData.read(reader).contentHeight; }); this.maxScroll = derived(this, reader => { var _a, _b; return (_b = (_a = this._templateRef.read(reader)) === null || _a === void 0 ? void 0 : _a.object.maxScroll.read(reader)) !== null && _b !== void 0 ? _b : { maxScroll: 0, scrollWidth: 0 }; }); this.template = derived(this, reader => { var _a; return (_a = this._templateRef.read(reader)) === null || _a === void 0 ? void 0 : _a.object; }); this._isHidden = observableValue(this, false); this._register(autorun((reader) => { var _a; const scrollLeft = this._scrollLeft.read(reader); (_a = this._templateRef.read(reader)) === null || _a === void 0 ? void 0 : _a.object.setScrollLeft(scrollLeft); })); this._register(autorun(reader => { const ref = this._templateRef.read(reader); if (!ref) { return; } const isHidden = this._isHidden.read(reader); if (!isHidden) { return; } const isFocused = ref.object.isFocused.read(reader); if (isFocused) { return; } this._clear(); })); } dispose() { this._clear(); super.dispose(); } toString() { var _a; return `VirtualViewItem(${(_a = this.viewModel.entry.value.modified) === null || _a === void 0 ? void 0 : _a.uri.toString()})`; } getKey() { return this.viewModel.getKey(); } setViewState(viewState, tx) { var _a; this.viewModel.collapsed.set(viewState.collapsed, tx); this._updateTemplateData(tx); const data = this.viewModel.lastTemplateData.get(); const selections = (_a = viewState.selections) === null || _a === void 0 ? void 0 : _a.map(Selection.liftSelection); this.viewModel.lastTemplateData.set({ ...data, selections, }, tx); const ref = this._templateRef.get(); if (ref) { if (selections) { ref.object.editor.setSelections(selections); } } } _updateTemplateData(tx) { var _a; const ref = this._templateRef.get(); if (!ref) { return; } this.viewModel.lastTemplateData.set({ contentHeight: ref.object.contentHeight.get(), selections: (_a = ref.object.editor.getSelections()) !== null && _a !== void 0 ? _a : undefined, }, tx); } _clear() { const ref = this._templateRef.get(); if (!ref) { return; } transaction(tx => { this._updateTemplateData(tx); ref.object.hide(); this._templateRef.set(undefined, tx); }); } hide() { this._isHidden.set(true, undefined); } render(verticalSpace, offset, width, viewPort) { this._isHidden.set(false, undefined); let ref = this._templateRef.get(); if (!ref) { ref = this._objectPool.getUnusedObj(new TemplateData(this.viewModel)); this._templateRef.set(ref, undefined); const selections = this.viewModel.lastTemplateData.get().selections; if (selections) { ref.object.editor.setSelections(selections); } } ref.object.render(verticalSpace, width, offset, viewPort); } }