Skip to content

Commit 1f02187

Browse files
committed
Retrieve active sessions from the main thread
1 parent 8fb2eea commit 1f02187

File tree

5 files changed

+34
-44
lines changed

5 files changed

+34
-44
lines changed

extensions/positron-r/src/commands.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,7 @@ export async function registerCommands(context: vscode.ExtensionContext, runtime
7676
if (!isInstalled) {
7777
return;
7878
}
79-
const session = RSessionManager.instance.getConsoleSession();
79+
const session = await RSessionManager.instance.getConsoleSession();
8080
if (!session) {
8181
return;
8282
}
@@ -169,7 +169,7 @@ export async function registerCommands(context: vscode.ExtensionContext, runtime
169169
}),
170170

171171
vscode.commands.registerCommand('r.scriptPath', async () => {
172-
const session = RSessionManager.instance.getConsoleSession();
172+
const session = await RSessionManager.instance.getConsoleSession();
173173
if (!session) {
174174
throw new Error(`Cannot get Rscript path; no R session available`);
175175
}

extensions/positron-r/src/llm-tools.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ export function registerRLanguageModelTools(context: vscode.ExtensionContext): v
1515
const rListPackageHelpTopicsTool = vscode.lm.registerTool<{ sessionIdentifier: string; packageName: string }>('listPackageHelpTopics', {
1616
invoke: async (options, token) => {
1717
const manager = RSessionManager.instance;
18-
const session = manager.getSessionById(options.input.sessionIdentifier);
18+
const session = await manager.getSessionById(options.input.sessionIdentifier);
1919
if (!session) {
2020
return new vscode.LanguageModelToolResult([
2121
new vscode.LanguageModelTextPart(`No active R session with identifier ${options.input.sessionIdentifier}`),
@@ -44,7 +44,7 @@ export function registerRLanguageModelTools(context: vscode.ExtensionContext): v
4444
const rListAvailableVignettesTool = vscode.lm.registerTool<{ sessionIdentifier: string; packageName: string }>('listAvailableVignettes', {
4545
invoke: async (options, token) => {
4646
const manager = RSessionManager.instance;
47-
const session = manager.getSessionById(options.input.sessionIdentifier);
47+
const session = await manager.getSessionById(options.input.sessionIdentifier);
4848
if (!session) {
4949
return new vscode.LanguageModelToolResult([
5050
new vscode.LanguageModelTextPart(`No active R session with identifier ${options.input.sessionIdentifier}`),
@@ -73,7 +73,7 @@ export function registerRLanguageModelTools(context: vscode.ExtensionContext): v
7373
const rGetPackageVignetteTool = vscode.lm.registerTool<{ sessionIdentifier: string; packageName: string; vignetteName: string }>('getPackageVignette', {
7474
invoke: async (options, token) => {
7575
const manager = RSessionManager.instance;
76-
const session = manager.getSessionById(options.input.sessionIdentifier);
76+
const session = await manager.getSessionById(options.input.sessionIdentifier);
7777
if (!session) {
7878
return new vscode.LanguageModelToolResult([
7979
new vscode.LanguageModelTextPart(`No active R session with identifier ${options.input.sessionIdentifier}`),
@@ -103,7 +103,7 @@ export function registerRLanguageModelTools(context: vscode.ExtensionContext): v
103103
const rGetHelpPageTool = vscode.lm.registerTool<{ sessionIdentifier: string; packageName?: string; helpTopic: string }>('getHelpPage', {
104104
invoke: async (options, token) => {
105105
const manager = RSessionManager.instance;
106-
const session = manager.getSessionById(options.input.sessionIdentifier);
106+
const session = await manager.getSessionById(options.input.sessionIdentifier);
107107
if (!session) {
108108
return new vscode.LanguageModelToolResult([
109109
new vscode.LanguageModelTextPart(`No active R session with identifier ${options.input.sessionIdentifier}`),

extensions/positron-r/src/session-manager.ts

Lines changed: 15 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,10 @@
55

66
import * as positron from 'positron';
77
import * as vscode from 'vscode';
8-
import { RSession } from './session';
8+
import { RSession, getActiveRSessions } from './session';
99

1010
/**
11-
* Manages all the R sessions. We keep our own references to each session in a
12-
* singleton instance of this class so that we can invoke methods/check status
13-
* directly, without going through Positron's API.
11+
* Manages all the R sessions.
1412
*/
1513
export class RSessionManager implements vscode.Disposable {
1614
/// Singleton instance
@@ -21,9 +19,6 @@ export class RSessionManager implements vscode.Disposable {
2119
/// but we may improve on this in the future so it is good practice to track them.
2220
private readonly _disposables: vscode.Disposable[] = [];
2321

24-
/// Map of session IDs to RSession instances
25-
private _sessions: Map<string, RSession> = new Map();
26-
2722
/// The most recent foreground R session (foreground implies it is a console session)
2823
private _lastForegroundSessionId: string | null = null;
2924

@@ -50,24 +45,11 @@ export class RSessionManager implements vscode.Disposable {
5045
}
5146

5247
/**
53-
* Registers a runtime with the manager. Throws an error if a runtime with
54-
* the same ID is already registered.
48+
* Registers a runtime with the manager.
5549
*
56-
* @param id The runtime's ID
57-
* @param runtime The runtime.
50+
* @param session The session.
5851
*/
59-
setSession(sessionId: string, session: RSession): void {
60-
if (this._sessions.has(sessionId)) {
61-
throw new Error(`Session ${sessionId} already registered.`);
62-
}
63-
this._sessions.set(sessionId, session);
64-
65-
session.register({
66-
dispose: () => {
67-
this._sessions.delete(sessionId);
68-
}
69-
});
70-
52+
setSession(session: RSession): void {
7153
session.register(
7254
session.onDidChangeRuntimeState(async (state) => {
7355
await this.didChangeSessionRuntimeState(session, state);
@@ -106,9 +88,8 @@ export class RSessionManager implements vscode.Disposable {
10688
return;
10789
}
10890

109-
// TODO: Switch to `getActiveRSessions()` built on `positron.runtime.getActiveSessions()`
110-
// and remove `this._sessions` entirely.
111-
const session = this._sessions.get(sessionId);
91+
const sessions = await getActiveRSessions();
92+
const session = sessions.find(s => s.metadata.sessionId === sessionId);
11293
if (!session) {
11394
// The foreground session is for another language.
11495
return;
@@ -127,7 +108,8 @@ export class RSessionManager implements vscode.Disposable {
127108
*/
128109
private async activateConsoleSession(session: RSession, reason: string): Promise<void> {
129110
// Deactivate other console session servers first
130-
await Promise.all(Array.from(this._sessions.values())
111+
const sessions = await getActiveRSessions();
112+
await Promise.all(sessions
131113
.filter(s => {
132114
return s.metadata.sessionId !== session.metadata.sessionId &&
133115
s.metadata.sessionMode === positron.LanguageRuntimeSessionMode.Console;
@@ -159,9 +141,10 @@ export class RSessionManager implements vscode.Disposable {
159141
*
160142
* @returns The R console session, or undefined if there isn't one.
161143
*/
162-
getConsoleSession(): RSession | undefined {
144+
async getConsoleSession(): Promise<RSession | undefined> {
145+
const sessions = await getActiveRSessions();
146+
163147
// Sort the sessions by creation time (descending)
164-
const sessions = Array.from(this._sessions.values());
165148
sessions.sort((a, b) => b.created - a.created);
166149

167150
// Remove any sessions that aren't console sessions and have either
@@ -193,8 +176,9 @@ export class RSessionManager implements vscode.Disposable {
193176
* @param sessionId The session identifier
194177
* @returns The R session, or undefined if not found
195178
*/
196-
getSessionById(sessionId: string): RSession | undefined {
197-
return this._sessions.get(sessionId);
179+
async getSessionById(sessionId: string): Promise<RSession | undefined> {
180+
const sessions = await getActiveRSessions();
181+
return sessions.find(s => s.metadata.sessionId === sessionId);
198182
}
199183

200184
/**

extensions/positron-r/src/session.ts

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -129,7 +129,7 @@ export class RSession implements positron.LanguageRuntimeSession, vscode.Disposa
129129
this._created = Date.now();
130130

131131
// Register this session with the session manager
132-
RSessionManager.instance.setSession(metadata.sessionId, this);
132+
RSessionManager.instance.setSession(this);
133133

134134
this.onDidChangeRuntimeState(async (state) => {
135135
await this.onStateChange(state);
@@ -988,25 +988,31 @@ export function createJupyterKernelExtra(): JupyterKernelExtra {
988988
export async function checkInstalled(pkgName: string,
989989
pkgVersion?: string,
990990
session?: RSession): Promise<boolean> {
991-
session = session || RSessionManager.instance.getConsoleSession();
991+
session = session || await RSessionManager.instance.getConsoleSession();
992992
if (session) {
993993
return session.checkInstalled(pkgName, pkgVersion);
994994
}
995995
throw new Error(`Cannot check install status of ${pkgName}; no R session available`);
996996
}
997997

998998
export async function getLocale(session?: RSession): Promise<Locale> {
999-
session = session || RSessionManager.instance.getConsoleSession();
999+
session = session || await RSessionManager.instance.getConsoleSession();
10001000
if (session) {
10011001
return session.getLocale();
10021002
}
10031003
throw new Error(`Cannot get locale information; no R session available`);
10041004
}
10051005

10061006
export async function getEnvVars(envVars: string[], session?: RSession): Promise<EnvVar[]> {
1007-
session = session || RSessionManager.instance.getConsoleSession();
1007+
session = session || await RSessionManager.instance.getConsoleSession();
10081008
if (session) {
10091009
return session.getEnvVars(envVars);
10101010
}
10111011
throw new Error(`Cannot get env var information; no R session available`);
10121012
}
1013+
1014+
/** Get the active R language runtime sessions. */
1015+
export async function getActiveRSessions(): Promise<RSession[]> {
1016+
const sessions = await positron.runtime.getActiveSessions();
1017+
return sessions.filter((session) => session instanceof RSession) as RSession[];
1018+
}

extensions/positron-r/src/uri-handler.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ export async function registerUriHandler() {
2424
// "fragment": "",
2525
// "fsPath": "/cli"
2626
// }
27-
function handleUri(uri: vscode.Uri): void {
27+
async function handleUri(uri: vscode.Uri): Promise<void> {
2828
if (uri.path !== '/cli') {
2929
return;
3030
}
@@ -44,7 +44,7 @@ function handleUri(uri: vscode.Uri): void {
4444
return;
4545
}
4646

47-
const session = RSessionManager.instance.getConsoleSession();
47+
const session = await RSessionManager.instance.getConsoleSession();
4848
if (!session) {
4949
return;
5050
}
@@ -54,7 +54,7 @@ function handleUri(uri: vscode.Uri): void {
5454
}
5555

5656
export async function prepCliEnvVars(session?: RSession): Promise<EnvVar> {
57-
session = session || RSessionManager.instance.getConsoleSession();
57+
session = session || await RSessionManager.instance.getConsoleSession();
5858
if (!session) {
5959
return {};
6060
}

0 commit comments

Comments
 (0)