44 *--------------------------------------------------------------------------------------------*/
55
66import { IWorkbenchContribution } from 'vs/workbench/common/contributions' ;
7- import { IUserDataSyncService , SyncStatus , SyncSource , CONTEXT_SYNC_STATE , IUserDataSyncStore , registerConfiguration , getUserDataSyncStore , ISyncConfiguration , IUserDataAuthTokenService , IUserDataAutoSyncService , USER_DATA_SYNC_SCHEME } from 'vs/platform/userDataSync/common/userDataSync' ;
7+ import { IUserDataSyncService , SyncStatus , SyncSource , CONTEXT_SYNC_STATE , IUserDataSyncStore , registerConfiguration , getUserDataSyncStore , ISyncConfiguration , IUserDataAuthTokenService , IUserDataAutoSyncService , USER_DATA_SYNC_SCHEME , toRemoteContentResource , getSyncSourceFromRemoteContentResource } from 'vs/platform/userDataSync/common/userDataSync' ;
88import { localize } from 'vs/nls' ;
9- import { Disposable , MutableDisposable , toDisposable , DisposableStore } from 'vs/base/common/lifecycle' ;
9+ import { Disposable , MutableDisposable , toDisposable , DisposableStore , dispose } from 'vs/base/common/lifecycle' ;
1010import { CommandsRegistry } from 'vs/platform/commands/common/commands' ;
1111import { IConfigurationService , ConfigurationTarget } from 'vs/platform/configuration/common/configuration' ;
1212import { MenuRegistry , MenuId , IMenuItem } from 'vs/platform/actions/common/actions' ;
@@ -15,8 +15,6 @@ import { IActivityService, IBadge, NumberBadge, ProgressBadge } from 'vs/workben
1515import { GLOBAL_ACTIVITY_ID } from 'vs/workbench/common/activity' ;
1616import { INotificationService , Severity } from 'vs/platform/notification/common/notification' ;
1717import { URI } from 'vs/base/common/uri' ;
18- import { registerAndGetAmdImageURL } from 'vs/base/common/amd' ;
19- import { ResourceContextKey } from 'vs/workbench/common/resources' ;
2018import { IEditorService } from 'vs/workbench/services/editor/common/editorService' ;
2119import { ITextFileService } from 'vs/workbench/services/textfile/common/textfiles' ;
2220import { Event } from 'vs/base/common/event' ;
@@ -41,15 +39,19 @@ import { ITextModelService, ITextModelContentProvider } from 'vs/editor/common/s
4139import { IModelService } from 'vs/editor/common/services/modelService' ;
4240import { IModeService } from 'vs/editor/common/services/modeService' ;
4341import type { ITextModel } from 'vs/editor/common/model' ;
42+ import type { IEditorContribution } from 'vs/editor/common/editorCommon' ;
43+ import type { ICodeEditor } from 'vs/editor/browser/editorBrowser' ;
44+ import { FloatingClickWidget } from 'vs/workbench/browser/parts/editor/editorWidgets' ;
45+ import { IFileService } from 'vs/platform/files/common/files' ;
46+ import { VSBuffer } from 'vs/base/common/buffer' ;
47+ import { registerEditorContribution } from 'vs/editor/browser/editorExtensions' ;
4448
4549const enum AuthStatus {
4650 Initializing = 'Initializing' ,
4751 SignedIn = 'SignedIn' ,
4852 SignedOut = 'SignedOut'
4953}
5054const CONTEXT_AUTH_TOKEN_STATE = new RawContextKey < string > ( 'authTokenStatus' , AuthStatus . Initializing ) ;
51- const SYNC_PUSH_LIGHT_ICON_URI = URI . parse ( registerAndGetAmdImageURL ( `vs/workbench/contrib/userDataSync/browser/media/check-light.svg` ) ) ;
52- const SYNC_PUSH_DARK_ICON_URI = URI . parse ( registerAndGetAmdImageURL ( `vs/workbench/contrib/userDataSync/browser/media/check-dark.svg` ) ) ;
5355
5456type ConfigureSyncQuickPickItem = { id : string , label : string , description ?: string } ;
5557
@@ -105,6 +107,7 @@ export class UserDataSyncWorkbenchContribution extends Disposable implements IWo
105107 } ) ;
106108
107109 textModelResolverService . registerTextModelContentProvider ( USER_DATA_SYNC_SCHEME , instantiationService . createInstance ( UserDataRemoteContentProvider ) ) ;
110+ registerEditorContribution ( AcceptChangesContribution . ID , AcceptChangesContribution ) ;
108111 }
109112 }
110113
@@ -459,7 +462,7 @@ export class UserDataSyncWorkbenchContribution extends Disposable implements IWo
459462 }
460463 if ( rightResource ) {
461464 await this . editorService . openEditor ( {
462- leftResource : URI . from ( { scheme : USER_DATA_SYNC_SCHEME , path : ` ${ this . userDataSyncService . conflictsSource } /remoteContent` } ) ,
465+ leftResource : toRemoteContentResource ( this . userDataSyncService . conflictsSource ! ) ,
463466 rightResource,
464467 label,
465468 options : {
@@ -548,14 +551,14 @@ export class UserDataSyncWorkbenchContribution extends Disposable implements IWo
548551 group : '5_sync' ,
549552 command : {
550553 id : resolveConflictsCommandId ,
551- title : localize ( 'resolveConflicts_global' , "Resolve sync conflicts (1)" ) ,
554+ title : localize ( 'resolveConflicts_global' , "Show sync conflicts (1)" ) ,
552555 } ,
553556 when : resolveConflictsWhenContext ,
554557 } ) ;
555558 MenuRegistry . appendMenuItem ( MenuId . CommandPalette , {
556559 command : {
557560 id : resolveConflictsCommandId ,
558- title : localize ( 'resolveConflicts ' , "Sync: Resolve sync conflicts" ) ,
561+ title : localize ( 'showConflicts ' , "Sync: Show sync conflicts" ) ,
559562 } ,
560563 when : resolveConflictsWhenContext ,
561564 } ) ;
@@ -569,32 +572,6 @@ export class UserDataSyncWorkbenchContribution extends Disposable implements IWo
569572 } ,
570573 when : ContextKeyExpr . and ( CONTEXT_SYNC_STATE . isEqualTo ( SyncStatus . HasConflicts ) ) ,
571574 } ) ;
572- MenuRegistry . appendMenuItem ( MenuId . EditorTitle , {
573- command : {
574- id : continueSyncCommandId ,
575- title : localize ( 'continue sync' , "Sync: Continue sync" ) ,
576- icon : {
577- light : SYNC_PUSH_LIGHT_ICON_URI ,
578- dark : SYNC_PUSH_DARK_ICON_URI
579- }
580- } ,
581- group : 'navigation' ,
582- order : 1 ,
583- when : ContextKeyExpr . and ( CONTEXT_SYNC_STATE . isEqualTo ( SyncStatus . HasConflicts ) , ResourceContextKey . Resource . isEqualTo ( this . workbenchEnvironmentService . settingsSyncPreviewResource . toString ( ) ) ) ,
584- } ) ;
585- MenuRegistry . appendMenuItem ( MenuId . EditorTitle , {
586- command : {
587- id : continueSyncCommandId ,
588- title : localize ( 'continue sync' , "Sync: Continue sync" ) ,
589- icon : {
590- light : SYNC_PUSH_LIGHT_ICON_URI ,
591- dark : SYNC_PUSH_DARK_ICON_URI
592- }
593- } ,
594- group : 'navigation' ,
595- order : 1 ,
596- when : ContextKeyExpr . and ( CONTEXT_SYNC_STATE . isEqualTo ( SyncStatus . HasConflicts ) , ResourceContextKey . Resource . isEqualTo ( this . workbenchEnvironmentService . keybindingsSyncPreviewResource . toString ( ) ) ) ,
597- } ) ;
598575
599576 const signOutMenuItem : IMenuItem = {
600577 group : '5_sync' ,
@@ -650,10 +627,10 @@ class UserDataRemoteContentProvider implements ITextModelContentProvider {
650627
651628 provideTextContent ( uri : URI ) : Promise < ITextModel > | null {
652629 let promise : Promise < string | null > | undefined ;
653- if ( uri . path === ` ${ SyncSource . Settings } /remoteContent` ) {
630+ if ( isEqual ( uri , toRemoteContentResource ( SyncSource . Settings ) ) ) {
654631 promise = this . userDataSyncService . getRemoteContent ( SyncSource . Settings ) ;
655632 }
656- if ( uri . path === ` ${ SyncSource . Keybindings } /remoteContent` ) {
633+ if ( isEqual ( uri , toRemoteContentResource ( SyncSource . Keybindings ) ) ) {
657634 promise = this . userDataSyncService . getRemoteContent ( SyncSource . Keybindings ) ;
658635 }
659636 if ( promise ) {
@@ -663,3 +640,99 @@ class UserDataRemoteContentProvider implements ITextModelContentProvider {
663640 }
664641}
665642
643+ class AcceptChangesContribution extends Disposable implements IEditorContribution {
644+
645+ static get ( editor : ICodeEditor ) : AcceptChangesContribution {
646+ return editor . getContribution < AcceptChangesContribution > ( AcceptChangesContribution . ID ) ;
647+ }
648+
649+ public static readonly ID = 'editor.contrib.acceptChangesButton' ;
650+
651+ private acceptChangesButton : FloatingClickWidget | undefined ;
652+
653+ constructor (
654+ private editor : ICodeEditor ,
655+ @IInstantiationService private readonly instantiationService : IInstantiationService ,
656+ @IWorkbenchEnvironmentService private readonly environmentService : IWorkbenchEnvironmentService ,
657+ @IUserDataSyncService private readonly userDataSyncService : IUserDataSyncService ,
658+ @IFileService private readonly fileService : IFileService
659+ ) {
660+ super ( ) ;
661+
662+ this . update ( ) ;
663+ this . registerListeners ( ) ;
664+ }
665+
666+ private registerListeners ( ) : void {
667+ this . _register ( this . editor . onDidChangeModel ( e => this . update ( ) ) ) ;
668+ }
669+
670+ private update ( ) : void {
671+ if ( ! this . shouldShowButton ( this . editor ) ) {
672+ this . disposeAcceptChangesWidgetRenderer ( ) ;
673+ return ;
674+ }
675+
676+ this . createAcceptChangesWidgetRenderer ( ) ;
677+ }
678+
679+ private shouldShowButton ( editor : ICodeEditor ) : boolean {
680+ const model = editor . getModel ( ) ;
681+ if ( ! model ) {
682+ return false ; // we need a model
683+ }
684+
685+ if ( isEqual ( model . uri , this . environmentService . settingsSyncPreviewResource ) ) {
686+ return true ;
687+ }
688+
689+ if ( isEqual ( model . uri , this . environmentService . keybindingsSyncPreviewResource ) ) {
690+ return true ;
691+ }
692+
693+ if ( getSyncSourceFromRemoteContentResource ( model . uri ) !== undefined ) {
694+ return true ;
695+ }
696+
697+ return false ;
698+ }
699+
700+ private createAcceptChangesWidgetRenderer ( ) : void {
701+ if ( ! this . acceptChangesButton ) {
702+ this . acceptChangesButton = this . instantiationService . createInstance ( FloatingClickWidget , this . editor , getSyncSourceFromRemoteContentResource ( this . editor . getModel ( ) ! . uri ) !== undefined ? localize ( 'accept remote' , "Accept (Remote)" ) : localize ( 'accept local' , "Accept (Local)" ) , null ) ;
703+ this . _register ( this . acceptChangesButton . onClick ( async ( ) => {
704+ const model = this . editor . getModel ( ) ;
705+ if ( model ) {
706+ const syncSource = getSyncSourceFromRemoteContentResource ( model . uri ) ;
707+ if ( syncSource === SyncSource . Settings ) {
708+ const remoteContent = await this . userDataSyncService . getRemoteContent ( SyncSource . Settings ) ;
709+ if ( remoteContent ) {
710+ await this . fileService . writeFile ( this . environmentService . settingsSyncPreviewResource , VSBuffer . fromString ( remoteContent ) ) ;
711+ }
712+ }
713+ else if ( syncSource === SyncSource . Keybindings ) {
714+ const remoteContent = await this . userDataSyncService . getRemoteContent ( SyncSource . Keybindings ) ;
715+ if ( remoteContent ) {
716+ await this . fileService . writeFile ( this . environmentService . keybindingsSyncPreviewResource , VSBuffer . fromString ( remoteContent ) ) ;
717+ }
718+ }
719+ await this . userDataSyncService . sync ( true ) ;
720+ }
721+ } ) ) ;
722+
723+ this . acceptChangesButton . render ( ) ;
724+ }
725+ }
726+
727+ private disposeAcceptChangesWidgetRenderer ( ) : void {
728+ dispose ( this . acceptChangesButton ) ;
729+ this . acceptChangesButton = undefined ;
730+ }
731+
732+ dispose ( ) : void {
733+ this . disposeAcceptChangesWidgetRenderer ( ) ;
734+
735+ super . dispose ( ) ;
736+ }
737+ }
738+
0 commit comments