Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions src/vs/platform/actions/common/actions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@ export class MenuId {
static readonly EditorContextPeek = new MenuId('EditorContextPeek');
static readonly EditorContextShare = new MenuId('EditorContextShare');
// --- Start Positron ---
static readonly PositronNotebookKernelSubmenu = new MenuId('PositronNotebookKernelSubmenu');
static readonly EditorActionsLeft = new MenuId('EditorActionsLeft');
static readonly EditorActionsRight = new MenuId('EditorActionsRight');
// --- End Positron ---
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -174,6 +174,7 @@ export const ActionBarButton = forwardRef<
{props.label}
</div>
}
{props.children}
{props.dropdownIndicator === 'enabled' &&
<div className='action-bar-button-drop-down-container'>
<div className='action-bar-button-drop-down-arrow codicon codicon-positron-drop-down-arrow' />
Expand Down Expand Up @@ -205,7 +206,6 @@ export const ActionBarButton = forwardRef<
onPressed={props.onPressed}
>
<ActionBarButtonFace />
{props.children}
</Button>
);
} else {
Expand Down Expand Up @@ -242,7 +242,6 @@ export const ActionBarButton = forwardRef<
>
<div className='action-bar-button-drop-down-arrow codicon codicon-positron-drop-down-arrow' />
</Button>
{props.children}
</div>
);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
import './actionBarMenuButton.css';

// React.
import React, { useEffect, useRef, useState } from 'react';
import React, { PropsWithChildren, useEffect, useRef, useState } from 'react';

// Other dependencies.
import { ActionBarButton } from './actionBarButton.js';
Expand Down Expand Up @@ -48,7 +48,7 @@ interface ActionBarMenuButtonProps {
* @param props An ActionBarMenuButtonProps that contains the component properties.
* @returns The rendered component.
*/
export const ActionBarMenuButton = (props: ActionBarMenuButtonProps) => {
export const ActionBarMenuButton = (props: PropsWithChildren<ActionBarMenuButtonProps>) => {
// Context hooks.
const services = usePositronReactServicesContext();
const positronActionBarContext = usePositronActionBarContext();
Expand All @@ -74,15 +74,16 @@ export const ActionBarMenuButton = (props: ActionBarMenuButtonProps) => {
}
}, [positronActionBarContext.menuShowing]);

const { actions: getActions } = props;
const getMenuActions = React.useCallback(async () => {
const actions = await props.actions();
const actions = await getActions();
const defaultAction = actions.find(action => action.checked);

setDefaultAction(defaultAction);
setActions(actions);

return actions;
}, [props]);
}, [getActions]);

useEffect(() => {
getMenuActions();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,6 @@
* Licensed under the Elastic License 2.0. See LICENSE.txt for license information.
*--------------------------------------------------------------------------------------------*/

.action-bar-widget {
padding-inline: 6px;
}

/**
* Error indicator shown when a widget fails to render.
* Displays a small error icon with tooltip explaining the failure.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,28 +12,17 @@ import React, { useEffect, useState } from 'react';
// Other dependencies.
import { IPositronConsoleInstance, PositronConsoleState } from '../../../../services/positronConsole/browser/interfaces/positronConsoleService.js';
import { DisposableStore } from '../../../../../base/common/lifecycle.js';

const enum StatusIconClassName {
ACTIVE = 'codicon-positron-status-active',
DISCONNECTED = 'codicon-positron-status-disconnected',
IDLE = 'codicon-positron-status-idle'
}

const statusIconClassNameToColor = {
[StatusIconClassName.ACTIVE]: 'var(--vscode-positronConsole-stateIconActive)',
[StatusIconClassName.DISCONNECTED]: 'var(--vscode-positronConsole-stateIconDisconnected)',
[StatusIconClassName.IDLE]: 'var(--vscode-positronConsole-stateIconIdle)'
}

const consoleStateToStatusIcon = {
[PositronConsoleState.Uninitialized]: StatusIconClassName.DISCONNECTED,
[PositronConsoleState.Disconnected]: StatusIconClassName.DISCONNECTED,
[PositronConsoleState.Starting]: StatusIconClassName.ACTIVE,
[PositronConsoleState.Busy]: StatusIconClassName.ACTIVE,
[PositronConsoleState.Ready]: StatusIconClassName.IDLE,
[PositronConsoleState.Offline]: StatusIconClassName.DISCONNECTED,
[PositronConsoleState.Exiting]: StatusIconClassName.ACTIVE,
[PositronConsoleState.Exited]: StatusIconClassName.DISCONNECTED
import { RuntimeStatus, RuntimeStatusIcon } from './runtimeStatus.js';

const consoleStateToRuntimeStatus = {
[PositronConsoleState.Uninitialized]: RuntimeStatus.Disconnected,
[PositronConsoleState.Disconnected]: RuntimeStatus.Disconnected,
[PositronConsoleState.Starting]: RuntimeStatus.Active,
[PositronConsoleState.Busy]: RuntimeStatus.Active,
[PositronConsoleState.Ready]: RuntimeStatus.Idle,
[PositronConsoleState.Offline]: RuntimeStatus.Disconnected,
[PositronConsoleState.Exiting]: RuntimeStatus.Active,
[PositronConsoleState.Exited]: RuntimeStatus.Disconnected
};

interface ConsoleInstanceStateProps {
Expand All @@ -55,13 +44,9 @@ export const ConsoleInstanceState = ({ positronConsoleInstance }: ConsoleInstanc
return () => disposableStore.dispose();
}, [positronConsoleInstance]);

const icon = consoleStateToStatusIcon[consoleState];
const color = statusIconClassNameToColor[icon];
const runtimeStatus = consoleStateToRuntimeStatus[consoleState];

return (
<span
className={`codicon ${icon}`}
style={{ color }}
/>
<RuntimeStatusIcon status={runtimeStatus} />
);
}
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import { PositronConsoleTabFocused } from '../../../../common/contextkeys.js';
import { usePositronReactServicesContext } from '../../../../../base/browser/positronReactRendererContext.js';
import { LanguageRuntimeSessionMode } from '../../../../services/languageRuntime/common/languageRuntimeService.js';
import { basename } from '../../../../../base/common/path.js';
import { RuntimeIcon } from './runtimeIcon.js';

/**
* The minimum width required for the delete action to be displayed on the console tab.
Expand Down Expand Up @@ -378,16 +379,10 @@ const ConsoleTab = ({ positronConsoleInstance, width, onChangeSession }: Console
onMouseDown={handleMouseDown}
>
<ConsoleInstanceState positronConsoleInstance={positronConsoleInstance} />
{
!isNotebookSession &&
<img
className='icon'
src={`data:image/svg+xml;base64,${positronConsoleInstance.runtimeMetadata.base64EncodedIconSvg}`}
/>
}
{isNotebookSession &&
<span className='codicon codicon-notebook icon'></span>
}
<RuntimeIcon
base64EncodedIconSvg={positronConsoleInstance.runtimeMetadata.base64EncodedIconSvg}
sessionMode={positronConsoleInstance.sessionMetadata.sessionMode}
/>
{isRenamingSession ? (
<input
ref={inputRef}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
/*---------------------------------------------------------------------------------------------
* Copyright (C) 2025 Posit Software, PBC. All rights reserved.
* Licensed under the Elastic License 2.0. See LICENSE.txt for license information.
*--------------------------------------------------------------------------------------------*/
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
/*---------------------------------------------------------------------------------------------
* Copyright (C) 2025 Posit Software, PBC. All rights reserved.
* Licensed under the Elastic License 2.0. See LICENSE.txt for license information.
*--------------------------------------------------------------------------------------------*/

// CSS.
import './runtimeStatus.css';

// React.
import React from 'react';

// Other dependencies.
import { LanguageRuntimeSessionMode } from '../../../../services/languageRuntime/common/languageRuntimeService.js';
import { Codicon } from '../../../../../base/common/codicons.js';
import { ThemeIcon } from '../../../../../base/common/themables.js';
import { positronClassNames } from '../../../../../base/common/positronUtilities.js';

export interface RuntimeIconProps {
base64EncodedIconSvg: string | undefined;
sessionMode: LanguageRuntimeSessionMode;
}

export const RuntimeIcon = ({ base64EncodedIconSvg, sessionMode }: RuntimeIconProps) => {
const classNames = ['icon']
if (sessionMode === LanguageRuntimeSessionMode.Notebook) {
classNames.push(...ThemeIcon.asClassNameArray(Codicon.notebook));
return <span className={positronClassNames(...classNames)}></span>;
}
if (base64EncodedIconSvg === undefined) {
return null;
}
return <img
className={positronClassNames(...classNames)}
src={`data:image/svg+xml;base64,${base64EncodedIconSvg}`}
/>;
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
/*---------------------------------------------------------------------------------------------
* Copyright (C) 2025 Posit Software, PBC. All rights reserved.
* Licensed under the Elastic License 2.0. See LICENSE.txt for license information.
*--------------------------------------------------------------------------------------------*/
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
/*---------------------------------------------------------------------------------------------
* Copyright (C) 2025 Posit Software, PBC. All rights reserved.
* Licensed under the Elastic License 2.0. See LICENSE.txt for license information.
*--------------------------------------------------------------------------------------------*/

// CSS.
import './runtimeStatus.css';

// React.
import React from 'react';

// Other dependencies.
import { POSITRON_CONSOLE_STATE_ICON_ACTIVE, POSITRON_CONSOLE_STATE_ICON_DISCONNECTED, POSITRON_CONSOLE_STATE_ICON_IDLE } from '../../../../common/theme.js';
import { ThemeIcon } from '../../../../../base/common/themables.js';
import { Codicon } from '../../../../../base/common/codicons.js';
import { registerIcon } from '../../../../../platform/theme/common/iconRegistry.js';
import { localize } from '../../../../../nls.js';
import { asCssVariable, ColorIdentifier } from '../../../../../platform/theme/common/colorUtils.js';

export const enum RuntimeStatus {
Active = 'Active',
Disconnected = 'Disconnected',
Idle = 'Idle'
}

const positronRuntimeStatusActiveIcon = registerIcon(
'positron-runtime-status-active',
Codicon.positronStatusActive,
localize('positronRuntimeStatusActiveIcon', 'Icon to indicate the \'active\' status of an interpreter session.')
);

const positronRuntimeStatusDisconnectedIcon = registerIcon(
'positron-runtime-status-disconnected',
Codicon.positronStatusDisconnected,
localize('positronRuntimeStatusDisconnectedIcon', 'Icon to indicate the \'disconnected\' status of an interpreter session.')
);

const positronRuntimeStatusIdleIcon = registerIcon(
'positron-runtime-status-idle',
Codicon.positronStatusIdle,
localize('positronRuntimeStatusIdleIcon', 'Icon to indicate the \'idle\' status of an interpreter session.')
);

const statusToIcon: Record<RuntimeStatus, ThemeIcon> = {
[RuntimeStatus.Active]: positronRuntimeStatusActiveIcon,
[RuntimeStatus.Disconnected]: positronRuntimeStatusDisconnectedIcon,
[RuntimeStatus.Idle]: positronRuntimeStatusIdleIcon,
};

const statusToIconColor: Record<RuntimeStatus, ColorIdentifier> = {
[RuntimeStatus.Active]: POSITRON_CONSOLE_STATE_ICON_ACTIVE,
[RuntimeStatus.Disconnected]: POSITRON_CONSOLE_STATE_ICON_DISCONNECTED,
[RuntimeStatus.Idle]: POSITRON_CONSOLE_STATE_ICON_IDLE,
};

export interface RuntimeStatusIconProps {
status: RuntimeStatus;
}

export const RuntimeStatusIcon = ({ status }: RuntimeStatusIconProps) => {
const icon = statusToIcon[status];
const className = ThemeIcon.asClassName(icon);
const color = statusToIconColor[status];
const colorCss = asCssVariable(color);
return (
<span
className={className}
style={{ color: colorCss }}
/>
);
};
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,13 @@ import { IObservable } from '../../../../base/common/observable.js';
import { URI } from '../../../../base/common/uri.js';
import { CellKind, IPositronNotebookCell } from './PositronNotebookCells/IPositronNotebookCell.js';
import { SelectionStateMachine } from './selectionMachine.js';
import { ILanguageRuntimeSession } from '../../../services/runtimeSession/common/runtimeSessionService.js';
import { INotebookLanguageRuntimeSession } from '../../../services/runtimeSession/common/runtimeSessionService.js';
import { Event } from '../../../../base/common/event.js';
import { ICodeEditor } from '../../../../editor/browser/editorBrowser.js';
import { IBaseCellEditorOptions } from '../../notebook/browser/notebookBrowser.js';
import { NotebookOptions } from '../../notebook/browser/notebookOptions.js';
import { PositronNotebookContextKeyManager } from './ContextKeysManager.js';
import { IScopedContextKeyService } from '../../../../platform/contextkey/common/contextkey.js';
/**
* Represents the possible states of a notebook's kernel connection
*/
Expand Down Expand Up @@ -54,6 +55,8 @@ export interface IPositronNotebookInstance {
*/
get uri(): URI;

readonly scopedContextKeyService: IScopedContextKeyService | undefined;

/**
* Indicates whether this notebook instance is currently connected to a view/editor.
* Used to determine if the notebook is currently being displayed.
Expand Down Expand Up @@ -88,7 +91,7 @@ export interface IPositronNotebookInstance {
* Observable reference to the current runtime session for the notebook.
* This manages the connection to the kernel and execution environment.
*/
readonly runtimeSession: IObservable<ILanguageRuntimeSession | undefined>;
readonly runtimeSession: IObservable<INotebookLanguageRuntimeSession | undefined>;

/**
* State machine that manages cell selection behavior and state.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,24 +10,22 @@
overflow: hidden;
text-overflow: ellipsis;
max-width: 200px;
margin-right: 4px;

& span.kernel-status {
font-weight: bold;
}

& .Uninitialized {
color: grey;
}
/* Use this property to take padding into account when sizing (prevents overflow) */
box-sizing: border-box;
display: flex;
align-items: center;
column-gap: 4px;

& .Connected {
color: forestgreen;
}

& .Disconnected {
color: red;
}
.runtime-name {
/* Grow items after session name to fill available space */
flex: 1;

& .Connecting {
color: orange;
margin: 0;
line-height: 22px;
overflow: hidden;
min-width: 0;
text-overflow: ellipsis;
}
}
Loading