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

Reserve focus for cell chat widget. #207000

Merged
merged 1 commit into from
Mar 7, 2024
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
Reserve focus for cell chat widget.
  • Loading branch information
rebornix committed Mar 6, 2024
commit 14373df929b404fa463e1db512b38c331e52d052
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ import { asProgressiveEdit, performAsyncTextEdit } from 'vs/workbench/contrib/in
import { CTX_INLINE_CHAT_LAST_RESPONSE_TYPE, EditMode, IInlineChatProgressItem, IInlineChatRequest, InlineChatResponseFeedbackKind, InlineChatResponseType } from 'vs/workbench/contrib/inlineChat/common/inlineChat';
import { insertCell, runDeleteAction } from 'vs/workbench/contrib/notebook/browser/controller/cellOperations';
import { CTX_NOTEBOOK_CELL_CHAT_FOCUSED, CTX_NOTEBOOK_CHAT_HAS_ACTIVE_REQUEST, CTX_NOTEBOOK_CHAT_OUTER_FOCUS_POSITION, CTX_NOTEBOOK_CHAT_USER_DID_EDIT, MENU_CELL_CHAT_INPUT, MENU_CELL_CHAT_WIDGET, MENU_CELL_CHAT_WIDGET_FEEDBACK, MENU_CELL_CHAT_WIDGET_STATUS } from 'vs/workbench/contrib/notebook/browser/controller/chat/notebookChatContext';
import { INotebookEditor, INotebookEditorContribution, INotebookViewZone, ScrollToRevealBehavior } from 'vs/workbench/contrib/notebook/browser/notebookBrowser';
import { INotebookEditor, INotebookEditorContribution, INotebookViewZone } from 'vs/workbench/contrib/notebook/browser/notebookBrowser';
import { registerNotebookContribution } from 'vs/workbench/contrib/notebook/browser/notebookEditorExtensions';
import { CellViewModel } from 'vs/workbench/contrib/notebook/browser/viewModel/notebookViewModelImpl';
import { CellKind } from 'vs/workbench/contrib/notebook/common/notebookCommon';
Expand Down Expand Up @@ -96,21 +96,35 @@ class NotebookChatWidget extends Disposable implements INotebookViewZone {
this._layoutWidget(inlineChatWidget, widgetContainer);
}

hasFocus() {
return this.inlineChatWidget.hasFocus();
}

focus() {
this.updateNotebookEditorFocusNSelections();
this.inlineChatWidget.focus();
}

updateNotebookEditorFocusNSelections() {
this._notebookEditor.focusContainer(true);
this._notebookEditor.setFocus({ start: this.afterModelPosition, end: this.afterModelPosition });
this._notebookEditor.setSelections([{
start: this.afterModelPosition,
end: this.afterModelPosition
}]);
}

getEditingCell() {
return this._editingCell;
}

async getOrCreateEditingCell(): Promise<{ cell: CellViewModel; editor: IActiveCodeEditor } | undefined> {
if (this._editingCell) {
await this._notebookEditor.focusNotebookCell(this._editingCell, 'editor');
if (this._notebookEditor.activeCodeEditor?.hasModel()) {
const codeEditor = this._notebookEditor.codeEditors.find(ce => ce[0] === this._editingCell)?.[1];
if (codeEditor?.hasModel()) {
return {
cell: this._editingCell,
editor: this._notebookEditor.activeCodeEditor
editor: codeEditor
};
} else {
return undefined;
Expand All @@ -121,17 +135,25 @@ class NotebookChatWidget extends Disposable implements INotebookViewZone {
return undefined;
}

const widgetHasFocus = this.inlineChatWidget.hasFocus();

this._editingCell = insertCell(this._languageService, this._notebookEditor, this.afterModelPosition, CellKind.Code, 'above');

if (!this._editingCell) {
return undefined;
}

await this._notebookEditor.focusNotebookCell(this._editingCell, 'editor', { revealBehavior: ScrollToRevealBehavior.firstLine });
if (this._notebookEditor.activeCodeEditor?.hasModel()) {
await this._notebookEditor.revealFirstLineIfOutsideViewport(this._editingCell);

if (widgetHasFocus) {
this.focus();
}

const codeEditor = this._notebookEditor.codeEditors.find(ce => ce[0] === this._editingCell)?.[1];
if (codeEditor?.hasModel()) {
return {
cell: this._editingCell,
editor: this._notebookEditor.activeCodeEditor
editor: codeEditor
};
}

Expand Down Expand Up @@ -389,12 +411,7 @@ export class NotebookChatController extends Disposable implements INotebookEdito
return;
}

this._notebookEditor.focusContainer(true);
this._notebookEditor.setFocus({ start: this._widget.afterModelPosition, end: this._widget.afterModelPosition });
this._notebookEditor.setSelections([{
start: this._widget.afterModelPosition,
end: this._widget.afterModelPosition
}]);
this._widget.updateNotebookEditorFocusNSelections();
}

async acceptInput() {
Expand Down Expand Up @@ -738,6 +755,10 @@ export class NotebookChatController extends Disposable implements INotebookEdito
await this._notebookEditor.focusNotebookCell(cell, 'editor');
}

hasFocus() {
return this._widget?.hasFocus() ?? false;
}

focus() {
this._focusWidget();
}
Expand Down Expand Up @@ -768,6 +789,10 @@ export class NotebookChatController extends Disposable implements INotebookEdito
this._activeRequestCts?.cancel();
}

getEditingCell() {
return this._widget?.getEditingCell();
}

discard() {
this._strategy?.cancel();
this._activeRequestCts?.cancel();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ import { IDebugService } from 'vs/workbench/contrib/debug/common/debug';
import { InlineChatController } from 'vs/workbench/contrib/inlineChat/browser/inlineChatController';
import { CTX_INLINE_CHAT_FOCUSED } from 'vs/workbench/contrib/inlineChat/common/inlineChat';
import { insertCell } from 'vs/workbench/contrib/notebook/browser/controller/cellOperations';
import { CTX_NOTEBOOK_CELL_CHAT_FOCUSED } from 'vs/workbench/contrib/notebook/browser/controller/chat/notebookChatContext';
import { NotebookChatController } from 'vs/workbench/contrib/notebook/browser/controller/chat/notebookChatController';
import { CELL_TITLE_CELL_GROUP_ID, CellToolbarOrder, INotebookActionContext, INotebookCellActionContext, INotebookCellToolbarActionContext, INotebookCommandContext, NOTEBOOK_EDITOR_WIDGET_ACTION_WEIGHT, NotebookAction, NotebookCellAction, NotebookMultiCellAction, cellExecutionArgs, executeNotebookCondition, getContextFromActiveEditor, getContextFromUri, parseMultiCellExecutionArgs } from 'vs/workbench/contrib/notebook/browser/controller/coreActions';
import { CellEditState, CellFocusMode, EXECUTE_CELL_COMMAND_ID, IFocusNotebookCellOptions, ScrollToRevealBehavior } from 'vs/workbench/contrib/notebook/browser/notebookBrowser';
import * as icons from 'vs/workbench/contrib/notebook/browser/notebookIcons';
Expand Down Expand Up @@ -198,7 +200,10 @@ registerAction2(class ExecuteCell extends NotebookMultiCellAction {
precondition: executeThisCellCondition,
title: localize('notebookActions.execute', "Execute Cell"),
keybinding: {
when: NOTEBOOK_CELL_LIST_FOCUSED,
when: ContextKeyExpr.or(
NOTEBOOK_CELL_LIST_FOCUSED,
ContextKeyExpr.and(CTX_NOTEBOOK_CELL_CHAT_FOCUSED, CTX_INLINE_CHAT_FOCUSED)
),
primary: KeyMod.WinCtrl | KeyCode.Enter,
win: {
primary: KeyMod.CtrlCmd | KeyMod.Alt | KeyCode.Enter
Expand Down Expand Up @@ -229,6 +234,21 @@ registerAction2(class ExecuteCell extends NotebookMultiCellAction {
await context.notebookEditor.focusNotebookCell(context.cell, 'container', { skipReveal: true });
}

const chatController = NotebookChatController.get(context.notebookEditor);
const editingCell = chatController?.getEditingCell();
if (chatController?.hasFocus() && editingCell) {
const group = editorGroupsService.activeGroup;

if (group) {
if (group.activeEditor) {
group.pinEditor(group.activeEditor);
}
}

await context.notebookEditor.executeNotebookCells([editingCell]);
return;
}

await runCell(editorGroupsService, context);
}
});
Expand Down
5 changes: 5 additions & 0 deletions src/vs/workbench/contrib/notebook/browser/notebookBrowser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -629,6 +629,11 @@ export interface INotebookEditor {
*/
revealInCenterIfOutsideViewport(cell: ICellViewModel): Promise<void>;

/**
* Reveal the first line of the cell into the view if the cell is outside of the viewport.
*/
revealFirstLineIfOutsideViewport(cell: ICellViewModel): Promise<void>;

/**
* Reveal a line in notebook cell into viewport with minimal scrolling.
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2122,8 +2122,8 @@ export class NotebookEditorWidget extends Disposable implements INotebookEditorD
await this._list.revealCell(cell, CellRevealType.CenterIfOutsideViewport);
}

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

async revealLineInViewAsync(cell: ICellViewModel, line: number): Promise<void> {
Expand Down Expand Up @@ -2446,7 +2446,7 @@ export class NotebookEditorWidget extends Disposable implements INotebookEditorD
this._cursorNavMode.set(true);
await this.revealInView(cell);
} else if (options?.revealBehavior === ScrollToRevealBehavior.firstLine) {
this.revealFirstLineIfOutsideViewport(cell);
await this.revealFirstLineIfOutsideViewport(cell);
} else if (options?.revealBehavior === ScrollToRevealBehavior.fullCell) {
await this.revealInView(cell);
} else {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -925,8 +925,12 @@ export class NotebookCellList extends WorkbenchList<CellViewModel> implements ID
break;
}

// wait for the editor to be created only if the cell is in editing mode (meaning it has an editor and will focus the editor)
if (cell.getEditState() === CellEditState.Editing && !cell.editorAttached) {
if ((
// wait for the editor to be created if the cell is in editing mode
cell.getEditState() === CellEditState.Editing
// wait for the editor to be created if we are revealing the first line of the cell
|| revealType === CellRevealType.FirstLineIfOutsideViewport
) && !cell.editorAttached) {
return getEditorAttachedPromise(cell);
}

Expand Down
Loading