@@ -12,6 +12,8 @@ import { USUAL_WORD_SEPARATORS } from 'vs/editor/common/model/wordHelper';
1212import { AccessibilitySupport } from 'vs/platform/accessibility/common/accessibility' ;
1313import { IConfigurationPropertySchema } from 'vs/platform/configuration/common/configurationRegistry' ;
1414import { IJSONSchema } from 'vs/base/common/jsonSchema' ;
15+ import * as arrays from 'vs/base/common/arrays' ;
16+ import * as objects from 'vs/base/common/objects' ;
1517
1618//#region typed options
1719
@@ -806,6 +808,11 @@ export interface IEditorOption<K1 extends EditorOption, V> {
806808 * @internal
807809 */
808810 compute ( env : IEnvironmentalOptions , options : IComputedEditorOptions , value : V ) : V ;
811+
812+ /**
813+ * Might modify `value`.
814+ */
815+ applyUpdate ( value : V , update : V ) : ApplyUpdateResult < V > ;
809816}
810817
811818type PossibleKeyName0 < V > = { [ K in keyof IEditorOptions ] : IEditorOptions [ K ] extends V | undefined ? K : never } [ keyof IEditorOptions ] ;
@@ -828,13 +835,45 @@ abstract class BaseEditorOption<K1 extends EditorOption, V> implements IEditorOp
828835 this . schema = schema ;
829836 }
830837
838+ public applyUpdate ( value : V , update : V ) : ApplyUpdateResult < V > {
839+ return applyUpdate ( value , update ) ;
840+ }
841+
831842 public abstract validate ( input : any ) : V ;
832843
833844 public compute ( env : IEnvironmentalOptions , options : IComputedEditorOptions , value : V ) : V {
834845 return value ;
835846 }
836847}
837848
849+ export class ApplyUpdateResult < T > {
850+ constructor (
851+ public readonly newValue : T ,
852+ public readonly didChange : boolean
853+ ) { }
854+ }
855+
856+ function applyUpdate < T > ( value : T , update : T ) : ApplyUpdateResult < T > {
857+ if ( typeof value !== 'object' || typeof update !== 'object' || ! value || ! update ) {
858+ return new ApplyUpdateResult ( update , value !== update ) ;
859+ }
860+ if ( Array . isArray ( value ) || Array . isArray ( update ) ) {
861+ const arrayEquals = Array . isArray ( value ) && Array . isArray ( update ) && arrays . equals ( value , update ) ;
862+ return new ApplyUpdateResult ( update , arrayEquals ) ;
863+ }
864+ let didChange = false ;
865+ for ( let key in update ) {
866+ if ( ( update as T & object ) . hasOwnProperty ( key ) ) {
867+ const result = applyUpdate ( value [ key ] , update [ key ] ) ;
868+ if ( result . didChange ) {
869+ value [ key ] = result . newValue ;
870+ didChange = true ;
871+ }
872+ }
873+ }
874+ return new ApplyUpdateResult ( value , didChange ) ;
875+ }
876+
838877/**
839878 * @internal
840879 */
@@ -853,6 +892,10 @@ abstract class ComputedEditorOption<K1 extends EditorOption, V> implements IEdit
853892 this . deps = deps ;
854893 }
855894
895+ public applyUpdate ( value : V , update : V ) : ApplyUpdateResult < V > {
896+ return applyUpdate ( value , update ) ;
897+ }
898+
856899 public validate ( input : any ) : V {
857900 return this . defaultValue ;
858901 }
@@ -874,6 +917,10 @@ class SimpleEditorOption<K1 extends EditorOption, V> implements IEditorOption<K1
874917 this . schema = schema ;
875918 }
876919
920+ public applyUpdate ( value : V , update : V ) : ApplyUpdateResult < V > {
921+ return applyUpdate ( value , update ) ;
922+ }
923+
877924 public validate ( input : any ) : V {
878925 if ( typeof input === 'undefined' ) {
879926 return this . defaultValue ;
@@ -3265,9 +3312,9 @@ export interface IUnicodeHighlightOptions {
32653312 ambiguousCharacters ?: boolean ;
32663313 includeComments ?: boolean | InUntrustedWorkspace ;
32673314 /**
3268- * A list of allowed code points in a single string .
3315+ * A map of allowed characters (true: allowed) .
32693316 */
3270- allowedCharacters ?: string ;
3317+ allowedCharacters ?: Record < string , true > ;
32713318}
32723319
32733320/**
@@ -3293,7 +3340,7 @@ class UnicodeHighlight extends BaseEditorOption<EditorOption.unicodeHighlighting
32933340 invisibleCharacters : true ,
32943341 ambiguousCharacters : true ,
32953342 includeComments : inUntrustedWorkspace ,
3296- allowedCharacters : '' ,
3343+ allowedCharacters : { } ,
32973344 } ;
32983345
32993346 super (
@@ -3327,14 +3374,34 @@ class UnicodeHighlight extends BaseEditorOption<EditorOption.unicodeHighlighting
33273374 } ,
33283375 [ unicodeHighlightConfigKeys . allowedCharacters ] : {
33293376 restricted : true ,
3330- type : 'string ' ,
3377+ type : 'object ' ,
33313378 default : defaults . allowedCharacters ,
3332- description : nls . localize ( 'unicodeHighlight.allowedCharacters' , "Defines allowed characters that are not being highlighted." )
3379+ description : nls . localize ( 'unicodeHighlight.allowedCharacters' , "Defines allowed characters that are not being highlighted." ) ,
3380+ additionalProperties : {
3381+ type : 'boolean'
3382+ }
33333383 } ,
33343384 }
33353385 ) ;
33363386 }
33373387
3388+ public override applyUpdate ( value : Required < Readonly < IUnicodeHighlightOptions > > , update : Required < Readonly < IUnicodeHighlightOptions > > ) : ApplyUpdateResult < Required < Readonly < IUnicodeHighlightOptions > > > {
3389+ let didChange = false ;
3390+ if ( update . allowedCharacters ) {
3391+ // Treat allowedCharacters atomically
3392+ if ( ! objects . equals ( value . allowedCharacters , update . allowedCharacters ) ) {
3393+ value = { ...value , allowedCharacters : update . allowedCharacters } ;
3394+ didChange = true ;
3395+ }
3396+ }
3397+
3398+ const result = super . applyUpdate ( value , update ) ;
3399+ if ( didChange ) {
3400+ return new ApplyUpdateResult ( result . newValue , true ) ;
3401+ }
3402+ return result ;
3403+ }
3404+
33383405 public validate ( _input : any ) : InternalUnicodeHighlightOptions {
33393406 if ( ! _input || typeof _input !== 'object' ) {
33403407 return this . defaultValue ;
@@ -3345,16 +3412,22 @@ class UnicodeHighlight extends BaseEditorOption<EditorOption.unicodeHighlighting
33453412 invisibleCharacters : boolean ( input . invisibleCharacters , this . defaultValue . invisibleCharacters ) ,
33463413 ambiguousCharacters : boolean ( input . ambiguousCharacters , this . defaultValue . ambiguousCharacters ) ,
33473414 includeComments : primitiveSet < boolean | InUntrustedWorkspace > ( input . includeComments , inUntrustedWorkspace , [ true , false , inUntrustedWorkspace ] ) ,
3348- allowedCharacters : string ( input . allowedCharacters , '' ) ,
3415+ allowedCharacters : this . validateAllowedCharacters ( _input . allowedCharacters , this . defaultValue . allowedCharacters ) ,
33493416 } ;
33503417 }
3351- }
33523418
3353- function string ( value : unknown , defaultValue : string ) : string {
3354- if ( typeof value !== 'string' ) {
3355- return defaultValue ;
3419+ private validateAllowedCharacters ( map : unknown , defaultValue : Record < string , true > ) : Record < string , true > {
3420+ if ( ( typeof map !== 'object' ) || ! map ) {
3421+ return defaultValue ;
3422+ }
3423+ const result : Record < string , true > = { } ;
3424+ for ( const [ key , value ] of Object . entries ( map ) ) {
3425+ if ( value === true ) {
3426+ result [ key ] = true ;
3427+ }
3428+ }
3429+ return result ;
33563430 }
3357- return value ;
33583431}
33593432
33603433//#endregion
0 commit comments