Skip to content

Commit

Permalink
Add RuntimeCodeExecutionMode to runtime.executeCode() in the API (#…
Browse files Browse the repository at this point in the history
  • Loading branch information
dhruvisompura authored Dec 3, 2024
1 parent 58d2069 commit e495864
Show file tree
Hide file tree
Showing 11 changed files with 107 additions and 61 deletions.
25 changes: 16 additions & 9 deletions extensions/positron-zed/src/positronZedLanguageRuntime.ts
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,8 @@ const HelpLines = [
'env rm X - Removes X variables',
'env update X - Updates X variables',
'error X Y Z - Simulates an unsuccessful X line input with Y lines of error message and Z lines of traceback (where X >= 1 and Y >= 1 and Z >= 0)',
'exec X Y - Executes a code snippet Y in the language X',
'exec silent X Y - Executes a code snippet Y in the language X silently',
'exec X Y - Executes a code snippet Y in the language X interactively',
'fancy - Simulates fancy HTML output',
'flicker - Simulates a flickering console prompt',
'help - Shows this help',
Expand Down Expand Up @@ -381,16 +382,17 @@ export class PositronZedRuntimeSession implements positron.LanguageRuntimeSessio
this.shutdown();
}
return;
// } else if (match = code.match(/^view( .+)?/)) {
// // Simulate a data viewer
// const title = (match.length > 1 && match[1]) ? match[1].trim() : 'Data';
// this.simulateDataView(id, code, `Zed: ${title}`);
// return;
} else if (match = code.match(/^exec silent ([a-zA-Z]+) (.+)/)) {
// Execute code silently in another language.
const languageId = match[1];
const codeToExecute = match[2];
this.simulateCodeExecution(id, code, languageId, codeToExecute, positron.RuntimeCodeExecutionMode.Silent);
return;
} else if (match = code.match(/^exec ([a-zA-Z]+) (.+)/)) {
// Execute code in another language.
const languageId = match[1];
const codeToExecute = match[2];
this.simulateCodeExecution(id, code, languageId, codeToExecute);
this.simulateCodeExecution(id, code, languageId, codeToExecute, positron.RuntimeCodeExecutionMode.Interactive);
return;
} else if (match = code.match(/^preview( .+)?/)) {
const command = (match.length > 1 && match[1]) ? match[1].trim() : 'default';
Expand Down Expand Up @@ -1602,20 +1604,25 @@ export class PositronZedRuntimeSession implements positron.LanguageRuntimeSessio
* @param code The Zed code the user entered.
* @param languageId The language identifier
* @param codeToExecute The code to execute.
* @param mode The execution mode to conform to.
*/
private async simulateCodeExecution(parentId: string,
code: string,
languageId: string,
codeToExecute: string) {
codeToExecute: string,
mode: positron.RuntimeCodeExecutionMode) {
// Enter busy state and output the code.
this.simulateBusyState(parentId);
this.simulateInputMessage(parentId, code);

// Let the user know what we're about to do
this.simulateOutputMessage(parentId, `Executing ${languageId} snippet: ${codeToExecute}`);

// Don't focus the console if code should being executed silently
const focus = mode !== positron.RuntimeCodeExecutionMode.Silent;

// Perform the execution
const success = await positron.runtime.executeCode(languageId, codeToExecute, true, true);
const success = await positron.runtime.executeCode(languageId, codeToExecute, focus, true, mode);
if (!success) {
this.simulateOutputMessage(parentId, `Failed; is there an active console for ${languageId}?`);
}
Expand Down
4 changes: 3 additions & 1 deletion src/positron-dts/positron.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1218,13 +1218,15 @@ declare module 'positron' {
* @param focus Whether to focus the runtime's console
* @param allowIncomplete Whether to bypass runtime code completeness checks. If true, the `code`
* will be executed by the runtime even if it is incomplete or invalid. Defaults to false
* @param mode Possible code execution modes for a language runtime
* @returns A Thenable that resolves with true if the code was sent to a
* runtime successfully, false otherwise.
*/
export function executeCode(languageId: string,
code: string,
focus: boolean,
allowIncomplete?: boolean): Thenable<boolean>;
allowIncomplete?: boolean,
mode?: RuntimeCodeExecutionMode): Thenable<boolean>;

/**
* Register a language runtime manager with Positron. Returns a
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1256,8 +1256,8 @@ export class MainThreadLanguageRuntime
}
}

$executeCode(languageId: string, code: string, focus: boolean, allowIncomplete?: boolean): Promise<boolean> {
return this._positronConsoleService.executeCode(languageId, code, focus, allowIncomplete);
$executeCode(languageId: string, code: string, focus: boolean, allowIncomplete?: boolean, mode?: RuntimeCodeExecutionMode): Promise<boolean> {
return this._positronConsoleService.executeCode(languageId, code, focus, allowIncomplete, mode);
}

public dispose(): void {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -76,8 +76,8 @@ export function createPositronApiFactoryAndRegisterActors(accessor: ServicesAcce

// --- Start Positron ---
const runtime: typeof positron.runtime = {
executeCode(languageId, code, focus, allowIncomplete): Thenable<boolean> {
return extHostLanguageRuntime.executeCode(languageId, code, focus, allowIncomplete);
executeCode(languageId, code, focus, allowIncomplete, mode): Thenable<boolean> {
return extHostLanguageRuntime.executeCode(languageId, code, focus, allowIncomplete, mode);
},
registerLanguageRuntimeManager(
manager: positron.LanguageRuntimeManager): vscode.Disposable {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ export interface MainThreadLanguageRuntimeShape extends IDisposable {
$startLanguageRuntime(runtimeId: string, sessionName: string, sessionMode: LanguageRuntimeSessionMode, notebookUri: URI | undefined): Promise<string>;
$completeLanguageRuntimeDiscovery(): void;
$unregisterLanguageRuntime(handle: number): void;
$executeCode(languageId: string, code: string, focus: boolean, allowIncomplete?: boolean): Promise<boolean>;
$executeCode(languageId: string, code: string, focus: boolean, allowIncomplete?: boolean, mode?: RuntimeCodeExecutionMode): Promise<boolean>;
$getPreferredRuntime(languageId: string): Promise<ILanguageRuntimeMetadata>;
$getForegroundSession(): Promise<string | undefined>;
$getNotebookSession(notebookUri: URI): Promise<string | undefined>;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -730,8 +730,8 @@ export class ExtHostLanguageRuntime implements extHostProtocol.ExtHostLanguageRu
});
}

public executeCode(languageId: string, code: string, focus: boolean, allowIncomplete?: boolean): Promise<boolean> {
return this._proxy.$executeCode(languageId, code, focus, allowIncomplete);
public executeCode(languageId: string, code: string, focus: boolean, allowIncomplete?: boolean, mode?: RuntimeCodeExecutionMode): Promise<boolean> {
return this._proxy.$executeCode(languageId, code, focus, allowIncomplete, mode);
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ import { ParameterHintsController } from 'vs/editor/contrib/parameterHints/brows
import { IInputHistoryEntry } from 'vs/workbench/contrib/executionHistory/common/executionHistoryService';
import { SelectionClipboardContributionID } from 'vs/workbench/contrib/codeEditor/browser/selectionClipboard';
import { usePositronConsoleContext } from 'vs/workbench/contrib/positronConsole/browser/positronConsoleContext';
import { RuntimeCodeFragmentStatus } from 'vs/workbench/services/languageRuntime/common/languageRuntimeService';
import { RuntimeCodeExecutionMode, RuntimeCodeFragmentStatus } from 'vs/workbench/services/languageRuntime/common/languageRuntimeService';
import { HistoryBrowserPopup } from 'vs/workbench/contrib/positronConsole/browser/components/historyBrowserPopup';
import { HistoryInfixMatchStrategy } from 'vs/workbench/contrib/positronConsole/common/historyInfixMatchStrategy';
import { HistoryPrefixMatchStrategy } from 'vs/workbench/contrib/positronConsole/common/historyPrefixMatchStrategy';
Expand Down Expand Up @@ -866,11 +866,12 @@ export const ConsoleInput = (props: ConsoleInputProps) => {
}));

// Add the onDidExecuteCode event handler.
disposableStore.add(props.positronConsoleInstance.onDidExecuteCode(code => {
// Trim the code. If it isn't empty, or a duplicate of the last history entry, add it to
// the history.
disposableStore.add(props.positronConsoleInstance.onDidExecuteCode(({ code, mode }) => {
// Trim the code
const trimmedCode = code.trim();
if (trimmedCode.length) {

// If the code isn't empty and run interactively, add it to the history.
if (trimmedCode.length && mode === RuntimeCodeExecutionMode.Interactive) {
// Creates an IInputHistoryEntry.
const createInputHistoryEntry = (): IInputHistoryEntry => ({
when: new Date().getTime(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -276,7 +276,7 @@ export const ConsoleInstance = (props: ConsoleInstanceProps) => {
}));

// Add the onDidExecuteCode event handler.
disposableStore.add(props.positronConsoleInstance.onDidExecuteCode(_code => {
disposableStore.add(props.positronConsoleInstance.onDidExecuteCode(() => {
scrollToBottom();
}));

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ import { ITextModel } from 'vs/editor/common/model';
import { IEditor } from 'vs/editor/common/editorCommon';
import { ILogService } from 'vs/platform/log/common/log';
import { Position } from 'vs/editor/common/core/position';
import { IStatementRange, StatementRangeProvider } from 'vs/editor/common/languages';
import { CancellationToken } from 'vs/base/common/cancellation';
import { KeyChord, KeyCode, KeyMod } from 'vs/base/common/keyCodes';
import { ILocalizedString } from 'vs/platform/action/common/action';
Expand All @@ -22,10 +21,12 @@ import { Action2, registerAction2 } from 'vs/platform/actions/common/actions';
import { IViewsService } from 'vs/workbench/services/views/common/viewsService';
import { ServicesAccessor } from 'vs/platform/instantiation/common/instantiation';
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
import { IStatementRange, StatementRangeProvider } from 'vs/editor/common/languages';
import { KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry';
import { ILanguageFeaturesService } from 'vs/editor/common/services/languageFeatures';
import { INotificationService, Severity } from 'vs/platform/notification/common/notification';
import { NOTEBOOK_EDITOR_FOCUSED } from 'vs/workbench/contrib/notebook/common/notebookContextKeys';
import { RuntimeCodeExecutionMode } from 'vs/workbench/services/languageRuntime/common/languageRuntimeService';
import { IExecutionHistoryService } from 'vs/workbench/contrib/executionHistory/common/executionHistoryService';
import { IPositronModalDialogsService } from 'vs/workbench/services/positronModalDialogs/common/positronModalDialogs';
import { IPositronConsoleService, POSITRON_CONSOLE_VIEW_ID } from 'vs/workbench/services/positronConsole/browser/interfaces/positronConsoleService';
Expand Down Expand Up @@ -268,14 +269,16 @@ export function registerPositronConsoleActions() {
* @param opts Options for code execution
* - allowIncomplete: Optionally, should incomplete statements be accepted? If `undefined`, treated as `false`.
* - languageId: Optionally, a language override for the code to execute. If `undefined`, the language of the active text editor is used. Useful for notebooks.
* @param advance Whether to advance the cursor to the next statement.
* - advance: Optionally, if the cursor should be advanced to the next statement. If `undefined`, fallbacks to `true`.
* - mode: Optionally, the code execution mode for a language runtime. If `undefined` fallbacks to `Interactive`.
*/
async run(
accessor: ServicesAccessor,
opts: {
allowIncomplete?: boolean;
languageId?: string;
advance?: boolean;
mode?: RuntimeCodeExecutionMode;
} = {}
) {
// Access services.
Expand Down Expand Up @@ -427,7 +430,7 @@ export function registerPositronConsoleActions() {

// Ask the Positron console service to execute the code. Do not focus the console as
// this will rip focus away from the editor.
if (!await positronConsoleService.executeCode(languageId, code, false, allowIncomplete)) {
if (!await positronConsoleService.executeCode(languageId, code, false, allowIncomplete, opts.mode)) {
const languageName = languageService.getLanguageName(languageId);
notificationService.notify({
severity: Severity.Info,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,10 @@
import { Event } from 'vs/base/common/event';
import { IEditor } from 'vs/editor/common/editorCommon';
import { createDecorator } from 'vs/platform/instantiation/common/instantiation';
import { ActivityItemPrompt } from 'vs/workbench/services/positronConsole/browser/classes/activityItemPrompt';
import { RuntimeItem } from 'vs/workbench/services/positronConsole/browser/classes/runtimeItem';
import { ILanguageRuntimeSession } from 'vs/workbench/services/runtimeSession/common/runtimeSessionService';
import { ActivityItemPrompt } from 'vs/workbench/services/positronConsole/browser/classes/activityItemPrompt';
import { RuntimeCodeExecutionMode } from 'vs/workbench/services/languageRuntime/common/languageRuntimeService';

// Create the decorator for the Positron console service (used in dependency injection).
export const IPositronConsoleService = createDecorator<IPositronConsoleService>('positronConsoleService');
Expand Down Expand Up @@ -88,9 +89,10 @@ export interface IPositronConsoleService {
* @param focus A value which indicates whether to focus Positron console instance.
* @param allowIncomplete Whether to bypass runtime code completeness checks. If true, the `code`
* will be executed by the runtime even if it is incomplete or invalid. Defaults to false
* @param mode Possible code execution modes for a language runtime
* @returns A value which indicates whether the code could be executed.
*/
executeCode(languageId: string, code: string, focus: boolean, allowIncomplete?: boolean): Promise<boolean>;
executeCode(languageId: string, code: string, focus: boolean, allowIncomplete?: boolean, mode?: RuntimeCodeExecutionMode): Promise<boolean>;
}

/**
Expand All @@ -110,6 +112,17 @@ export enum SessionAttachMode {
Connected = 'connected',
}

/**
* Represents a code fragment and its execution options sent to a language runtime.
*/
export interface ILanguageRuntimeCodeExecutedEvent {
/* The code that was executed in the language runtime session */
code: string;

/* The mode used to execute the code in the language runtime session */
mode: RuntimeCodeExecutionMode;
}

/**
* IPositronConsoleInstance interface.
*/
Expand Down Expand Up @@ -212,7 +225,7 @@ export interface IPositronConsoleInstance {
/**
* The onDidExecuteCode event.
*/
readonly onDidExecuteCode: Event<string>;
readonly onDidExecuteCode: Event<ILanguageRuntimeCodeExecutedEvent>;

/**
* The onDidSelectPlot event.
Expand Down Expand Up @@ -296,14 +309,16 @@ export interface IPositronConsoleInstance {
* @param code The code to enqueue.
* @param allowIncomplete Whether to bypass runtime code completeness checks. If true, the `code`
* will be executed by the runtime even if it is incomplete or invalid. Defaults to false
* @param mode Possible code execution modes for a language runtime.
*/
enqueueCode(code: string, allowIncomplete?: boolean): Promise<void>;
enqueueCode(code: string, allowIncomplete?: boolean, mode?: RuntimeCodeExecutionMode): Promise<void>;

/**
* Executes code.
* @param code The code to execute.
* @param mode Possible code execution modes for a language runtime.
*/
executeCode(code: string): void;
executeCode(code: string, mode?: RuntimeCodeExecutionMode): void;

/**
* Replies to a prompt.
Expand Down
Loading

0 comments on commit e495864

Please sign in to comment.