Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

notebook cell chat widget #198276

Merged
merged 12 commits into from
Nov 15, 2023
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,9 @@ export class InlineChatController implements IEditorContribution {

private _messages = this._store.add(new Emitter<Message>());

private readonly _onWillStartSession = this._store.add(new Emitter<void>());
readonly onWillStartSession = this._onWillStartSession.event;

readonly onDidAcceptInput = Event.filter(this._messages.event, m => m === Message.ACCEPT_INPUT, this._store);
readonly onDidCancelInput = Event.filter(this._messages.event, m => m === Message.CANCEL_INPUT || m === Message.CANCEL_SESSION, this._store);

Expand Down Expand Up @@ -218,6 +221,7 @@ export class InlineChatController implements IEditorContribution {
if (options.initialSelection) {
this._editor.setSelection(options.initialSelection);
}
this._onWillStartSession.fire();
this._currentRun = this._nextState(State.CREATE_SESSION, options);
await this._currentRun;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ import { IEditorWorkerService } from 'vs/editor/common/services/editorWorker';

const defaultAriaLabel = localize('aria-label', "Inline Chat Input");

const _inputEditorOptions: IEditorConstructionOptions = {
export const _inputEditorOptions: IEditorConstructionOptions = {
padding: { top: 2, bottom: 2 },
overviewRulerLanes: 0,
glyphMargin: false,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,26 @@ const INSERT_MARKDOWN_CELL_ABOVE_COMMAND_ID = 'notebook.cell.insertMarkdownCellA
const INSERT_MARKDOWN_CELL_BELOW_COMMAND_ID = 'notebook.cell.insertMarkdownCellBelow';
const INSERT_MARKDOWN_CELL_AT_TOP_COMMAND_ID = 'notebook.cell.insertMarkdownCellAtTop';

abstract class InsertCellCommand extends NotebookAction {
export function insertNewCell(accessor: ServicesAccessor, context: INotebookActionContext, kind: CellKind, direction: 'above' | 'below', focusEditor: boolean) {
let newCell: CellViewModel | null = null;
if (context.ui) {
context.notebookEditor.focus();
}

const languageService = accessor.get(ILanguageService);
if (context.cell) {
const idx = context.notebookEditor.getCellIndex(context.cell);
newCell = insertCell(languageService, context.notebookEditor, idx, kind, direction, undefined, true);
} else {
const focusRange = context.notebookEditor.getFocus();
const next = Math.max(focusRange.end - 1, 0);
newCell = insertCell(languageService, context.notebookEditor, next, kind, direction, undefined, true);
}

return newCell;
}

export abstract class InsertCellCommand extends NotebookAction {
constructor(
desc: Readonly<IAction2Options>,
private kind: CellKind,
Expand All @@ -38,20 +57,7 @@ abstract class InsertCellCommand extends NotebookAction {
}

async runWithContext(accessor: ServicesAccessor, context: INotebookActionContext): Promise<void> {
let newCell: CellViewModel | null = null;
if (context.ui) {
context.notebookEditor.focus();
}

const languageService = accessor.get(ILanguageService);
if (context.cell) {
const idx = context.notebookEditor.getCellIndex(context.cell);
newCell = insertCell(languageService, context.notebookEditor, idx, this.kind, this.direction, undefined, true);
} else {
const focusRange = context.notebookEditor.getFocus();
const next = Math.max(focusRange.end - 1, 0);
newCell = insertCell(languageService, context.notebookEditor, next, this.kind, this.direction, undefined, true);
}
const newCell = await insertNewCell(accessor, context, this.kind, this.direction, this.focusEditor);

if (newCell) {
await context.notebookEditor.focusNotebookCell(newCell, this.focusEditor ? 'editor' : 'container');
Expand Down
103 changes: 103 additions & 0 deletions src/vs/workbench/contrib/notebook/browser/media/notebookCellChat.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/

.monaco-workbench .notebookOverlay .cell-chat-part {
display: none;
color: inherit;
padding: 6px;
border-radius: 6px;
border: 1px solid var(--vscode-inlineChat-border);
background: var(--vscode-inlineChat-background);
}
.monaco-workbench .notebookOverlay .cell-chat-part .cell-chat-container {
padding: 8px 8px 0px 8px;
}

.monaco-workbench .notebookOverlay .cell-chat-part .cell-chat-container .body {
display: flex;
}

.monaco-workbench .notebookOverlay .cell-chat-part .cell-chat-container .body .content {
display: flex;
box-sizing: border-box;
outline: 1px solid var(--vscode-inlineChatInput-border);
outline-offset: -1px;
border-radius: 2px;
}

.monaco-workbench .notebookOverlay .cell-chat-part .cell-chat-container .body .content.synthetic-focus {
outline: 1px solid var(--vscode-inlineChatInput-focusBorder);
}

.monaco-workbench .notebookOverlay .cell-chat-part .cell-chat-container .body .content .input {
display: flex;
align-items: center;
justify-content: space-between;
padding: 2px 2px 2px 6px;
background-color: var(--vscode-inlineChatInput-background);
cursor: text;
}

.monaco-workbench .notebookOverlay .cell-chat-part .cell-chat-container .body .content .input .monaco-editor-background {
background-color: var(--vscode-inlineChatInput-background);
}

.monaco-workbench .notebookOverlay .cell-chat-part .cell-chat-container .body .content .input .editor-placeholder {
position: absolute;
z-index: 1;
color: var(--vscode-inlineChatInput-placeholderForeground);
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}

.monaco-workbench .notebookOverlay .cell-chat-part .cell-chat-container .body .content .input .editor-placeholder.hidden {
display: none;
}

.monaco-workbench .notebookOverlay .cell-chat-part .cell-chat-container .body .content .input .editor-container {
vertical-align: middle;
}
.monaco-workbench .notebookOverlay .cell-chat-part .cell-chat-container .body .toolbar {
display: flex;
flex-direction: column;
align-self: stretch;
padding-right: 4px;
border-top-right-radius: 2px;
border-bottom-right-radius: 2px;
background: var(--vscode-inlineChatInput-background);
}

.monaco-workbench .notebookOverlay .cell-chat-part .cell-chat-container .body .toolbar .actions-container {
display: flex;
flex-direction: row;
gap: 4px;
}

/* progress */

.monaco-workbench .notebookOverlay .cell-chat-part .cell-chat-container .progress {
position: relative;
}

.monaco-workbench .notebookOverlay .cell-chat-part .cell-chat-container .progress .monaco-progress-container {
top: 0;
}

/* status */

.monaco-workbench .notebookOverlay .cell-chat-part .cell-chat-container .status {
height: 22px;
margin: 4px;
}


.monaco-workbench .notebookOverlay .cell-chat-part .cell-chat-container .status span {
overflow: hidden;
color: var(--vscode-descriptionForeground);
font-size: 11px;
align-self: baseline;
display: flex;
}
Original file line number Diff line number Diff line change
Expand Up @@ -79,9 +79,10 @@
align-items: center;
}

.monaco-workbench .notebookOverlay .cell-list-top-cell-toolbar-container .action-item:first-child,
.monaco-workbench .notebookOverlay > .cell-list-container > .monaco-list > .monaco-scrollable-element > .monaco-list-rows > .monaco-list-row .cell-bottom-toolbar-container .action-item:first-child {
margin-right: 16px;
.monaco-workbench .notebookOverlay .cell-list-top-cell-toolbar-container .action-item,
.monaco-workbench .notebookOverlay > .cell-list-container > .monaco-list > .monaco-scrollable-element > .monaco-list-rows > .monaco-list-row .cell-bottom-toolbar-container .action-item {
margin-left: 8px;
margin-right: 8px;
}

.monaco-workbench .notebookOverlay .cell-list-top-cell-toolbar-container span.codicon,
Expand Down
13 changes: 9 additions & 4 deletions src/vs/workbench/contrib/notebook/browser/notebookBrowser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -171,6 +171,7 @@ export enum CellLayoutState {

export interface CodeCellLayoutInfo {
readonly fontInfo: FontInfo | null;
readonly chatHeight: number;
readonly editorHeight: number;
readonly editorWidth: number;
readonly estimatedHasHorizontalScrolling: boolean;
Expand All @@ -189,6 +190,7 @@ export interface CodeCellLayoutInfo {

export interface CodeCellLayoutChangeEvent {
readonly source?: string;
readonly chatHeight?: boolean;
readonly editorHeight?: boolean;
readonly commentHeight?: boolean;
readonly outputHeight?: boolean;
Expand All @@ -200,6 +202,7 @@ export interface CodeCellLayoutChangeEvent {

export interface MarkupCellLayoutInfo {
readonly fontInfo: FontInfo | null;
readonly chatHeight: number;
readonly editorWidth: number;
readonly editorHeight: number;
readonly statusBarHeight: number;
Expand Down Expand Up @@ -232,7 +235,7 @@ export interface ICellViewModel extends IGenericCellViewModel {
readonly model: NotebookCellTextModel;
readonly id: string;
readonly textBuffer: IReadonlyTextBuffer;
readonly layoutInfo: { totalHeight: number; bottomToolbarOffset: number; editorWidth: number; editorHeight: number; statusBarHeight: number };
readonly layoutInfo: { totalHeight: number; bottomToolbarOffset: number; editorWidth: number; editorHeight: number; statusBarHeight: number; chatHeight: number };
readonly onDidChangeLayout: Event<ICommonCellViewModelLayoutChangeInfo>;
readonly onDidChangeCellStatusBarItems: Event<void>;
readonly onCellDecorationsChanged: Event<{ added: INotebookCellDecorationOptions[]; removed: INotebookCellDecorationOptions[] }>;
Expand All @@ -249,6 +252,7 @@ export interface ICellViewModel extends IGenericCellViewModel {
readonly mime: string;
cellKind: CellKind;
lineNumbers: 'on' | 'off' | 'inherit';
chatHeight: number;
focusMode: CellFocusMode;
outputIsHovered: boolean;
getText(): string;
Expand Down Expand Up @@ -588,7 +592,7 @@ export interface INotebookEditor {
/**
* Reveal cell into viewport.
*/
revealInView(cell: ICellViewModel): void;
revealInView(cell: ICellViewModel): Promise<void>;

/**
* Reveal cell into the top of viewport.
Expand All @@ -603,7 +607,7 @@ export interface INotebookEditor {
/**
* Reveal cell into viewport center if cell is currently out of the viewport.
*/
revealInCenterIfOutsideViewport(cell: ICellViewModel): void;
revealInCenterIfOutsideViewport(cell: ICellViewModel): Promise<void>;

/**
* Reveal a line in notebook cell into viewport with minimal scrolling.
Expand Down Expand Up @@ -798,7 +802,8 @@ export enum CellEditState {
export enum CellFocusMode {
Container,
Editor,
Output
Output,
ChatInput
}

export enum CursorAtBoundary {
Expand Down
22 changes: 15 additions & 7 deletions src/vs/workbench/contrib/notebook/browser/notebookEditorWidget.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
*--------------------------------------------------------------------------------------------*/

import 'vs/css!./media/notebook';
import 'vs/css!./media/notebookCellChat';
import 'vs/css!./media/notebookCellEditorHint';
import 'vs/css!./media/notebookCellInsertToolbar';
import 'vs/css!./media/notebookCellStatusBar';
Expand Down Expand Up @@ -859,6 +860,13 @@ export class NotebookEditorWidget extends Disposable implements INotebookEditorD
}
`);

// chat
styleSheets.push(`
.monaco-workbench .notebookOverlay .cell-chat-part {
margin: 0 ${cellRightMargin}px 8px 6px;
}
`);

this._styleElement.textContent = styleSheets.join('\n');
}

Expand Down Expand Up @@ -2065,7 +2073,7 @@ export class NotebookEditorWidget extends Disposable implements INotebookEditorD
}

revealInView(cell: ICellViewModel) {
this._list.revealCell(cell, CellRevealType.Default);
return this._list.revealCell(cell, CellRevealType.Default);
}

revealInViewAtTop(cell: ICellViewModel) {
Expand All @@ -2076,8 +2084,8 @@ export class NotebookEditorWidget extends Disposable implements INotebookEditorD
this._list.revealCell(cell, CellRevealType.Center);
}

revealInCenterIfOutsideViewport(cell: ICellViewModel) {
this._list.revealCell(cell, CellRevealType.CenterIfOutsideViewport);
async revealInCenterIfOutsideViewport(cell: ICellViewModel) {
await this._list.revealCell(cell, CellRevealType.CenterIfOutsideViewport);
}

revealFirstLineIfOutsideViewport(cell: ICellViewModel) {
Expand Down Expand Up @@ -2346,7 +2354,7 @@ export class NotebookEditorWidget extends Disposable implements INotebookEditorD
const firstSelectionPosition = selectionsStartPosition[0];
await this.revealRangeInViewAsync(cell, Range.fromPositions(firstSelectionPosition, firstSelectionPosition));
} else {
this.revealInView(cell);
await this.revealInView(cell);
}
}

Expand Down Expand Up @@ -2384,13 +2392,13 @@ export class NotebookEditorWidget extends Disposable implements INotebookEditorD
if (!options?.skipReveal) {
if (typeof options?.focusEditorLine === 'number') {
this._cursorNavMode.set(true);
this.revealInView(cell);
await this.revealInView(cell);
} else if (options?.revealBehavior === ScrollToRevealBehavior.firstLine) {
this.revealFirstLineIfOutsideViewport(cell);
} else if (options?.revealBehavior === ScrollToRevealBehavior.fullCell) {
this.revealInView(cell);
await this.revealInView(cell);
} else {
this.revealInCenterIfOutsideViewport(cell);
await this.revealInCenterIfOutsideViewport(cell);
}
}
this._list.focusView();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ export class CellExecutionPart extends CellContentPart {
DOM.hide(this._executionOrderLabel);
} else {
DOM.show(this._executionOrderLabel);
const top = element.layoutInfo.editorHeight - 22 + element.layoutInfo.statusBarHeight;
const top = element.layoutInfo.editorHeight - 22 + element.layoutInfo.statusBarHeight + element.layoutInfo.chatHeight;
this._executionOrderLabel.style.top = `${top}px`;
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -80,15 +80,18 @@ export class CellFocusIndicator extends CellContentPart {
this.bottom.domNode.style.transform = `translateY(${indicatorPostion.bottomIndicatorTop}px)`;
this.left.setHeight(indicatorPostion.verticalIndicatorHeight);
this.right.setHeight(indicatorPostion.verticalIndicatorHeight);
this.codeFocusIndicator.setHeight(indicatorPostion.verticalIndicatorHeight - this.getIndicatorTopMargin() * 2);
this.codeFocusIndicator.setTop(element.layoutInfo.chatHeight);
this.codeFocusIndicator.setHeight(indicatorPostion.verticalIndicatorHeight - this.getIndicatorTopMargin() * 2 - element.layoutInfo.chatHeight);
} else {
const cell = element as CodeCellViewModel;
const layoutInfo = this.notebookEditor.notebookOptions.getLayoutConfiguration();
const bottomToolbarDimensions = this.notebookEditor.notebookOptions.computeBottomToolbarDimensions(this.notebookEditor.textModel?.viewType);
const indicatorHeight = cell.layoutInfo.codeIndicatorHeight + cell.layoutInfo.outputIndicatorHeight + cell.layoutInfo.commentHeight;
this.left.setHeight(indicatorHeight);
this.right.setHeight(indicatorHeight);
this.codeFocusIndicator.setTop(cell.layoutInfo.chatHeight);
this.codeFocusIndicator.setHeight(cell.layoutInfo.codeIndicatorHeight);
this.outputFocusIndicator.setTop(cell.layoutInfo.chatHeight);
this.outputFocusIndicator.setHeight(Math.max(cell.layoutInfo.outputIndicatorHeight - cell.viewContext.notebookOptions.getLayoutConfiguration().focusIndicatorGap, 0));
this.bottom.domNode.style.transform = `translateY(${cell.layoutInfo.totalHeight - bottomToolbarDimensions.bottomToolbarGap - layoutInfo.cellBottomMargin}px)`;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -136,7 +136,9 @@ export class CellEditorStatusBar extends CellContentPart {
element.focusMode = CellFocusMode.Editor;
} else {
const currentMode = element.focusMode;
if (currentMode === CellFocusMode.Output && this._notebookEditor.hasWebviewFocus()) {
if (currentMode === CellFocusMode.ChatInput) {
element.focusMode = CellFocusMode.ChatInput;
} else if (currentMode === CellFocusMode.Output && this._notebookEditor.hasWebviewFocus()) {
element.focusMode = CellFocusMode.Output;
} else {
element.focusMode = CellFocusMode.Container;
Expand Down
Loading
Loading