Skip to content

Commit a8d965b

Browse files
authored
Display commands when necessary (#9986)
For #8869
1 parent 0562234 commit a8d965b

File tree

10 files changed

+138
-55
lines changed

10 files changed

+138
-55
lines changed

news/3 Code Health/8869.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Display `Commands` related to `Interactive Window` and `Notebooks` only when necessary.

package.json

Lines changed: 66 additions & 31 deletions
Large diffs are not rendered by default.

src/client/common/contextKey.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
import { ICommandManager } from './application/types';
22

33
export class ContextKey {
4+
public get value(): boolean | undefined {
5+
return this.lastValue;
6+
}
47
private lastValue?: boolean;
58

69
constructor(private name: string, private commandManager: ICommandManager) {}

src/client/datascience/constants.ts

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -79,12 +79,16 @@ export namespace EditorContexts {
7979
export const HaveInteractiveCells = 'python.datascience.haveinteractivecells';
8080
export const HaveRedoableCells = 'python.datascience.haveredoablecells';
8181
export const HaveInteractive = 'python.datascience.haveinteractive';
82-
export const IsInteractive = 'python.datascience.isinteractive';
82+
export const IsInteractiveActive = 'python.datascience.isinteractiveactive';
8383
export const OwnsSelection = 'python.datascience.ownsSelection';
8484
export const HaveNativeCells = 'python.datascience.havenativecells';
8585
export const HaveNativeRedoableCells = 'python.datascience.havenativeredoablecells';
8686
export const HaveNative = 'python.datascience.havenative';
87-
export const IsNative = 'python.datascience.isnative';
87+
export const IsNativeActive = 'python.datascience.isnativeactive';
88+
export const IsInteractiveOrNativeActive = 'python.datascience.isinteractiveornativeactive';
89+
export const IsPythonOrNativeActive = 'python.datascience.ispythonornativeactive';
90+
export const IsPythonOrInteractiveActive = 'python.datascience.ispythonorinteractiveeactive';
91+
export const IsPythonOrInteractiveOrNativeActive = 'python.datascience.ispythonorinteractiveornativeeactive';
8892
export const HaveCellSelected = 'python.datascience.havecellselected';
8993
}
9094

src/client/datascience/context/activeEditorContext.ts

Lines changed: 34 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,10 @@
44
'use strict';
55

66
import { inject, injectable } from 'inversify';
7+
import { TextEditor } from 'vscode';
78
import { IExtensionSingleActivationService } from '../../activation/types';
8-
import { ICommandManager } from '../../common/application/types';
9+
import { ICommandManager, IDocumentManager } from '../../common/application/types';
10+
import { PYTHON_LANGUAGE } from '../../common/constants';
911
import { ContextKey } from '../../common/contextKey';
1012
import { IDisposable, IDisposableRegistry } from '../../common/types';
1113
import { EditorContexts } from '../constants';
@@ -14,28 +16,55 @@ import { IInteractiveWindow, IInteractiveWindowProvider, INotebookEditor, INoteb
1416
@injectable()
1517
export class ActiveEditorContextService implements IExtensionSingleActivationService, IDisposable {
1618
private readonly disposables: IDisposable[] = [];
19+
private nativeContext: ContextKey;
20+
private interactiveContext: ContextKey;
21+
private interactiveOrNativeContext: ContextKey;
22+
private pythonOrInteractiveContext: ContextKey;
23+
private pythonOrNativeContext: ContextKey;
24+
private pythonOrInteractiveOrNativeContext: ContextKey;
25+
private isPythonFileActive: boolean = false;
1726
constructor(
1827
@inject(IInteractiveWindowProvider) private readonly interactiveProvider: IInteractiveWindowProvider,
1928
@inject(INotebookEditorProvider) private readonly notebookProvider: INotebookEditorProvider,
29+
@inject(IDocumentManager) private readonly docManager: IDocumentManager,
2030
@inject(ICommandManager) private readonly commandManager: ICommandManager,
2131
@inject(IDisposableRegistry) disposables: IDisposableRegistry
2232
) {
2333
disposables.push(this);
34+
this.nativeContext = new ContextKey(EditorContexts.IsNativeActive, this.commandManager);
35+
this.interactiveContext = new ContextKey(EditorContexts.IsInteractiveActive, this.commandManager);
36+
this.interactiveOrNativeContext = new ContextKey(EditorContexts.IsInteractiveOrNativeActive, this.commandManager);
37+
this.pythonOrNativeContext = new ContextKey(EditorContexts.IsPythonOrNativeActive, this.commandManager);
38+
this.pythonOrInteractiveContext = new ContextKey(EditorContexts.IsPythonOrInteractiveActive, this.commandManager);
39+
this.pythonOrInteractiveOrNativeContext = new ContextKey(EditorContexts.IsPythonOrInteractiveOrNativeActive, this.commandManager);
2440
}
2541
public dispose() {
2642
this.disposables.forEach(item => item.dispose());
2743
}
2844
public async activate(): Promise<void> {
45+
this.docManager.onDidChangeActiveTextEditor(this.onDidChangeActiveTextEditor, this, this.disposables);
2946
this.interactiveProvider.onDidChangeActiveInteractiveWindow(this.onDidChangeActiveInteractiveWindow, this, this.disposables);
3047
this.notebookProvider.onDidChangeActiveNotebookEditor(this.onDidChangeActiveNotebookEditor, this, this.disposables);
3148
}
3249

3350
private onDidChangeActiveInteractiveWindow(e?: IInteractiveWindow) {
34-
const interactiveContext = new ContextKey(EditorContexts.IsInteractive, this.commandManager);
35-
interactiveContext.set(!!e).ignoreErrors();
51+
this.interactiveContext.set(!!e).ignoreErrors();
52+
this.updateMergedContexts();
3653
}
3754
private onDidChangeActiveNotebookEditor(e?: INotebookEditor) {
38-
const interactiveContext = new ContextKey(EditorContexts.IsNative, this.commandManager);
39-
interactiveContext.set(!!e).ignoreErrors();
55+
this.nativeContext.set(!!e).ignoreErrors();
56+
this.updateMergedContexts();
57+
}
58+
private onDidChangeActiveTextEditor(e?: TextEditor) {
59+
this.isPythonFileActive = e?.document.languageId === PYTHON_LANGUAGE;
60+
this.updateMergedContexts();
61+
}
62+
private updateMergedContexts() {
63+
this.interactiveOrNativeContext.set(this.nativeContext.value === true && this.interactiveContext.value === true).ignoreErrors();
64+
this.pythonOrNativeContext.set(this.nativeContext.value === true || this.isPythonFileActive === true).ignoreErrors();
65+
this.pythonOrInteractiveContext.set(this.interactiveContext.value === true || this.isPythonFileActive === true).ignoreErrors();
66+
this.pythonOrInteractiveOrNativeContext
67+
.set(this.nativeContext.value === true || (this.interactiveContext.value === true && this.isPythonFileActive === true))
68+
.ignoreErrors();
4069
}
4170
}

src/client/datascience/interactive-common/interactiveBase.ts

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,8 @@ import {
6969
INotebookServerOptions,
7070
InterruptResult,
7171
IStatusProvider,
72-
IThemeFinder
72+
IThemeFinder,
73+
WebViewViewChangeEventArgs
7374
} from '../types';
7475
import { WebViewHost } from '../webViewHost';
7576
import { InteractiveWindowMessageListener } from './interactiveWindowMessageListener';
@@ -389,7 +390,7 @@ export abstract class InteractiveBase extends WebViewHost<IInteractiveWindowMapp
389390
});
390391
}
391392

392-
protected onViewStateChanged(_visible: boolean, active: boolean) {
393+
protected onViewStateChanged(args: WebViewViewChangeEventArgs) {
393394
// Only activate if the active editor is empty. This means that
394395
// vscode thinks we are actually supposed to have focus. It would be
395396
// nice if they would more accurrately tell us this, but this works for now.
@@ -398,7 +399,7 @@ export abstract class InteractiveBase extends WebViewHost<IInteractiveWindowMapp
398399
// it's been activated. However if there's no active text editor and we're active, we
399400
// can safely attempt to give ourselves focus. This won't actually give us focus if we aren't
400401
// allowed to have it.
401-
if (active && !this.viewState.active) {
402+
if (args.current.active && !args.previous.active) {
402403
this.activating().ignoreErrors();
403404
}
404405
}

src/client/datascience/interactive-ipynb/nativeEditor.ts

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,8 @@ import {
5656
INotebookImporter,
5757
INotebookServerOptions,
5858
IStatusProvider,
59-
IThemeFinder
59+
IThemeFinder,
60+
WebViewViewChangeEventArgs
6061
} from '../types';
6162

6263
// tslint:disable-next-line:no-require-imports no-var-requires
@@ -495,12 +496,12 @@ export class NativeEditor extends InteractiveBase implements INotebookEditor {
495496
}
496497
}
497498

498-
protected async onViewStateChanged(visible: boolean, active: boolean) {
499-
super.onViewStateChanged(visible, active);
499+
protected async onViewStateChanged(args: WebViewViewChangeEventArgs) {
500+
super.onViewStateChanged(args);
500501

501502
// Update our contexts
502503
const interactiveContext = new ContextKey(EditorContexts.HaveNative, this.commandManager);
503-
interactiveContext.set(visible && active).catch();
504+
interactiveContext.set(args.current.visible && args.current.active).catch();
504505
this._onDidChangeViewState.fire();
505506
}
506507

src/client/datascience/interactive-window/interactiveWindow.ts

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,8 @@ import {
3434
INotebookExporter,
3535
INotebookServerOptions,
3636
IStatusProvider,
37-
IThemeFinder
37+
IThemeFinder,
38+
WebViewViewChangeEventArgs
3839
} from '../types';
3940

4041
const historyReactDir = path.join(EXTENSION_ROOT_DIR, 'out', 'datascience-ui', 'notebook');
@@ -241,8 +242,8 @@ export class InteractiveWindow extends InteractiveBase implements IInteractiveWi
241242
public scrollToCell(id: string): void {
242243
this.postMessage(InteractiveWindowMessages.ScrollToCell, { id }).ignoreErrors();
243244
}
244-
protected async onViewStateChanged(visible: boolean, active: boolean) {
245-
super.onViewStateChanged(visible, active);
245+
protected async onViewStateChanged(args: WebViewViewChangeEventArgs) {
246+
super.onViewStateChanged(args);
246247
this._onDidChangeViewState.fire();
247248
}
248249

src/client/datascience/types.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -725,3 +725,9 @@ export interface IJupyterInterpreterDependencyManager {
725725
*/
726726
installMissingDependencies(err?: JupyterInstallError): Promise<void>;
727727
}
728+
729+
type WebViewViewState = {
730+
readonly visible: boolean;
731+
readonly active: boolean;
732+
};
733+
export type WebViewViewChangeEventArgs = { current: WebViewViewState; previous: WebViewViewState };

src/client/datascience/webViewHost.ts

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ import { StopWatch } from '../common/utils/stopWatch';
1616
import { captureTelemetry, sendTelemetryEvent } from '../telemetry';
1717
import { DefaultTheme, Telemetry } from './constants';
1818
import { CssMessages, IGetCssRequest, IGetMonacoThemeRequest, SharedMessages } from './messages';
19-
import { ICodeCssGenerator, IDataScienceExtraSettings, IThemeFinder } from './types';
19+
import { ICodeCssGenerator, IDataScienceExtraSettings, IThemeFinder, WebViewViewChangeEventArgs } from './types';
2020

2121
@injectable() // For some reason this is necessary to get the class hierarchy to work.
2222
export class WebViewHost<IMapping> implements IDisposable {
@@ -144,7 +144,7 @@ export class WebViewHost<IMapping> implements IDisposable {
144144
this.messageListener.onMessage(type.toString(), payload);
145145
}
146146

147-
protected onViewStateChanged(_visible: boolean, _active: boolean) {
147+
protected onViewStateChanged(_args: WebViewViewChangeEventArgs) {
148148
noop();
149149
}
150150

@@ -263,11 +263,13 @@ export class WebViewHost<IMapping> implements IDisposable {
263263
}
264264

265265
private webPanelViewStateChanged = (webPanel: IWebPanel) => {
266-
const isVisible = webPanel.isVisible();
267-
const isActive = webPanel.isActive();
268-
this.onViewStateChanged(isVisible, isActive);
269-
this.viewState.visible = isVisible;
270-
this.viewState.active = isActive;
266+
const visible = webPanel.isVisible();
267+
const active = webPanel.isActive();
268+
const current = { visible, active };
269+
const previous = { visible: this.viewState.visible, active: this.viewState.active };
270+
this.viewState.visible = visible;
271+
this.viewState.active = active;
272+
this.onViewStateChanged({ current, previous });
271273
};
272274

273275
@captureTelemetry(Telemetry.WebviewStyleUpdate)

0 commit comments

Comments
 (0)