From 7a8b59fa8d2f1d89fc47af14ae230164b8e62111 Mon Sep 17 00:00:00 2001 From: Don Jayamanne Date: Tue, 18 Feb 2020 14:24:09 -0800 Subject: [PATCH 01/11] Misc --- .vscode/launch.json | 2 +- src/datascience-ui/interactive-common/redux/helpers.ts | 4 ++-- .../interactive-common/redux/postOffice.ts | 9 +-------- 3 files changed, 4 insertions(+), 11 deletions(-) diff --git a/.vscode/launch.json b/.vscode/launch.json index 39f2c4888690..533d67a2ddb8 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -16,7 +16,7 @@ "outFiles": [ "${workspaceFolder}/out/**/*" ], - "preLaunchTask": "Compile", + // "preLaunchTask": "Compile", "skipFiles": [ "/**" ] diff --git a/src/datascience-ui/interactive-common/redux/helpers.ts b/src/datascience-ui/interactive-common/redux/helpers.ts index ee880e687c2d..382cfb7273fe 100644 --- a/src/datascience-ui/interactive-common/redux/helpers.ts +++ b/src/datascience-ui/interactive-common/redux/helpers.ts @@ -128,7 +128,7 @@ export function reBroadcastMessageIfRequired( }; // tslint:disable-next-line: no-any const syncPayload = { type: message, payload: syncPayloadData } as any; - // Send this out. - dispatcher(InteractiveWindowMessages.Sync, syncPayload); + // First focus on UX perf, hence the setTimeout (i.e. ensure other code in event loop executes). + setTimeout(() => dispatcher(InteractiveWindowMessages.Sync, syncPayload), 1); } } diff --git a/src/datascience-ui/interactive-common/redux/postOffice.ts b/src/datascience-ui/interactive-common/redux/postOffice.ts index 4ba3a4d25a2a..5f231921a4d2 100644 --- a/src/datascience-ui/interactive-common/redux/postOffice.ts +++ b/src/datascience-ui/interactive-common/redux/postOffice.ts @@ -24,14 +24,7 @@ export function generatePostOfficeSendReducer(postOffice: PostOffice): Redux.Red // Do not rebroadcast messages that have been sent through as part of a synchronization packet. // If `messageType` is a number, then its some part of a synchronization packet. if (payload?.messageDirection === 'incoming') { - // We can delay this, first focus on UX perf. - setTimeout(() => { - reBroadcastMessageIfRequired( - postOffice.sendMessage.bind(postOffice), - action.type, - action?.payload - ); - }, 1); + reBroadcastMessageIfRequired(postOffice.sendMessage.bind(postOffice), action.type, action?.payload); } } } From 216a25f0184e4c9e7e3ab18846eba36d3a354919 Mon Sep 17 00:00:00 2001 From: Don Jayamanne Date: Tue, 18 Feb 2020 16:52:15 -0800 Subject: [PATCH 02/11] Add support for syncing edits --- .../interactive-common/synchronization.ts | 212 +++++++++--------- .../datascience/interactive-common/types.ts | 12 +- .../interactive-ipynb/nativeEditor.ts | 10 +- .../nativeEditorSynchronizer.ts | 30 +++ src/client/datascience/serviceRegistry.ts | 97 ++++++-- .../interactive-common/redux/helpers.ts | 11 +- .../interactive-common/redux/store.ts | 6 +- 7 files changed, 241 insertions(+), 137 deletions(-) create mode 100644 src/client/datascience/interactive-ipynb/nativeEditorSynchronizer.ts diff --git a/src/client/datascience/interactive-common/synchronization.ts b/src/client/datascience/interactive-common/synchronization.ts index 03c4741f443b..285973753e19 100644 --- a/src/client/datascience/interactive-common/synchronization.ts +++ b/src/client/datascience/interactive-common/synchronization.ts @@ -12,7 +12,7 @@ export enum MessageType { /** * Action dispatched as result of some user action. */ - userAction = 0, + other = 0, /** * Action dispatched to re-broadcast a message across other editors of the same file in the same session. */ @@ -35,147 +35,147 @@ export type IInteractiveActionMapping = MessageMapping & MessageMapping = { - [CommonActionType.ADD_AND_FOCUS_NEW_CELL]: MessageType.userAction, + [CommonActionType.ADD_AND_FOCUS_NEW_CELL]: MessageType.other, [CommonActionType.ADD_NEW_CELL]: MessageType.syncAcrossSameNotebooks | MessageType.syncWithLiveShare, [CommonActionType.ARROW_DOWN]: MessageType.syncWithLiveShare, [CommonActionType.ARROW_UP]: MessageType.syncWithLiveShare, [CommonActionType.CHANGE_CELL_TYPE]: MessageType.syncAcrossSameNotebooks | MessageType.syncWithLiveShare, [CommonActionType.CLICK_CELL]: MessageType.syncWithLiveShare, - [CommonActionType.DELETE_CELL]: MessageType.syncWithLiveShare, + [CommonActionType.DELETE_CELL]: MessageType.syncAcrossSameNotebooks | MessageType.syncWithLiveShare, [CommonActionType.CODE_CREATED]: MessageType.noIdea, - [CommonActionType.COPY_CELL_CODE]: MessageType.userAction, - [CommonActionType.EDITOR_LOADED]: MessageType.userAction, + [CommonActionType.COPY_CELL_CODE]: MessageType.other, + [CommonActionType.EDITOR_LOADED]: MessageType.other, [CommonActionType.EDIT_CELL]: MessageType.syncAcrossSameNotebooks | MessageType.syncWithLiveShare, - [CommonActionType.EXECUTE_CELL_AND_ADVANCE]: MessageType.userAction, - [CommonActionType.EXECUTE_ABOVE]: MessageType.userAction, - [CommonActionType.EXECUTE_ALL_CELLS]: MessageType.userAction, - [CommonActionType.EXECUTE_CELL]: MessageType.userAction, - [CommonActionType.EXECUTE_CELL_AND_BELOW]: MessageType.userAction, - [CommonActionType.EXPORT]: MessageType.userAction, + [CommonActionType.EXECUTE_CELL_AND_ADVANCE]: MessageType.other, + [CommonActionType.EXECUTE_ABOVE]: MessageType.other, + [CommonActionType.EXECUTE_ALL_CELLS]: MessageType.other, + [CommonActionType.EXECUTE_CELL]: MessageType.other, + [CommonActionType.EXECUTE_CELL_AND_BELOW]: MessageType.other, + [CommonActionType.EXPORT]: MessageType.other, [CommonActionType.FOCUS_CELL]: MessageType.syncWithLiveShare, - [CommonActionType.GATHER_CELL]: MessageType.userAction, - [CommonActionType.GET_VARIABLE_DATA]: MessageType.userAction, + [CommonActionType.GATHER_CELL]: MessageType.other, + [CommonActionType.GET_VARIABLE_DATA]: MessageType.other, [CommonActionType.GOTO_CELL]: MessageType.syncWithLiveShare, - [CommonActionType.INSERT_ABOVE_AND_FOCUS_NEW_CELL]: MessageType.userAction, + [CommonActionType.INSERT_ABOVE_AND_FOCUS_NEW_CELL]: MessageType.other, [CommonActionType.INSERT_ABOVE]: MessageType.syncAcrossSameNotebooks | MessageType.syncWithLiveShare, - [CommonActionType.INSERT_ABOVE_FIRST_AND_FOCUS_NEW_CELL]: MessageType.userAction, + [CommonActionType.INSERT_ABOVE_FIRST_AND_FOCUS_NEW_CELL]: MessageType.other, [CommonActionType.INSERT_ABOVE_FIRST]: MessageType.syncAcrossSameNotebooks | MessageType.syncWithLiveShare, [CommonActionType.INSERT_BELOW]: MessageType.syncAcrossSameNotebooks | MessageType.syncWithLiveShare, - [CommonActionType.INSERT_BELOW_AND_FOCUS_NEW_CELL]: MessageType.userAction, - [CommonActionType.INTERRUPT_KERNEL]: MessageType.userAction, - [CommonActionType.LOADED_ALL_CELLS]: MessageType.userAction, - [CommonActionType.LINK_CLICK]: MessageType.userAction, + [CommonActionType.INSERT_BELOW_AND_FOCUS_NEW_CELL]: MessageType.other, + [CommonActionType.INTERRUPT_KERNEL]: MessageType.other, + [CommonActionType.LOADED_ALL_CELLS]: MessageType.other, + [CommonActionType.LINK_CLICK]: MessageType.other, [CommonActionType.MOVE_CELL_DOWN]: MessageType.syncAcrossSameNotebooks | MessageType.syncWithLiveShare, [CommonActionType.MOVE_CELL_UP]: MessageType.syncAcrossSameNotebooks | MessageType.syncWithLiveShare, - [CommonActionType.OPEN_SETTINGS]: MessageType.userAction, - [CommonActionType.RESTART_KERNEL]: MessageType.userAction, - [CommonActionType.SAVE]: MessageType.userAction, + [CommonActionType.OPEN_SETTINGS]: MessageType.other, + [CommonActionType.RESTART_KERNEL]: MessageType.other, + [CommonActionType.SAVE]: MessageType.other, [CommonActionType.SCROLL]: MessageType.syncWithLiveShare, [CommonActionType.SELECT_CELL]: MessageType.syncWithLiveShare, - [CommonActionType.SELECT_SERVER]: MessageType.userAction, - [CommonActionType.SEND_COMMAND]: MessageType.userAction, - [CommonActionType.SHOW_DATA_VIEWER]: MessageType.userAction, - [CommonActionType.SUBMIT_INPUT]: MessageType.userAction, + [CommonActionType.SELECT_SERVER]: MessageType.other, + [CommonActionType.SEND_COMMAND]: MessageType.other, + [CommonActionType.SHOW_DATA_VIEWER]: MessageType.other, + [CommonActionType.SUBMIT_INPUT]: MessageType.other, [CommonActionType.TOGGLE_INPUT_BLOCK]: MessageType.syncAcrossSameNotebooks | MessageType.syncWithLiveShare, [CommonActionType.TOGGLE_LINE_NUMBERS]: MessageType.syncWithLiveShare, [CommonActionType.TOGGLE_OUTPUT]: MessageType.syncWithLiveShare, [CommonActionType.TOGGLE_VARIABLE_EXPLORER]: MessageType.syncWithLiveShare, [CommonActionType.UNFOCUS_CELL]: MessageType.syncWithLiveShare, - [CommonActionType.UNMOUNT]: MessageType.userAction, - [CommonActionType.PostOutgoingMessage]: MessageType.userAction, - [CommonActionType.REFRESH_VARIABLES]: MessageType.userAction, - [CommonActionType.FOCUS_INPUT]: MessageType.userAction, + [CommonActionType.UNMOUNT]: MessageType.other, + [CommonActionType.PostOutgoingMessage]: MessageType.other, + [CommonActionType.REFRESH_VARIABLES]: MessageType.other, + [CommonActionType.FOCUS_INPUT]: MessageType.other, // Types from InteractiveWindowMessages - [InteractiveWindowMessages.Activate]: MessageType.userAction, - [InteractiveWindowMessages.AddedSysInfo]: MessageType.userAction, - [InteractiveWindowMessages.CancelCompletionItemsRequest]: MessageType.userAction, - [InteractiveWindowMessages.CancelHoverRequest]: MessageType.userAction, - [InteractiveWindowMessages.CancelResolveCompletionItemRequest]: MessageType.userAction, - [InteractiveWindowMessages.CancelSignatureHelpRequest]: MessageType.userAction, + [InteractiveWindowMessages.Activate]: MessageType.other, + [InteractiveWindowMessages.AddedSysInfo]: MessageType.other, + [InteractiveWindowMessages.CancelCompletionItemsRequest]: MessageType.other, + [InteractiveWindowMessages.CancelHoverRequest]: MessageType.other, + [InteractiveWindowMessages.CancelResolveCompletionItemRequest]: MessageType.other, + [InteractiveWindowMessages.CancelSignatureHelpRequest]: MessageType.other, [InteractiveWindowMessages.ClearAllOutputs]: MessageType.syncAcrossSameNotebooks | MessageType.syncWithLiveShare, [InteractiveWindowMessages.CollapseAll]: MessageType.syncWithLiveShare, - [InteractiveWindowMessages.CopyCodeCell]: MessageType.userAction, + [InteractiveWindowMessages.CopyCodeCell]: MessageType.other, [InteractiveWindowMessages.DeleteAllCells]: MessageType.syncAcrossSameNotebooks | MessageType.syncWithLiveShare, - [InteractiveWindowMessages.DoSave]: MessageType.userAction, - [InteractiveWindowMessages.ExecutionRendered]: MessageType.userAction, + [InteractiveWindowMessages.DoSave]: MessageType.other, + [InteractiveWindowMessages.ExecutionRendered]: MessageType.other, [InteractiveWindowMessages.ExpandAll]: MessageType.syncWithLiveShare, - [InteractiveWindowMessages.Export]: MessageType.userAction, - [InteractiveWindowMessages.FinishCell]: MessageType.userAction, + [InteractiveWindowMessages.Export]: MessageType.other, + [InteractiveWindowMessages.FinishCell]: MessageType.syncAcrossSameNotebooks | MessageType.syncWithLiveShare, [InteractiveWindowMessages.FocusedCellEditor]: MessageType.syncWithLiveShare, - [InteractiveWindowMessages.GatherCodeRequest]: MessageType.userAction, - [InteractiveWindowMessages.GetAllCells]: MessageType.userAction, - [InteractiveWindowMessages.GetVariablesRequest]: MessageType.userAction, - [InteractiveWindowMessages.GetVariablesResponse]: MessageType.userAction, + [InteractiveWindowMessages.GatherCodeRequest]: MessageType.other, + [InteractiveWindowMessages.GetAllCells]: MessageType.other, + [InteractiveWindowMessages.GetVariablesRequest]: MessageType.other, + [InteractiveWindowMessages.GetVariablesResponse]: MessageType.other, [InteractiveWindowMessages.GotoCodeCell]: MessageType.syncWithLiveShare, [InteractiveWindowMessages.GotoCodeCell]: MessageType.syncWithLiveShare, - [InteractiveWindowMessages.Interrupt]: MessageType.userAction, - [InteractiveWindowMessages.LoadAllCells]: MessageType.userAction, - [InteractiveWindowMessages.LoadAllCellsComplete]: MessageType.userAction, - [InteractiveWindowMessages.LoadOnigasmAssemblyRequest]: MessageType.userAction, - [InteractiveWindowMessages.LoadOnigasmAssemblyResponse]: MessageType.userAction, - [InteractiveWindowMessages.LoadTmLanguageRequest]: MessageType.userAction, - [InteractiveWindowMessages.LoadTmLanguageResponse]: MessageType.userAction, - [InteractiveWindowMessages.MonacoReady]: MessageType.userAction, - [InteractiveWindowMessages.NativeCommand]: MessageType.userAction, + [InteractiveWindowMessages.Interrupt]: MessageType.other, + [InteractiveWindowMessages.LoadAllCells]: MessageType.other, + [InteractiveWindowMessages.LoadAllCellsComplete]: MessageType.other, + [InteractiveWindowMessages.LoadOnigasmAssemblyRequest]: MessageType.other, + [InteractiveWindowMessages.LoadOnigasmAssemblyResponse]: MessageType.other, + [InteractiveWindowMessages.LoadTmLanguageRequest]: MessageType.other, + [InteractiveWindowMessages.LoadTmLanguageResponse]: MessageType.other, + [InteractiveWindowMessages.MonacoReady]: MessageType.other, + [InteractiveWindowMessages.NativeCommand]: MessageType.other, [InteractiveWindowMessages.NotebookAddCellBelow]: MessageType.syncAcrossSameNotebooks | MessageType.syncWithLiveShare, - [InteractiveWindowMessages.NotebookClean]: MessageType.userAction, - [InteractiveWindowMessages.NotebookDirty]: MessageType.userAction, - [InteractiveWindowMessages.NotebookExecutionActivated]: MessageType.userAction, - [InteractiveWindowMessages.NotebookIdentity]: MessageType.userAction, - [InteractiveWindowMessages.NotebookRunAllCells]: MessageType.userAction, - [InteractiveWindowMessages.NotebookRunSelectedCell]: MessageType.userAction, - [InteractiveWindowMessages.OpenLink]: MessageType.userAction, - [InteractiveWindowMessages.OpenSettings]: MessageType.userAction, - [InteractiveWindowMessages.ProvideCompletionItemsRequest]: MessageType.userAction, - [InteractiveWindowMessages.ProvideCompletionItemsResponse]: MessageType.userAction, - [InteractiveWindowMessages.ProvideHoverRequest]: MessageType.userAction, - [InteractiveWindowMessages.ProvideHoverResponse]: MessageType.userAction, - [InteractiveWindowMessages.ProvideSignatureHelpRequest]: MessageType.userAction, - [InteractiveWindowMessages.ProvideSignatureHelpResponse]: MessageType.userAction, - [InteractiveWindowMessages.ReExecuteCells]: MessageType.userAction, - [InteractiveWindowMessages.Redo]: MessageType.userAction, - [InteractiveWindowMessages.RemoteAddCode]: MessageType.userAction, - [InteractiveWindowMessages.ReceivedUpdateModel]: MessageType.userAction, - [InteractiveWindowMessages.RemoteReexecuteCode]: MessageType.userAction, - [InteractiveWindowMessages.ResolveCompletionItemRequest]: MessageType.userAction, - [InteractiveWindowMessages.ResolveCompletionItemResponse]: MessageType.userAction, - [InteractiveWindowMessages.RestartKernel]: MessageType.userAction, - [InteractiveWindowMessages.ReturnAllCells]: MessageType.userAction, - [InteractiveWindowMessages.SaveAll]: MessageType.userAction, - [InteractiveWindowMessages.SavePng]: MessageType.userAction, + [InteractiveWindowMessages.NotebookClean]: MessageType.other, + [InteractiveWindowMessages.NotebookDirty]: MessageType.other, + [InteractiveWindowMessages.NotebookExecutionActivated]: MessageType.other, + [InteractiveWindowMessages.NotebookIdentity]: MessageType.other, + [InteractiveWindowMessages.NotebookRunAllCells]: MessageType.other, + [InteractiveWindowMessages.NotebookRunSelectedCell]: MessageType.other, + [InteractiveWindowMessages.OpenLink]: MessageType.other, + [InteractiveWindowMessages.OpenSettings]: MessageType.other, + [InteractiveWindowMessages.ProvideCompletionItemsRequest]: MessageType.other, + [InteractiveWindowMessages.ProvideCompletionItemsResponse]: MessageType.other, + [InteractiveWindowMessages.ProvideHoverRequest]: MessageType.other, + [InteractiveWindowMessages.ProvideHoverResponse]: MessageType.other, + [InteractiveWindowMessages.ProvideSignatureHelpRequest]: MessageType.other, + [InteractiveWindowMessages.ProvideSignatureHelpResponse]: MessageType.other, + [InteractiveWindowMessages.ReExecuteCells]: MessageType.other, + [InteractiveWindowMessages.Redo]: MessageType.other, + [InteractiveWindowMessages.RemoteAddCode]: MessageType.other, + [InteractiveWindowMessages.ReceivedUpdateModel]: MessageType.other, + [InteractiveWindowMessages.RemoteReexecuteCode]: MessageType.other, + [InteractiveWindowMessages.ResolveCompletionItemRequest]: MessageType.other, + [InteractiveWindowMessages.ResolveCompletionItemResponse]: MessageType.other, + [InteractiveWindowMessages.RestartKernel]: MessageType.other, + [InteractiveWindowMessages.ReturnAllCells]: MessageType.other, + [InteractiveWindowMessages.SaveAll]: MessageType.other, + [InteractiveWindowMessages.SavePng]: MessageType.other, [InteractiveWindowMessages.ScrollToCell]: MessageType.syncWithLiveShare, - [InteractiveWindowMessages.SelectJupyterServer]: MessageType.userAction, - [InteractiveWindowMessages.SelectKernel]: MessageType.userAction, - [InteractiveWindowMessages.SendInfo]: MessageType.userAction, - [InteractiveWindowMessages.SettingsUpdated]: MessageType.userAction, - [InteractiveWindowMessages.ShowDataViewer]: MessageType.userAction, - [InteractiveWindowMessages.ShowPlot]: MessageType.userAction, - [InteractiveWindowMessages.StartCell]: MessageType.userAction, - [InteractiveWindowMessages.StartDebugging]: MessageType.userAction, - [InteractiveWindowMessages.StartProgress]: MessageType.userAction, - [InteractiveWindowMessages.Started]: MessageType.userAction, - [InteractiveWindowMessages.StopDebugging]: MessageType.userAction, - [InteractiveWindowMessages.StopProgress]: MessageType.userAction, - [InteractiveWindowMessages.SubmitNewCell]: MessageType.userAction, - [InteractiveWindowMessages.Sync]: MessageType.userAction, - [InteractiveWindowMessages.Undo]: MessageType.userAction, + [InteractiveWindowMessages.SelectJupyterServer]: MessageType.other, + [InteractiveWindowMessages.SelectKernel]: MessageType.other, + [InteractiveWindowMessages.SendInfo]: MessageType.other, + [InteractiveWindowMessages.SettingsUpdated]: MessageType.other, + [InteractiveWindowMessages.ShowDataViewer]: MessageType.other, + [InteractiveWindowMessages.ShowPlot]: MessageType.other, + [InteractiveWindowMessages.StartCell]: MessageType.syncAcrossSameNotebooks | MessageType.syncWithLiveShare, + [InteractiveWindowMessages.StartDebugging]: MessageType.other, + [InteractiveWindowMessages.StartProgress]: MessageType.other, + [InteractiveWindowMessages.Started]: MessageType.other, + [InteractiveWindowMessages.StopDebugging]: MessageType.other, + [InteractiveWindowMessages.StopProgress]: MessageType.other, + [InteractiveWindowMessages.SubmitNewCell]: MessageType.other, + [InteractiveWindowMessages.Sync]: MessageType.other, + [InteractiveWindowMessages.Undo]: MessageType.other, [InteractiveWindowMessages.UnfocusedCellEditor]: MessageType.syncWithLiveShare, - [InteractiveWindowMessages.UpdateCell]: MessageType.userAction, + [InteractiveWindowMessages.UpdateCell]: MessageType.syncAcrossSameNotebooks | MessageType.syncWithLiveShare, [InteractiveWindowMessages.UpdateModel]: MessageType.syncAcrossSameNotebooks | MessageType.syncWithLiveShare, - [InteractiveWindowMessages.UpdateKernel]: MessageType.userAction, - [InteractiveWindowMessages.VariableExplorerToggle]: MessageType.userAction, - [InteractiveWindowMessages.VariablesComplete]: MessageType.userAction, + [InteractiveWindowMessages.UpdateKernel]: MessageType.syncAcrossSameNotebooks | MessageType.syncWithLiveShare, + [InteractiveWindowMessages.VariableExplorerToggle]: MessageType.other, + [InteractiveWindowMessages.VariablesComplete]: MessageType.other, // Types from CssMessages - [CssMessages.GetCssRequest]: MessageType.userAction, - [CssMessages.GetCssResponse]: MessageType.userAction, - [CssMessages.GetMonacoThemeRequest]: MessageType.userAction, - [CssMessages.GetMonacoThemeResponse]: MessageType.userAction, + [CssMessages.GetCssRequest]: MessageType.other, + [CssMessages.GetCssResponse]: MessageType.other, + [CssMessages.GetMonacoThemeRequest]: MessageType.other, + [CssMessages.GetMonacoThemeResponse]: MessageType.other, // Types from Shared Messages - [SharedMessages.LocInit]: MessageType.userAction, - [SharedMessages.Started]: MessageType.userAction, - [SharedMessages.UpdateSettings]: MessageType.userAction + [SharedMessages.LocInit]: MessageType.other, + [SharedMessages.Started]: MessageType.other, + [SharedMessages.UpdateSettings]: MessageType.other }; /** @@ -209,7 +209,7 @@ export function shouldRebroadcast(message: keyof IInteractiveWindowMapping): [bo messageType === undefined || (messageType & MessageType.syncAcrossSameNotebooks) !== MessageType.syncAcrossSameNotebooks ) { - return [false, MessageType.userAction]; + return [false, MessageType.other]; } return [ diff --git a/src/client/datascience/interactive-common/types.ts b/src/client/datascience/interactive-common/types.ts index bab7a55d2e09..9ba94ccc0d3e 100644 --- a/src/client/datascience/interactive-common/types.ts +++ b/src/client/datascience/interactive-common/types.ts @@ -3,6 +3,9 @@ 'use strict'; +import { CommonActionType } from '../../../datascience-ui/interactive-common/redux/reducers/types'; +import { CssMessages, SharedMessages } from '../messages'; +import { InteractiveWindowMessages } from './interactiveWindowTypes'; import { MessageType } from './synchronization'; // Stuff common to React and Extensions. @@ -29,6 +32,11 @@ type BaseDataWithPayload = { // This forms the base content of every payload in all dispatchers. export type BaseReduxActionPayload = T extends never ? T extends undefined - ? BaseData - : BaseDataWithPayload + ? BaseData + : BaseDataWithPayload : BaseDataWithPayload; +// tslint:disable-next-line: no-any +export type SyncPayload = { + type: InteractiveWindowMessages | SharedMessages | CommonActionType | CssMessages; + payload: BaseReduxActionPayload; +}; diff --git a/src/client/datascience/interactive-ipynb/nativeEditor.ts b/src/client/datascience/interactive-ipynb/nativeEditor.ts index 125a4a385cd5..fe677f07b0d5 100644 --- a/src/client/datascience/interactive-ipynb/nativeEditor.ts +++ b/src/client/datascience/interactive-ipynb/nativeEditor.ts @@ -83,6 +83,7 @@ import { IThemeFinder, WebViewViewChangeEventArgs } from '../types'; +import { NativeEditorSynchronizer } from './nativeEditorSynchronizer'; import { nbformat } from '@jupyterlab/coreutils'; // tslint:disable-next-line: no-require-imports @@ -164,6 +165,7 @@ export class NativeEditor extends InteractiveBase implements INotebookEditor { @inject(ICommandManager) commandManager: ICommandManager, @inject(INotebookExporter) jupyterExporter: INotebookExporter, @inject(IWorkspaceService) workspaceService: IWorkspaceService, + @inject(NativeEditorSynchronizer) private readonly synchronizer: NativeEditorSynchronizer, @inject(INotebookEditorProvider) private editorProvider: INotebookEditorProvider, @inject(IDataViewerProvider) dataExplorerProvider: IDataViewerProvider, @inject(IJupyterVariables) jupyterVariables: IJupyterVariables, @@ -211,6 +213,8 @@ export class NativeEditor extends InteractiveBase implements INotebookEditor { switcher ); asyncRegistry.push(this); + + this.synchronizer.subscribeToUserActions(this, this.postMessage.bind(this)); } public dispose(): Promise { @@ -247,7 +251,11 @@ export class NativeEditor extends InteractiveBase implements INotebookEditor { public onMessage(message: string, payload: any) { super.onMessage(message, payload); switch (message) { - case InteractiveWindowMessages.ReExecuteCells: + case InteractiveWindowMessages.Sync: + this.synchronizer.notifyUserAction(payload, this); + break; + + case InteractiveWindowMessages.ReExecuteCell: this.executedEvent.fire(this); break; diff --git a/src/client/datascience/interactive-ipynb/nativeEditorSynchronizer.ts b/src/client/datascience/interactive-ipynb/nativeEditorSynchronizer.ts new file mode 100644 index 000000000000..94274162c8d9 --- /dev/null +++ b/src/client/datascience/interactive-ipynb/nativeEditorSynchronizer.ts @@ -0,0 +1,30 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +'use strict'; + +import { inject, injectable } from 'inversify'; +import { IFileSystem } from '../../common/platform/types'; +import { IInteractiveWindowMapping, InteractiveWindowMessages } from '../interactive-common/interactiveWindowTypes'; +import { SyncPayload } from '../interactive-common/types'; +import { INotebookEditor } from '../types'; + +// tslint:disable: no-any + +type UserActionNotificationCallback = (type: T, payload?: M[T]) => void; + +@injectable() +export class NativeEditorSynchronizer { + private registeredNotebooks = new Map(); + constructor(@inject(IFileSystem) private readonly fs: IFileSystem) {} + public notifyUserAction(message: SyncPayload, editor: INotebookEditor) { + this.registeredNotebooks.forEach((cb, item) => { + if (item !== editor && this.fs.arePathsSame(item.file.fsPath, editor.file.fsPath)) { + cb(InteractiveWindowMessages.Sync, message as any); + } + }); + } + public subscribeToUserActions(editor: INotebookEditor, cb: UserActionNotificationCallback) { + this.registeredNotebooks.set(editor, cb); + } +} diff --git a/src/client/datascience/serviceRegistry.ts b/src/client/datascience/serviceRegistry.ts index 0fcd8fb9f30c..008f77423dfb 100644 --- a/src/client/datascience/serviceRegistry.ts +++ b/src/client/datascience/serviceRegistry.ts @@ -38,6 +38,7 @@ import { NativeEditorOldWebView } from './interactive-ipynb/nativeEditorOldWebVi import { NativeEditorProvider } from './interactive-ipynb/nativeEditorProvider'; import { NativeEditorProviderOld } from './interactive-ipynb/nativeEditorProviderOld'; import { NativeEditorStorage } from './interactive-ipynb/nativeEditorStorage'; +import { NativeEditorSynchronizer } from './interactive-ipynb/nativeEditorSynchronizer'; import { InteractiveWindow } from './interactive-window/interactiveWindow'; import { InteractiveWindowCommandListener } from './interactive-window/interactiveWindowCommandListener'; import { InteractiveWindowProvider } from './interactive-window/interactiveWindowProvider'; @@ -119,7 +120,8 @@ import { // tslint:disable-next-line: max-func-body-length export function registerTypes(serviceManager: IServiceManager) { - const useCustomEditorApi = serviceManager.get(IApplicationEnvironment).packageJson.enableProposedApi; + const useCustomEditorApi = serviceManager.get(IApplicationEnvironment).packageJson + .enableProposedApi; serviceManager.addSingletonInstance(UseCustomEditorApi, useCustomEditorApi); serviceManager.add(ICellHashLogger, CellHashLogger, undefined, [INotebookExecutionLogger]); @@ -142,45 +144,83 @@ export function registerTypes(serviceManager: IServiceManager) { serviceManager.add(INotebookStorage, NativeEditorStorage); serviceManager.add(IPlotViewer, PlotViewer); serviceManager.addSingleton(ActiveEditorContextService, ActiveEditorContextService); - serviceManager.addSingleton(CellOutputMimeTypeTracker, CellOutputMimeTypeTracker, undefined, [IExtensionSingleActivationService, INotebookExecutionLogger]); + serviceManager.addSingleton( + CellOutputMimeTypeTracker, + CellOutputMimeTypeTracker, + undefined, + [IExtensionSingleActivationService, INotebookExecutionLogger] + ); serviceManager.addSingleton(CommandRegistry, CommandRegistry); serviceManager.addSingleton(DataViewerDependencyService, DataViewerDependencyService); serviceManager.addSingleton(ICodeCssGenerator, CodeCssGenerator); - serviceManager.addSingleton(ICodeLensFactory, CodeLensFactory, undefined, [IInteractiveWindowListener]); + serviceManager.addSingleton(ICodeLensFactory, CodeLensFactory, undefined, [ + IInteractiveWindowListener + ]); serviceManager.addSingleton(IDataScience, DataScience); - serviceManager.addSingleton(IDataScienceCodeLensProvider, DataScienceCodeLensProvider); - serviceManager.addSingleton(IDataScienceCommandListener, InteractiveWindowCommandListener); + serviceManager.addSingleton( + IDataScienceCodeLensProvider, + DataScienceCodeLensProvider + ); + serviceManager.addSingleton( + IDataScienceCommandListener, + InteractiveWindowCommandListener + ); serviceManager.addSingleton(IDataScienceCommandListener, NativeEditorCommandListener); serviceManager.addSingleton(IDataViewerProvider, DataViewerProvider); serviceManager.addSingleton(IDebugLocationTracker, DebugLocationTrackerFactory); serviceManager.addSingleton(IExtensionSingleActivationService, Activation); serviceManager.addSingleton(IExtensionSingleActivationService, Decorator); - serviceManager.addSingleton(IExtensionSingleActivationService, JupyterInterpreterSelectionCommand); - serviceManager.addSingleton(IExtensionSingleActivationService, PreWarmActivatedJupyterEnvironmentVariables); - serviceManager.addSingleton(IExtensionSingleActivationService, ServerPreload); - serviceManager.addSingleton(IExtensionSingleActivationService, ServerPreload); + serviceManager.addSingleton( + IExtensionSingleActivationService, + JupyterInterpreterSelectionCommand + ); + serviceManager.addSingleton( + IExtensionSingleActivationService, + PreWarmActivatedJupyterEnvironmentVariables + ); serviceManager.addSingleton(IExtensionSingleActivationService, ServerPreload); serviceManager.addSingleton(IInteractiveWindowListener, DataScienceSurveyBannerLogger); serviceManager.addSingleton(IInteractiveWindowProvider, InteractiveWindowProvider); serviceManager.addSingleton(IJupyterDebugger, JupyterDebugger, undefined, [ICellHashListener]); serviceManager.addSingleton(IJupyterExecution, JupyterExecutionFactory); serviceManager.addSingleton(IJupyterPasswordConnect, JupyterPasswordConnect); - serviceManager.addSingleton(IJupyterSessionManagerFactory, JupyterSessionManagerFactory); + serviceManager.addSingleton( + IJupyterSessionManagerFactory, + JupyterSessionManagerFactory + ); serviceManager.addSingleton(IJupyterVariables, JupyterVariables); - serviceManager.addSingleton(INotebookEditorProvider, useCustomEditorApi ? NativeEditorProvider : NativeEditorProviderOld); + serviceManager.addSingleton( + INotebookEditorProvider, + useCustomEditorApi ? NativeEditorProvider : NativeEditorProviderOld + ); serviceManager.addSingleton(IPlotViewerProvider, PlotViewerProvider); serviceManager.addSingleton(IStatusProvider, StatusProvider); serviceManager.addSingleton(IThemeFinder, ThemeFinder); serviceManager.addSingleton(JupyterCommandFinder, JupyterCommandFinder); serviceManager.addSingleton(JupyterCommandLineSelector, JupyterCommandLineSelector); - serviceManager.addSingleton(JupyterCommandLineSelectorCommand, JupyterCommandLineSelectorCommand); - serviceManager.addSingleton(JupyterInterpreterDependencyService, JupyterInterpreterDependencyService); - serviceManager.addSingleton(JupyterInterpreterOldCacheStateStore, JupyterInterpreterOldCacheStateStore); + serviceManager.addSingleton( + JupyterCommandLineSelectorCommand, + JupyterCommandLineSelectorCommand + ); + serviceManager.addSingleton( + JupyterInterpreterDependencyService, + JupyterInterpreterDependencyService + ); + serviceManager.addSingleton( + JupyterInterpreterOldCacheStateStore, + JupyterInterpreterOldCacheStateStore + ); serviceManager.addSingleton(JupyterInterpreterSelector, JupyterInterpreterSelector); serviceManager.addSingleton(JupyterInterpreterService, JupyterInterpreterService); - serviceManager.addSingleton(JupyterInterpreterStateStore, JupyterInterpreterStateStore); + serviceManager.addSingleton( + JupyterInterpreterStateStore, + JupyterInterpreterStateStore + ); serviceManager.addSingleton(JupyterServerSelector, JupyterServerSelector); - serviceManager.addSingleton(JupyterServerSelectorCommand, JupyterServerSelectorCommand); + serviceManager.addSingleton( + JupyterServerSelectorCommand, + JupyterServerSelectorCommand + ); serviceManager.addSingleton(KernelSelectionProvider, KernelSelectionProvider); serviceManager.addSingleton(KernelSelector, KernelSelector); serviceManager.addSingleton(KernelService, KernelService); @@ -188,15 +228,30 @@ export function registerTypes(serviceManager: IServiceManager) { serviceManager.addSingleton(KernelSwitcherCommand, KernelSwitcherCommand); serviceManager.addSingleton(NotebookStarter, NotebookStarter); serviceManager.addSingleton(ProgressReporter, ProgressReporter); + serviceManager.addSingleton(NativeEditorSynchronizer, NativeEditorSynchronizer); // Temporary code, to allow users to revert to the old behavior. - const cfg = serviceManager.get(IWorkspaceService).getConfiguration('python.dataScience', undefined); + const cfg = serviceManager + .get(IWorkspaceService) + .getConfiguration('python.dataScience', undefined); if (cfg.get('useOldJupyterServer', false)) { - serviceManager.addSingleton(IJupyterInterpreterDependencyManager, JupyterCommandInterpreterDependencyService); - serviceManager.addSingleton(IJupyterSubCommandExecutionService, JupyterCommandFinderInterpreterExecutionService); + serviceManager.addSingleton( + IJupyterInterpreterDependencyManager, + JupyterCommandInterpreterDependencyService + ); + serviceManager.addSingleton( + IJupyterSubCommandExecutionService, + JupyterCommandFinderInterpreterExecutionService + ); } else { - serviceManager.addSingleton(IJupyterInterpreterDependencyManager, JupyterInterpreterSubCommandExecutionService); - serviceManager.addSingleton(IJupyterSubCommandExecutionService, JupyterInterpreterSubCommandExecutionService); + serviceManager.addSingleton( + IJupyterInterpreterDependencyManager, + JupyterInterpreterSubCommandExecutionService + ); + serviceManager.addSingleton( + IJupyterSubCommandExecutionService, + JupyterInterpreterSubCommandExecutionService + ); } registerGatherTypes(serviceManager); diff --git a/src/datascience-ui/interactive-common/redux/helpers.ts b/src/datascience-ui/interactive-common/redux/helpers.ts index 382cfb7273fe..3400fa34d9d2 100644 --- a/src/datascience-ui/interactive-common/redux/helpers.ts +++ b/src/datascience-ui/interactive-common/redux/helpers.ts @@ -13,7 +13,7 @@ import { MessageType, shouldRebroadcast } from '../../../client/datascience/interactive-common/synchronization'; -import { BaseReduxActionPayload } from '../../../client/datascience/interactive-common/types'; +import { BaseReduxActionPayload, SyncPayload } from '../../../client/datascience/interactive-common/types'; import { CssMessages, SharedMessages } from '../../../client/datascience/messages'; import { QueueAnotherFunc } from '../../react-common/reduxUtils'; import { CommonActionType, CommonActionTypeMapping } from './reducers/types'; @@ -87,7 +87,7 @@ export function postActionToExtension(originalReducerArg: ReducerArg, message: a const newPayload: BaseReduxActionPayload = ({ data: payload, messageDirection: 'outgoing', - messageType: MessageType.userAction + messageType: MessageType.other // tslint:disable-next-line: no-any } as any) as BaseReduxActionPayload; const action = { type: CommonActionType.PostOutgoingMessage, payload: { payload: newPayload, type: message } }; @@ -107,10 +107,11 @@ export function reBroadcastMessageIfRequired( message: InteractiveWindowMessages | SharedMessages | CommonActionType | CssMessages, payload?: BaseReduxActionPayload<{}> ) { + const messageType = payload?.messageType || 0; if ( message === InteractiveWindowMessages.Sync || - payload?.messageType === MessageType.syncAcrossSameNotebooks || - payload?.messageType === MessageType.syncWithLiveShare || + (messageType && MessageType.syncAcrossSameNotebooks) === MessageType.syncAcrossSameNotebooks || + (messageType && MessageType.syncWithLiveShare) === MessageType.syncWithLiveShare || payload?.messageDirection === 'outgoing' ) { return; @@ -127,7 +128,7 @@ export function reBroadcastMessageIfRequired( messageDirection: 'incoming' }; // tslint:disable-next-line: no-any - const syncPayload = { type: message, payload: syncPayloadData } as any; + const syncPayload: SyncPayload = { type: message, payload: syncPayloadData }; // First focus on UX perf, hence the setTimeout (i.e. ensure other code in event loop executes). setTimeout(() => dispatcher(InteractiveWindowMessages.Sync, syncPayload), 1); } diff --git a/src/datascience-ui/interactive-common/redux/store.ts b/src/datascience-ui/interactive-common/redux/store.ts index 04a41739f9e8..2ca41392c136 100644 --- a/src/datascience-ui/interactive-common/redux/store.ts +++ b/src/datascience-ui/interactive-common/redux/store.ts @@ -87,7 +87,7 @@ function createSendInfoMiddleware(): Redux.Middleware<{}, IStore> { const afterState = store.getState(); // If the action is part of a sync message, then do not send it to the extension. - const messageType = (action?.payload as BaseReduxActionPayload).messageType ?? MessageType.userAction; + const messageType = (action?.payload as BaseReduxActionPayload).messageType ?? MessageType.other; const isSyncMessage = (messageType & MessageType.syncAcrossSameNotebooks) === MessageType.syncAcrossSameNotebooks && (messageType & MessageType.syncAcrossSameNotebooks) === MessageType.syncWithLiveShare; @@ -341,11 +341,13 @@ export function createStore( // This is a message that has been sent from extension purely for synchronization purposes. // Unwrap the message. message = payload.type; + // This is a message that came in as a result of an outgoing message from another view. + basePayload.messageDirection = 'outgoing'; basePayload.messageType = payload.payload.messageType ?? MessageType.syncAcrossSameNotebooks; basePayload.data = payload.payload.data; } else { // Messages result of some user action. - basePayload.messageType = basePayload.messageType ?? MessageType.userAction; + basePayload.messageType = basePayload.messageType ?? MessageType.other; } store.dispatch({ type: message, payload: basePayload }); } From c63aa9495792261e4b0d7cbd2baa5c0156f717c2 Mon Sep 17 00:00:00 2001 From: Don Jayamanne Date: Tue, 18 Feb 2020 16:58:31 -0800 Subject: [PATCH 03/11] Oops --- .vscode/launch.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.vscode/launch.json b/.vscode/launch.json index 533d67a2ddb8..39f2c4888690 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -16,7 +16,7 @@ "outFiles": [ "${workspaceFolder}/out/**/*" ], - // "preLaunchTask": "Compile", + "preLaunchTask": "Compile", "skipFiles": [ "/**" ] From b4997d69ccee946dfb4dc43f60aa89bf1973af49 Mon Sep 17 00:00:00 2001 From: Don Jayamanne Date: Tue, 10 Mar 2020 11:41:01 -0700 Subject: [PATCH 04/11] Fix compilation --- .../datascience/interactive-ipynb/nativeEditor.ts | 2 +- .../interactive-ipynb/nativeEditorOldWebView.ts | 6 +++++- .../interactive-ipynb/nativeEditorSynchronizer.ts | 15 +++++++++++++-- 3 files changed, 19 insertions(+), 4 deletions(-) diff --git a/src/client/datascience/interactive-ipynb/nativeEditor.ts b/src/client/datascience/interactive-ipynb/nativeEditor.ts index fe677f07b0d5..065bd6ea9068 100644 --- a/src/client/datascience/interactive-ipynb/nativeEditor.ts +++ b/src/client/datascience/interactive-ipynb/nativeEditor.ts @@ -255,7 +255,7 @@ export class NativeEditor extends InteractiveBase implements INotebookEditor { this.synchronizer.notifyUserAction(payload, this); break; - case InteractiveWindowMessages.ReExecuteCell: + case InteractiveWindowMessages.ReExecuteCells: this.executedEvent.fire(this); break; diff --git a/src/client/datascience/interactive-ipynb/nativeEditorOldWebView.ts b/src/client/datascience/interactive-ipynb/nativeEditorOldWebView.ts index 88abc82cb188..0214c929e6da 100644 --- a/src/client/datascience/interactive-ipynb/nativeEditorOldWebView.ts +++ b/src/client/datascience/interactive-ipynb/nativeEditorOldWebView.ts @@ -50,6 +50,7 @@ import { } from '../types'; import { NativeEditor } from './nativeEditor'; import { NativeEditorStorage } from './nativeEditorStorage'; +import { NativeEditorSynchronizer } from './nativeEditorSynchronizer'; enum AskForSaveResult { Yes, @@ -85,6 +86,7 @@ export class NativeEditorOldWebView extends NativeEditor { @inject(ICommandManager) commandManager: ICommandManager, @inject(INotebookExporter) jupyterExporter: INotebookExporter, @inject(IWorkspaceService) workspaceService: IWorkspaceService, + @inject(NativeEditorSynchronizer) synchronizer: NativeEditorSynchronizer, @inject(INotebookEditorProvider) editorProvider: INotebookEditorProvider, @inject(IDataViewerProvider) dataExplorerProvider: IDataViewerProvider, @inject(IJupyterVariables) jupyterVariables: IJupyterVariables, @@ -114,6 +116,7 @@ export class NativeEditorOldWebView extends NativeEditor { commandManager, jupyterExporter, workspaceService, + synchronizer, editorProvider, dataExplorerProvider, jupyterVariables, @@ -127,6 +130,7 @@ export class NativeEditorOldWebView extends NativeEditor { switcher ); asyncRegistry.push(this); + synchronizer.disable(); } public async load(model: INotebookModel, webViewPanel: WebviewPanel): Promise { await super.load(model, webViewPanel); @@ -263,7 +267,7 @@ export class NativeEditorOldWebView extends NativeEditor { const defaultUri = Array.isArray(this.workspaceService.workspaceFolders) && - this.workspaceService.workspaceFolders.length > 0 + this.workspaceService.workspaceFolders.length > 0 ? this.workspaceService.workspaceFolders[0].uri : undefined; fileToSaveTo = await this.applicationShell.showSaveDialog({ diff --git a/src/client/datascience/interactive-ipynb/nativeEditorSynchronizer.ts b/src/client/datascience/interactive-ipynb/nativeEditorSynchronizer.ts index 94274162c8d9..2ee9a25a13e1 100644 --- a/src/client/datascience/interactive-ipynb/nativeEditorSynchronizer.ts +++ b/src/client/datascience/interactive-ipynb/nativeEditorSynchronizer.ts @@ -11,13 +11,20 @@ import { INotebookEditor } from '../types'; // tslint:disable: no-any -type UserActionNotificationCallback = (type: T, payload?: M[T]) => void; +type UserActionNotificationCallback = ( + type: T, + payload?: M[T] +) => void; @injectable() export class NativeEditorSynchronizer { private registeredNotebooks = new Map(); - constructor(@inject(IFileSystem) private readonly fs: IFileSystem) {} + private enabled = false; + constructor(@inject(IFileSystem) private readonly fs: IFileSystem) { } public notifyUserAction(message: SyncPayload, editor: INotebookEditor) { + if (!this.enabled) { + return; + } this.registeredNotebooks.forEach((cb, item) => { if (item !== editor && this.fs.arePathsSame(item.file.fsPath, editor.file.fsPath)) { cb(InteractiveWindowMessages.Sync, message as any); @@ -27,4 +34,8 @@ export class NativeEditorSynchronizer { public subscribeToUserActions(editor: INotebookEditor, cb: UserActionNotificationCallback) { this.registeredNotebooks.set(editor, cb); } + public disable() { + this.enabled = false; + this.registeredNotebooks.clear(); + } } From 60bd1c06357497f8fd7abe389c67837791e480d1 Mon Sep 17 00:00:00 2001 From: Don Jayamanne Date: Tue, 10 Mar 2020 11:57:04 -0700 Subject: [PATCH 05/11] Fixes --- .../nativeEditorOldWebView.ts | 1 + src/client/datascience/serviceRegistry.ts | 93 ++++--------------- 2 files changed, 20 insertions(+), 74 deletions(-) diff --git a/src/client/datascience/interactive-ipynb/nativeEditorOldWebView.ts b/src/client/datascience/interactive-ipynb/nativeEditorOldWebView.ts index 0214c929e6da..c7d6c7996381 100644 --- a/src/client/datascience/interactive-ipynb/nativeEditorOldWebView.ts +++ b/src/client/datascience/interactive-ipynb/nativeEditorOldWebView.ts @@ -130,6 +130,7 @@ export class NativeEditorOldWebView extends NativeEditor { switcher ); asyncRegistry.push(this); + // No ui syncing in old notebooks. synchronizer.disable(); } public async load(model: INotebookModel, webViewPanel: WebviewPanel): Promise { diff --git a/src/client/datascience/serviceRegistry.ts b/src/client/datascience/serviceRegistry.ts index 008f77423dfb..eb8e120414ef 100644 --- a/src/client/datascience/serviceRegistry.ts +++ b/src/client/datascience/serviceRegistry.ts @@ -120,8 +120,7 @@ import { // tslint:disable-next-line: max-func-body-length export function registerTypes(serviceManager: IServiceManager) { - const useCustomEditorApi = serviceManager.get(IApplicationEnvironment).packageJson - .enableProposedApi; + const useCustomEditorApi = serviceManager.get(IApplicationEnvironment).packageJson.enableProposedApi; serviceManager.addSingletonInstance(UseCustomEditorApi, useCustomEditorApi); serviceManager.add(ICellHashLogger, CellHashLogger, undefined, [INotebookExecutionLogger]); @@ -144,83 +143,43 @@ export function registerTypes(serviceManager: IServiceManager) { serviceManager.add(INotebookStorage, NativeEditorStorage); serviceManager.add(IPlotViewer, PlotViewer); serviceManager.addSingleton(ActiveEditorContextService, ActiveEditorContextService); - serviceManager.addSingleton( - CellOutputMimeTypeTracker, - CellOutputMimeTypeTracker, - undefined, - [IExtensionSingleActivationService, INotebookExecutionLogger] - ); + serviceManager.addSingleton(CellOutputMimeTypeTracker, CellOutputMimeTypeTracker, undefined, [IExtensionSingleActivationService, INotebookExecutionLogger]); serviceManager.addSingleton(CommandRegistry, CommandRegistry); serviceManager.addSingleton(DataViewerDependencyService, DataViewerDependencyService); serviceManager.addSingleton(ICodeCssGenerator, CodeCssGenerator); - serviceManager.addSingleton(ICodeLensFactory, CodeLensFactory, undefined, [ - IInteractiveWindowListener - ]); + serviceManager.addSingleton(ICodeLensFactory, CodeLensFactory, undefined, [IInteractiveWindowListener]); serviceManager.addSingleton(IDataScience, DataScience); - serviceManager.addSingleton( - IDataScienceCodeLensProvider, - DataScienceCodeLensProvider - ); - serviceManager.addSingleton( - IDataScienceCommandListener, - InteractiveWindowCommandListener - ); + serviceManager.addSingleton(IDataScienceCodeLensProvider, DataScienceCodeLensProvider); + serviceManager.addSingleton(IDataScienceCommandListener, InteractiveWindowCommandListener); serviceManager.addSingleton(IDataScienceCommandListener, NativeEditorCommandListener); serviceManager.addSingleton(IDataViewerProvider, DataViewerProvider); serviceManager.addSingleton(IDebugLocationTracker, DebugLocationTrackerFactory); serviceManager.addSingleton(IExtensionSingleActivationService, Activation); serviceManager.addSingleton(IExtensionSingleActivationService, Decorator); - serviceManager.addSingleton( - IExtensionSingleActivationService, - JupyterInterpreterSelectionCommand - ); - serviceManager.addSingleton( - IExtensionSingleActivationService, - PreWarmActivatedJupyterEnvironmentVariables - ); + serviceManager.addSingleton(IExtensionSingleActivationService, JupyterInterpreterSelectionCommand); + serviceManager.addSingleton(IExtensionSingleActivationService, PreWarmActivatedJupyterEnvironmentVariables); serviceManager.addSingleton(IExtensionSingleActivationService, ServerPreload); serviceManager.addSingleton(IInteractiveWindowListener, DataScienceSurveyBannerLogger); serviceManager.addSingleton(IInteractiveWindowProvider, InteractiveWindowProvider); serviceManager.addSingleton(IJupyterDebugger, JupyterDebugger, undefined, [ICellHashListener]); serviceManager.addSingleton(IJupyterExecution, JupyterExecutionFactory); serviceManager.addSingleton(IJupyterPasswordConnect, JupyterPasswordConnect); - serviceManager.addSingleton( - IJupyterSessionManagerFactory, - JupyterSessionManagerFactory - ); + serviceManager.addSingleton(IJupyterSessionManagerFactory, JupyterSessionManagerFactory); serviceManager.addSingleton(IJupyterVariables, JupyterVariables); - serviceManager.addSingleton( - INotebookEditorProvider, - useCustomEditorApi ? NativeEditorProvider : NativeEditorProviderOld - ); + serviceManager.addSingleton(INotebookEditorProvider, useCustomEditorApi ? NativeEditorProvider : NativeEditorProviderOld); serviceManager.addSingleton(IPlotViewerProvider, PlotViewerProvider); serviceManager.addSingleton(IStatusProvider, StatusProvider); serviceManager.addSingleton(IThemeFinder, ThemeFinder); serviceManager.addSingleton(JupyterCommandFinder, JupyterCommandFinder); serviceManager.addSingleton(JupyterCommandLineSelector, JupyterCommandLineSelector); - serviceManager.addSingleton( - JupyterCommandLineSelectorCommand, - JupyterCommandLineSelectorCommand - ); - serviceManager.addSingleton( - JupyterInterpreterDependencyService, - JupyterInterpreterDependencyService - ); - serviceManager.addSingleton( - JupyterInterpreterOldCacheStateStore, - JupyterInterpreterOldCacheStateStore - ); + serviceManager.addSingleton(JupyterCommandLineSelectorCommand, JupyterCommandLineSelectorCommand); + serviceManager.addSingleton(JupyterInterpreterDependencyService, JupyterInterpreterDependencyService); + serviceManager.addSingleton(JupyterInterpreterOldCacheStateStore, JupyterInterpreterOldCacheStateStore); serviceManager.addSingleton(JupyterInterpreterSelector, JupyterInterpreterSelector); serviceManager.addSingleton(JupyterInterpreterService, JupyterInterpreterService); - serviceManager.addSingleton( - JupyterInterpreterStateStore, - JupyterInterpreterStateStore - ); + serviceManager.addSingleton(JupyterInterpreterStateStore, JupyterInterpreterStateStore); serviceManager.addSingleton(JupyterServerSelector, JupyterServerSelector); - serviceManager.addSingleton( - JupyterServerSelectorCommand, - JupyterServerSelectorCommand - ); + serviceManager.addSingleton(JupyterServerSelectorCommand, JupyterServerSelectorCommand); serviceManager.addSingleton(KernelSelectionProvider, KernelSelectionProvider); serviceManager.addSingleton(KernelSelector, KernelSelector); serviceManager.addSingleton(KernelService, KernelService); @@ -231,27 +190,13 @@ export function registerTypes(serviceManager: IServiceManager) { serviceManager.addSingleton(NativeEditorSynchronizer, NativeEditorSynchronizer); // Temporary code, to allow users to revert to the old behavior. - const cfg = serviceManager - .get(IWorkspaceService) - .getConfiguration('python.dataScience', undefined); + const cfg = serviceManager.get(IWorkspaceService).getConfiguration('python.dataScience', undefined); if (cfg.get('useOldJupyterServer', false)) { - serviceManager.addSingleton( - IJupyterInterpreterDependencyManager, - JupyterCommandInterpreterDependencyService - ); - serviceManager.addSingleton( - IJupyterSubCommandExecutionService, - JupyterCommandFinderInterpreterExecutionService - ); + serviceManager.addSingleton(IJupyterInterpreterDependencyManager, JupyterCommandInterpreterDependencyService); + serviceManager.addSingleton(IJupyterSubCommandExecutionService, JupyterCommandFinderInterpreterExecutionService); } else { - serviceManager.addSingleton( - IJupyterInterpreterDependencyManager, - JupyterInterpreterSubCommandExecutionService - ); - serviceManager.addSingleton( - IJupyterSubCommandExecutionService, - JupyterInterpreterSubCommandExecutionService - ); + serviceManager.addSingleton(IJupyterInterpreterDependencyManager, JupyterInterpreterSubCommandExecutionService); + serviceManager.addSingleton(IJupyterSubCommandExecutionService, JupyterInterpreterSubCommandExecutionService); } registerGatherTypes(serviceManager); From 308cd7f6909f1722ce3db851fcb92374373125d7 Mon Sep 17 00:00:00 2001 From: Don Jayamanne Date: Tue, 10 Mar 2020 12:46:44 -0700 Subject: [PATCH 06/11] Allow syncing edits and disabled in old notebook --- .../interactive-ipynb/nativeEditorSynchronizer.ts | 2 +- .../interactive-common/redux/helpers.ts | 13 +++++++++++++ .../interactive-common/redux/reducers/transfer.ts | 8 ++++++-- 3 files changed, 20 insertions(+), 3 deletions(-) diff --git a/src/client/datascience/interactive-ipynb/nativeEditorSynchronizer.ts b/src/client/datascience/interactive-ipynb/nativeEditorSynchronizer.ts index 2ee9a25a13e1..4e3090c53fcd 100644 --- a/src/client/datascience/interactive-ipynb/nativeEditorSynchronizer.ts +++ b/src/client/datascience/interactive-ipynb/nativeEditorSynchronizer.ts @@ -19,7 +19,7 @@ type UserActionNotificationCallback = (); - private enabled = false; + private enabled = true; constructor(@inject(IFileSystem) private readonly fs: IFileSystem) { } public notifyUserAction(message: SyncPayload, editor: INotebookEditor) { if (!this.enabled) { diff --git a/src/datascience-ui/interactive-common/redux/helpers.ts b/src/datascience-ui/interactive-common/redux/helpers.ts index 3400fa34d9d2..e68b91d0c2a9 100644 --- a/src/datascience-ui/interactive-common/redux/helpers.ts +++ b/src/datascience-ui/interactive-common/redux/helpers.ts @@ -102,6 +102,19 @@ export function unwrapPostableAction( return { type, payload }; } +/** + * Whether this is a message type that indicates it is part of a scynchronization message. + */ +export function isSyncingMessage(messageType?: MessageType) { + if (!messageType) { + return false; + } + + return ( + (messageType && MessageType.syncAcrossSameNotebooks) === MessageType.syncAcrossSameNotebooks || + (messageType && MessageType.syncWithLiveShare) === MessageType.syncWithLiveShare + ); +} export function reBroadcastMessageIfRequired( dispatcher: Function, message: InteractiveWindowMessages | SharedMessages | CommonActionType | CssMessages, diff --git a/src/datascience-ui/interactive-common/redux/reducers/transfer.ts b/src/datascience-ui/interactive-common/redux/reducers/transfer.ts index 02894f56296b..f39d35bac67c 100644 --- a/src/datascience-ui/interactive-common/redux/reducers/transfer.ts +++ b/src/datascience-ui/interactive-common/redux/reducers/transfer.ts @@ -10,7 +10,7 @@ import { import { CssMessages } from '../../../../client/datascience/messages'; import { ICell } from '../../../../client/datascience/types'; import { extractInputText, getSelectedAndFocusedInfo, IMainState } from '../../mainState'; -import { postActionToExtension } from '../helpers'; +import { isSyncingMessage, postActionToExtension } from '../helpers'; import { Helpers } from './helpers'; import { CommonActionType, @@ -231,7 +231,11 @@ export namespace Transfer { // when focus is lost const index = arg.prevState.cellVMs.findIndex(c => c.cell.id === arg.payload.data.cellId); const selectionInfo = getSelectedAndFocusedInfo(arg.prevState); - if (index >= 0 && selectionInfo.focusedCellId === arg.payload.data.cellId) { + // If this is the focused cell, then user is editing it, hence it needs to be updated. + const isThisTheFocusedCell = selectionInfo.focusedCellId === arg.payload.data.cellId; + // If this edit is part of a sycning comging from another notebook, then we need to update it again. + const isSyncFromAnotherNotebook = isSyncingMessage(arg.payload.messageType); + if (index >= 0 && (isThisTheFocusedCell || isSyncFromAnotherNotebook)) { const newVMs = [...arg.prevState.cellVMs]; const current = arg.prevState.cellVMs[index]; const newCell = { From e66f21d82d3b7ba95ae5b47c00cfe81b99d7d934 Mon Sep 17 00:00:00 2001 From: Don Jayamanne Date: Tue, 10 Mar 2020 12:49:35 -0700 Subject: [PATCH 07/11] Fix formatting --- src/client/datascience/interactive-common/types.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/client/datascience/interactive-common/types.ts b/src/client/datascience/interactive-common/types.ts index 9ba94ccc0d3e..3c22935868a2 100644 --- a/src/client/datascience/interactive-common/types.ts +++ b/src/client/datascience/interactive-common/types.ts @@ -32,11 +32,11 @@ type BaseDataWithPayload = { // This forms the base content of every payload in all dispatchers. export type BaseReduxActionPayload = T extends never ? T extends undefined - ? BaseData - : BaseDataWithPayload + ? BaseData + : BaseDataWithPayload : BaseDataWithPayload; -// tslint:disable-next-line: no-any export type SyncPayload = { type: InteractiveWindowMessages | SharedMessages | CommonActionType | CssMessages; + // tslint:disable-next-line: no-any payload: BaseReduxActionPayload; }; From 826a693fb687a4307ee1871524e82d4f527697fd Mon Sep 17 00:00:00 2001 From: Don Jayamanne Date: Tue, 10 Mar 2020 12:50:16 -0700 Subject: [PATCH 08/11] Fixes --- .../datascience/interactive-ipynb/nativeEditorSynchronizer.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/client/datascience/interactive-ipynb/nativeEditorSynchronizer.ts b/src/client/datascience/interactive-ipynb/nativeEditorSynchronizer.ts index 4e3090c53fcd..435d02f9163c 100644 --- a/src/client/datascience/interactive-ipynb/nativeEditorSynchronizer.ts +++ b/src/client/datascience/interactive-ipynb/nativeEditorSynchronizer.ts @@ -20,7 +20,7 @@ type UserActionNotificationCallback = (); private enabled = true; - constructor(@inject(IFileSystem) private readonly fs: IFileSystem) { } + constructor(@inject(IFileSystem) private readonly fs: IFileSystem) {} public notifyUserAction(message: SyncPayload, editor: INotebookEditor) { if (!this.enabled) { return; From 4094a9295d65c0d5a80450592588377e17fc6713 Mon Sep 17 00:00:00 2001 From: Don Jayamanne Date: Tue, 10 Mar 2020 13:40:26 -0700 Subject: [PATCH 09/11] Fixes --- .../datascience/interactive-ipynb/nativeEditorOldWebView.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/client/datascience/interactive-ipynb/nativeEditorOldWebView.ts b/src/client/datascience/interactive-ipynb/nativeEditorOldWebView.ts index c7d6c7996381..b870fd65e294 100644 --- a/src/client/datascience/interactive-ipynb/nativeEditorOldWebView.ts +++ b/src/client/datascience/interactive-ipynb/nativeEditorOldWebView.ts @@ -268,7 +268,7 @@ export class NativeEditorOldWebView extends NativeEditor { const defaultUri = Array.isArray(this.workspaceService.workspaceFolders) && - this.workspaceService.workspaceFolders.length > 0 + this.workspaceService.workspaceFolders.length > 0 ? this.workspaceService.workspaceFolders[0].uri : undefined; fileToSaveTo = await this.applicationShell.showSaveDialog({ From aad521b52a31fbe56ab1ec9b139bbea8418f2c57 Mon Sep 17 00:00:00 2001 From: Don Jayamanne Date: Tue, 10 Mar 2020 13:45:41 -0700 Subject: [PATCH 10/11] Disable --- src/test/datascience/dataScienceIocContainer.ts | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/test/datascience/dataScienceIocContainer.ts b/src/test/datascience/dataScienceIocContainer.ts index 8ec338021b60..36028c212fac 100644 --- a/src/test/datascience/dataScienceIocContainer.ts +++ b/src/test/datascience/dataScienceIocContainer.ts @@ -181,6 +181,7 @@ import { NativeEditor } from '../../client/datascience/interactive-ipynb/nativeE import { NativeEditorCommandListener } from '../../client/datascience/interactive-ipynb/nativeEditorCommandListener'; import { NativeEditorOldWebView } from '../../client/datascience/interactive-ipynb/nativeEditorOldWebView'; import { NativeEditorStorage } from '../../client/datascience/interactive-ipynb/nativeEditorStorage'; +import { NativeEditorSynchronizer } from '../../client/datascience/interactive-ipynb/nativeEditorSynchronizer'; import { InteractiveWindow } from '../../client/datascience/interactive-window/interactiveWindow'; import { InteractiveWindowCommandListener } from '../../client/datascience/interactive-window/interactiveWindowCommandListener'; import { JupyterCommandFactory } from '../../client/datascience/jupyter/interpreter/jupyterCommand'; @@ -1061,7 +1062,9 @@ export class DataScienceIocContainer extends UnitTestIocContainer { this.serviceManager.addSingleton(IJupyterPasswordConnect, JupyterPasswordConnect); this.serviceManager.addSingleton(IProcessLogger, ProcessLogger); } - + this.serviceManager.addSingleton(NativeEditorSynchronizer, NativeEditorSynchronizer); + // Disable syncrhonizing edits + this.serviceContainer.get(NativeEditorSynchronizer).disable(); const dummyDisposable = { dispose: () => { return; @@ -1320,7 +1323,7 @@ export class DataScienceIocContainer extends UnitTestIocContainer { this.postMessageToWebPanel(msg); }, // tslint:disable-next-line:no-any no-empty - setState: (_msg: any) => {}, + setState: (_msg: any) => { }, // tslint:disable-next-line:no-any no-empty getState: () => { return {}; From ad544d6354c4f3c0f2bd563eaba04352700405a5 Mon Sep 17 00:00:00 2001 From: Don Jayamanne Date: Tue, 10 Mar 2020 14:22:25 -0700 Subject: [PATCH 11/11] Fix linter issues --- src/test/datascience/dataScienceIocContainer.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/datascience/dataScienceIocContainer.ts b/src/test/datascience/dataScienceIocContainer.ts index 36028c212fac..30a6f12336db 100644 --- a/src/test/datascience/dataScienceIocContainer.ts +++ b/src/test/datascience/dataScienceIocContainer.ts @@ -1323,7 +1323,7 @@ export class DataScienceIocContainer extends UnitTestIocContainer { this.postMessageToWebPanel(msg); }, // tslint:disable-next-line:no-any no-empty - setState: (_msg: any) => { }, + setState: (_msg: any) => {}, // tslint:disable-next-line:no-any no-empty getState: () => { return {};