提交 2a720880 编写于 作者: A Alex Dima

Introduce a new way to manage editor options

上级 1930ce78
......@@ -6,7 +6,7 @@
import 'vs/css!./lineNumbers';
import * as platform from 'vs/base/common/platform';
import { DynamicViewOverlay } from 'vs/editor/browser/view/dynamicViewOverlay';
import { RenderLineNumbersType } from 'vs/editor/common/config/editorOptions';
import { RenderLineNumbersType, EditorOptionId, EditorOption } from 'vs/editor/common/config/editorOptions';
import { Position } from 'vs/editor/common/core/position';
import { editorActiveLineNumber, editorLineNumbers } from 'vs/editor/common/view/editorColorRegistry';
import { RenderingContext } from 'vs/editor/common/view/renderingContext';
......@@ -45,7 +45,7 @@ export class LineNumbersOverlay extends DynamicViewOverlay {
this._lineHeight = config.lineHeight;
this._renderLineNumbers = config.viewInfo.renderLineNumbers;
this._renderCustomLineNumbers = config.viewInfo.renderCustomLineNumbers;
this._renderFinalNewline = config.viewInfo.renderFinalNewline;
this._renderFinalNewline = this._context.configuration.options.get(EditorOptionId.RenderFinalNewline, EditorOption.RenderFinalNewline);
this._lineNumbersLeft = config.layoutInfo.lineNumbersLeft;
this._lineNumbersWidth = config.layoutInfo.lineNumbersWidth;
}
......
......@@ -63,6 +63,58 @@ export interface IEnvConfiguration {
const hasOwnProperty = Object.hasOwnProperty;
export class EditorConfiguration2 {
public static readOptions(options: editorOptions.IEditorOptions): editorOptions.RawEditorOptions {
// console.log(`parseOptions`, options);
const result = new editorOptions.RawEditorOptions();
for (const editorOption of editorOptions.editorOptionsRegistry) {
result._write(editorOption.id, editorOption.read(options));
}
return result;
}
public static mixOptions(a: editorOptions.RawEditorOptions, b: editorOptions.IEditorOptions): editorOptions.RawEditorOptions {
// console.log(`mixOptions`, a, b);
const result = new editorOptions.RawEditorOptions();
for (const editorOption of editorOptions.editorOptionsRegistry) {
result._write(editorOption.id, editorOption.mix(a._read(editorOption.id), editorOption.read(b)));
}
return result;
}
public static validateOptions(options: editorOptions.RawEditorOptions): editorOptions.ValidatedEditorOptions {
// console.log(`validateOptions`, options);
const result = new editorOptions.ValidatedEditorOptions();
for (const editorOption of editorOptions.editorOptionsRegistry) {
result._write(editorOption.id, editorOption.validate(options._read(editorOption.id)));
}
return result;
}
public static computeOptions(options: editorOptions.ValidatedEditorOptions, env: editorOptions.IEnvironmentalOptions): editorOptions.ComputedEditorOptions {
// console.log(`computeOptions`, options, env);
const result = new editorOptions.ComputedEditorOptions();
for (const editorOption of editorOptions.editorOptionsRegistry) {
result._write(editorOption.id, editorOption.compute(options._read(editorOption.id)));
}
return result;
}
public static checkEquals(a: editorOptions.ComputedEditorOptions, b: editorOptions.ComputedEditorOptions): editorOptions.ChangedEditorOptions | null {
// console.log(`equals`, a, b);
const result = new editorOptions.ChangedEditorOptions();
let somethingChanged = false;
for (const editorOption of editorOptions.editorOptionsRegistry) {
const equals = editorOption.equals(a._read(editorOption.id), b._read(editorOption.id));
result._write(editorOption.id, equals);
if (!equals) {
somethingChanged = true;
}
}
return (somethingChanged ? result : null);
}
}
export abstract class CommonEditorConfiguration extends Disposable implements editorCommon.IConfiguration {
public readonly isSimpleWidget: boolean;
......@@ -75,6 +127,10 @@ export abstract class CommonEditorConfiguration extends Disposable implements ed
private _onDidChange = this._register(new Emitter<editorOptions.IConfigurationChangedEvent>());
public readonly onDidChange: Event<editorOptions.IConfigurationChangedEvent> = this._onDidChange.event;
private _rawOptions2: editorOptions.RawEditorOptions;
private _validatedOptions2: editorOptions.ValidatedEditorOptions;
public options!: editorOptions.ComputedEditorOptions;
constructor(isSimpleWidget: boolean, options: editorOptions.IEditorOptions) {
super();
......@@ -89,6 +145,10 @@ export abstract class CommonEditorConfiguration extends Disposable implements ed
this._rawOptions.parameterHints = objects.mixin({}, this._rawOptions.parameterHints || {});
this._validatedOptions = editorOptions.EditorOptionsValidator.validate(this._rawOptions, EDITOR_DEFAULTS);
this._rawOptions2 = EditorConfiguration2.readOptions(options);
this._validatedOptions2 = EditorConfiguration2.validateOptions(this._rawOptions2);
this._isDominatedByLongLines = false;
this._lineNumbersDigitCount = 1;
......@@ -105,16 +165,20 @@ export abstract class CommonEditorConfiguration extends Disposable implements ed
protected _recomputeOptions(): void {
const oldOptions = this.editor;
const newOptions = this._computeInternalOptions();
const oldOptions2 = this.options;
const [newOptions, newOptions2] = this._computeInternalOptions();
const changeEvent = (oldOptions2 ? EditorConfiguration2.checkEquals(oldOptions2, newOptions2) : null);
if (oldOptions && oldOptions.equals(newOptions)) {
if (oldOptions && oldOptions.equals(newOptions) && oldOptions2 && changeEvent === null) {
return;
}
this.editor = newOptions;
this.options = newOptions2;
if (oldOptions) {
this._onDidChange.fire(oldOptions.createChangeEvent(newOptions));
this._onDidChange.fire(oldOptions.createChangeEvent(newOptions, changeEvent));
}
}
......@@ -122,7 +186,7 @@ export abstract class CommonEditorConfiguration extends Disposable implements ed
return this._rawOptions;
}
private _computeInternalOptions(): editorOptions.InternalEditorOptions {
private _computeInternalOptions(): [editorOptions.InternalEditorOptions, editorOptions.ComputedEditorOptions] {
const opts = this._validatedOptions;
const partialEnv = this._getEnvConfiguration();
const bareFontInfo = BareFontInfo.createFromRawSettings(this._rawOptions, partialEnv.zoomLevel, this.isSimpleWidget);
......@@ -138,7 +202,9 @@ export abstract class CommonEditorConfiguration extends Disposable implements ed
tabFocusMode: TabFocus.getTabFocusMode(),
accessibilitySupport: partialEnv.accessibilitySupport
};
return editorOptions.InternalEditorOptionsFactory.createInternalEditorOptions(env, opts);
const r = editorOptions.InternalEditorOptionsFactory.createInternalEditorOptions(env, opts);
const r2 = EditorConfiguration2.computeOptions(this._validatedOptions2, env);
return [r, r2];
}
private static _primitiveArrayEquals(a: any[], b: any[]): boolean {
......@@ -189,7 +255,11 @@ export abstract class CommonEditorConfiguration extends Disposable implements ed
return;
}
this._rawOptions = objects.mixin(this._rawOptions, newOptions || {});
this._rawOptions2 = EditorConfiguration2.mixOptions(this._rawOptions2, newOptions);
this._validatedOptions = editorOptions.EditorOptionsValidator.validate(this._rawOptions, EDITOR_DEFAULTS);
this._validatedOptions2 = EditorConfiguration2.validateOptions(this._rawOptions2);
this._recomputeOptions();
}
......@@ -275,7 +345,7 @@ const editorConfiguration: IConfigurationNode = {
},
'editor.renderFinalNewline': {
'type': 'boolean',
'default': EDITOR_DEFAULTS.viewInfo.renderFinalNewline,
'default': editorOptions.EditorOption.RenderFinalNewline.defaultValue,
'description': nls.localize('renderFinalNewline', "Render last line number when the file ends with a newline.")
},
'editor.rulers': {
......
......@@ -997,7 +997,6 @@ export interface InternalEditorViewOptions {
readonly renderLineNumbers: RenderLineNumbersType;
readonly renderCustomLineNumbers: ((lineNumber: number) => string) | null;
readonly cursorSurroundingLines: number;
readonly renderFinalNewline: boolean;
readonly selectOnLineNumbers: boolean;
readonly glyphMargin: boolean;
readonly revealHorizontalRightPadding: number;
......@@ -1230,8 +1229,14 @@ export class InternalEditorOptions {
/**
* @internal
*/
public createChangeEvent(newOpts: InternalEditorOptions): IConfigurationChangedEvent {
public createChangeEvent(newOpts: InternalEditorOptions, changeEvent: ChangedEditorOptions | null): IConfigurationChangedEvent {
return {
hasChanged: (id: EditorOptionId) => {
if (!changeEvent) {
return false;
}
return changeEvent.get(id);
},
canUseLayerHinting: (this.canUseLayerHinting !== newOpts.canUseLayerHinting),
pixelRatio: (this.pixelRatio !== newOpts.pixelRatio),
editorClassName: (this.editorClassName !== newOpts.editorClassName),
......@@ -1312,7 +1317,6 @@ export class InternalEditorOptions {
&& a.renderLineNumbers === b.renderLineNumbers
&& a.renderCustomLineNumbers === b.renderCustomLineNumbers
&& a.cursorSurroundingLines === b.cursorSurroundingLines
&& a.renderFinalNewline === b.renderFinalNewline
&& a.selectOnLineNumbers === b.selectOnLineNumbers
&& a.glyphMargin === b.glyphMargin
&& a.revealHorizontalRightPadding === b.revealHorizontalRightPadding
......@@ -1638,6 +1642,7 @@ export interface EditorLayoutInfo {
* An event describing that the configuration of the editor has changed.
*/
export interface IConfigurationChangedEvent {
hasChanged(id: EditorOptionId): boolean;
readonly canUseLayerHinting: boolean;
readonly pixelRatio: boolean;
readonly editorClassName: boolean;
......@@ -2076,7 +2081,6 @@ export class EditorOptionsValidator {
cursorSurroundingLines: _clampedInt(opts.cursorSurroundingLines, defaults.cursorWidth, 0, Number.MAX_VALUE),
renderLineNumbers: renderLineNumbers,
renderCustomLineNumbers: renderCustomLineNumbers,
renderFinalNewline: _boolean(opts.renderFinalNewline, defaults.renderFinalNewline),
selectOnLineNumbers: _boolean(opts.selectOnLineNumbers, defaults.selectOnLineNumbers),
glyphMargin: _boolean(opts.glyphMargin, defaults.glyphMargin),
revealHorizontalRightPadding: _clampedInt(opts.revealHorizontalRightPadding, defaults.revealHorizontalRightPadding, 0, 1000),
......@@ -2198,7 +2202,6 @@ export class InternalEditorOptionsFactory {
renderLineNumbers: opts.viewInfo.renderLineNumbers,
renderCustomLineNumbers: opts.viewInfo.renderCustomLineNumbers,
cursorSurroundingLines: opts.viewInfo.cursorSurroundingLines,
renderFinalNewline: opts.viewInfo.renderFinalNewline,
selectOnLineNumbers: opts.viewInfo.selectOnLineNumbers,
glyphMargin: opts.viewInfo.glyphMargin,
revealHorizontalRightPadding: opts.viewInfo.revealHorizontalRightPadding,
......@@ -2665,7 +2668,6 @@ export const EDITOR_DEFAULTS: IValidatedEditorOptions = {
renderLineNumbers: RenderLineNumbersType.On,
renderCustomLineNumbers: null,
cursorSurroundingLines: 0,
renderFinalNewline: true,
selectOnLineNumbers: true,
glyphMargin: true,
revealHorizontalRightPadding: 30,
......@@ -2770,3 +2772,127 @@ export const EDITOR_DEFAULTS: IValidatedEditorOptions = {
codeActionsOnSaveTimeout: 750
},
};
export interface IRawEditorOptionsBag {
[key: string]: any;
}
/**
* @internal
*/
export class RawEditorOptions {
private readonly _values: any[] = [];
public _read<T>(id: EditorOptionId): T | undefined {
return this._values[id];
}
public _write<T>(id: EditorOptionId, value: T | undefined): void {
this._values[id] = value;
}
}
/**
* @internal
*/
export class ValidatedEditorOptions {
private readonly _values: any[] = [];
public _read<T>(option: EditorOptionId): T {
return this._values[option];
}
public _write<T>(option: EditorOptionId, value: T): void {
this._values[option] = value;
}
}
export interface IComputedEditorOptions {
get<T1, T2, T3>(id: EditorOptionId, option: IEditorOption<T1, T2, T3>): T3;
}
/**
* @internal
*/
export class ComputedEditorOptions {
private readonly _values: any[] = [];
public _read<T>(id: EditorOptionId): T {
return this._values[id];
}
public get<T1, T2, T3>(id: EditorOptionId, option: IEditorOption<T1, T2, T3>): T3 {
return this._values[id];
}
public _write<T>(id: EditorOptionId, value: T): void {
this._values[id] = value;
}
}
/**
* @internal
*/
export class ChangedEditorOptions {
private readonly _values: boolean[] = [];
public get(id: EditorOptionId): boolean {
return this._values[id];
}
public _write(id: EditorOptionId, value: boolean): void {
this._values[id] = value;
}
}
interface IEditorOption<T1, T2 = T1, T3 = T2> {
readonly id: EditorOptionId;
readonly name: string;
readonly defaultValue: T1;
read(options: IRawEditorOptionsBag): T1 | undefined;
mix(a: T1 | undefined, b: T1 | undefined): T1 | undefined;
validate(input: T1 | undefined): T2;
compute(value: T2): T3;
equals(a: T3, b: T3): boolean;
}
class BooleanEditorOption implements IEditorOption<boolean> {
public readonly id: EditorOptionId;
public readonly name: string;
public readonly defaultValue: boolean;
constructor(id: EditorOptionId, name: string, defaultValue: boolean) {
this.id = id;
this.name = name;
this.defaultValue = defaultValue;
}
public read(options: IRawEditorOptionsBag): boolean | undefined {
return options[this.name];
}
public mix(a: boolean | undefined, b: boolean | undefined): boolean | undefined {
return (typeof b !== 'undefined' ? b : a);
}
public validate(input: boolean | undefined): boolean {
return _boolean(input, this.defaultValue);
}
public compute(value: boolean): boolean {
return value;
}
public equals(a: boolean, b: boolean): boolean {
return (a === b);
}
}
/**
* @internal
*/
export const editorOptionsRegistry: IEditorOption<any>[] = [];
function registerEditorOption<T1, T2, T3>(option: IEditorOption<T1, T2, T3>): IEditorOption<T1, T2, T3> {
editorOptionsRegistry[option.id] = option;
return option;
}
export const enum EditorOptionId {
RenderFinalNewline,
}
export const EditorOption = {
RenderFinalNewline: registerEditorOption(new BooleanEditorOption(EditorOptionId.RenderFinalNewline, 'renderFinalNewline', true))
};
......@@ -152,6 +152,7 @@ export interface IConfiguration extends IDisposable {
onDidChange(listener: (e: editorOptions.IConfigurationChangedEvent) => void): IDisposable;
readonly editor: editorOptions.InternalEditorOptions;
readonly options: editorOptions.IComputedEditorOptions;
setMaxLineNumber(maxLineNumber: number): void;
updateOptions(newOptions: editorOptions.IEditorOptions): void;
......
......@@ -430,6 +430,10 @@ export enum RenderLineNumbersType {
Custom = 4
}
export enum EditorOptionId {
RenderFinalNewline = 0
}
/**
* A positioning preference for rendering content widgets.
*/
......
......@@ -369,6 +369,7 @@ export function createMonacoEditorAPI(): typeof monaco.editor {
RenderMinimap: standaloneEnums.RenderMinimap,
ScrollType: standaloneEnums.ScrollType,
RenderLineNumbersType: standaloneEnums.RenderLineNumbersType,
EditorOptionId: standaloneEnums.EditorOptionId,
// classes
InternalEditorOptions: <any>editorOptions.InternalEditorOptions,
......@@ -378,7 +379,8 @@ export function createMonacoEditorAPI(): typeof monaco.editor {
FindMatch: <any>FindMatch,
// vars
EditorType: editorCommon.EditorType
EditorType: editorCommon.EditorType,
EditorOption: <any>editorOptions.EditorOption,
};
}
......@@ -3312,7 +3312,6 @@ declare namespace monaco.editor {
readonly renderLineNumbers: RenderLineNumbersType;
readonly renderCustomLineNumbers: ((lineNumber: number) => string) | null;
readonly cursorSurroundingLines: number;
readonly renderFinalNewline: boolean;
readonly selectOnLineNumbers: boolean;
readonly glyphMargin: boolean;
readonly revealHorizontalRightPadding: number;
......@@ -3525,6 +3524,7 @@ declare namespace monaco.editor {
* An event describing that the configuration of the editor has changed.
*/
export interface IConfigurationChangedEvent {
hasChanged(id: EditorOptionId): boolean;
readonly canUseLayerHinting: boolean;
readonly pixelRatio: boolean;
readonly editorClassName: boolean;
......@@ -3551,6 +3551,33 @@ declare namespace monaco.editor {
readonly contribInfo: boolean;
}
export interface IRawEditorOptionsBag {
[key: string]: any;
}
export interface IComputedEditorOptions {
get<T1, T2, T3>(id: EditorOptionId, option: IEditorOption<T1, T2, T3>): T3;
}
interface IEditorOption<T1, T2 = T1, T3 = T2> {
readonly id: EditorOptionId;
readonly name: string;
readonly defaultValue: T1;
read(options: IRawEditorOptionsBag): T1 | undefined;
mix(a: T1 | undefined, b: T1 | undefined): T1 | undefined;
validate(input: T1 | undefined): T2;
compute(value: T2): T3;
equals(a: T3, b: T3): boolean;
}
export enum EditorOptionId {
RenderFinalNewline = 0
}
export const EditorOption: {
RenderFinalNewline: IEditorOption<boolean, boolean, boolean>;
};
/**
* A view zone is a full horizontal rectangle that 'pushes' text down.
* The editor reserves space for view zones when rendering.
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册