From 1643b7b1455e6aa99f0157ccb2f1fbd54373f088 Mon Sep 17 00:00:00 2001 From: Burhanuddin Vora Date: Fri, 13 Nov 2026 22:24:57 +0530 Subject: [PATCH] feat: recommend JBang for single Java file usage When a user opens a single Java file with no workspace folder, or a workspace folder with just a single Java file, show an information message recommending the JBang extension for running Java scripts. Includes option to install the jbang-vscode extension from the marketplace, and a 'Don't Show Again' option to suppress future notifications. Fixes #3111 --- package.json | 5 +++++ package.nls.json | 3 ++- src/commands.ts | 5 +++++ src/extension.ts | 56 ++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 68 insertions(+), 1 deletion(-) diff --git a/package.json b/package.json index 99513c139..e1861da37 100644 --- a/package.json +++ b/package.json @@ -1900,6 +1900,11 @@ "command": "java.action.copyFullyQualifiedName", "title": "%java.action.copyFullyQualifiedName%", "category": "Java" + }, + { + "command": "java.jbang.recommend", + "title": "%java.jbang.recommend%", + "category": "Java" } ], "keybindings": [ diff --git a/package.nls.json b/package.nls.json index 8709bc914..9a59ca628 100644 --- a/package.nls.json +++ b/package.nls.json @@ -26,5 +26,6 @@ "java.change.searchScope": "Change Search Scope", "java.action.showExtendedOutline": "Open Extended Outline", "java.runtimes.add": "Add Java Runtime", - "java.action.copyFullyQualifiedName": "Copy Fully Qualified Name" + "java.action.copyFullyQualifiedName": "Copy Fully Qualified Name", + "java.jbang.recommend": "Recommend JBang" } diff --git a/src/commands.ts b/src/commands.ts index 533372c73..e46ad2cd7 100644 --- a/src/commands.ts +++ b/src/commands.ts @@ -368,6 +368,11 @@ export namespace Commands { */ export const COPY_FULLY_QUALIFIED_NAME = 'java.action.copyFullyQualifiedName'; export const GET_FULLY_QUALIFIED_NAME = 'java.getFullyQualifiedName'; + + /** + * Recommend JBang for single Java file usage. + */ + export const JBANG_RECOMMEND = 'java.jbang.recommend'; } /** diff --git a/src/extension.ts b/src/extension.ts index 0fcdb138a..7cde39ff8 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -437,6 +437,15 @@ export async function activate(context: ExtensionContext): Promise cleanWorkspaceExists ); + // Recommend JBang when working with a single Java file (issue #3111) + void showJBangRecommendation(context); + + context.subscriptions.push(workspace.onDidOpenTextDocument(async (document) => { + if (document.languageId === 'java') { + await showJBangRecommendation(context); + } + })); + return apiManager.getApiInstance(); } @@ -1412,3 +1421,50 @@ function addRevealCommand(client: LanguageClient, codeAction: CodeAction, lspEdi } return codeAction; } + +const JBANG_RECOMMENDATION_KEY = 'jbangRecommendationShown'; +const JBANG_EXTENSION_ID = 'jbangdev.jbang-vscode'; +const JBANG_MARKETPLACE_URL = 'https://marketplace.visualstudio.com/items?itemName=jbangdev.jbang-vscode'; + +function shouldRecommendJBang(): boolean { + // Case 1: No workspace folder (standalone file mode) + if (!workspace.workspaceFolders) { + return true; + } + // Case 2: Workspace folder with just a single Java file + if (workspace.workspaceFolders.length === 1) { + const javaFileCount = workspace.textDocuments.filter(doc => doc.languageId === 'java').length; + if (javaFileCount <= 1) { + return true; + } + } + return false; +} + +async function showJBangRecommendation(context: ExtensionContext): Promise { + const alreadyShown = context.globalState.get(JBANG_RECOMMENDATION_KEY, false); + if (alreadyShown) { + return; + } + + if (!shouldRecommendJBang()) { + return; + } + + const install = 'Install JBang'; + const maybeLater = 'Maybe Later'; + const dontShowAgain = "Don't Show Again"; + + const choice = await window.showInformationMessage( + 'You are working with a single Java file. JBang makes it easy to run Java scripts. Would you like to install the JBang extension?', + install, maybeLater, dontShowAgain + ); + + if (choice === install) { + await commands.executeCommand(Commands.OPEN_BROWSER, Uri.parse(JBANG_MARKETPLACE_URL)); + } + + if (choice === dontShowAgain || choice === install) { + await context.globalState.update(JBANG_RECOMMENDATION_KEY, true); + } +}