UNPKG

monaco-editor

Version:
1,143 lines (1,142 loc) • 185 kB
import { equals as equals$1 } from '../../../base/common/arrays.js'; import { equals } from '../../../base/common/objects.js'; import { isLinux, isMacintosh, isChrome, isEdge, isNative } from '../../../base/common/platform.js'; import { EDITOR_FONT_DEFAULTS, FONT_VARIATION_OFF, FONT_VARIATION_TRANSLATE, FontInfo } from './fontInfo.js'; import { EDITOR_MODEL_DEFAULTS } from '../core/misc/textModelDefaults.js'; import { USUAL_WORD_SEPARATORS } from '../core/wordHelper.js'; import { localize } from '../../../nls.js'; /*--------------------------------------------------------------------------------------------- * Copyright (c) Microsoft Corporation. All rights reserved. * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ /** * @internal * The width of the minimap gutter, in pixels. */ const MINIMAP_GUTTER_WIDTH = 8; //#endregion /** * An event describing that the configuration of the editor has changed. */ class ConfigurationChangedEvent { /** * @internal */ constructor(values) { this._values = values; } hasChanged(id) { return this._values[id]; } } /** * @internal */ class ComputeOptionsMemory { constructor() { this.stableMinimapLayoutInput = null; this.stableFitMaxMinimapScale = 0; this.stableFitRemainingWidth = 0; } } /** * @internal */ class BaseEditorOption { constructor(id, name, defaultValue, schema) { this.id = id; this.name = name; this.defaultValue = defaultValue; this.schema = schema; } applyUpdate(value, update) { return applyUpdate(value, update); } compute(env, options, value) { return value; } } class ApplyUpdateResult { constructor(newValue, didChange) { this.newValue = newValue; this.didChange = didChange; } } function applyUpdate(value, update) { if (typeof value !== 'object' || typeof update !== 'object' || !value || !update) { return new ApplyUpdateResult(update, value !== update); } if (Array.isArray(value) || Array.isArray(update)) { const arrayEquals = Array.isArray(value) && Array.isArray(update) && equals$1(value, update); return new ApplyUpdateResult(update, !arrayEquals); } let didChange = false; for (const key in update) { if (update.hasOwnProperty(key)) { const result = applyUpdate(value[key], update[key]); if (result.didChange) { value[key] = result.newValue; didChange = true; } } } return new ApplyUpdateResult(value, didChange); } /** * @internal */ class ComputedEditorOption { constructor(id, defaultValue) { this.schema = undefined; this.id = id; this.name = '_never_'; this.defaultValue = defaultValue; } applyUpdate(value, update) { return applyUpdate(value, update); } validate(input) { return this.defaultValue; } } class SimpleEditorOption { constructor(id, name, defaultValue, schema) { this.id = id; this.name = name; this.defaultValue = defaultValue; this.schema = schema; } applyUpdate(value, update) { return applyUpdate(value, update); } compute(env, options, value) { return value; } } /** * @internal */ function boolean(value, defaultValue) { if (typeof value === 'undefined') { return defaultValue; } if (value === 'false') { // treat the string 'false' as false return false; } return Boolean(value); } class EditorBooleanOption extends SimpleEditorOption { constructor(id, name, defaultValue, schema = undefined) { if (typeof schema !== 'undefined') { schema.type = 'boolean'; schema.default = defaultValue; } super(id, name, defaultValue, schema); } validate(input) { return boolean(input, this.defaultValue); } } /** * @internal */ function clampedInt(value, defaultValue, minimum, maximum) { if (typeof value === 'string') { value = parseInt(value, 10); } if (typeof value !== 'number' || isNaN(value)) { return defaultValue; } let r = value; r = Math.max(minimum, r); r = Math.min(maximum, r); return r | 0; } class EditorIntOption extends SimpleEditorOption { static clampedInt(value, defaultValue, minimum, maximum) { return clampedInt(value, defaultValue, minimum, maximum); } constructor(id, name, defaultValue, minimum, maximum, schema = undefined) { if (typeof schema !== 'undefined') { schema.type = 'integer'; schema.default = defaultValue; schema.minimum = minimum; schema.maximum = maximum; } super(id, name, defaultValue, schema); this.minimum = minimum; this.maximum = maximum; } validate(input) { return EditorIntOption.clampedInt(input, this.defaultValue, this.minimum, this.maximum); } } /** * @internal */ function clampedFloat(value, defaultValue, minimum, maximum) { if (typeof value === 'undefined') { return defaultValue; } const r = EditorFloatOption.float(value, defaultValue); return EditorFloatOption.clamp(r, minimum, maximum); } class EditorFloatOption extends SimpleEditorOption { static clamp(n, min, max) { if (n < min) { return min; } if (n > max) { return max; } return n; } static float(value, defaultValue) { if (typeof value === 'string') { value = parseFloat(value); } if (typeof value !== 'number' || isNaN(value)) { return defaultValue; } return value; } constructor(id, name, defaultValue, validationFn, schema, minimum, maximum) { if (typeof schema !== 'undefined') { schema.type = 'number'; schema.default = defaultValue; schema.minimum = minimum; schema.maximum = maximum; } super(id, name, defaultValue, schema); this.validationFn = validationFn; this.minimum = minimum; this.maximum = maximum; } validate(input) { return this.validationFn(EditorFloatOption.float(input, this.defaultValue)); } } class EditorStringOption extends SimpleEditorOption { static string(value, defaultValue) { if (typeof value !== 'string') { return defaultValue; } return value; } constructor(id, name, defaultValue, schema = undefined) { if (typeof schema !== 'undefined') { schema.type = 'string'; schema.default = defaultValue; } super(id, name, defaultValue, schema); } validate(input) { return EditorStringOption.string(input, this.defaultValue); } } /** * @internal */ function stringSet(value, defaultValue, allowedValues, renamedValues) { if (typeof value !== 'string') { return defaultValue; } if (renamedValues && value in renamedValues) { return renamedValues[value]; } if (allowedValues.indexOf(value) === -1) { return defaultValue; } return value; } class EditorStringEnumOption extends SimpleEditorOption { constructor(id, name, defaultValue, allowedValues, schema = undefined) { if (typeof schema !== 'undefined') { schema.type = 'string'; schema.enum = allowedValues.slice(0); schema.default = defaultValue; } super(id, name, defaultValue, schema); this._allowedValues = allowedValues; } validate(input) { return stringSet(input, this.defaultValue, this._allowedValues); } } class EditorEnumOption extends BaseEditorOption { constructor(id, name, defaultValue, defaultStringValue, allowedValues, convert, schema = undefined) { if (typeof schema !== 'undefined') { schema.type = 'string'; schema.enum = allowedValues; schema.default = defaultStringValue; } super(id, name, defaultValue, schema); this._allowedValues = allowedValues; this._convert = convert; } validate(input) { if (typeof input !== 'string') { return this.defaultValue; } if (this._allowedValues.indexOf(input) === -1) { return this.defaultValue; } return this._convert(input); } } //#endregion //#region autoIndent function _autoIndentFromString(autoIndent) { switch (autoIndent) { case 'none': return 0 /* EditorAutoIndentStrategy.None */; case 'keep': return 1 /* EditorAutoIndentStrategy.Keep */; case 'brackets': return 2 /* EditorAutoIndentStrategy.Brackets */; case 'advanced': return 3 /* EditorAutoIndentStrategy.Advanced */; case 'full': return 4 /* EditorAutoIndentStrategy.Full */; } } //#endregion //#region accessibilitySupport class EditorAccessibilitySupport extends BaseEditorOption { constructor() { super(2 /* EditorOption.accessibilitySupport */, 'accessibilitySupport', 0 /* AccessibilitySupport.Unknown */, { type: 'string', enum: ['auto', 'on', 'off'], enumDescriptions: [ localize(201, "Use platform APIs to detect when a Screen Reader is attached."), localize(202, "Optimize for usage with a Screen Reader."), localize(203, "Assume a screen reader is not attached."), ], default: 'auto', tags: ['accessibility'], description: localize(204, "Controls if the UI should run in a mode where it is optimized for screen readers.") }); } validate(input) { switch (input) { case 'auto': return 0 /* AccessibilitySupport.Unknown */; case 'off': return 1 /* AccessibilitySupport.Disabled */; case 'on': return 2 /* AccessibilitySupport.Enabled */; } return this.defaultValue; } compute(env, options, value) { if (value === 0 /* AccessibilitySupport.Unknown */) { // The editor reads the `accessibilitySupport` from the environment return env.accessibilitySupport; } return value; } } class EditorComments extends BaseEditorOption { constructor() { const defaults = { insertSpace: true, ignoreEmptyLines: true, }; super(29 /* EditorOption.comments */, 'comments', defaults, { 'editor.comments.insertSpace': { type: 'boolean', default: defaults.insertSpace, description: localize(205, "Controls whether a space character is inserted when commenting.") }, 'editor.comments.ignoreEmptyLines': { type: 'boolean', default: defaults.ignoreEmptyLines, description: localize(206, 'Controls if empty lines should be ignored with toggle, add or remove actions for line comments.') }, }); } validate(_input) { if (!_input || typeof _input !== 'object') { return this.defaultValue; } const input = _input; return { insertSpace: boolean(input.insertSpace, this.defaultValue.insertSpace), ignoreEmptyLines: boolean(input.ignoreEmptyLines, this.defaultValue.ignoreEmptyLines), }; } } /** * @internal */ function cursorBlinkingStyleFromString(cursorBlinkingStyle) { switch (cursorBlinkingStyle) { case 'blink': return 1 /* TextEditorCursorBlinkingStyle.Blink */; case 'smooth': return 2 /* TextEditorCursorBlinkingStyle.Smooth */; case 'phase': return 3 /* TextEditorCursorBlinkingStyle.Phase */; case 'expand': return 4 /* TextEditorCursorBlinkingStyle.Expand */; case 'solid': return 5 /* TextEditorCursorBlinkingStyle.Solid */; } } //#endregion //#region cursorStyle /** * The style in which the editor's cursor should be rendered. */ var TextEditorCursorStyle; (function (TextEditorCursorStyle) { /** * As a vertical line (sitting between two characters). */ TextEditorCursorStyle[TextEditorCursorStyle["Line"] = 1] = "Line"; /** * As a block (sitting on top of a character). */ TextEditorCursorStyle[TextEditorCursorStyle["Block"] = 2] = "Block"; /** * As a horizontal line (sitting under a character). */ TextEditorCursorStyle[TextEditorCursorStyle["Underline"] = 3] = "Underline"; /** * As a thin vertical line (sitting between two characters). */ TextEditorCursorStyle[TextEditorCursorStyle["LineThin"] = 4] = "LineThin"; /** * As an outlined block (sitting on top of a character). */ TextEditorCursorStyle[TextEditorCursorStyle["BlockOutline"] = 5] = "BlockOutline"; /** * As a thin horizontal line (sitting under a character). */ TextEditorCursorStyle[TextEditorCursorStyle["UnderlineThin"] = 6] = "UnderlineThin"; })(TextEditorCursorStyle || (TextEditorCursorStyle = {})); /** * @internal */ function cursorStyleFromString(cursorStyle) { switch (cursorStyle) { case 'line': return TextEditorCursorStyle.Line; case 'block': return TextEditorCursorStyle.Block; case 'underline': return TextEditorCursorStyle.Underline; case 'line-thin': return TextEditorCursorStyle.LineThin; case 'block-outline': return TextEditorCursorStyle.BlockOutline; case 'underline-thin': return TextEditorCursorStyle.UnderlineThin; } } //#endregion //#region editorClassName class EditorClassName extends ComputedEditorOption { constructor() { super(162 /* EditorOption.editorClassName */, ''); } compute(env, options, _) { const classNames = ['monaco-editor']; if (options.get(48 /* EditorOption.extraEditorClassName */)) { classNames.push(options.get(48 /* EditorOption.extraEditorClassName */)); } if (env.extraEditorClassName) { classNames.push(env.extraEditorClassName); } if (options.get(82 /* EditorOption.mouseStyle */) === 'default') { classNames.push('mouse-default'); } else if (options.get(82 /* EditorOption.mouseStyle */) === 'copy') { classNames.push('mouse-copy'); } if (options.get(127 /* EditorOption.showUnused */)) { classNames.push('showUnused'); } if (options.get(157 /* EditorOption.showDeprecated */)) { classNames.push('showDeprecated'); } return classNames.join(' '); } } //#endregion //#region emptySelectionClipboard class EditorEmptySelectionClipboard extends EditorBooleanOption { constructor() { super(45 /* EditorOption.emptySelectionClipboard */, 'emptySelectionClipboard', true, { description: localize(207, "Controls whether copying without a selection copies the current line.") }); } compute(env, options, value) { return value && env.emptySelectionClipboard; } } class EditorFind extends BaseEditorOption { constructor() { const defaults = { cursorMoveOnType: true, findOnType: true, seedSearchStringFromSelection: 'always', autoFindInSelection: 'never', globalFindClipboard: false, addExtraSpaceOnTop: true, loop: true, history: 'workspace', replaceHistory: 'workspace', }; super(50 /* EditorOption.find */, 'find', defaults, { 'editor.find.cursorMoveOnType': { type: 'boolean', default: defaults.cursorMoveOnType, description: localize(208, "Controls whether the cursor should jump to find matches while typing.") }, 'editor.find.seedSearchStringFromSelection': { type: 'string', enum: ['never', 'always', 'selection'], default: defaults.seedSearchStringFromSelection, enumDescriptions: [ localize(209, 'Never seed search string from the editor selection.'), localize(210, 'Always seed search string from the editor selection, including word at cursor position.'), localize(211, 'Only seed search string from the editor selection.') ], description: localize(212, "Controls whether the search string in the Find Widget is seeded from the editor selection.") }, 'editor.find.autoFindInSelection': { type: 'string', enum: ['never', 'always', 'multiline'], default: defaults.autoFindInSelection, enumDescriptions: [ localize(213, 'Never turn on Find in Selection automatically (default).'), localize(214, 'Always turn on Find in Selection automatically.'), localize(215, 'Turn on Find in Selection automatically when multiple lines of content are selected.') ], description: localize(216, "Controls the condition for turning on Find in Selection automatically.") }, 'editor.find.globalFindClipboard': { type: 'boolean', default: defaults.globalFindClipboard, description: localize(217, "Controls whether the Find Widget should read or modify the shared find clipboard on macOS."), included: isMacintosh }, 'editor.find.addExtraSpaceOnTop': { type: 'boolean', default: defaults.addExtraSpaceOnTop, description: localize(218, "Controls whether the Find Widget should add extra lines on top of the editor. When true, you can scroll beyond the first line when the Find Widget is visible.") }, 'editor.find.loop': { type: 'boolean', default: defaults.loop, description: localize(219, "Controls whether the search automatically restarts from the beginning (or the end) when no further matches can be found.") }, 'editor.find.history': { type: 'string', enum: ['never', 'workspace'], default: 'workspace', enumDescriptions: [ localize(220, 'Do not store search history from the find widget.'), localize(221, 'Store search history across the active workspace'), ], description: localize(222, "Controls how the find widget history should be stored") }, 'editor.find.replaceHistory': { type: 'string', enum: ['never', 'workspace'], default: 'workspace', enumDescriptions: [ localize(223, 'Do not store history from the replace widget.'), localize(224, 'Store replace history across the active workspace'), ], description: localize(225, "Controls how the replace widget history should be stored") }, 'editor.find.findOnType': { type: 'boolean', default: defaults.findOnType, description: localize(226, "Controls whether the Find Widget should search as you type.") }, }); } validate(_input) { if (!_input || typeof _input !== 'object') { return this.defaultValue; } const input = _input; return { cursorMoveOnType: boolean(input.cursorMoveOnType, this.defaultValue.cursorMoveOnType), findOnType: boolean(input.findOnType, this.defaultValue.findOnType), seedSearchStringFromSelection: typeof input.seedSearchStringFromSelection === 'boolean' ? (input.seedSearchStringFromSelection ? 'always' : 'never') : stringSet(input.seedSearchStringFromSelection, this.defaultValue.seedSearchStringFromSelection, ['never', 'always', 'selection']), autoFindInSelection: typeof input.autoFindInSelection === 'boolean' ? (input.autoFindInSelection ? 'always' : 'never') : stringSet(input.autoFindInSelection, this.defaultValue.autoFindInSelection, ['never', 'always', 'multiline']), globalFindClipboard: boolean(input.globalFindClipboard, this.defaultValue.globalFindClipboard), addExtraSpaceOnTop: boolean(input.addExtraSpaceOnTop, this.defaultValue.addExtraSpaceOnTop), loop: boolean(input.loop, this.defaultValue.loop), history: stringSet(input.history, this.defaultValue.history, ['never', 'workspace']), replaceHistory: stringSet(input.replaceHistory, this.defaultValue.replaceHistory, ['never', 'workspace']), }; } } //#endregion //#region fontLigatures /** * @internal */ class EditorFontLigatures extends BaseEditorOption { static { this.OFF = '"liga" off, "calt" off'; } static { this.ON = '"liga" on, "calt" on'; } constructor() { super(60 /* EditorOption.fontLigatures */, 'fontLigatures', EditorFontLigatures.OFF, { anyOf: [ { type: 'boolean', description: localize(227, "Enables/Disables font ligatures ('calt' and 'liga' font features). Change this to a string for fine-grained control of the 'font-feature-settings' CSS property."), }, { type: 'string', description: localize(228, "Explicit 'font-feature-settings' CSS property. A boolean can be passed instead if one only needs to turn on/off ligatures.") } ], description: localize(229, "Configures font ligatures or font features. Can be either a boolean to enable/disable ligatures or a string for the value of the CSS 'font-feature-settings' property."), default: false }); } validate(input) { if (typeof input === 'undefined') { return this.defaultValue; } if (typeof input === 'string') { if (input === 'false' || input.length === 0) { return EditorFontLigatures.OFF; } if (input === 'true') { return EditorFontLigatures.ON; } return input; } if (Boolean(input)) { return EditorFontLigatures.ON; } return EditorFontLigatures.OFF; } } //#endregion //#region fontVariations /** * @internal */ class EditorFontVariations extends BaseEditorOption { // Text is laid out using default settings. static { this.OFF = FONT_VARIATION_OFF; } // Translate `fontWeight` config to the `font-variation-settings` CSS property. static { this.TRANSLATE = FONT_VARIATION_TRANSLATE; } constructor() { super(63 /* EditorOption.fontVariations */, 'fontVariations', EditorFontVariations.OFF, { anyOf: [ { type: 'boolean', description: localize(230, "Enables/Disables the translation from font-weight to font-variation-settings. Change this to a string for fine-grained control of the 'font-variation-settings' CSS property."), }, { type: 'string', description: localize(231, "Explicit 'font-variation-settings' CSS property. A boolean can be passed instead if one only needs to translate font-weight to font-variation-settings.") } ], description: localize(232, "Configures font variations. Can be either a boolean to enable/disable the translation from font-weight to font-variation-settings or a string for the value of the CSS 'font-variation-settings' property."), default: false }); } validate(input) { if (typeof input === 'undefined') { return this.defaultValue; } if (typeof input === 'string') { if (input === 'false') { return EditorFontVariations.OFF; } if (input === 'true') { return EditorFontVariations.TRANSLATE; } return input; } if (Boolean(input)) { return EditorFontVariations.TRANSLATE; } return EditorFontVariations.OFF; } compute(env, options, value) { // The value is computed from the fontWeight if it is true. // So take the result from env.fontInfo return env.fontInfo.fontVariationSettings; } } //#endregion //#region fontInfo class EditorFontInfo extends ComputedEditorOption { constructor() { super(59 /* EditorOption.fontInfo */, new FontInfo({ pixelRatio: 0, fontFamily: '', fontWeight: '', fontSize: 0, fontFeatureSettings: '', fontVariationSettings: '', lineHeight: 0, letterSpacing: 0, isMonospace: false, typicalHalfwidthCharacterWidth: 0, typicalFullwidthCharacterWidth: 0, canUseHalfwidthRightwardsArrow: false, spaceWidth: 0, middotWidth: 0, wsmiddotWidth: 0, maxDigitWidth: 0, }, false)); } compute(env, options, _) { return env.fontInfo; } } //#endregion //#region effectiveCursorStyle class EffectiveCursorStyle extends ComputedEditorOption { constructor() { super(161 /* EditorOption.effectiveCursorStyle */, TextEditorCursorStyle.Line); } compute(env, options, _) { return env.inputMode === 'overtype' ? options.get(92 /* EditorOption.overtypeCursorStyle */) : options.get(34 /* EditorOption.cursorStyle */); } } //#endregion //#region effectiveExperimentalEditContext class EffectiveEditContextEnabled extends ComputedEditorOption { constructor() { super(170 /* EditorOption.effectiveEditContext */, false); } compute(env, options) { return env.editContextSupported && options.get(44 /* EditorOption.editContext */); } } //#endregion //#region effectiveAllowVariableFonts class EffectiveAllowVariableFonts extends ComputedEditorOption { constructor() { super(172 /* EditorOption.effectiveAllowVariableFonts */, false); } compute(env, options) { const accessibilitySupport = env.accessibilitySupport; if (accessibilitySupport === 2 /* AccessibilitySupport.Enabled */) { return options.get(7 /* EditorOption.allowVariableFontsInAccessibilityMode */); } else { return options.get(6 /* EditorOption.allowVariableFonts */); } } } //#engregion //#region fontSize class EditorFontSize extends SimpleEditorOption { constructor() { super(61 /* EditorOption.fontSize */, 'fontSize', EDITOR_FONT_DEFAULTS.fontSize, { type: 'number', minimum: 6, maximum: 100, default: EDITOR_FONT_DEFAULTS.fontSize, description: localize(233, "Controls the font size in pixels.") }); } validate(input) { const r = EditorFloatOption.float(input, this.defaultValue); if (r === 0) { return EDITOR_FONT_DEFAULTS.fontSize; } return EditorFloatOption.clamp(r, 6, 100); } compute(env, options, value) { // The final fontSize respects the editor zoom level. // So take the result from env.fontInfo return env.fontInfo.fontSize; } } //#endregion //#region fontWeight class EditorFontWeight extends BaseEditorOption { static { this.SUGGESTION_VALUES = ['normal', 'bold', '100', '200', '300', '400', '500', '600', '700', '800', '900']; } static { this.MINIMUM_VALUE = 1; } static { this.MAXIMUM_VALUE = 1000; } constructor() { super(62 /* EditorOption.fontWeight */, 'fontWeight', EDITOR_FONT_DEFAULTS.fontWeight, { anyOf: [ { type: 'number', minimum: EditorFontWeight.MINIMUM_VALUE, maximum: EditorFontWeight.MAXIMUM_VALUE, errorMessage: localize(234, "Only \"normal\" and \"bold\" keywords or numbers between 1 and 1000 are allowed.") }, { type: 'string', pattern: '^(normal|bold|1000|[1-9][0-9]{0,2})$' }, { enum: EditorFontWeight.SUGGESTION_VALUES } ], default: EDITOR_FONT_DEFAULTS.fontWeight, description: localize(235, "Controls the font weight. Accepts \"normal\" and \"bold\" keywords or numbers between 1 and 1000.") }); } validate(input) { if (input === 'normal' || input === 'bold') { return input; } return String(EditorIntOption.clampedInt(input, EDITOR_FONT_DEFAULTS.fontWeight, EditorFontWeight.MINIMUM_VALUE, EditorFontWeight.MAXIMUM_VALUE)); } } class EditorGoToLocation extends BaseEditorOption { constructor() { const defaults = { multiple: 'peek', multipleDefinitions: 'peek', multipleTypeDefinitions: 'peek', multipleDeclarations: 'peek', multipleImplementations: 'peek', multipleReferences: 'peek', multipleTests: 'peek', alternativeDefinitionCommand: 'editor.action.goToReferences', alternativeTypeDefinitionCommand: 'editor.action.goToReferences', alternativeDeclarationCommand: 'editor.action.goToReferences', alternativeImplementationCommand: '', alternativeReferenceCommand: '', alternativeTestsCommand: '', }; const jsonSubset = { type: 'string', enum: ['peek', 'gotoAndPeek', 'goto'], default: defaults.multiple, enumDescriptions: [ localize(236, 'Show Peek view of the results (default)'), localize(237, 'Go to the primary result and show a Peek view'), localize(238, 'Go to the primary result and enable Peek-less navigation to others') ] }; const alternativeCommandOptions = ['', 'editor.action.referenceSearch.trigger', 'editor.action.goToReferences', 'editor.action.peekImplementation', 'editor.action.goToImplementation', 'editor.action.peekTypeDefinition', 'editor.action.goToTypeDefinition', 'editor.action.peekDeclaration', 'editor.action.revealDeclaration', 'editor.action.peekDefinition', 'editor.action.revealDefinitionAside', 'editor.action.revealDefinition']; super(67 /* EditorOption.gotoLocation */, 'gotoLocation', defaults, { 'editor.gotoLocation.multiple': { deprecationMessage: localize(239, "This setting is deprecated, please use separate settings like 'editor.editor.gotoLocation.multipleDefinitions' or 'editor.editor.gotoLocation.multipleImplementations' instead."), }, 'editor.gotoLocation.multipleDefinitions': { description: localize(240, "Controls the behavior the 'Go to Definition'-command when multiple target locations exist."), ...jsonSubset, }, 'editor.gotoLocation.multipleTypeDefinitions': { description: localize(241, "Controls the behavior the 'Go to Type Definition'-command when multiple target locations exist."), ...jsonSubset, }, 'editor.gotoLocation.multipleDeclarations': { description: localize(242, "Controls the behavior the 'Go to Declaration'-command when multiple target locations exist."), ...jsonSubset, }, 'editor.gotoLocation.multipleImplementations': { description: localize(243, "Controls the behavior the 'Go to Implementations'-command when multiple target locations exist."), ...jsonSubset, }, 'editor.gotoLocation.multipleReferences': { description: localize(244, "Controls the behavior the 'Go to References'-command when multiple target locations exist."), ...jsonSubset, }, 'editor.gotoLocation.alternativeDefinitionCommand': { type: 'string', default: defaults.alternativeDefinitionCommand, enum: alternativeCommandOptions, description: localize(245, "Alternative command id that is being executed when the result of 'Go to Definition' is the current location.") }, 'editor.gotoLocation.alternativeTypeDefinitionCommand': { type: 'string', default: defaults.alternativeTypeDefinitionCommand, enum: alternativeCommandOptions, description: localize(246, "Alternative command id that is being executed when the result of 'Go to Type Definition' is the current location.") }, 'editor.gotoLocation.alternativeDeclarationCommand': { type: 'string', default: defaults.alternativeDeclarationCommand, enum: alternativeCommandOptions, description: localize(247, "Alternative command id that is being executed when the result of 'Go to Declaration' is the current location.") }, 'editor.gotoLocation.alternativeImplementationCommand': { type: 'string', default: defaults.alternativeImplementationCommand, enum: alternativeCommandOptions, description: localize(248, "Alternative command id that is being executed when the result of 'Go to Implementation' is the current location.") }, 'editor.gotoLocation.alternativeReferenceCommand': { type: 'string', default: defaults.alternativeReferenceCommand, enum: alternativeCommandOptions, description: localize(249, "Alternative command id that is being executed when the result of 'Go to Reference' is the current location.") }, }); } validate(_input) { if (!_input || typeof _input !== 'object') { return this.defaultValue; } const input = _input; return { multiple: stringSet(input.multiple, this.defaultValue.multiple, ['peek', 'gotoAndPeek', 'goto']), multipleDefinitions: stringSet(input.multipleDefinitions, 'peek', ['peek', 'gotoAndPeek', 'goto']), multipleTypeDefinitions: stringSet(input.multipleTypeDefinitions, 'peek', ['peek', 'gotoAndPeek', 'goto']), multipleDeclarations: stringSet(input.multipleDeclarations, 'peek', ['peek', 'gotoAndPeek', 'goto']), multipleImplementations: stringSet(input.multipleImplementations, 'peek', ['peek', 'gotoAndPeek', 'goto']), multipleReferences: stringSet(input.multipleReferences, 'peek', ['peek', 'gotoAndPeek', 'goto']), multipleTests: stringSet(input.multipleTests, 'peek', ['peek', 'gotoAndPeek', 'goto']), alternativeDefinitionCommand: EditorStringOption.string(input.alternativeDefinitionCommand, this.defaultValue.alternativeDefinitionCommand), alternativeTypeDefinitionCommand: EditorStringOption.string(input.alternativeTypeDefinitionCommand, this.defaultValue.alternativeTypeDefinitionCommand), alternativeDeclarationCommand: EditorStringOption.string(input.alternativeDeclarationCommand, this.defaultValue.alternativeDeclarationCommand), alternativeImplementationCommand: EditorStringOption.string(input.alternativeImplementationCommand, this.defaultValue.alternativeImplementationCommand), alternativeReferenceCommand: EditorStringOption.string(input.alternativeReferenceCommand, this.defaultValue.alternativeReferenceCommand), alternativeTestsCommand: EditorStringOption.string(input.alternativeTestsCommand, this.defaultValue.alternativeTestsCommand), }; } } class EditorHover extends BaseEditorOption { constructor() { const defaults = { enabled: true, delay: 300, hidingDelay: 300, sticky: true, above: true, }; super(69 /* EditorOption.hover */, 'hover', defaults, { 'editor.hover.enabled': { type: 'boolean', default: defaults.enabled, description: localize(250, "Controls whether the hover is shown.") }, 'editor.hover.delay': { type: 'number', default: defaults.delay, minimum: 0, maximum: 10000, description: localize(251, "Controls the delay in milliseconds after which the hover is shown.") }, 'editor.hover.sticky': { type: 'boolean', default: defaults.sticky, description: localize(252, "Controls whether the hover should remain visible when mouse is moved over it.") }, 'editor.hover.hidingDelay': { type: 'integer', minimum: 0, default: defaults.hidingDelay, markdownDescription: localize(253, "Controls the delay in milliseconds after which the hover is hidden. Requires `#editor.hover.sticky#` to be enabled.") }, 'editor.hover.above': { type: 'boolean', default: defaults.above, description: localize(254, "Prefer showing hovers above the line, if there's space.") }, }); } validate(_input) { if (!_input || typeof _input !== 'object') { return this.defaultValue; } const input = _input; return { enabled: boolean(input.enabled, this.defaultValue.enabled), delay: EditorIntOption.clampedInt(input.delay, this.defaultValue.delay, 0, 10000), sticky: boolean(input.sticky, this.defaultValue.sticky), hidingDelay: EditorIntOption.clampedInt(input.hidingDelay, this.defaultValue.hidingDelay, 0, 600000), above: boolean(input.above, this.defaultValue.above), }; } } /** * @internal */ class EditorLayoutInfoComputer extends ComputedEditorOption { constructor() { super(165 /* EditorOption.layoutInfo */, { width: 0, height: 0, glyphMarginLeft: 0, glyphMarginWidth: 0, glyphMarginDecorationLaneCount: 0, lineNumbersLeft: 0, lineNumbersWidth: 0, decorationsLeft: 0, decorationsWidth: 0, contentLeft: 0, contentWidth: 0, minimap: { renderMinimap: 0 /* RenderMinimap.None */, minimapLeft: 0, minimapWidth: 0, minimapHeightIsEditorHeight: false, minimapIsSampling: false, minimapScale: 1, minimapLineHeight: 1, minimapCanvasInnerWidth: 0, minimapCanvasInnerHeight: 0, minimapCanvasOuterWidth: 0, minimapCanvasOuterHeight: 0, }, viewportColumn: 0, isWordWrapMinified: false, isViewportWrapping: false, wrappingColumn: -1, verticalScrollbarWidth: 0, horizontalScrollbarHeight: 0, overviewRuler: { top: 0, width: 0, height: 0, right: 0 } }); } compute(env, options, _) { return EditorLayoutInfoComputer.computeLayout(options, { memory: env.memory, outerWidth: env.outerWidth, outerHeight: env.outerHeight, isDominatedByLongLines: env.isDominatedByLongLines, lineHeight: env.fontInfo.lineHeight, viewLineCount: env.viewLineCount, lineNumbersDigitCount: env.lineNumbersDigitCount, typicalHalfwidthCharacterWidth: env.fontInfo.typicalHalfwidthCharacterWidth, maxDigitWidth: env.fontInfo.maxDigitWidth, pixelRatio: env.pixelRatio, glyphMarginDecorationLaneCount: env.glyphMarginDecorationLaneCount }); } static computeContainedMinimapLineCount(input) { const typicalViewportLineCount = input.height / input.lineHeight; const extraLinesBeforeFirstLine = Math.floor(input.paddingTop / input.lineHeight); let extraLinesBeyondLastLine = Math.floor(input.paddingBottom / input.lineHeight); if (input.scrollBeyondLastLine) { extraLinesBeyondLastLine = Math.max(extraLinesBeyondLastLine, typicalViewportLineCount - 1); } const desiredRatio = (extraLinesBeforeFirstLine + input.viewLineCount + extraLinesBeyondLastLine) / (input.pixelRatio * input.height); const minimapLineCount = Math.floor(input.viewLineCount / desiredRatio); return { typicalViewportLineCount, extraLinesBeforeFirstLine, extraLinesBeyondLastLine, desiredRatio, minimapLineCount }; } static _computeMinimapLayout(input, memory) { const outerWidth = input.outerWidth; const outerHeight = input.outerHeight; const pixelRatio = input.pixelRatio; if (!input.minimap.enabled) { return { renderMinimap: 0 /* RenderMinimap.None */, minimapLeft: 0, minimapWidth: 0, minimapHeightIsEditorHeight: false, minimapIsSampling: false, minimapScale: 1, minimapLineHeight: 1, minimapCanvasInnerWidth: 0, minimapCanvasInnerHeight: Math.floor(pixelRatio * outerHeight), minimapCanvasOuterWidth: 0, minimapCanvasOuterHeight: outerHeight, }; } // Can use memory if only the `viewLineCount` and `remainingWidth` have changed const stableMinimapLayoutInput = memory.stableMinimapLayoutInput; const couldUseMemory = (stableMinimapLayoutInput // && input.outerWidth === lastMinimapLayoutInput.outerWidth !!! INTENTIONAL OMITTED && input.outerHeight === stableMinimapLayoutInput.outerHeight && input.lineHeight === stableMinimapLayoutInput.lineHeight && input.typicalHalfwidthCharacterWidth === stableMinimapLayoutInput.typicalHalfwidthCharacterWidth && input.pixelRatio === stableMinimapLayoutInput.pixelRatio && input.scrollBeyondLastLine === stableMinimapLayoutInput.scrollBeyondLastLine && input.paddingTop === stableMinimapLayoutInput.paddingTop && input.paddingBottom === stableMinimapLayoutInput.paddingBottom && input.minimap.enabled === stableMinimapLayoutInput.minimap.enabled && input.minimap.side === stableMinimapLayoutInput.minimap.side && input.minimap.size === stableMinimapLayoutInput.minimap.size && input.minimap.showSlider === stableMinimapLayoutInput.minimap.showSlider && input.minimap.renderCharacters === stableMinimapLayoutInput.minimap.renderCharacters && input.minimap.maxColumn === stableMinimapLayoutInput.minimap.maxColumn && input.minimap.scale === stableMinimapLayoutInput.minimap.scale && input.verticalScrollbarWidth === stableMinimapLayoutInput.verticalScrollbarWidth // && input.viewLineCount === lastMinimapLayoutInput.viewLineCount !!! INTENTIONAL OMITTED // && input.remainingWidth === lastMinimapLayoutInput.remainingWidth !!! INTENTIONAL OMITTED && input.isViewportWrapping === stableMinimapLayoutInput.isViewportWrapping); const lineHeight = input.lineHeight; const typicalHalfwidthCharacterWidth = input.typicalHalfwidthCharacterWidth; const scrollBeyondLastLine = input.scrollBeyondLastLine; const minimapRenderCharacters = input.minimap.renderCharacters; let minimapScale = (pixelRatio >= 2 ? Math.round(input.minimap.scale * 2) : input.minimap.scale); const minimapMaxColumn = input.minimap.maxColumn; const minimapSize = input.minimap.size; const minimapSide = input.minimap.side; const verticalScrollbarWidth = input.verticalScrollbarWidth; const viewLineCount = input.viewLineCount; const remainingWidth = input.remainingWidth; const isViewportWrapping = input.isViewportWrapping; const baseCharHeight = minimapRenderCharacters ? 2 : 3; let minimapCanvasInnerHeight = Math.floor(pixelRatio * outerHeight); const minimapCanvasOuterHeight = minimapCanvasInnerHeight / pixelRatio; let minimapHeightIsEditorHeight = false; let minimapIsSampling = false; let minimapLineHeight = baseCharHeight * minimapScale; let minimapCharWidth = minimapScale / pixelRatio; let minimapWidthMultiplier = 1; if (minimapSize === 'fill' || minimapSize === 'fit') { const { typicalViewportLineCount, extraLinesBeforeFirstLine, extraLinesBeyondLastLine, desiredRatio, minimapLineCount } = EditorLayoutInfoComputer.computeContainedMinimapLineCount({ viewLineCount: viewLineCount, scrollBeyondLastLine: scrollBeyondLastLine, paddingTop: input.paddingTop, paddingBottom: input.paddingBottom, height: outerHeight, lineHeight: lineHeight, pixelRatio: pixelRatio }); // ratio is intentionally not part of the layout to avoid the layout changing all the time // when doing sampling const ratio = viewLineCount / minimapLineCount; if (ratio > 1) { minimapHeightIsEditorHeight = true; minimapIsSampling = true; minimapScale = 1; minimapLineHeight = 1; minimapCharWidth = minimapScale / pixelRatio; } else { let fitBecomesFill = false; let maxMinimapScale = minimapScale + 1; if (minimapSize === 'fit') { const effectiveMinimapHeight = Math.ceil((extraLinesBeforeFirstLine + viewLineCount + extraLinesBeyondLastLine) * minimapLineHeight); if (isViewportWrapping && couldUseMemory && remainingWidth <= memory.stableFitRemainingWidth) { // There is a loop when using `fit` and viewport wrapping: // - view line count impacts minimap layout // - minimap layout impacts viewport width // - viewport width impacts view line count // To break the loop, once we go to a smaller minimap scale, we try to stick with it. fitBecomesFill = true; maxMinimapScale = memory.stableFitMaxMinimapScale; } else { fitBecomesFill = (effectiveMinimapHeight > minimapCanvasInnerHeight); } } if (minimapSize === 'fill' || fitBecomesFill) { minimapHeightIsEditorHeight = true; const configuredMinimapScale = minimapScale; minimapLineHeight = Math.min(lineHeight * pixelRatio, Math.max(1, Math.floor(1 / desiredRatio))); if (isViewportWrapping && couldUseMemory && remainingWidth <= memory.stableFitRemainingWidth) { // There is a loop when using `fill` and viewport wrapping: // - view line count impacts minimap layout // - minimap layout impacts viewport width // - viewport width impacts view line count // To break the loop, once we go to a smaller minimap scale, we try to stick with it. maxMinimapScale = memory.stableFitMaxMinimapScale; } minimapScale = Math.min(maxMinimapScale, Math.max(1, Math.floor(minimapLineHeight / baseCharHeight))); if (minimapScale > configuredMinimapScale) { minimapWidthMultiplier = Math.min(2, minimapScale / configuredMinimapScale); } minimapCharWidth = minimapScale / pixelRatio / minimapWidthMultiplier; minimapCanvasInnerHeight = Math.ceil((Math.max(typicalViewportLineCount, extraLinesBeforeFirstLine + viewLineCount + extraLinesBeyondLastLine)) * minimapLineHeight); if (isViewportWrapping) { // remember for next time memory.stableMinimapLayoutInput = input; memory.stableFitRemainingWidth = remainingWidth; memory.stableFitMaxMinimapScale = minimapScale; } else { memory.stableMinimapLayoutInput = null; memory.stableFitRemainingWidth = 0; } } } } // Given: // (leaving 2px for the cursor to have space after the last