Repository: stateful/vscode-runme
Pull request #630 (2023-06-22 20:28:56)

Use survey infra for lang not supported notification
Until we get shebang support out the door.


Patch:
diff --git a/package.json b/package.json
index 30f5a88f..d987f34b 100644
--- a/package.json
+++ b/package.json
@@ -97,6 +97,11 @@
         "category": "Runme",
         "title": "Prompt to participate in Feedback survey"
       },
+      {
+        "command": "runme.surveyShebangComingSoon",
+        "category": "Runme",
+        "title": "Prompt when a cell language is unsupported"
+      },
       {
         "command": "runme.openAsRunmeNotebook",
         "category": "Runme",
diff --git a/src/extension/kernel.ts b/src/extension/kernel.ts
index b4ea20c7..594220be 100644
--- a/src/extension/kernel.ts
+++ b/src/extension/kernel.ts
@@ -27,6 +27,7 @@ import {
 import { API } from '../utils/deno/api'
 import { postClientMessage } from '../utils/messaging'
 
+import * as survey from './survey'
 import getLogger from './logger'
 import executor, { type IEnvironmentManager, ENV_STORE_MANAGER } from './executors'
 import { DENO_ACCESS_TOKEN_KEY } from './constants'
@@ -54,6 +55,7 @@ import { handleCellOutputMessage } from './messages/cellOutput'
 import handleGitHubMessage from './messages/github'
 import { getNotebookCategories } from './utils'
 import { handleCloudApiMessage } from './messages/cloudApiRequest'
+import { SurveyShebangComingSoon } from './survey'
 
 enum ConfirmationItems {
   Yes = 'Yes',
@@ -68,6 +70,7 @@ export class Kernel implements Disposable {
   static readonly type = 'runme' as const
 
   readonly #experiments = new Map<string, boolean>()
+  readonly #shebangComingSoon: SurveyShebangComingSoon
 
   #disposables: Disposable[] = []
   #controller = notebooks.createNotebookController(
@@ -90,6 +93,8 @@ export class Kernel implements Disposable {
     this.#experiments.set('grpcRunner', config.get<boolean>('grpcRunner', true))
     this.#experiments.set('grpcServer', config.get<boolean>('grpcServer', true))
 
+    this.#shebangComingSoon = new survey.SurveyShebangComingSoon(context)
+
     this.#controller.supportsExecutionOrder = false
     this.#controller.description = 'Run your Markdown'
     this.#controller.executeHandler = this._executeAll.bind(this)
@@ -110,6 +115,7 @@ export class Kernel implements Disposable {
 
     this.messaging.postMessage({ from: 'kernel' })
     this.#disposables.push(
+      this.#shebangComingSoon,
       this.messaging.onDidReceiveMessage(this.#handleRendererMessage.bind(this)),
       workspace.onDidOpenNotebookDocument(this.#handleOpenNotebook.bind(this)),
       workspace.onDidSaveNotebookDocument(this.#handleSaveNotebook.bind(this)),
@@ -511,7 +517,7 @@ export class Kernel implements Disposable {
           environmentManager
         )
       } else {
-        window.showErrorMessage('Cell language is not executable')
+        this.#shebangComingSoon.open()
 
         successfulCellExecution = false
       }
diff --git a/src/extension/survey.ts b/src/extension/survey.ts
index 46e28211..85699053 100644
--- a/src/extension/survey.ts
+++ b/src/extension/survey.ts
@@ -49,6 +49,8 @@ abstract class Survey implements Disposable {
   protected async done() {
     await this.context.globalState.update(this.id, true)
   }
+
+  abstract prompt(runDirect: boolean): Promise<void>
 }
 
 export class WinDefaultShell extends Survey {
@@ -283,3 +285,34 @@ export class SurveyActiveUserFeedback extends Survey {
     await this.done()
   }
 }
+
+export class SurveyShebangComingSoon extends Survey {
+  static readonly #id: string = 'runme.surveyShebangComingSoon'
+
+  constructor(protected context: ExtensionContext) {
+    super(context, SurveyShebangComingSoon.#id)
+
+    commands.registerCommand(SurveyShebangComingSoon.#id, this.prompt.bind(this))
+  }
+
+  open() {
+    commands.executeCommand(SurveyShebangComingSoon.#id)
+  }
+
+  async prompt(): Promise<void> {
+    const option = await window.showWarningMessage(
+      'Not every language is executable... yet! Coming soon: Mix and match languages in Runme.',
+      'Learn more',
+      'Dismiss'
+    )
+    if (option === 'Dismiss' || option === undefined) {
+      return
+    }
+
+    TelemetryReporter.sendTelemetryEvent('survey.ShebangComingSoon', { never: 'false' })
+    await commands.executeCommand(
+      'vscode.open',
+      Uri.parse('https://runme.dev/spotlight/shebang-support')
+    )
+  }
+}


Test patch:
diff --git a/tests/extension/extension.test.ts b/tests/extension/extension.test.ts
index 596e5183..14086e83 100644
--- a/tests/extension/extension.test.ts
+++ b/tests/extension/extension.test.ts
@@ -73,7 +73,7 @@ test('initializes all providers', async () => {
   await ext.initialize(context)
   expect(notebooks.registerNotebookCellStatusBarItemProvider).toBeCalledTimes(6)
   expect(workspace.registerNotebookSerializer).toBeCalledTimes(1)
-  expect(commands.registerCommand).toBeCalledTimes(24)
+  expect(commands.registerCommand).toBeCalledTimes(25)
   expect(window.registerTreeDataProvider).toBeCalledTimes(1)
   expect(window.registerUriHandler).toBeCalledTimes(1)
   expect(bootFile).toBeCalledTimes(1)
diff --git a/tests/extension/kernel.test.ts b/tests/extension/kernel.test.ts
index 5d1dd403..e0449fa6 100644
--- a/tests/extension/kernel.test.ts
+++ b/tests/extension/kernel.test.ts
@@ -233,8 +233,6 @@ suite('_doExecuteCell', () => {
       'cell.endExecute',
       { 'cell.success': 'false' }
     )
-
-    expect(window.showErrorMessage).toHaveBeenCalledWith('Cell language is not executable')
   })
 })
 
diff --git a/tests/extension/provider/annotations.test.ts b/tests/extension/provider/annotations.test.ts
index a6b44e85..bf6bd763 100644
--- a/tests/extension/provider/annotations.test.ts
+++ b/tests/extension/provider/annotations.test.ts
@@ -37,7 +37,7 @@ describe('Runme Annotations', () => {
   const kernel = new Kernel({} as any)
   it('should register a command when initializing', () => {
     new AnnotationsProvider(kernel)
-    expect(commands.registerCommand).toBeCalledTimes(1)
+    expect(commands.registerCommand).toBeCalledTimes(2)
     expect(commands.registerCommand).toBeCalledWith('runme.toggleCellAnnotations', expect.anything(), undefined)
   })