1- import * as py from "@vscode/python-extension" ;
1+ import { execFile } from "node:child_process" ;
2+ import * as semver from "@std/semver" ;
3+ import type * as py from "@vscode/python-extension" ;
24import * as vscode from "vscode" ;
35import type * as lsp from "vscode-languageclient" ;
6+
47import * as cmds from "./commands.ts" ;
58import { Logger } from "./logging.ts" ;
9+ import { getPythonApi } from "./python.ts" ;
610import { notebookType } from "./types.ts" ;
711
812export function createNotebookControllerManager (
913 client : lsp . BaseLanguageClient ,
1014 options : { signal : AbortSignal } ,
1115) {
16+ // Single map for both controller and environment
1217 const controllers = new Map < string , vscode . NotebookController > ( ) ;
1318 const selectedControllers = new WeakMap <
1419 vscode . NotebookDocument ,
@@ -28,9 +33,9 @@ export function createNotebookControllerManager(
2833
2934 {
3035 // Just update the controller if it exists
31- const controller = controllers . get ( controllerId ) ;
32- if ( controller ) {
33- controller . label = controllerLabel ;
36+ const existing = controllers . get ( controllerId ) ;
37+ if ( existing ) {
38+ existing . label = controllerLabel ;
3439 Logger . trace (
3540 "Controller.Update" ,
3641 "Updated controller:" ,
@@ -51,6 +56,37 @@ export function createNotebookControllerManager(
5156 cellCount : cells . length ,
5257 notebook : notebook . uri . toString ( ) ,
5358 } ) ;
59+
60+ const version = await tryGetMarimoVersion ( env , options ) ;
61+
62+ if ( ! version ) {
63+ const envName = resolvePythonEnvironmentName ( env ) ;
64+ const envLabel = envName
65+ ? `"${ envName } "`
66+ : "the selected environment" ;
67+ await vscode . window . showErrorMessage (
68+ `Could not find marimo in ${ envLabel } . Please ensure marimo is installed.` ,
69+ { modal : true } ,
70+ ) ;
71+
72+ return ;
73+ }
74+
75+ if (
76+ ! semver . greaterOrEqual ( version , { major : 0 , minor : 14 , patch : 0 } )
77+ ) {
78+ const envName = resolvePythonEnvironmentName ( env ) ;
79+ const envLabel = envName
80+ ? `"${ envName } "`
81+ : "the selected environment" ;
82+ await vscode . window . showWarningMessage (
83+ `marimo version in ${ envLabel } is outdated (v${ semver . format ( version ) } ). Please update to v0.14.0 or later.` ,
84+ { modal : true } ,
85+ ) ;
86+
87+ return ;
88+ }
89+
5490 await cmds . executeCommand ( client , {
5591 command : "marimo.run" ,
5692 params : {
@@ -136,7 +172,7 @@ export function createNotebookControllerManager(
136172 }
137173
138174 // TODO: await this somewhere?
139- py . PythonExtension . api ( )
175+ getPythonApi ( )
140176 . then ( ( api ) => initialize ( api ) )
141177 . catch ( ( error ) => {
142178 Logger . error (
@@ -158,18 +194,6 @@ export function createNotebookControllerManager(
158194 } ;
159195}
160196
161- function resolvePythonEnvironmentName ( env : py . Environment ) : string | undefined {
162- if ( env . environment ?. name ) {
163- return env . environment . name ;
164- }
165- if ( env . environment ?. folderUri ) {
166- return vscode . Uri . parse ( env . environment . folderUri . toString ( ) )
167- . path . split ( "/" )
168- . pop ( ) ;
169- }
170- return undefined ;
171- }
172-
173197/**
174198 * Format a {@link py.Environment} similar to vscode-jupyter
175199 *
@@ -198,3 +222,38 @@ function formatControllerLabel(env: py.Environment): string {
198222 }
199223 return formatted ;
200224}
225+
226+ async function tryGetMarimoVersion (
227+ env : py . Environment ,
228+ options : {
229+ signal ?: AbortSignal ;
230+ } ,
231+ ) : Promise < semver . SemVer | undefined > {
232+ return new Promise ( ( resolve ) => {
233+ execFile (
234+ env . path ,
235+ [ "-c" , "import marimo; print(marimo.__version__)" ] ,
236+ { signal : options . signal } ,
237+ ( error , stdout ) => {
238+ resolve ( error ? undefined : semver . tryParse ( stdout . trim ( ) ) ) ;
239+ } ,
240+ ) ;
241+ } ) ;
242+ }
243+
244+ /**
245+ * A human readable name for a {@link py.Environment}
246+ */
247+ export function resolvePythonEnvironmentName (
248+ env : py . Environment ,
249+ ) : string | undefined {
250+ if ( env . environment ?. name ) {
251+ return env . environment . name ;
252+ }
253+ if ( env . environment ?. folderUri ) {
254+ return vscode . Uri . parse ( env . environment . folderUri . toString ( ) )
255+ . path . split ( "/" )
256+ . pop ( ) ;
257+ }
258+ return undefined ;
259+ }
0 commit comments