diff --git a/.vscode/settings.json b/.vscode/settings.json index d2abaca7005..1f0f99b5df7 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -170,5 +170,5 @@ }, "css.format.spaceAroundSelectorSeparator": true, "typescript.enablePromptUseWorkspaceTsdk": true, - "inlineChat.experimental.onlyZoneWidget": true + "chat.commandCenter.enabled": true } diff --git a/src/vs/platform/actions/browser/dropdownWithPrimaryActionViewItem.ts b/src/vs/platform/actions/browser/dropdownWithPrimaryActionViewItem.ts index 37ab032480c..e8f00698cf8 100644 --- a/src/vs/platform/actions/browser/dropdownWithPrimaryActionViewItem.ts +++ b/src/vs/platform/actions/browser/dropdownWithPrimaryActionViewItem.ts @@ -61,7 +61,7 @@ export class DropdownWithPrimaryActionViewItem extends BaseActionViewItem { menuAsChild: _options?.menuAsChild ?? true, classNames: className ? ['codicon', 'codicon-chevron-down', className] : ['codicon', 'codicon-chevron-down'], actionRunner: this._options?.actionRunner, - keybindingProvider: this._options?.getKeyBinding, + keybindingProvider: this._options?.getKeyBinding ?? (action => _keybindingService.lookupKeybinding(action.id)), hoverDelegate: _options?.hoverDelegate }); } diff --git a/src/vs/workbench/contrib/chat/browser/actions/chatQuickInputActions.ts b/src/vs/workbench/contrib/chat/browser/actions/chatQuickInputActions.ts index 96617956b60..05652beb196 100644 --- a/src/vs/workbench/contrib/chat/browser/actions/chatQuickInputActions.ts +++ b/src/vs/workbench/contrib/chat/browser/actions/chatQuickInputActions.ts @@ -116,7 +116,7 @@ class QuickChatGlobalAction extends Action2 { }, menu: { id: MenuId.ChatCommandCenter, - group: 'open', + group: 'c_quickChat', order: 5 }, metadata: { diff --git a/src/vs/workbench/contrib/chat/browser/chat.contribution.ts b/src/vs/workbench/contrib/chat/browser/chat.contribution.ts index 23dc3df331c..bec60f8fd12 100644 --- a/src/vs/workbench/contrib/chat/browser/chat.contribution.ts +++ b/src/vs/workbench/contrib/chat/browser/chat.contribution.ts @@ -103,8 +103,9 @@ configurationRegistry.registerConfiguration({ }, 'chat.commandCenter.enabled': { type: 'boolean', + tags: ['experimental'], markdownDescription: nls.localize('chat.commandCenter.enabled', "Controls whether the command center shows a menu for chat actions (requires {0}).", '`#window.commandCenter#`'), - default: true + default: false }, 'chat.experimental.implicitContext': { type: 'boolean', diff --git a/src/vs/workbench/contrib/inlineChat/browser/inlineChatActions.ts b/src/vs/workbench/contrib/inlineChat/browser/inlineChatActions.ts index 7fdc59e70ee..9dee0206e0e 100644 --- a/src/vs/workbench/contrib/inlineChat/browser/inlineChatActions.ts +++ b/src/vs/workbench/contrib/inlineChat/browser/inlineChatActions.ts @@ -11,9 +11,9 @@ import { EmbeddedDiffEditorWidget } from '../../../../editor/browser/widget/diff import { EmbeddedCodeEditorWidget } from '../../../../editor/browser/widget/codeEditor/embeddedCodeEditorWidget.js'; import { EditorContextKeys } from '../../../../editor/common/editorContextKeys.js'; import { InlineChatController, InlineChatRunOptions } from './inlineChatController.js'; -import { ACTION_ACCEPT_CHANGES, CTX_INLINE_CHAT_HAS_AGENT, CTX_INLINE_CHAT_HAS_STASHED_SESSION, CTX_INLINE_CHAT_FOCUSED, CTX_INLINE_CHAT_INNER_CURSOR_FIRST, CTX_INLINE_CHAT_INNER_CURSOR_LAST, CTX_INLINE_CHAT_VISIBLE, CTX_INLINE_CHAT_OUTER_CURSOR_POSITION, CTX_INLINE_CHAT_USER_DID_EDIT, CTX_INLINE_CHAT_DOCUMENT_CHANGED, CTX_INLINE_CHAT_EDIT_MODE, EditMode, MENU_INLINE_CHAT_WIDGET_STATUS, CTX_INLINE_CHAT_REQUEST_IN_PROGRESS, CTX_INLINE_CHAT_RESPONSE_TYPE, InlineChatResponseType, ACTION_REGENERATE_RESPONSE, ACTION_VIEW_IN_CHAT, ACTION_TOGGLE_DIFF, CTX_INLINE_CHAT_CHANGE_HAS_DIFF, CTX_INLINE_CHAT_CHANGE_SHOWS_DIFF, MENU_INLINE_CHAT_ZONE, ACTION_DISCARD_CHANGES } from '../common/inlineChat.js'; +import { ACTION_ACCEPT_CHANGES, CTX_INLINE_CHAT_HAS_AGENT, CTX_INLINE_CHAT_HAS_STASHED_SESSION, CTX_INLINE_CHAT_FOCUSED, CTX_INLINE_CHAT_INNER_CURSOR_FIRST, CTX_INLINE_CHAT_INNER_CURSOR_LAST, CTX_INLINE_CHAT_VISIBLE, CTX_INLINE_CHAT_OUTER_CURSOR_POSITION, CTX_INLINE_CHAT_USER_DID_EDIT, CTX_INLINE_CHAT_DOCUMENT_CHANGED, CTX_INLINE_CHAT_EDIT_MODE, EditMode, MENU_INLINE_CHAT_WIDGET_STATUS, CTX_INLINE_CHAT_REQUEST_IN_PROGRESS, CTX_INLINE_CHAT_RESPONSE_TYPE, InlineChatResponseType, ACTION_REGENERATE_RESPONSE, ACTION_VIEW_IN_CHAT, ACTION_TOGGLE_DIFF, CTX_INLINE_CHAT_CHANGE_HAS_DIFF, CTX_INLINE_CHAT_CHANGE_SHOWS_DIFF, MENU_INLINE_CHAT_ZONE, ACTION_DISCARD_CHANGES, CTX_INLINE_CHAT_POSSIBLE } from '../common/inlineChat.js'; import { localize, localize2 } from '../../../../nls.js'; -import { Action2, IAction2Options } from '../../../../platform/actions/common/actions.js'; +import { Action2, IAction2Options, MenuId } from '../../../../platform/actions/common/actions.js'; import { ContextKeyExpr } from '../../../../platform/contextkey/common/contextkey.js'; import { IInstantiationService, ServicesAccessor } from '../../../../platform/instantiation/common/instantiation.js'; import { KeybindingWeight } from '../../../../platform/keybinding/common/keybindingsRegistry.js'; @@ -49,17 +49,26 @@ export class StartSessionAction extends EditorAction2 { constructor() { super({ id: 'inlineChat.start', - title: localize2('run', 'Editor Chat'), + title: localize2('run', 'Editor Inline Chat'), category: AbstractInlineChatAction.category, f1: true, - precondition: ContextKeyExpr.and(CTX_INLINE_CHAT_HAS_AGENT, EditorContextKeys.writable), + precondition: ContextKeyExpr.and( + CTX_INLINE_CHAT_HAS_AGENT, + CTX_INLINE_CHAT_POSSIBLE, + EditorContextKeys.writable + ), keybinding: { when: EditorContextKeys.focus, weight: KeybindingWeight.WorkbenchContrib, primary: KeyMod.CtrlCmd | KeyCode.KeyI, secondary: [KeyChord(KeyMod.CtrlCmd | KeyCode.KeyK, KeyCode.KeyI)], }, - icon: START_INLINE_CHAT + icon: START_INLINE_CHAT, + menu: { + id: MenuId.ChatCommandCenter, + group: 'b_inlineChat', + order: 10, + } }); } diff --git a/src/vs/workbench/contrib/inlineChat/browser/inlineChatSessionServiceImpl.ts b/src/vs/workbench/contrib/inlineChat/browser/inlineChatSessionServiceImpl.ts index f6f773e1f64..f88d75ea5fd 100644 --- a/src/vs/workbench/contrib/inlineChat/browser/inlineChatSessionServiceImpl.ts +++ b/src/vs/workbench/contrib/inlineChat/browser/inlineChatSessionServiceImpl.ts @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import { CancellationToken } from '../../../../base/common/cancellation.js'; import { Emitter, Event } from '../../../../base/common/event.js'; -import { DisposableStore, IDisposable, MutableDisposable, toDisposable } from '../../../../base/common/lifecycle.js'; +import { DisposableMap, DisposableStore, IDisposable, MutableDisposable, toDisposable } from '../../../../base/common/lifecycle.js'; import { Schemas } from '../../../../base/common/network.js'; import { URI } from '../../../../base/common/uri.js'; import { generateUuid } from '../../../../base/common/uuid.js'; @@ -22,7 +22,7 @@ import { ITelemetryService } from '../../../../platform/telemetry/common/telemet import { DEFAULT_EDITOR_ASSOCIATION } from '../../../common/editor.js'; import { ChatAgentLocation, IChatAgentService } from '../../chat/common/chatAgents.js'; import { IChatService } from '../../chat/common/chatService.js'; -import { CTX_INLINE_CHAT_HAS_AGENT, EditMode } from '../common/inlineChat.js'; +import { CTX_INLINE_CHAT_HAS_AGENT, CTX_INLINE_CHAT_POSSIBLE, EditMode, INLINE_CHAT_ID } from '../common/inlineChat.js'; import { IEditorService } from '../../../services/editor/common/editorService.js'; import { UntitledTextEditorInput } from '../../../services/untitled/common/untitledTextEditorInput.js'; import { HunkData, Session, SessionWholeRange, StashedSession, TelemetryData, TelemetryDataClassification } from './inlineChatSession.js'; @@ -30,6 +30,8 @@ import { IInlineChatSessionEndEvent, IInlineChatSessionEvent, IInlineChatSession import { isEqual } from '../../../../base/common/resources.js'; import { ILanguageService } from '../../../../editor/common/languages/language.js'; import { ITextFileService } from '../../../services/textfile/common/textfiles.js'; +import { ICodeEditorService } from '../../../../editor/browser/services/codeEditorService.js'; +import { EditorOption } from '../../../../editor/common/config/editorOptions.js'; type SessionData = { @@ -319,21 +321,51 @@ export class InlineChatEnabler { static Id = 'inlineChat.enabler'; private readonly _ctxHasProvider: IContextKey; + private readonly _ctxPossible: IContextKey; private readonly _store = new DisposableStore(); constructor( @IContextKeyService contextKeyService: IContextKeyService, - @IChatAgentService chatAgentService: IChatAgentService + @IChatAgentService chatAgentService: IChatAgentService, + @ICodeEditorService codeEditorService: ICodeEditorService, + @IEditorService editorService: IEditorService, ) { this._ctxHasProvider = CTX_INLINE_CHAT_HAS_AGENT.bindTo(contextKeyService); - this._store.add(chatAgentService.onDidChangeAgents(() => { + this._ctxPossible = CTX_INLINE_CHAT_POSSIBLE.bindTo(contextKeyService); + + const updateAgent = () => { const hasEditorAgent = Boolean(chatAgentService.getDefaultAgent(ChatAgentLocation.Editor)); this._ctxHasProvider.set(hasEditorAgent); + }; + + this._store.add(chatAgentService.onDidChangeAgents(updateAgent)); + updateAgent(); + + const updateEditor = () => { + const editor = codeEditorService.getFocusedCodeEditor() ?? codeEditorService.getActiveCodeEditor(); + + this._ctxPossible.set(Boolean(editor + && editor.getContribution(INLINE_CHAT_ID) + && editor.hasWidgetFocus() + && !editor.getOption(EditorOption.readOnly) + && !editor.isSimpleWidget + )); + }; + + this._store.add(editorService.onDidActiveEditorChange(updateEditor)); + + const editorDisposables = this._store.add(new DisposableMap()); + this._store.add(codeEditorService.onCodeEditorAdd(e => { + editorDisposables.set(e, Event.any(e.onDidBlurEditorWidget, e.onDidFocusEditorWidget)(updateEditor)); + })); + this._store.add(codeEditorService.onCodeEditorRemove(e => { + editorDisposables.deleteAndDispose(e); })); } dispose() { + this._ctxPossible.reset(); this._ctxHasProvider.reset(); this._store.dispose(); } diff --git a/src/vs/workbench/contrib/inlineChat/common/inlineChat.ts b/src/vs/workbench/contrib/inlineChat/common/inlineChat.ts index 9cb7e6d7409..b58d2ccb37c 100644 --- a/src/vs/workbench/contrib/inlineChat/common/inlineChat.ts +++ b/src/vs/workbench/contrib/inlineChat/common/inlineChat.ts @@ -88,6 +88,7 @@ export const enum InlineChatResponseType { MessagesAndEdits = 'messagesAndEdits' } +export const CTX_INLINE_CHAT_POSSIBLE = new RawContextKey('inlineChatPossible', false, localize('inlineChatHasPossible', "Whether a provider for inline chat exists and whether an editor for inline chat is open")); export const CTX_INLINE_CHAT_HAS_AGENT = new RawContextKey('inlineChatHasProvider', false, localize('inlineChatHasProvider', "Whether a provider for interactive editors exists")); export const CTX_INLINE_CHAT_VISIBLE = new RawContextKey('inlineChatVisible', false, localize('inlineChatVisible', "Whether the interactive editor input is visible")); export const CTX_INLINE_CHAT_FOCUSED = new RawContextKey('inlineChatFocused', false, localize('inlineChatFocused', "Whether the interactive editor input is focused"));