monaco-editor-core
Version:
A browser based code editor
285 lines (284 loc) • 12.1 kB
JavaScript
/*---------------------------------------------------------------------------------------------
* 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 * as browser from '../../../base/browser/browser.js';
import * as arrays from '../../../base/common/arrays.js';
import { Emitter } from '../../../base/common/event.js';
import { Disposable } from '../../../base/common/lifecycle.js';
import * as objects from '../../../base/common/objects.js';
import * as platform from '../../../base/common/platform.js';
import { ElementSizeObserver } from './elementSizeObserver.js';
import { FontMeasurements } from './fontMeasurements.js';
import { migrateOptions } from './migrateOptions.js';
import { TabFocus } from './tabFocus.js';
import { ComputeOptionsMemory, ConfigurationChangedEvent, editorOptionsRegistry } from '../../common/config/editorOptions.js';
import { EditorZoom } from '../../common/config/editorZoom.js';
import { BareFontInfo } from '../../common/config/fontInfo.js';
import { IAccessibilityService } from '../../../platform/accessibility/common/accessibility.js';
import { getWindow, getWindowById } from '../../../base/browser/dom.js';
import { PixelRatio } from '../../../base/browser/pixelRatio.js';
let EditorConfiguration = class EditorConfiguration extends Disposable {
constructor(isSimpleWidget, contextMenuId, options, container, _accessibilityService) {
super();
this._accessibilityService = _accessibilityService;
this._onDidChange = this._register(new Emitter());
this.onDidChange = this._onDidChange.event;
this._onDidChangeFast = this._register(new Emitter());
this.onDidChangeFast = this._onDidChangeFast.event;
this._isDominatedByLongLines = false;
this._viewLineCount = 1;
this._lineNumbersDigitCount = 1;
this._reservedHeight = 0;
this._glyphMarginDecorationLaneCount = 1;
this._computeOptionsMemory = new ComputeOptionsMemory();
this.isSimpleWidget = isSimpleWidget;
this.contextMenuId = contextMenuId;
this._containerObserver = this._register(new ElementSizeObserver(container, options.dimension));
this._targetWindowId = getWindow(container).vscodeWindowId;
this._rawOptions = deepCloneAndMigrateOptions(options);
this._validatedOptions = EditorOptionsUtil.validateOptions(this._rawOptions);
this.options = this._computeOptions();
if (this.options.get(13 /* EditorOption.automaticLayout */)) {
this._containerObserver.startObserving();
}
this._register(EditorZoom.onDidChangeZoomLevel(() => this._recomputeOptions()));
this._register(TabFocus.onDidChangeTabFocus(() => this._recomputeOptions()));
this._register(this._containerObserver.onDidChange(() => this._recomputeOptions()));
this._register(FontMeasurements.onDidChange(() => this._recomputeOptions()));
this._register(PixelRatio.getInstance(getWindow(container)).onDidChange(() => this._recomputeOptions()));
this._register(this._accessibilityService.onDidChangeScreenReaderOptimized(() => this._recomputeOptions()));
}
_recomputeOptions() {
const newOptions = this._computeOptions();
const changeEvent = EditorOptionsUtil.checkEquals(this.options, newOptions);
if (changeEvent === null) {
// nothing changed!
return;
}
this.options = newOptions;
this._onDidChangeFast.fire(changeEvent);
this._onDidChange.fire(changeEvent);
}
_computeOptions() {
const partialEnv = this._readEnvConfiguration();
const bareFontInfo = BareFontInfo.createFromValidatedSettings(this._validatedOptions, partialEnv.pixelRatio, this.isSimpleWidget);
const fontInfo = this._readFontInfo(bareFontInfo);
const env = {
memory: this._computeOptionsMemory,
outerWidth: partialEnv.outerWidth,
outerHeight: partialEnv.outerHeight - this._reservedHeight,
fontInfo: fontInfo,
extraEditorClassName: partialEnv.extraEditorClassName,
isDominatedByLongLines: this._isDominatedByLongLines,
viewLineCount: this._viewLineCount,
lineNumbersDigitCount: this._lineNumbersDigitCount,
emptySelectionClipboard: partialEnv.emptySelectionClipboard,
pixelRatio: partialEnv.pixelRatio,
tabFocusMode: TabFocus.getTabFocusMode(),
accessibilitySupport: partialEnv.accessibilitySupport,
glyphMarginDecorationLaneCount: this._glyphMarginDecorationLaneCount
};
return EditorOptionsUtil.computeOptions(this._validatedOptions, env);
}
_readEnvConfiguration() {
return {
extraEditorClassName: getExtraEditorClassName(),
outerWidth: this._containerObserver.getWidth(),
outerHeight: this._containerObserver.getHeight(),
emptySelectionClipboard: browser.isWebKit || browser.isFirefox,
pixelRatio: PixelRatio.getInstance(getWindowById(this._targetWindowId, true).window).value,
accessibilitySupport: (this._accessibilityService.isScreenReaderOptimized()
? 2 /* AccessibilitySupport.Enabled */
: this._accessibilityService.getAccessibilitySupport())
};
}
_readFontInfo(bareFontInfo) {
return FontMeasurements.readFontInfo(getWindowById(this._targetWindowId, true).window, bareFontInfo);
}
getRawOptions() {
return this._rawOptions;
}
updateOptions(_newOptions) {
const newOptions = deepCloneAndMigrateOptions(_newOptions);
const didChange = EditorOptionsUtil.applyUpdate(this._rawOptions, newOptions);
if (!didChange) {
return;
}
this._validatedOptions = EditorOptionsUtil.validateOptions(this._rawOptions);
this._recomputeOptions();
}
observeContainer(dimension) {
this._containerObserver.observe(dimension);
}
setIsDominatedByLongLines(isDominatedByLongLines) {
if (this._isDominatedByLongLines === isDominatedByLongLines) {
return;
}
this._isDominatedByLongLines = isDominatedByLongLines;
this._recomputeOptions();
}
setModelLineCount(modelLineCount) {
const lineNumbersDigitCount = digitCount(modelLineCount);
if (this._lineNumbersDigitCount === lineNumbersDigitCount) {
return;
}
this._lineNumbersDigitCount = lineNumbersDigitCount;
this._recomputeOptions();
}
setViewLineCount(viewLineCount) {
if (this._viewLineCount === viewLineCount) {
return;
}
this._viewLineCount = viewLineCount;
this._recomputeOptions();
}
setReservedHeight(reservedHeight) {
if (this._reservedHeight === reservedHeight) {
return;
}
this._reservedHeight = reservedHeight;
this._recomputeOptions();
}
setGlyphMarginDecorationLaneCount(decorationLaneCount) {
if (this._glyphMarginDecorationLaneCount === decorationLaneCount) {
return;
}
this._glyphMarginDecorationLaneCount = decorationLaneCount;
this._recomputeOptions();
}
};
EditorConfiguration = __decorate([
__param(4, IAccessibilityService)
], EditorConfiguration);
export { EditorConfiguration };
function digitCount(n) {
let r = 0;
while (n) {
n = Math.floor(n / 10);
r++;
}
return r ? r : 1;
}
function getExtraEditorClassName() {
let extra = '';
if (!browser.isSafari && !browser.isWebkitWebView) {
// Use user-select: none in all browsers except Safari and native macOS WebView
extra += 'no-user-select ';
}
if (browser.isSafari) {
// See https://github.com/microsoft/vscode/issues/108822
extra += 'no-minimap-shadow ';
extra += 'enable-user-select ';
}
if (platform.isMacintosh) {
extra += 'mac ';
}
return extra;
}
class ValidatedEditorOptions {
constructor() {
this._values = [];
}
_read(option) {
return this._values[option];
}
get(id) {
return this._values[id];
}
_write(option, value) {
this._values[option] = value;
}
}
export class ComputedEditorOptions {
constructor() {
this._values = [];
}
_read(id) {
if (id >= this._values.length) {
throw new Error('Cannot read uninitialized value');
}
return this._values[id];
}
get(id) {
return this._read(id);
}
_write(id, value) {
this._values[id] = value;
}
}
class EditorOptionsUtil {
static validateOptions(options) {
const result = new ValidatedEditorOptions();
for (const editorOption of editorOptionsRegistry) {
const value = (editorOption.name === '_never_' ? undefined : options[editorOption.name]);
result._write(editorOption.id, editorOption.validate(value));
}
return result;
}
static computeOptions(options, env) {
const result = new ComputedEditorOptions();
for (const editorOption of editorOptionsRegistry) {
result._write(editorOption.id, editorOption.compute(env, result, options._read(editorOption.id)));
}
return result;
}
static _deepEquals(a, b) {
if (typeof a !== 'object' || typeof b !== 'object' || !a || !b) {
return a === b;
}
if (Array.isArray(a) || Array.isArray(b)) {
return (Array.isArray(a) && Array.isArray(b) ? arrays.equals(a, b) : false);
}
if (Object.keys(a).length !== Object.keys(b).length) {
return false;
}
for (const key in a) {
if (!EditorOptionsUtil._deepEquals(a[key], b[key])) {
return false;
}
}
return true;
}
static checkEquals(a, b) {
const result = [];
let somethingChanged = false;
for (const editorOption of editorOptionsRegistry) {
const changed = !EditorOptionsUtil._deepEquals(a._read(editorOption.id), b._read(editorOption.id));
result[editorOption.id] = changed;
if (changed) {
somethingChanged = true;
}
}
return (somethingChanged ? new ConfigurationChangedEvent(result) : null);
}
/**
* Returns true if something changed.
* Modifies `options`.
*/
static applyUpdate(options, update) {
let changed = false;
for (const editorOption of editorOptionsRegistry) {
if (update.hasOwnProperty(editorOption.name)) {
const result = editorOption.applyUpdate(options[editorOption.name], update[editorOption.name]);
options[editorOption.name] = result.newValue;
changed = changed || result.didChange;
}
}
return changed;
}
}
function deepCloneAndMigrateOptions(_options) {
const options = objects.deepClone(_options);
migrateOptions(options);
return options;
}