@@ -9,14 +9,16 @@ import { Event, Emitter } from 'vs/base/common/event';
99import { Disposable } from 'vs/base/common/lifecycle' ;
1010import { RawContextKey , IContextKey , IContextKeyService } from 'vs/platform/contextkey/common/contextkey' ;
1111import { IConfigurationService } from 'vs/platform/configuration/common/configuration' ;
12- import { IFilesConfiguration , AutoSaveConfiguration , HotExitConfiguration , FILES_READONLY_INCLUDE_CONFIG , FILES_READONLY_EXCLUDE_CONFIG , IFileStatWithMetadata , IGlobPatterns } from 'vs/platform/files/common/files' ;
12+ import { IFilesConfiguration , AutoSaveConfiguration , HotExitConfiguration , FILES_READONLY_INCLUDE_CONFIG , FILES_READONLY_EXCLUDE_CONFIG , IFileStatWithMetadata } from 'vs/platform/files/common/files' ;
1313import { equals } from 'vs/base/common/objects' ;
1414import { URI } from 'vs/base/common/uri' ;
1515import { isWeb } from 'vs/base/common/platform' ;
1616import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace' ;
1717import { ResourceGlobMatcher } from 'vs/workbench/common/resources' ;
1818import { IdleValue } from 'vs/base/common/async' ;
19- import { Schemas } from 'vs/base/common/network' ;
19+ import { IUriIdentityService } from 'vs/platform/uriIdentity/common/uriIdentity' ;
20+ import { IEnvironmentService } from 'vs/platform/environment/common/environment' ;
21+ import { ResourceSet } from 'vs/base/common/map' ;
2022
2123export const AutoSaveAfterShortDelayContext = new RawContextKey < boolean > ( 'autoSaveAfterShortDelayContext' , false , true ) ;
2224
@@ -54,11 +56,11 @@ export interface IFilesConfigurationService {
5456
5557 //#region Configured Readonly
5658
57- readonly onReadonlyConfigurationChange : Event < void > ;
59+ readonly onReadonlyChange : Event < void > ;
5860
5961 isReadonly ( resource : URI , stat ?: IFileStatWithMetadata ) : boolean ;
6062
61- updateReadonly ( resource : URI , readonly : true | false | 'toggle' ) : Promise < boolean > ;
63+ updateReadonly ( resource : URI , readonly : true | false | 'toggle' ) : void ;
6264
6365 //#endregion
6466
@@ -84,7 +86,7 @@ export class FilesConfigurationService extends Disposable implements IFilesConfi
8486 readonly onFilesAssociationChange = this . _onFilesAssociationChange . event ;
8587
8688 private readonly _onReadonlyConfigurationChange = this . _register ( new Emitter < void > ( ) ) ;
87- readonly onReadonlyConfigurationChange = this . _onReadonlyConfigurationChange . event ;
89+ readonly onReadonlyChange = this . _onReadonlyConfigurationChange . event ;
8890
8991 private configuredAutoSaveDelay ?: number ;
9092 private configuredAutoSaveOnFocusChange : boolean | undefined ;
@@ -100,10 +102,15 @@ export class FilesConfigurationService extends Disposable implements IFilesConfi
100102 private readonly readonlyExcludeMatcher = this . _register ( new IdleValue ( ( ) => this . createMatcher ( FILES_READONLY_EXCLUDE_CONFIG ) ) ) ;
101103 private configuredReadonlyFromPermissions : boolean | undefined ;
102104
105+ private readonly sessionReadonlyResources = new ResourceSet ( resource => this . uriIdentityService . extUri . getComparisonKey ( resource ) ) ;
106+ private readonly sessionWriteableResources = new ResourceSet ( resource => this . uriIdentityService . extUri . getComparisonKey ( resource ) ) ;
107+
103108 constructor (
104109 @IContextKeyService contextKeyService : IContextKeyService ,
105110 @IConfigurationService private readonly configurationService : IConfigurationService ,
106- @IWorkspaceContextService private readonly contextService : IWorkspaceContextService
111+ @IWorkspaceContextService private readonly contextService : IWorkspaceContextService ,
112+ @IEnvironmentService private readonly environmentService : IEnvironmentService ,
113+ @IUriIdentityService private readonly uriIdentityService : IUriIdentityService
107114 ) {
108115 super ( ) ;
109116
@@ -133,50 +140,40 @@ export class FilesConfigurationService extends Disposable implements IFilesConfi
133140 }
134141
135142 isReadonly ( resource : URI , stat ?: IFileStatWithMetadata ) : boolean {
143+ if ( this . sessionReadonlyResources . has ( resource ) ) {
144+ return true ; // session override: readonly
145+ }
146+
147+ if ( this . sessionWriteableResources . has ( resource ) ) {
148+ return false ; // session override: writeable
149+ }
150+
151+ if ( this . uriIdentityService . extUri . isEqualOrParent ( resource , this . environmentService . userRoamingDataHome ) ) {
152+ return false ; // never turn configuration folder readonly
153+ }
154+
136155 if ( this . configuredReadonlyFromPermissions && stat ?. locked ) {
137156 return true ; // leverage file permissions if configured as such
138157 }
139158
140159 return this . readonlyIncludeMatcher . value . matches ( resource ) && ! this . readonlyExcludeMatcher . value . matches ( resource ) ;
141160 }
142161
143- async updateReadonly ( resource : URI , readonly : true | false | 'toggle' ) : Promise < boolean > {
162+ updateReadonly ( resource : URI , readonly : true | false | 'toggle' ) : void {
144163 if ( readonly === 'toggle' ) {
145164 readonly = ! this . isReadonly ( resource ) ;
146165 }
147166
148- // Add to target setting
149- if ( readonly ) {
150- const targetSettingToAdd = FILES_READONLY_INCLUDE_CONFIG ;
151- const configurationToAdd = this . configurationService . inspect < IGlobPatterns | undefined > ( targetSettingToAdd , { resource } ) ;
152-
153- await this . configurationService . updateValue ( targetSettingToAdd , {
154- ...configurationToAdd . user ?. value ,
155- [ this . uriToPath ( resource ) ] : true
156- } ) ;
157- }
158-
159- // Remove from other setting
160- const targetSettingsToRemove = readonly ? [ FILES_READONLY_EXCLUDE_CONFIG ] : [ FILES_READONLY_INCLUDE_CONFIG , FILES_READONLY_EXCLUDE_CONFIG ] ;
161- for ( const targetSettingToRemove of targetSettingsToRemove ) {
162- const configurationToRemove = this . configurationService . inspect < IGlobPatterns | undefined > ( targetSettingToRemove , { resource } ) ;
163- if ( configurationToRemove . user ?. value ) {
164- const configurationClone = { ...configurationToRemove . user . value } ;
165- delete configurationClone [ this . uriToPath ( resource ) ] ;
166-
167- await this . configurationService . updateValue ( targetSettingToRemove , configurationClone ) ;
168- }
169- }
167+ this . sessionReadonlyResources . delete ( resource ) ;
168+ this . sessionWriteableResources . delete ( resource ) ;
170169
171- return this . isReadonly ( resource ) === readonly ;
172- }
173-
174- private uriToPath ( uri : URI ) : string {
175- if ( uri . scheme === Schemas . file ) {
176- return uri . fsPath ;
170+ if ( readonly ) {
171+ this . sessionReadonlyResources . add ( resource ) ;
172+ } else {
173+ this . sessionWriteableResources . add ( resource ) ;
177174 }
178175
179- return uri . path ;
176+ this . _onReadonlyConfigurationChange . fire ( ) ;
180177 }
181178
182179 private registerListeners ( ) : void {
0 commit comments