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

joh/lovely jackal #183517

Merged
merged 5 commits into from May 26, 2023
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.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
4 changes: 3 additions & 1 deletion src/vs/platform/actions/browser/menuEntryActionViewItem.ts
Expand Up @@ -155,7 +155,9 @@ export class MenuEntryActionViewItem extends ActionViewItem {
super.render(container);
container.classList.add('menu-entry');

this._updateItemClass(this._menuItemAction.item);
if (this.options.icon) {
this._updateItemClass(this._menuItemAction.item);
}

let mouseOver = false;

Expand Down
Expand Up @@ -90,28 +90,43 @@
/* status */

.monaco-editor .interactive-editor .status {
padding: 6px 0px 2px 0px;
margin-top: 3px;
display: flex;
justify-content: space-between;
align-items: center;
}

.monaco-editor .interactive-editor .status.actions {
margin-top: 6px;
}

.monaco-editor .interactive-editor .status .actions.hidden {
display: none;
}

.monaco-editor .interactive-editor .status .label {
overflow: hidden;
padding-left: 10px;
padding-right: 4px;
margin-left: auto;
color: var(--vscode-descriptionForeground);
font-size: 11px;
align-self: baseline;
display: flex;
}

.monaco-editor .interactive-editor .status .label.hidden {
display: none;
}

.monaco-editor .interactive-editor .status .label.info {
margin-right: auto;
padding-left: 2px;
}

.monaco-editor .interactive-editor .status .label.status {
padding-left: 10px;
padding-right: 4px;
margin-left: auto;
}

.monaco-editor .interactive-editor .markdownMessage {
padding-top: 10px;
}
Expand Down Expand Up @@ -161,6 +176,18 @@
outline: 1px solid var(--vscode-inputOption-activeBorder);
}

.monaco-editor .interactive-editor .status .monaco-toolbar .action-item.button-item .action-label {
color: var(--vscode-button-foreground);
background-color: var(--vscode-button-background);
border-radius: 2px;
padding: 4px 6px;
}

.monaco-editor .interactive-editor .status .monaco-toolbar .action-item.button-item .action-label>.codicon {
color: unset;
font-size: 14px;
}

/* preview */

.monaco-editor .interactive-editor .preview {
Expand Down
Expand Up @@ -10,7 +10,7 @@ import { EditorAction2 } from 'vs/editor/browser/editorExtensions';
import { EmbeddedCodeEditorWidget, EmbeddedDiffEditorWidget } from 'vs/editor/browser/widget/embeddedCodeEditorWidget';
import { EditorContextKeys } from 'vs/editor/common/editorContextKeys';
import { InteractiveEditorController, InteractiveEditorRunOptions } from 'vs/workbench/contrib/interactiveEditor/browser/interactiveEditorController';
import { CTX_INTERACTIVE_EDITOR_FOCUSED, CTX_INTERACTIVE_EDITOR_HAS_ACTIVE_REQUEST, CTX_INTERACTIVE_EDITOR_HAS_PROVIDER, CTX_INTERACTIVE_EDITOR_INNER_CURSOR_FIRST, CTX_INTERACTIVE_EDITOR_INNER_CURSOR_LAST, CTX_INTERACTIVE_EDITOR_EMPTY, CTX_INTERACTIVE_EDITOR_OUTER_CURSOR_POSITION, CTX_INTERACTIVE_EDITOR_VISIBLE, MENU_INTERACTIVE_EDITOR_WIDGET, MENU_INTERACTIVE_EDITOR_WIDGET_DISCARD, MENU_INTERACTIVE_EDITOR_WIDGET_STATUS, CTX_INTERACTIVE_EDITOR_LAST_FEEDBACK, CTX_INTERACTIVE_EDITOR_SHOWING_DIFF, CTX_INTERACTIVE_EDITOR_EDIT_MODE, EditMode, CTX_INTERACTIVE_EDITOR_LAST_RESPONSE_TYPE, MENU_INTERACTIVE_EDITOR_WIDGET_MARKDOWN_MESSAGE, CTX_INTERACTIVE_EDITOR_MESSAGE_CROP_STATE, CTX_INTERACTIVE_EDITOR_DOCUMENT_CHANGED, CTX_INTERACTIVE_EDITOR_DID_EDIT, CTX_INTERACTIVE_EDITOR_HAS_STASHED_SESSION } from 'vs/workbench/contrib/interactiveEditor/common/interactiveEditor';
import { CTX_INTERACTIVE_EDITOR_FOCUSED, CTX_INTERACTIVE_EDITOR_HAS_ACTIVE_REQUEST, CTX_INTERACTIVE_EDITOR_HAS_PROVIDER, CTX_INTERACTIVE_EDITOR_INNER_CURSOR_FIRST, CTX_INTERACTIVE_EDITOR_INNER_CURSOR_LAST, CTX_INTERACTIVE_EDITOR_EMPTY, CTX_INTERACTIVE_EDITOR_OUTER_CURSOR_POSITION, CTX_INTERACTIVE_EDITOR_VISIBLE, MENU_INTERACTIVE_EDITOR_WIDGET, MENU_INTERACTIVE_EDITOR_WIDGET_DISCARD, MENU_INTERACTIVE_EDITOR_WIDGET_STATUS, CTX_INTERACTIVE_EDITOR_LAST_FEEDBACK, CTX_INTERACTIVE_EDITOR_SHOWING_DIFF, CTX_INTERACTIVE_EDITOR_EDIT_MODE, EditMode, CTX_INTERACTIVE_EDITOR_LAST_RESPONSE_TYPE, MENU_INTERACTIVE_EDITOR_WIDGET_MARKDOWN_MESSAGE, CTX_INTERACTIVE_EDITOR_MESSAGE_CROP_STATE, CTX_INTERACTIVE_EDITOR_DOCUMENT_CHANGED, CTX_INTERACTIVE_EDITOR_DID_EDIT, CTX_INTERACTIVE_EDITOR_HAS_STASHED_SESSION, MENU_INTERACTIVE_EDITOR_WIDGET_FEEDBACK, ACTION_ACCEPT_CHANGES } from 'vs/workbench/contrib/interactiveEditor/common/interactiveEditor';
import { localize } from 'vs/nls';
import { IAction2Options, MenuRegistry } from 'vs/platform/actions/common/actions';
import { IClipboardService } from 'vs/platform/clipboard/common/clipboardService';
Expand Down Expand Up @@ -377,7 +377,7 @@ export class FeebackHelpfulCommand extends AbstractInteractiveEditorAction {
precondition: CTX_INTERACTIVE_EDITOR_VISIBLE,
toggled: CTX_INTERACTIVE_EDITOR_LAST_FEEDBACK.isEqualTo('helpful'),
menu: {
id: MENU_INTERACTIVE_EDITOR_WIDGET_STATUS,
id: MENU_INTERACTIVE_EDITOR_WIDGET_FEEDBACK,
when: CTX_INTERACTIVE_EDITOR_LAST_RESPONSE_TYPE.notEqualsTo(undefined),
group: '2_feedback',
order: 1
Expand All @@ -399,7 +399,7 @@ export class FeebackUnhelpfulCommand extends AbstractInteractiveEditorAction {
precondition: CTX_INTERACTIVE_EDITOR_VISIBLE,
toggled: CTX_INTERACTIVE_EDITOR_LAST_FEEDBACK.isEqualTo('unhelpful'),
menu: {
id: MENU_INTERACTIVE_EDITOR_WIDGET_STATUS,
id: MENU_INTERACTIVE_EDITOR_WIDGET_FEEDBACK,
when: CTX_INTERACTIVE_EDITOR_LAST_RESPONSE_TYPE.notEqualsTo(undefined),
group: '2_feedback',
order: 2
Expand All @@ -419,11 +419,11 @@ export class ToggleInlineDiff extends AbstractInteractiveEditorAction {
id: 'interactiveEditor.toggleDiff',
title: localize('toggleDiff', 'Toggle Diff'),
icon: Codicon.diff,
precondition: CTX_INTERACTIVE_EDITOR_VISIBLE,
precondition: ContextKeyExpr.and(CTX_INTERACTIVE_EDITOR_VISIBLE, CTX_INTERACTIVE_EDITOR_DID_EDIT),
toggled: CTX_INTERACTIVE_EDITOR_SHOWING_DIFF,
menu: {
id: MENU_INTERACTIVE_EDITOR_WIDGET_STATUS,
when: ContextKeyExpr.and(CTX_INTERACTIVE_EDITOR_EDIT_MODE.notEqualsTo(EditMode.Preview), CTX_INTERACTIVE_EDITOR_DID_EDIT),
when: CTX_INTERACTIVE_EDITOR_EDIT_MODE.notEqualsTo(EditMode.Preview),
group: '0_main',
order: 10
}
Expand All @@ -439,8 +439,9 @@ export class ApplyPreviewEdits extends AbstractInteractiveEditorAction {

constructor() {
super({
id: 'interactiveEditor.applyEdits',
title: localize('applyEdits', 'Apply Changes'),
id: ACTION_ACCEPT_CHANGES,
title: localize('apply1', 'Accept Changes'),
shortTitle: localize('apply2', 'Accept'),
icon: Codicon.check,
precondition: ContextKeyExpr.and(CTX_INTERACTIVE_EDITOR_VISIBLE, ContextKeyExpr.or(CTX_INTERACTIVE_EDITOR_DOCUMENT_CHANGED.toNegated(), CTX_INTERACTIVE_EDITOR_EDIT_MODE.notEqualsTo(EditMode.Preview))),
keybinding: [{
Expand Down
Expand Up @@ -257,7 +257,7 @@ export class InteractiveEditorController implements IEditorContribution {

this._zone.widget.updateSlashCommands(this._activeSession.session.slashCommands ?? []);
this._zone.widget.placeholder = this._getPlaceholderText();
this._zone.widget.updateStatus(this._activeSession.session.message ?? localize('welcome.1', "AI-generated code may be incorrect"));
this._zone.widget.updateInfo(this._activeSession.session.message ?? localize('welcome.1', "AI-generated code may be incorrect"));
this._zone.show(this._activeSession.wholeRange.getEndPosition());

this._sessionStore.add(this._editor.onDidChangeModel(() => {
Expand Down Expand Up @@ -443,6 +443,7 @@ export class InteractiveEditorController implements IEditorContribution {
let reply: IInteractiveEditorResponse | null | undefined;
try {
this._zone.widget.updateProgress(true);
this._zone.widget.updateInfo(!this._activeSession.lastExchange ? localize('thinking', "Thinking\u2026") : '');
this._ctxHasActiveRequest.set(true);
reply = await raceCancellationError(Promise.resolve(task), requestCts.token);

Expand All @@ -460,6 +461,7 @@ export class InteractiveEditorController implements IEditorContribution {
} finally {
this._ctxHasActiveRequest.set(false);
this._zone.widget.updateProgress(false);
this._zone.widget.updateInfo('');
this._logService.trace('[IE] request took', sw.elapsed(), this._activeSession.provider.debugName);

}
Expand Down
Expand Up @@ -326,11 +326,11 @@ export class LiveStrategy extends EditModeStrategy {
}
let message: string;
if (linesChanged === 0) {
message = localize('lines.0', "Generated reply");
message = localize('lines.0', "Nothing changed");
} else if (linesChanged === 1) {
message = localize('lines.1', "Generated reply and changed 1 line");
message = localize('lines.1', "Changed 1 line");
} else {
message = localize('lines.N', "Generated reply and changed {0} lines", linesChanged);
message = localize('lines.N', "Changed {0} lines", linesChanged);
}
this._widget.updateStatus(message);
}
Expand Down
Expand Up @@ -12,7 +12,7 @@ import { localize } from 'vs/nls';
import { IContextKey, IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
import { ZoneWidget } from 'vs/editor/contrib/zoneWidget/browser/zoneWidget';
import { CTX_INTERACTIVE_EDITOR_FOCUSED, CTX_INTERACTIVE_EDITOR_INNER_CURSOR_FIRST, CTX_INTERACTIVE_EDITOR_INNER_CURSOR_LAST, CTX_INTERACTIVE_EDITOR_EMPTY, CTX_INTERACTIVE_EDITOR_OUTER_CURSOR_POSITION, CTX_INTERACTIVE_EDITOR_VISIBLE, MENU_INTERACTIVE_EDITOR_WIDGET, MENU_INTERACTIVE_EDITOR_WIDGET_STATUS, MENU_INTERACTIVE_EDITOR_WIDGET_MARKDOWN_MESSAGE, CTX_INTERACTIVE_EDITOR_MESSAGE_CROP_STATE, IInteractiveEditorSlashCommand } from 'vs/workbench/contrib/interactiveEditor/common/interactiveEditor';
import { CTX_INTERACTIVE_EDITOR_FOCUSED, CTX_INTERACTIVE_EDITOR_INNER_CURSOR_FIRST, CTX_INTERACTIVE_EDITOR_INNER_CURSOR_LAST, CTX_INTERACTIVE_EDITOR_EMPTY, CTX_INTERACTIVE_EDITOR_OUTER_CURSOR_POSITION, CTX_INTERACTIVE_EDITOR_VISIBLE, MENU_INTERACTIVE_EDITOR_WIDGET, MENU_INTERACTIVE_EDITOR_WIDGET_STATUS, MENU_INTERACTIVE_EDITOR_WIDGET_MARKDOWN_MESSAGE, CTX_INTERACTIVE_EDITOR_MESSAGE_CROP_STATE, IInteractiveEditorSlashCommand, MENU_INTERACTIVE_EDITOR_WIDGET_FEEDBACK, ACTION_ACCEPT_CHANGES } from 'vs/workbench/contrib/interactiveEditor/common/interactiveEditor';
import { IModelDeltaDecoration, ITextModel } from 'vs/editor/common/model';
import { Dimension, addDisposableListener, getTotalHeight, getTotalWidth, h, reset } from 'vs/base/browser/dom';
import { Emitter, Event, MicrotaskEmitter } from 'vs/base/common/event';
Expand All @@ -28,7 +28,7 @@ import { ProgressBar } from 'vs/base/browser/ui/progressbar/progressbar';
import { SuggestController } from 'vs/editor/contrib/suggest/browser/suggestController';
import { IPosition, Position } from 'vs/editor/common/core/position';
import { DEFAULT_FONT_FAMILY } from 'vs/workbench/browser/style';
import { DropdownWithDefaultActionViewItem, createActionViewItem } from 'vs/platform/actions/browser/menuEntryActionViewItem';
import { DropdownWithDefaultActionViewItem, IMenuEntryActionViewItemOptions, MenuEntryActionViewItem, createActionViewItem } from 'vs/platform/actions/browser/menuEntryActionViewItem';
import { CompletionItem, CompletionItemInsertTextRule, CompletionItemKind, CompletionItemProvider, CompletionList, ProviderResult, TextEdit } from 'vs/editor/common/languages';
import { EditOperation, ISingleEditOperation } from 'vs/editor/common/core/editOperation';
import { ILanguageSelection, ILanguageService } from 'vs/editor/common/languages/language';
Expand All @@ -44,10 +44,12 @@ import { invertLineRange, lineRangeAsRange } from 'vs/workbench/contrib/interact
import { ICodeEditorViewState, ScrollType } from 'vs/editor/common/editorCommon';
import { LineRange } from 'vs/editor/common/core/lineRange';
import { IAccessibilityService } from 'vs/platform/accessibility/common/accessibility';
import { SubmenuItemAction } from 'vs/platform/actions/common/actions';
import { MenuItemAction, SubmenuItemAction } from 'vs/platform/actions/common/actions';
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';
import { AccessibilityVerbositySettingId } from 'vs/workbench/contrib/accessibility/browser/accessibilityContribution';
import { assertType } from 'vs/base/common/types';
import { renderLabelWithIcons } from 'vs/base/browser/ui/iconLabel/iconLabels';

const defaultAriaLabel = localize('aria-label', "Interactive Editor Input");

Expand Down Expand Up @@ -136,8 +138,10 @@ export class InteractiveEditorWidget {
h('div.previewCreateTitle.show-file-icons@previewCreateTitle'),
h('div.previewCreate.hidden@previewCreate'),
h('div.status@status', [
h('div.label.info.hidden@infoLabel'),
h('div.actions.hidden@statusToolbar'),
h('div.label.hidden@statusLabel')
h('div.label.status.hidden@statusLabel'),
h('div.actions.hidden@feedbackToolbar'),
]),
h('div.markdownMessage.hidden@markdownMessage', [
h('div.message@message'),
Expand Down Expand Up @@ -286,13 +290,42 @@ export class InteractiveEditorWidget {
return this._instantiationService.createInstance(DropdownWithDefaultActionViewItem, action, { ...options, renderKeybindingWithDefaultActionLabel: true, persistLastActionId: false });
}

if (action.id === ACTION_ACCEPT_CHANGES) {
const ButtonLikeActionViewItem = class extends MenuEntryActionViewItem {

override render(container: HTMLElement): void {
this.options.icon = false;
super.render(container);
assertType(this.element);
this.element.classList.add('button-item');
}

protected override updateLabel(): void {
assertType(this.label);
assertType(this.action instanceof MenuItemAction);
const label = MenuItemAction.label(this.action.item, { renderShortTitle: true });
const labelElements = renderLabelWithIcons(`$(check)${label}`);
reset(this.label, ...labelElements);
}

protected override updateClass(): void {
// noop
}
};
return this._instantiationService.createInstance(ButtonLikeActionViewItem, <MenuItemAction>action, <IMenuEntryActionViewItemOptions>options);
}

return createActionViewItem(this._instantiationService, action, options);
}
};
const statusToolbar = this._instantiationService.createInstance(MenuWorkbenchToolBar, this._elements.statusToolbar, MENU_INTERACTIVE_EDITOR_WIDGET_STATUS, { ...workbenchToolbarOptions, hiddenItemStrategy: HiddenItemStrategy.Ignore });
this._store.add(statusToolbar.onDidChangeMenuItems(() => this._onDidChangeHeight.fire()));
this._store.add(statusToolbar);

const feedbackToolbar = this._instantiationService.createInstance(MenuWorkbenchToolBar, this._elements.feedbackToolbar, MENU_INTERACTIVE_EDITOR_WIDGET_FEEDBACK, { ...workbenchToolbarOptions, hiddenItemStrategy: HiddenItemStrategy.Ignore });
this._store.add(feedbackToolbar.onDidChangeMenuItems(() => this._onDidChangeHeight.fire()));
this._store.add(feedbackToolbar);

// preview editors
this._previewDiffEditor = this._store.add(_instantiationService.createInstance(EmbeddedDiffEditorWidget, this._elements.previewDiff, _previewEditorEditorOptions, { modifiedEditor: codeEditorWidgetOptions, originalEditor: codeEditorWidgetOptions }, parentEditor));

Expand Down Expand Up @@ -389,6 +422,8 @@ export class InteractiveEditorWidget {

updateToolbar(show: boolean) {
this._elements.statusToolbar.classList.toggle('hidden', !show);
this._elements.feedbackToolbar.classList.toggle('hidden', !show);
this._elements.status.classList.toggle('actions', show);
this._onDidChangeHeight.fire();
}

Expand All @@ -409,6 +444,12 @@ export class InteractiveEditorWidget {
this._onDidChangeHeight.fire();
}

updateInfo(message: string): void {
this._elements.infoLabel.classList.toggle('hidden', !message);
this._elements.infoLabel.innerText = message;
this._onDidChangeHeight.fire();
}

updateStatus(message: string, ops: { classes?: string[]; resetAfter?: number; keepMessage?: boolean } = {}) {
const isTempMessage = typeof ops.resetAfter === 'number';
if (isTempMessage && !this._elements.statusLabel.dataset['state']) {
Expand All @@ -419,7 +460,7 @@ export class InteractiveEditorWidget {
}, ops.resetAfter);
}
reset(this._elements.statusLabel, message);
this._elements.statusLabel.className = `label ${(ops.classes ?? []).join(' ')}`;
this._elements.statusLabel.className = `label status ${(ops.classes ?? []).join(' ')}`;
this._elements.statusLabel.classList.toggle('hidden', !message);
if (isTempMessage) {
this._elements.statusLabel.dataset['state'] = 'temp';
Expand All @@ -437,6 +478,7 @@ export class InteractiveEditorWidget {
reset(this._elements.statusLabel);
this._elements.statusLabel.classList.toggle('hidden', true);
this._elements.statusToolbar.classList.add('hidden');
this._elements.feedbackToolbar.classList.add('hidden');
this.hideCreatePreview();
this.hideEditsPreview();
this._onDidChangeHeight.fire();
Expand Down
Expand Up @@ -100,7 +100,6 @@ export interface IInteractiveEditorService {

export const INTERACTIVE_EDITOR_ID = 'interactiveEditor';


export const CTX_INTERACTIVE_EDITOR_HAS_PROVIDER = new RawContextKey<boolean>('interactiveEditorHasProvider', false, localize('interactiveEditorHasProvider', "Whether a provider for interactive editors exists"));
export const CTX_INTERACTIVE_EDITOR_VISIBLE = new RawContextKey<boolean>('interactiveEditorVisible', false, localize('interactiveEditorVisible', "Whether the interactive editor input is visible"));
export const CTX_INTERACTIVE_EDITOR_FOCUSED = new RawContextKey<boolean>('interactiveEditorFocused', false, localize('interactiveEditorFocused', "Whether the interactive editor input is focused"));
Expand All @@ -118,11 +117,16 @@ export const CTX_INTERACTIVE_EDITOR_LAST_FEEDBACK = new RawContextKey<'unhelpful
export const CTX_INTERACTIVE_EDITOR_DOCUMENT_CHANGED = new RawContextKey<boolean>('interactiveEditorDocumentChanged', false, localize('interactiveEditorDocumentChanged', "Whether the document has changed concurrently"));
export const CTX_INTERACTIVE_EDITOR_EDIT_MODE = new RawContextKey<EditMode>('config.interactiveEditor.editMode', EditMode.Live);

// --- (select) action identifier

export const ACTION_ACCEPT_CHANGES = 'interactive.acceptChanges';

// --- menus

export const MENU_INTERACTIVE_EDITOR_WIDGET = MenuId.for('interactiveEditorWidget');
export const MENU_INTERACTIVE_EDITOR_WIDGET_MARKDOWN_MESSAGE = MenuId.for('interactiveEditorWidget.markdownMessage');
export const MENU_INTERACTIVE_EDITOR_WIDGET_STATUS = MenuId.for('interactiveEditorWidget.status');
export const MENU_INTERACTIVE_EDITOR_WIDGET_FEEDBACK = MenuId.for('interactiveEditorWidget.feedback');
export const MENU_INTERACTIVE_EDITOR_WIDGET_DISCARD = MenuId.for('interactiveEditorWidget.undo');

// --- colors
Expand Down