Skip to content

Commit

Permalink
Merged PR posit-dev/positron-python#218: Add force quit method
Browse files Browse the repository at this point in the history
Merge pull request #218 from posit-dev/feature/force-quit

Add force quit method
--------------------
Commit message for posit-dev/positron-python@b06f70d:

add force quit method


Authored-by: Jonathan McPherson <jonathan@rstudio.com>
Signed-off-by: Jonathan McPherson <jonathan@rstudio.com>
  • Loading branch information
jmcphers committed Sep 29, 2023
1 parent 94038f1 commit 1cf48c1
Show file tree
Hide file tree
Showing 2 changed files with 57 additions and 20 deletions.
24 changes: 21 additions & 3 deletions extensions/positron-python/positron-dts/positron.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -358,6 +358,7 @@ declare module 'positron' {
export enum RuntimeClientType {
Environment = 'positron.environment',
Lsp = 'positron.lsp',
Dap = 'positron.dap',
Plot = 'positron.plot',
DataViewer = 'positron.dataViewer',
FrontEnd = 'positron.frontEnd',
Expand Down Expand Up @@ -508,10 +509,19 @@ declare module 'positron' {
restart(): Thenable<void>;

/**
* Shut down the runtime; returns a Thenable that resolves when the runtime shutdown
* sequence has been successfully started (not necessarily when it has completed).
* Shut down the runtime; returns a Thenable that resolves when the
* runtime shutdown sequence has been successfully started (not
* necessarily when it has completed).
*/
shutdown(): Thenable<void>;

/**
* Forcibly quits the runtime; returns a Thenable that resolves when the
* runtime has been terminated. This may be called by Positron if the
* runtime fails to respond to an interrupt and/or shutdown call, and
* should forcibly terminate any underlying processes.
*/
forceQuit(): Thenable<void>;
}


Expand Down Expand Up @@ -673,7 +683,8 @@ declare module 'positron' {
export interface StatementRangeProvider {
/**
* Given a cursor position, return the range of the statement that the
* cursor is within.
* cursor is within. If the cursor is not within a statement, return the
* range of the next statement, if one exists.
*
* @param document The document in which the command was invoked.
* @param position The position at which the command was invoked.
Expand Down Expand Up @@ -758,6 +769,13 @@ declare module 'positron' {
*/
export function selectLanguageRuntime(runtimeId: string): Thenable<void>;

/**
* Restart a running runtime.
*
* @param runtimeId The ID of the running runtime to restart.
*/
export function restartLanguageRuntime(runtimeId: string): Thenable<void>;

/**
* Register a handler for runtime client instances. This handler will be called
* whenever a new client instance is created by a language runtime of the given
Expand Down
53 changes: 36 additions & 17 deletions extensions/positron-python/src/client/positron/runtime.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@ import { PythonLsp, LspState } from './lsp';
* Protocol client.
*/
export class PythonRuntime implements positron.LanguageRuntime, vscode.Disposable {

/** The Language Server Protocol client wrapper */
private _lsp: PythonLsp;

Expand All @@ -33,12 +32,10 @@ export class PythonRuntime implements positron.LanguageRuntime, vscode.Disposabl
private _kernel?: JupyterLanguageRuntime;

/** The emitter for language runtime messages */
private _messageEmitter =
new vscode.EventEmitter<positron.LanguageRuntimeMessage>();
private _messageEmitter = new vscode.EventEmitter<positron.LanguageRuntimeMessage>();

/** The emitter for language runtime state changes */
private _stateEmitter =
new vscode.EventEmitter<positron.RuntimeState>();
private _stateEmitter = new vscode.EventEmitter<positron.RuntimeState>();

/** The Jupyter Adapter extension API */
private adapterApi?: JupyterAdapterApi;
Expand All @@ -52,7 +49,6 @@ export class PythonRuntime implements positron.LanguageRuntime, vscode.Disposabl
private readonly installer: IInstaller,
readonly extra?: JupyterKernelExtra,
) {

this._lsp = new PythonLsp(metadata.languageVersion, languageClientOptions);
this._queue = new PQueue({ concurrency: 1 });
this.onDidReceiveRuntimeMessage = this._messageEmitter.event;
Expand All @@ -61,14 +57,18 @@ export class PythonRuntime implements positron.LanguageRuntime, vscode.Disposabl
this.onDidChangeRuntimeState((state) => {
this.onStateChange(state);
});

}

onDidReceiveRuntimeMessage: vscode.Event<positron.LanguageRuntimeMessage>;

onDidChangeRuntimeState: vscode.Event<positron.RuntimeState>;

execute(code: string, id: string, mode: positron.RuntimeCodeExecutionMode, errorBehavior: positron.RuntimeErrorBehavior): void {
execute(
code: string,
id: string,
mode: positron.RuntimeCodeExecutionMode,
errorBehavior: positron.RuntimeErrorBehavior,
): void {
if (this._kernel) {
this._kernel.execute(code, id, mode, errorBehavior);
} else {
Expand Down Expand Up @@ -139,18 +139,26 @@ export class PythonRuntime implements positron.LanguageRuntime, vscode.Disposabl
// Using a process to install modules avoids using the terminal service,
// which has issues waiting for the outcome of the install.
const installOptions: InstallOptions = { installAsProcess: true };
const messageOptions: vscode.MessageOptions = { modal: true }
const messageOptions: vscode.MessageOptions = { modal: true };

const response = await this.installer.promptToInstall(Product.ipykernel,
this.interpreter, installerToken, undefined, installOptions, messageOptions);
const response = await this.installer.promptToInstall(
Product.ipykernel,
this.interpreter,
installerToken,
undefined,
installOptions,
messageOptions,
);

switch (response) {
case InstallerResponse.Installed:
traceInfo(`Successfully installed ipykernel for ${this.interpreter?.displayName}`);
break;
case InstallerResponse.Ignore:
case InstallerResponse.Disabled:
throw new Error(`Could not start runtime: failed to install ipykernel for ${this.interpreter?.displayName}.`);
throw new Error(
`Could not start runtime: failed to install ipykernel for ${this.interpreter?.displayName}.`,
);
default:
throw new Error(`Unknown installer response type: ${response}`);
}
Expand Down Expand Up @@ -193,6 +201,21 @@ export class PythonRuntime implements positron.LanguageRuntime, vscode.Disposabl
}
}

async forceQuit(): Promise<void> {
if (this._kernel) {
// Stop the LSP client before shutting down the kernel. We only give
// the LSP a quarter of a second to shut down before we force the
// kernel to quit; we need to balance the need to respond to the
// force-quit quickly with the fact that the LSP will show error
// messages if we yank the kernel out from beneath it without
// warning.
await Promise.race([this._lsp.deactivate(true), new Promise((resolve) => setTimeout(resolve, 250))]);
return this._kernel.forceQuit();
} else {
throw new Error('Cannot force quit; kernel not started');
}
}

async dispose() {
await this._lsp.dispose();
if (this._kernel) {
Expand All @@ -209,11 +232,7 @@ export class PythonRuntime implements positron.LanguageRuntime, vscode.Disposabl
await ext.activate();
}
this.adapterApi = ext?.exports as JupyterAdapterApi;
const kernel = this.adapterApi.adaptKernel(
this.kernelSpec,
this.metadata,
this.dynState,
this.extra);
const kernel = this.adapterApi.adaptKernel(this.kernelSpec, this.metadata, this.dynState, this.extra);

kernel.onDidChangeRuntimeState((state) => {
this._stateEmitter.fire(state);
Expand Down

0 comments on commit 1cf48c1

Please sign in to comment.