Path: blob/main/src/vs/workbench/contrib/mergeEditor/browser/utils.ts
5260 views
/*---------------------------------------------------------------------------------------------1* Copyright (c) Microsoft Corporation. All rights reserved.2* Licensed under the MIT License. See License.txt in the project root for license information.3*--------------------------------------------------------------------------------------------*/45import { ArrayQueue, CompareResult } from '../../../../base/common/arrays.js';6import { onUnexpectedError } from '../../../../base/common/errors.js';7import { DisposableStore, IDisposable } from '../../../../base/common/lifecycle.js';8import { IObservable, autorunOpts } from '../../../../base/common/observable.js';9import { CodeEditorWidget } from '../../../../editor/browser/widget/codeEditor/codeEditorWidget.js';10import { IModelDeltaDecoration } from '../../../../editor/common/model.js';11import { IStorageService, StorageScope, StorageTarget } from '../../../../platform/storage/common/storage.js';1213export function setStyle(14element: HTMLElement,15style: {16width?: number | string;17height?: number | string;18left?: number | string;19top?: number | string;20}21): void {22Object.entries(style).forEach(([key, value]) => {23element.style.setProperty(key, toSize(value));24});25}2627function toSize(value: number | string): string {28return typeof value === 'number' ? `${value}px` : value;29}3031export function applyObservableDecorations(editor: CodeEditorWidget, decorations: IObservable<IModelDeltaDecoration[]>): IDisposable {32const d = new DisposableStore();33let decorationIds: string[] = [];34d.add(autorunOpts({ debugName: () => `Apply decorations from ${decorations.debugName}` }, reader => {35const d = decorations.read(reader);36editor.changeDecorations(a => {37decorationIds = a.deltaDecorations(decorationIds, d);38});39}));40d.add({41dispose: () => {42editor.changeDecorations(a => {43decorationIds = a.deltaDecorations(decorationIds, []);44});45}46});47return d;48}4950export function* leftJoin<TLeft, TRight>(51left: Iterable<TLeft>,52right: readonly TRight[],53compare: (left: TLeft, right: TRight) => CompareResult,54): IterableIterator<{ left: TLeft; rights: TRight[] }> {55const rightQueue = new ArrayQueue(right);56for (const leftElement of left) {57rightQueue.takeWhile(rightElement => CompareResult.isGreaterThan(compare(leftElement, rightElement)));58const equals = rightQueue.takeWhile(rightElement => CompareResult.isNeitherLessOrGreaterThan(compare(leftElement, rightElement)));59yield { left: leftElement, rights: equals || [] };60}61}6263export function* join<TLeft, TRight>(64left: Iterable<TLeft>,65right: readonly TRight[],66compare: (left: TLeft, right: TRight) => CompareResult,67): IterableIterator<{ left?: TLeft; rights: TRight[] }> {68const rightQueue = new ArrayQueue(right);69for (const leftElement of left) {70const skipped = rightQueue.takeWhile(rightElement => CompareResult.isGreaterThan(compare(leftElement, rightElement)));71if (skipped) {72yield { rights: skipped };73}74const equals = rightQueue.takeWhile(rightElement => CompareResult.isNeitherLessOrGreaterThan(compare(leftElement, rightElement)));75yield { left: leftElement, rights: equals || [] };76}77}7879export function elementAtOrUndefined<T>(arr: T[], index: number): T | undefined {80return arr[index];81}8283export function setFields<T extends {}>(obj: T, fields: Partial<T>): T {84return Object.assign(obj, fields);85}8687export function deepMerge<T extends {}>(source1: T, source2: Partial<T>): T {88// eslint-disable-next-line local/code-no-any-casts89const result = {} as any as T;90for (const key in source1) {91result[key] = source1[key];92}93for (const key in source2) {94const source2Value = source2[key];95if (typeof result[key] === 'object' && source2Value && typeof source2Value === 'object') {96result[key] = deepMerge<any>(result[key], source2Value);97} else {98// eslint-disable-next-line local/code-no-any-casts99result[key] = source2Value as any;100}101}102return result;103}104105export class PersistentStore<T> {106private hasValue = false;107private value: Readonly<T> | undefined = undefined;108109constructor(110private readonly key: string,111@IStorageService private readonly storageService: IStorageService112) { }113114public get(): Readonly<T> | undefined {115if (!this.hasValue) {116const value = this.storageService.get(this.key, StorageScope.PROFILE);117if (value !== undefined) {118try {119// eslint-disable-next-line local/code-no-any-casts120this.value = JSON.parse(value) as any;121} catch (e) {122onUnexpectedError(e);123}124}125this.hasValue = true;126}127128return this.value;129}130131public set(newValue: T | undefined): void {132this.value = newValue;133134this.storageService.store(135this.key,136JSON.stringify(this.value),137StorageScope.PROFILE,138StorageTarget.USER139);140}141}142143144