diff --git a/extensions/positron-r/package.json b/extensions/positron-r/package.json index 36a54533225..dfc94bedd2a 100644 --- a/extensions/positron-r/package.json +++ b/extensions/positron-r/package.json @@ -667,6 +667,11 @@ "view": "testing", "contents": "No testthat tests found.\n[Add a test](command:r.useTest)", "when": "isRPackage && config.positron.r.testing && testthatIsConfigured && !testthatHasTests" + }, + { + "view": "debug", + "contents": "%r.welcome.views.debugger.content%", + "when": "debugStartLanguage == 'r'" } ], "taskDefinitions": [ @@ -678,7 +683,9 @@ "debuggers": [ { "type": "ark", - "label": "R Debugger" + "label": "R Debugger", + "languages": ["r"], + "supportsUiLaunch": false } ], "notebookRenderer": [ diff --git a/extensions/positron-r/package.nls.json b/extensions/positron-r/package.nls.json index 2af72d8307e..36e2778a884 100644 --- a/extensions/positron-r/package.nls.json +++ b/extensions/positron-r/package.nls.json @@ -83,6 +83,7 @@ "r.walkthrough.migrateFromRStudio.workspaces.title": "Projects, folders, and workspaces", "r.walkthrough.migrateFromRStudio.workspaces.description": " \n[Open an existing folder](command:workbench.action.files.openFolder)", "r.walkthrough.migrateFromRStudio.formatting.title": "Formatting your R code", - "r.walkthrough.migrateFromRStudio.formatting.description": " \n[Configure Air to format on save](command:r.walkthrough.formatOnSave)" + "r.walkthrough.migrateFromRStudio.formatting.description": " \n[Configure Air to format on save](command:r.walkthrough.formatOnSave)", + "r.welcome.views.debugger.content": "Positron currently provides limited debugging support for R code, but you can use R's native debugging features in Positron.\n[Learn more](https://positron.posit.co/guide-r.html#debugging)" } diff --git a/src/vs/workbench/contrib/debug/browser/debugAdapterManager.ts b/src/vs/workbench/contrib/debug/browser/debugAdapterManager.ts index 7504a9c9d32..a23494a0dba 100644 --- a/src/vs/workbench/contrib/debug/browser/debugAdapterManager.ts +++ b/src/vs/workbench/contrib/debug/browser/debugAdapterManager.ts @@ -341,6 +341,15 @@ export class AdapterManager extends Disposable implements IAdapterManager { .find(a => a.interestedInLanguage(languageId)); } + // --- Start Positron --- + someDebuggerInterestedInLanguageSupportsUiLaunch(languageId: string): boolean { + const interestedDebuggers = this.debuggers + .filter(d => d.enabled && d.interestedInLanguage(languageId)); + // Return true if at least one interested debugger supports UI launch + return interestedDebuggers.some(d => d.supportsUiLaunch !== false); + } + // --- End Positron --- + async guessDebugger(gettingConfigurations: boolean): Promise { const activeTextEditorControl = this.editorService.activeTextEditorControl; let candidates: Debugger[] = []; diff --git a/src/vs/workbench/contrib/debug/browser/welcomeView.ts b/src/vs/workbench/contrib/debug/browser/welcomeView.ts index 481f775794f..6d87f5b40ba 100644 --- a/src/vs/workbench/contrib/debug/browser/welcomeView.ts +++ b/src/vs/workbench/contrib/debug/browser/welcomeView.ts @@ -25,6 +25,10 @@ import { WorkbenchStateContext } from '../../../common/contextkeys.js'; import { Extensions, IViewDescriptorService, IViewsRegistry, ViewContentGroups } from '../../../common/views.js'; import { IEditorService } from '../../../services/editor/common/editorService.js'; import { CONTEXT_DEBUGGERS_AVAILABLE, CONTEXT_DEBUG_EXTENSION_AVAILABLE, IDebugService } from '../common/debug.js'; +// --- Start Positron --- +// eslint-disable-next-line no-duplicate-imports +import { CONTEXT_DEBUGGER_SUPPORTS_UI_LAUNCH } from '../common/debug.js'; +// --- End Positron --- import { DEBUG_CONFIGURE_COMMAND_ID, DEBUG_START_COMMAND_ID } from './debugCommands.js'; const debugStartLanguageKey = 'debugStartLanguage'; @@ -38,6 +42,9 @@ export class WelcomeView extends ViewPane { private debugStartLanguageContext: IContextKey; private debuggerInterestedContext: IContextKey; + // --- Start Positron --- + private debuggerSupportsUiLaunchContext: IContextKey; + // --- End Positron --- constructor( options: IViewletViewOptions, @@ -58,6 +65,9 @@ export class WelcomeView extends ViewPane { this.debugStartLanguageContext = CONTEXT_DEBUG_START_LANGUAGE.bindTo(contextKeyService); this.debuggerInterestedContext = CONTEXT_DEBUGGER_INTERESTED_IN_ACTIVE_EDITOR.bindTo(contextKeyService); + // --- Start Positron --- + this.debuggerSupportsUiLaunchContext = CONTEXT_DEBUGGER_SUPPORTS_UI_LAUNCH.bindTo(contextKeyService); + // --- End Positron --- const lastSetLanguage = storageSevice.get(debugStartLanguageKey, StorageScope.WORKSPACE); this.debugStartLanguageContext.set(lastSetLanguage); @@ -70,14 +80,25 @@ export class WelcomeView extends ViewPane { if (isCodeEditor(editorControl)) { const model = editorControl.getModel(); const language = model ? model.getLanguageId() : undefined; + if (language && this.debugService.getAdapterManager().someDebuggerInterestedInLanguage(language)) { this.debugStartLanguageContext.set(language); this.debuggerInterestedContext.set(true); storageSevice.store(debugStartLanguageKey, language, StorageScope.WORKSPACE, StorageTarget.MACHINE); + // --- Start Positron --- + // Check if any debugger interested in this language supports UI launch + const supportsUiLaunch = this.debugService.getAdapterManager().someDebuggerInterestedInLanguageSupportsUiLaunch(language); + this.debuggerSupportsUiLaunchContext.set(supportsUiLaunch); + // --- End Positron --- return; } + } this.debuggerInterestedContext.set(false); + // --- Start Positron --- + this.debuggerSupportsUiLaunchContext.set(true); // Default to true when no debugger + this.debugStartLanguageContext.reset(); // Clear the language context when no debugger is interested + // --- End Positron --- }; const disposables = new DisposableStore(); @@ -133,7 +154,10 @@ viewsRegistry.registerViewWelcomeContent(WelcomeView.ID, { let debugKeybindingLabel = ''; viewsRegistry.registerViewWelcomeContent(WelcomeView.ID, { content: `[${localize('runAndDebugAction', "Run and Debug")}${debugKeybindingLabel}](command:${DEBUG_START_COMMAND_ID})`, - when: CONTEXT_DEBUGGERS_AVAILABLE, + // --- Start Positron --- + // when: CONTEXT_DEBUGGERS_AVAILABLE, + when: ContextKeyExpr.and(CONTEXT_DEBUGGERS_AVAILABLE, CONTEXT_DEBUGGER_SUPPORTS_UI_LAUNCH), + // --- End Positron --- group: ViewContentGroups.Debug, // Allow inserting more buttons directly after this one (by setting order to 1). order: 1 @@ -142,7 +166,10 @@ viewsRegistry.registerViewWelcomeContent(WelcomeView.ID, { viewsRegistry.registerViewWelcomeContent(WelcomeView.ID, { content: localize({ key: 'customizeRunAndDebug2', comment: ['{Locked="launch.json"}', '{Locked="["}', '{Locked="]({0})"}'] }, "To customize Run and Debug [create a launch.json file]({0}).", `${createCommandUri(DEBUG_CONFIGURE_COMMAND_ID, { addNew: true }).toString()}`), - when: ContextKeyExpr.and(CONTEXT_DEBUGGERS_AVAILABLE, WorkbenchStateContext.notEqualsTo('empty')), + // --- Start Positron --- + // when: ContextKeyExpr.and(CONTEXT_DEBUGGERS_AVAILABLE, WorkbenchStateContext.notEqualsTo('empty')), + when: ContextKeyExpr.and(CONTEXT_DEBUGGERS_AVAILABLE, WorkbenchStateContext.notEqualsTo('empty'), CONTEXT_DEBUGGER_SUPPORTS_UI_LAUNCH), + // --- End Positron --- group: ViewContentGroups.Debug }); diff --git a/src/vs/workbench/contrib/debug/common/debug.ts b/src/vs/workbench/contrib/debug/common/debug.ts index be135eff8f4..8c570ec22c3 100644 --- a/src/vs/workbench/contrib/debug/common/debug.ts +++ b/src/vs/workbench/contrib/debug/common/debug.ts @@ -80,6 +80,9 @@ export const CONTEXT_STEP_INTO_TARGETS_SUPPORTED = new RawContextKey('s export const CONTEXT_BREAKPOINTS_EXIST = new RawContextKey('breakpointsExist', false, { type: 'boolean', description: nls.localize('breakpointsExist', "True when at least one breakpoint exists.") }); export const CONTEXT_DEBUGGERS_AVAILABLE = new RawContextKey('debuggersAvailable', false, { type: 'boolean', description: nls.localize('debuggersAvailable', "True when there is at least one debug extensions active.") }); export const CONTEXT_DEBUG_EXTENSION_AVAILABLE = new RawContextKey('debugExtensionAvailable', true, { type: 'boolean', description: nls.localize('debugExtensionsAvailable', "True when there is at least one debug extension installed and enabled.") }); +// --- Start Positron --- +export const CONTEXT_DEBUGGER_SUPPORTS_UI_LAUNCH = new RawContextKey('debuggerSupportsUiLaunch', true, { type: 'boolean', description: nls.localize('debuggersupportsUiLaunch', "True when the debugger for the current file supports launching from the Run and Debug UI. Some debuggers (like R) use alternative debugging approaches.") }); +// --- End Positron --- export const CONTEXT_DEBUG_PROTOCOL_VARIABLE_MENU_CONTEXT = new RawContextKey('debugProtocolVariableMenuContext', undefined, { type: 'string', description: nls.localize('debugProtocolVariableMenuContext', "Represents the context the debug adapter sets on the focused variable in the VARIABLES view.") }); export const CONTEXT_SET_VARIABLE_SUPPORTED = new RawContextKey('debugSetVariableSupported', false, { type: 'boolean', description: nls.localize('debugSetVariableSupported', "True when the focused session supports 'setVariable' request.") }); export const CONTEXT_SET_DATA_BREAKPOINT_BYTES_SUPPORTED = new RawContextKey('debugSetDataBreakpointAddressSupported', false, { type: 'boolean', description: nls.localize('debugSetDataBreakpointAddressSupported', "True when the focused session supports 'getBreakpointInfo' request on an address.") }); @@ -951,6 +954,11 @@ export interface IDebuggerContribution extends IPlatformSpecificAdapterContribut // supported languages languages?: string[]; + // --- Start Positron --- + // Whether this debugger supports launching from the Run and Debug UI + supportsUiLaunch?: boolean; + // --- End Positron --- + // debug configuration support configurationAttributes?: Record; initialConfigurations?: unknown[]; @@ -1051,6 +1059,9 @@ export interface IAdapterManager { getDebugAdapterDescriptor(session: IDebugSession): Promise; getDebuggerLabel(type: string): string | undefined; someDebuggerInterestedInLanguage(language: string): boolean; + // --- Start Positron --- + someDebuggerInterestedInLanguageSupportsUiLaunch(language: string): boolean; + // --- End Positron --- getDebugger(type: string): IDebuggerMetadata | undefined; activateDebuggers(activationEvent: string, debugType?: string): Promise; diff --git a/src/vs/workbench/contrib/debug/common/debugSchemas.ts b/src/vs/workbench/contrib/debug/common/debugSchemas.ts index d8f86e982f5..fd2aa9d5c18 100644 --- a/src/vs/workbench/contrib/debug/common/debugSchemas.ts +++ b/src/vs/workbench/contrib/debug/common/debugSchemas.ts @@ -64,6 +64,13 @@ export const debuggersExtPoint = extensionsRegistry.ExtensionsRegistry.registerE description: nls.localize('vscode.extension.contributes.debuggers.languages', "List of languages for which the debug extension could be considered the \"default debugger\"."), type: 'array' }, + // --- Start Positron --- + supportsUiLaunch: { + description: nls.localize('positron.extension.contributes.debuggers.supportsUiLaunch', "Whether this debugger supports launching from the Run and Debug UI. Set to false for debuggers that use alternative debugging approaches (e.g., R's browser(), debug(), etc.). Defaults to true."), + type: 'boolean', + default: true + }, + // --- End Positron --- configurationSnippets: { description: nls.localize('vscode.extension.contributes.debuggers.configurationSnippets', "Snippets for adding new configurations in \'launch.json\'."), type: 'array' diff --git a/src/vs/workbench/contrib/debug/common/debugger.ts b/src/vs/workbench/contrib/debug/common/debugger.ts index 7461a886bf0..0e8186bfa9a 100644 --- a/src/vs/workbench/contrib/debug/common/debugger.ts +++ b/src/vs/workbench/contrib/debug/common/debugger.ts @@ -145,6 +145,12 @@ export class Debugger implements IDebugger, IDebuggerMetadata { return this.debuggerContribution.languages; } + // --- Start Positron --- + get supportsUiLaunch(): boolean { + return this.debuggerContribution.supportsUiLaunch !== false; // Defaults to true + } + // --- End Positron --- + get when(): ContextKeyExpression | undefined { return this.debuggerWhen; }