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

enable inline chat in IW/REPL #228998

Merged
merged 4 commits into from
Sep 19, 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
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ import { extname, isEqual } from '../../../../base/common/resources.js';
import { isFalsyOrWhitespace } from '../../../../base/common/strings.js';
import { URI, UriComponents } from '../../../../base/common/uri.js';
import { IBulkEditService } from '../../../../editor/browser/services/bulkEditService.js';
import { CodeEditorWidget } from '../../../../editor/browser/widget/codeEditor/codeEditorWidget.js';
import { EditOperation } from '../../../../editor/common/core/editOperation.js';
import { PLAINTEXT_LANGUAGE_ID } from '../../../../editor/common/languages/modesRegistry.js';
import { ITextModel } from '../../../../editor/common/model.js';
Expand All @@ -36,7 +35,7 @@ import { Registry } from '../../../../platform/registry/common/platform.js';
import { contrastBorder, ifDefinedThenElse, listInactiveSelectionBackground, registerColor } from '../../../../platform/theme/common/colorRegistry.js';
import { EditorPaneDescriptor, IEditorPaneRegistry } from '../../../browser/editor.js';
import { IWorkbenchContribution, WorkbenchPhase, registerWorkbenchContribution2 } from '../../../common/contributions.js';
import { EditorExtensions, EditorsOrder, IEditorFactoryRegistry, IEditorSerializer, IUntypedEditorInput } from '../../../common/editor.js';
import { EditorExtensions, EditorsOrder, IEditorControl, IEditorFactoryRegistry, IEditorSerializer, IUntypedEditorInput } from '../../../common/editor.js';
import { EditorInput } from '../../../common/editor/editorInput.js';
import { PANEL_BORDER } from '../../../common/theme.js';
import { ResourceNotebookCellEdit } from '../../bulkEdit/browser/bulkCellEdits.js';
Expand All @@ -47,7 +46,6 @@ import { InteractiveEditorInput } from './interactiveEditorInput.js';
import { IInteractiveHistoryService, InteractiveHistoryService } from './interactiveHistoryService.js';
import { NOTEBOOK_EDITOR_WIDGET_ACTION_WEIGHT } from '../../notebook/browser/controller/coreActions.js';
import { INotebookEditorOptions } from '../../notebook/browser/notebookBrowser.js';
import { NotebookEditorWidget } from '../../notebook/browser/notebookEditorWidget.js';
import * as icons from '../../notebook/browser/notebookIcons.js';
import { INotebookEditorService } from '../../notebook/browser/services/notebookEditorService.js';
import { CellEditType, CellKind, CellUri, INTERACTIVE_WINDOW_EDITOR_ID, NotebookSetting, NotebookWorkingCopyTypeIdentifier } from '../../notebook/common/notebookCommon.js';
Expand All @@ -61,6 +59,8 @@ import { IEditorService } from '../../../services/editor/common/editorService.js
import { IExtensionService } from '../../../services/extensions/common/extensions.js';
import { IWorkingCopyIdentifier } from '../../../services/workingCopy/common/workingCopy.js';
import { IWorkingCopyEditorHandler, IWorkingCopyEditorService } from '../../../services/workingCopy/common/workingCopyEditorService.js';
import { isReplEditorControl, ReplEditorControl } from '../../replNotebook/browser/replEditor.js';
import { InlineChatController } from '../../inlineChat/browser/inlineChatController.js';

const interactiveWindowCategory: ILocalizedString = localize2('interactiveWindow', "Interactive Window");

Expand Down Expand Up @@ -396,7 +396,7 @@ registerAction2(class extends Action2 {
const editorInput = editors[0].editor as InteractiveEditorInput;
const currentGroup = editors[0].groupId;
const editor = await editorService.openEditor(editorInput, editorOptions, currentGroup);
const editorControl = editor?.getControl() as { notebookEditor: NotebookEditorWidget | undefined; codeEditor: CodeEditorWidget } | undefined;
const editorControl = editor?.getControl() as ReplEditorControl;

return {
notebookUri: editorInput.resource,
Expand Down Expand Up @@ -437,7 +437,7 @@ registerAction2(class extends Action2 {
historyService.clearHistory(notebookUri);
const editorInput: IUntypedEditorInput = { resource: notebookUri, options: editorOptions };
const editorPane = await editorService.openEditor(editorInput, group);
const editorControl = editorPane?.getControl() as { notebookEditor: NotebookEditorWidget | undefined; codeEditor: CodeEditorWidget } | undefined;
const editorControl = editorPane?.getControl() as ReplEditorControl;
// Extensions must retain references to these URIs to manipulate the interactive editor
logService.debug('New interactive window opened. Notebook editor id', editorControl?.notebookEditor?.getId());
return { notebookUri, inputUri, notebookEditorId: editorControl?.notebookEditor?.getId() };
Expand Down Expand Up @@ -495,26 +495,26 @@ registerAction2(class extends Action2 {
const bulkEditService = accessor.get(IBulkEditService);
const historyService = accessor.get(IInteractiveHistoryService);
const notebookEditorService = accessor.get(INotebookEditorService);
let editorControl: { notebookEditor: NotebookEditorWidget | undefined; codeEditor: CodeEditorWidget } | undefined;
let editorControl: IEditorControl | undefined;
if (context) {
const resourceUri = URI.revive(context);
const editors = editorService.findEditors(resourceUri);
for (const found of editors) {
if (found.editor.typeId === InteractiveEditorInput.ID) {
const editor = await editorService.openEditor(found.editor, found.groupId);
editorControl = editor?.getControl() as { notebookEditor: NotebookEditorWidget | undefined; codeEditor: CodeEditorWidget } | undefined;
editorControl = editor?.getControl();
break;
}
}
}
else {
editorControl = editorService.activeEditorPane?.getControl() as { notebookEditor: NotebookEditorWidget | undefined; codeEditor: CodeEditorWidget } | undefined;
editorControl = editorService.activeEditorPane?.getControl();
}


if (editorControl && editorControl.notebookEditor && editorControl.codeEditor) {
if (editorControl && isReplEditorControl(editorControl) && editorControl.notebookEditor) {
const notebookDocument = editorControl.notebookEditor.textModel;
const textModel = editorControl.codeEditor.getModel();
const textModel = editorControl.activeCodeEditor.getModel();
const activeKernel = editorControl.notebookEditor.activeKernel;
const language = activeKernel?.supportedLanguages[0] ?? PLAINTEXT_LANGUAGE_ID;

Expand All @@ -526,6 +526,11 @@ registerAction2(class extends Action2 {
return;
}

const ctrl = InlineChatController.get(editorControl.activeCodeEditor);
if (ctrl) {
ctrl.acceptHunk();
}

historyService.replaceLast(notebookDocument.uri, value);
historyService.addToHistory(notebookDocument.uri, '');
textModel.setValue('');
Expand Down Expand Up @@ -584,15 +589,15 @@ registerAction2(class extends Action2 {

async run(accessor: ServicesAccessor): Promise<void> {
const editorService = accessor.get(IEditorService);
const editorControl = editorService.activeEditorPane?.getControl() as { notebookEditor: NotebookEditorWidget | undefined; codeEditor: CodeEditorWidget } | undefined;
const editorControl = editorService.activeEditorPane?.getControl();

if (editorControl && editorControl.notebookEditor && editorControl.codeEditor) {
if (editorControl && isReplEditorControl(editorControl) && editorControl.notebookEditor) {
const notebookDocument = editorControl.notebookEditor.textModel;
const textModel = editorControl.codeEditor.getModel();
const range = editorControl.codeEditor.getModel()?.getFullModelRange();
const textModel = editorControl.activeCodeEditor.getModel();
const range = editorControl.activeCodeEditor.getModel()?.getFullModelRange();

if (notebookDocument && textModel && range) {
editorControl.codeEditor.executeEdits('', [EditOperation.replace(range, null)]);
editorControl.activeCodeEditor.executeEdits('', [EditOperation.replace(range, null)]);
}
}
}
Expand Down Expand Up @@ -630,13 +635,13 @@ registerAction2(class extends Action2 {
async run(accessor: ServicesAccessor): Promise<void> {
const editorService = accessor.get(IEditorService);
const historyService = accessor.get(IInteractiveHistoryService);
const editorControl = editorService.activeEditorPane?.getControl() as { notebookEditor: NotebookEditorWidget | undefined; codeEditor: CodeEditorWidget } | undefined;
const editorControl = editorService.activeEditorPane?.getControl();



if (editorControl && editorControl.notebookEditor && editorControl.codeEditor) {
if (editorControl && isReplEditorControl(editorControl) && editorControl.notebookEditor) {
const notebookDocument = editorControl.notebookEditor.textModel;
const textModel = editorControl.codeEditor.getModel();
const textModel = editorControl.activeCodeEditor.getModel();

if (notebookDocument && textModel) {
const previousValue = historyService.getPreviousValue(notebookDocument.uri);
Expand Down Expand Up @@ -680,11 +685,11 @@ registerAction2(class extends Action2 {
async run(accessor: ServicesAccessor): Promise<void> {
const editorService = accessor.get(IEditorService);
const historyService = accessor.get(IInteractiveHistoryService);
const editorControl = editorService.activeEditorPane?.getControl() as { notebookEditor: NotebookEditorWidget | undefined; codeEditor: CodeEditorWidget } | undefined;
const editorControl = editorService.activeEditorPane?.getControl();

if (editorControl && editorControl.notebookEditor && editorControl.codeEditor) {
if (editorControl && isReplEditorControl(editorControl) && editorControl.notebookEditor) {
const notebookDocument = editorControl.notebookEditor.textModel;
const textModel = editorControl.codeEditor.getModel();
const textModel = editorControl.activeCodeEditor.getModel();

if (notebookDocument && textModel) {
const nextValue = historyService.getNextValue(notebookDocument.uri);
Expand Down Expand Up @@ -714,9 +719,9 @@ registerAction2(class extends Action2 {

async run(accessor: ServicesAccessor): Promise<void> {
const editorService = accessor.get(IEditorService);
const editorControl = editorService.activeEditorPane?.getControl() as { notebookEditor: NotebookEditorWidget | undefined; codeEditor: CodeEditorWidget } | undefined;
const editorControl = editorService.activeEditorPane?.getControl();

if (editorControl && editorControl.notebookEditor && editorControl.codeEditor) {
if (editorControl && isReplEditorControl(editorControl) && editorControl.notebookEditor) {
if (editorControl.notebookEditor.getLength() === 0) {
return;
}
Expand All @@ -743,9 +748,9 @@ registerAction2(class extends Action2 {

async run(accessor: ServicesAccessor): Promise<void> {
const editorService = accessor.get(IEditorService);
const editorControl = editorService.activeEditorPane?.getControl() as { notebookEditor: NotebookEditorWidget | undefined; codeEditor: CodeEditorWidget } | undefined;
const editorControl = editorService.activeEditorPane?.getControl();

if (editorControl && editorControl.notebookEditor && editorControl.codeEditor) {
if (editorControl && isReplEditorControl(editorControl) && editorControl.notebookEditor) {
if (editorControl.notebookEditor.getLength() === 0) {
return;
}
Expand All @@ -772,9 +777,9 @@ registerAction2(class extends Action2 {

async run(accessor: ServicesAccessor): Promise<void> {
const editorService = accessor.get(IEditorService);
const editorControl = editorService.activeEditorPane?.getControl() as { notebookEditor: NotebookEditorWidget | undefined; codeEditor: CodeEditorWidget } | undefined;
const editorControl = editorService.activeEditorPane?.getControl();

if (editorControl && editorControl.notebookEditor && editorControl.codeEditor) {
if (editorControl && isReplEditorControl(editorControl) && editorControl.notebookEditor) {
editorService.activeEditorPane?.focus();
}
else {
Expand All @@ -785,9 +790,9 @@ registerAction2(class extends Action2 {
const editorInput = interactiveWindow.editor as InteractiveEditorInput;
const currentGroup = interactiveWindow.groupId;
const editor = await editorService.openEditor(editorInput, currentGroup);
const editorControl = editor?.getControl() as { notebookEditor: NotebookEditorWidget | undefined; codeEditor: CodeEditorWidget } | undefined;
const editorControl = editor?.getControl();

if (editorControl && editorControl.notebookEditor && editorControl.codeEditor) {
if (editorControl && isReplEditorControl(editorControl) && editorControl.notebookEditor) {
editorService.activeEditorPane?.focus();
}
}
Expand All @@ -811,9 +816,9 @@ registerAction2(class extends Action2 {

async run(accessor: ServicesAccessor): Promise<void> {
const editorService = accessor.get(IEditorService);
const editorControl = editorService.activeEditorPane?.getControl() as { notebookEditor: NotebookEditorWidget | undefined; codeEditor: CodeEditorWidget; focusHistory: () => void } | undefined;
const editorControl = editorService.activeEditorPane?.getControl();

if (editorControl && editorControl.notebookEditor && editorControl.codeEditor) {
if (editorControl && isReplEditorControl(editorControl) && editorControl.notebookEditor) {
editorControl.notebookEditor.focus();
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,11 @@
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/

.interactive-editor .input-cell-container:focus-within .input-editor-container .monaco-editor {
.interactive-editor .input-cell-container:focus-within .input-editor-container>.monaco-editor {
outline: solid 1px var(--vscode-notebook-focusedCellBorder);
}

.interactive-editor .input-cell-container .input-editor-container .monaco-editor {
.interactive-editor .input-cell-container .input-editor-container>.monaco-editor {
outline: solid 1px var(--vscode-notebook-inactiveFocusedCellBorder);
}

Expand Down
30 changes: 25 additions & 5 deletions src/vs/workbench/contrib/interactive/browser/interactiveEditor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import { Emitter, Event } from '../../../../base/common/event.js';
import { DisposableStore, MutableDisposable } from '../../../../base/common/lifecycle.js';
import { ICodeEditorService } from '../../../../editor/browser/services/codeEditorService.js';
import { CodeEditorWidget } from '../../../../editor/browser/widget/codeEditor/codeEditorWidget.js';
import { ICodeEditorViewState } from '../../../../editor/common/editorCommon.js';
import { ICodeEditorViewState, ICompositeCodeEditor } from '../../../../editor/common/editorCommon.js';
import { IContextKeyService } from '../../../../platform/contextkey/common/contextkey.js';
import { IInstantiationService } from '../../../../platform/instantiation/common/instantiation.js';
import { IStorageService } from '../../../../platform/storage/common/storage.js';
Expand Down Expand Up @@ -64,6 +64,8 @@ import { ContentHoverController } from '../../../../editor/contrib/hover/browser
import { GlyphHoverController } from '../../../../editor/contrib/hover/browser/glyphHoverController.js';
import { ReplInputHintContentWidget } from './replInputHintContentWidget.js';
import { ServiceCollection } from '../../../../platform/instantiation/common/serviceCollection.js';
import { INLINE_CHAT_ID } from '../../inlineChat/common/inlineChat.js';
import { ReplEditorControl } from '../../replNotebook/browser/replEditor.js';

const DECORATION_KEY = 'interactiveInputDecoration';
const INTERACTIVE_EDITOR_VIEW_STATE_PREFERENCE_KEY = 'InteractiveEditorViewState';
Expand Down Expand Up @@ -408,7 +410,8 @@ export class InteractiveEditor extends EditorPane implements IEditorPaneWithScro
TabCompletionController.ID,
ContentHoverController.ID,
GlyphHoverController.ID,
MarkerController.ID
MarkerController.ID,
INLINE_CHAT_ID
])
}
});
Expand Down Expand Up @@ -503,6 +506,12 @@ export class InteractiveEditor extends EditorPane implements IEditorPaneWithScro
}
}));

this._codeEditorWidget.onDidChangeModelDecorations(() => {
if (this.isVisible()) {
this._updateInputHint();
}
});

this._widgetDisposableStore.add(this._codeEditorWidget.onDidChangeModel(() => {
this._updateInputHint();
}));
Expand Down Expand Up @@ -653,6 +662,15 @@ export class InteractiveEditor extends EditorPane implements IEditorPaneWithScro
return new DOM.Dimension(Math.max(0, width), Math.max(0, height));
}

private _hasConflictingDecoration() {
return Boolean(this._codeEditorWidget.getLineDecorations(1)?.find((d) =>
d.options.beforeContentClassName
|| d.options.afterContentClassName
|| d.options.before?.content
|| d.options.after?.content
));
}

private _updateInputHint(): void {
if (!this._codeEditorWidget) {
return;
Expand All @@ -661,7 +679,8 @@ export class InteractiveEditor extends EditorPane implements IEditorPaneWithScro
const shouldHide =
!this._codeEditorWidget.hasModel() ||
this._configurationService.getValue<boolean>(InteractiveWindowSetting.showExecutionHint) === false ||
this._codeEditorWidget.getModel()!.getValueLength() !== 0;
this._codeEditorWidget.getModel()!.getValueLength() !== 0 ||
this._hasConflictingDecoration();

if (!this._hintElement && !shouldHide) {
this._hintElement = this._instantiationService.createInstance(ReplInputHintContentWidget, this._codeEditorWidget);
Expand Down Expand Up @@ -721,10 +740,11 @@ export class InteractiveEditor extends EditorPane implements IEditorPaneWithScro
super.clearInput();
}

override getControl(): { notebookEditor: NotebookEditorWidget | undefined; codeEditor: CodeEditorWidget } {
override getControl(): ReplEditorControl & ICompositeCodeEditor {
return {
notebookEditor: this._notebookWidget.value,
codeEditor: this._codeEditorWidget
activeCodeEditor: this._codeEditorWidget,
onDidChangeActiveEditor: Event.None
};
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,11 @@
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/

.interactive-editor .input-cell-container:focus-within .input-editor-container .monaco-editor {
.interactive-editor .input-cell-container:focus-within .input-editor-container>.monaco-editor {
outline: solid 1px var(--vscode-notebook-focusedCellBorder);
}

.interactive-editor .input-cell-container .input-editor-container .monaco-editor {
.interactive-editor .input-cell-container .input-editor-container>.monaco-editor {
outline: solid 1px var(--vscode-notebook-inactiveFocusedCellBorder);
}

Expand Down
Loading
Loading