Skip to content

Commit

Permalink
Merge pull request #198276 from microsoft/rebornix/lonely-wildfowl
Browse files Browse the repository at this point in the history
notebook cell chat widget
  • Loading branch information
rebornix authored Nov 15, 2023
2 parents d5b7d48 + defffc1 commit f5a048f
Show file tree
Hide file tree
Showing 19 changed files with 949 additions and 41 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,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 @@ -220,6 +223,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

0 comments on commit f5a048f

Please sign in to comment.