removing the code for the gutter icon and the toolbar icon

This commit is contained in:
Aiday Marlen Kyzy
2023-12-13 10:49:08 +01:00
parent 5da45d17d1
commit 8f81492eb2
4 changed files with 4 additions and 292 deletions
@@ -7,7 +7,7 @@ import { registerAction2 } from 'vs/platform/actions/common/actions';
import { EditorContributionInstantiation, registerEditorContribution } from 'vs/editor/browser/editorExtensions';
import { InlineChatController } from 'vs/workbench/contrib/inlineChat/browser/inlineChatController';
import * as InlineChatActions from 'vs/workbench/contrib/inlineChat/browser/inlineChatActions';
import { IInlineChatService, INLINE_CHAT_DECORATIONS_ID, INLINE_CHAT_ID, INTERACTIVE_EDITOR_ACCESSIBILITY_HELP_ID } from 'vs/workbench/contrib/inlineChat/common/inlineChat';
import { IInlineChatService, INLINE_CHAT_ID, INTERACTIVE_EDITOR_ACCESSIBILITY_HELP_ID } from 'vs/workbench/contrib/inlineChat/common/inlineChat';
import { InstantiationType, registerSingleton } from 'vs/platform/instantiation/common/extensions';
import { InlineChatServiceImpl } from 'vs/workbench/contrib/inlineChat/common/inlineChatServiceImpl';
import { IInlineChatSessionService, InlineChatSessionService } from 'vs/workbench/contrib/inlineChat/browser/inlineChatSession';
@@ -16,14 +16,12 @@ import { LifecyclePhase } from 'vs/workbench/services/lifecycle/common/lifecycle
import { InlineChatNotebookContribution } from 'vs/workbench/contrib/inlineChat/browser/inlineChatNotebook';
import { IWorkbenchContributionsRegistry, Extensions as WorkbenchExtensions } from 'vs/workbench/common/contributions';
import { InlineChatAccessibleViewContribution } from './inlineChatAccessibleView';
import { InlineChatDecorationsContribution } from 'vs/workbench/contrib/inlineChat/browser/inlineChatDecorations';
registerSingleton(IInlineChatService, InlineChatServiceImpl, InstantiationType.Delayed);
registerSingleton(IInlineChatSessionService, InlineChatSessionService, InstantiationType.Delayed);
registerEditorContribution(INLINE_CHAT_ID, InlineChatController, EditorContributionInstantiation.Eager); // EAGER because of notebook dispose/create of editors
registerEditorContribution(INTERACTIVE_EDITOR_ACCESSIBILITY_HELP_ID, InlineChatActions.InlineAccessibilityHelpContribution, EditorContributionInstantiation.Eventually);
registerEditorContribution(INLINE_CHAT_DECORATIONS_ID, InlineChatDecorationsContribution, EditorContributionInstantiation.AfterFirstRender);
registerAction2(InlineChatActions.StartSessionAction);
registerAction2(InlineChatActions.UnstashSessionAction);
@@ -10,9 +10,9 @@ import { EditorAction2 } from 'vs/editor/browser/editorExtensions';
import { EmbeddedCodeEditorWidget, EmbeddedDiffEditorWidget } from 'vs/editor/browser/widget/embeddedCodeEditorWidget';
import { EditorContextKeys } from 'vs/editor/common/editorContextKeys';
import { InlineChatController, InlineChatRunOptions } from 'vs/workbench/contrib/inlineChat/browser/inlineChatController';
import { CTX_INLINE_CHAT_FOCUSED, CTX_INLINE_CHAT_HAS_ACTIVE_REQUEST, CTX_INLINE_CHAT_HAS_PROVIDER, CTX_INLINE_CHAT_INNER_CURSOR_FIRST, CTX_INLINE_CHAT_INNER_CURSOR_LAST, CTX_INLINE_CHAT_EMPTY, CTX_INLINE_CHAT_OUTER_CURSOR_POSITION, CTX_INLINE_CHAT_VISIBLE, MENU_INLINE_CHAT_WIDGET, MENU_INLINE_CHAT_WIDGET_DISCARD, MENU_INLINE_CHAT_WIDGET_STATUS, CTX_INLINE_CHAT_LAST_FEEDBACK, CTX_INLINE_CHAT_EDIT_MODE, EditMode, CTX_INLINE_CHAT_LAST_RESPONSE_TYPE, MENU_INLINE_CHAT_WIDGET_MARKDOWN_MESSAGE, CTX_INLINE_CHAT_MESSAGE_CROP_STATE, CTX_INLINE_CHAT_DOCUMENT_CHANGED, CTX_INLINE_CHAT_DID_EDIT, CTX_INLINE_CHAT_HAS_STASHED_SESSION, MENU_INLINE_CHAT_WIDGET_FEEDBACK, ACTION_ACCEPT_CHANGES, ACTION_REGENERATE_RESPONSE, InlineChatResponseType, CTX_INLINE_CHAT_RESPONSE_TYPES, InlineChateResponseTypes, ACTION_VIEW_IN_CHAT, CTX_INLINE_CHAT_USER_DID_EDIT, MENU_INLINE_CHAT_WIDGET_TOGGLE, CTX_INLINE_CHAT_INNER_CURSOR_START, CTX_INLINE_CHAT_INNER_CURSOR_END, CTX_INLINE_CHAT_RESPONSE_FOCUSED, CTX_INLINE_CHAT_SUPPORT_ISSUE_REPORTING, InlineChatResponseFeedbackKind, CTX_INLINE_CHAT_TOOLBAR_ICON_ENABLED, CTX_INLINE_CHAT_CHANGE_SHOWS_DIFF, CTX_INLINE_CHAT_CHANGE_HAS_DIFF } from 'vs/workbench/contrib/inlineChat/common/inlineChat';
import { CTX_INLINE_CHAT_FOCUSED, CTX_INLINE_CHAT_HAS_ACTIVE_REQUEST, CTX_INLINE_CHAT_HAS_PROVIDER, CTX_INLINE_CHAT_INNER_CURSOR_FIRST, CTX_INLINE_CHAT_INNER_CURSOR_LAST, CTX_INLINE_CHAT_EMPTY, CTX_INLINE_CHAT_OUTER_CURSOR_POSITION, CTX_INLINE_CHAT_VISIBLE, MENU_INLINE_CHAT_WIDGET, MENU_INLINE_CHAT_WIDGET_DISCARD, MENU_INLINE_CHAT_WIDGET_STATUS, CTX_INLINE_CHAT_LAST_FEEDBACK, CTX_INLINE_CHAT_EDIT_MODE, EditMode, CTX_INLINE_CHAT_LAST_RESPONSE_TYPE, MENU_INLINE_CHAT_WIDGET_MARKDOWN_MESSAGE, CTX_INLINE_CHAT_MESSAGE_CROP_STATE, CTX_INLINE_CHAT_DOCUMENT_CHANGED, CTX_INLINE_CHAT_DID_EDIT, CTX_INLINE_CHAT_HAS_STASHED_SESSION, MENU_INLINE_CHAT_WIDGET_FEEDBACK, ACTION_ACCEPT_CHANGES, ACTION_REGENERATE_RESPONSE, InlineChatResponseType, CTX_INLINE_CHAT_RESPONSE_TYPES, InlineChateResponseTypes, ACTION_VIEW_IN_CHAT, CTX_INLINE_CHAT_USER_DID_EDIT, MENU_INLINE_CHAT_WIDGET_TOGGLE, CTX_INLINE_CHAT_INNER_CURSOR_START, CTX_INLINE_CHAT_INNER_CURSOR_END, CTX_INLINE_CHAT_RESPONSE_FOCUSED, CTX_INLINE_CHAT_SUPPORT_ISSUE_REPORTING, InlineChatResponseFeedbackKind, CTX_INLINE_CHAT_CHANGE_SHOWS_DIFF, CTX_INLINE_CHAT_CHANGE_HAS_DIFF } from 'vs/workbench/contrib/inlineChat/common/inlineChat';
import { localize, localize2 } from 'vs/nls';
import { IAction2Options, MenuId, MenuRegistry } from 'vs/platform/actions/common/actions';
import { IAction2Options, MenuRegistry } from 'vs/platform/actions/common/actions';
import { IClipboardService } from 'vs/platform/clipboard/common/clipboardService';
import { ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey';
import { ServicesAccessor } from 'vs/platform/instantiation/common/instantiation';
@@ -50,13 +50,7 @@ export class StartSessionAction extends EditorAction2 {
primary: KeyMod.CtrlCmd | KeyCode.KeyI,
secondary: [KeyChord(KeyMod.CtrlCmd | KeyCode.KeyK, KeyCode.KeyI)],
},
icon: START_INLINE_CHAT,
menu: [{
id: MenuId.EditorTitle,
when: ContextKeyExpr.and(CTX_INLINE_CHAT_TOOLBAR_ICON_ENABLED, CTX_INLINE_CHAT_HAS_PROVIDER, CTX_INLINE_CHAT_VISIBLE.toNegated(), EditorContextKeys.focus),
group: 'navigation',
order: -1000000, // at the very front
}],
icon: START_INLINE_CHAT
});
}
@@ -1,256 +0,0 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { Codicon } from 'vs/base/common/codicons';
import { ThemeIcon } from 'vs/base/common/themables';
import { IActiveCodeEditor, ICodeEditor, IEditorMouseEvent } from 'vs/editor/browser/editorBrowser';
import { IEditorContribution } from 'vs/editor/common/editorCommon';
import { GlyphMarginLane, IModelDecorationOptions, IModelDecorationsChangeAccessor, TrackedRangeStickiness } from 'vs/editor/common/model';
import { ModelDecorationOptions } from 'vs/editor/common/model/textModel';
import { localize } from 'vs/nls';
import { registerIcon } from 'vs/platform/theme/common/iconRegistry';
import { InlineChatController } from 'vs/workbench/contrib/inlineChat/browser/inlineChatController';
import { IConfigurationService, IConfigurationChangeEvent } from 'vs/platform/configuration/common/configuration';
import { DisposableStore, Disposable } from 'vs/base/common/lifecycle';
import { GutterActionsRegistry } from 'vs/workbench/contrib/codeEditor/browser/editorLineNumberMenu';
import { Action } from 'vs/base/common/actions';
import { IInlineChatService, ShowGutterIcon } from 'vs/workbench/contrib/inlineChat/common/inlineChat';
import { RunOnceScheduler } from 'vs/base/common/async';
import { Iterable } from 'vs/base/common/iterator';
import { Range } from 'vs/editor/common/core/range';
import { IInlineChatSessionService } from 'vs/workbench/contrib/inlineChat/browser/inlineChatSession';
import { MarkdownString } from 'vs/base/common/htmlContent';
import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';
import { LOCALIZED_START_INLINE_CHAT_STRING } from 'vs/workbench/contrib/inlineChat/browser/inlineChatActions';
import { IBreakpoint, IDebugService, IDebugSession } from 'vs/workbench/contrib/debug/common/debug';
import { IPreferencesService } from 'vs/workbench/services/preferences/common/preferences';
import { URI } from 'vs/base/common/uri';
import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
const GUTTER_INLINE_CHAT_OPAQUE_ICON = registerIcon('inline-chat-opaque', Codicon.sparkle, localize('startInlineChatOpaqueIcon', 'Icon which spawns the inline chat from the gutter. It is half opaque by default and becomes completely opaque on hover.'));
const GUTTER_INLINE_CHAT_TRANSPARENT_ICON = registerIcon('inline-chat-transparent', Codicon.sparkle, localize('startInlineChatTransparentIcon', 'Icon which spawns the inline chat from the gutter. It is transparent by default and becomes opaque on hover.'));
export class InlineChatDecorationsContribution extends Disposable implements IEditorContribution {
private _currentBreakpoints: readonly IBreakpoint[] = [];
private _gutterDecorationID: string | undefined;
private _inlineChatKeybinding: string | undefined;
private _hasInlineChatSession: boolean = false;
private _hasActiveDebugSession: boolean = false;
private _debugSessions: Set<IDebugSession> = new Set();
private readonly _localToDispose = new DisposableStore();
private readonly _gutterDecorationOpaque: IModelDecorationOptions;
private readonly _gutterDecorationTransparent: IModelDecorationOptions;
public static readonly TOOLBAR_SETTING_ID = 'inlineChat.showToolbarIcon';
public static readonly GUTTER_SETTING_ID = 'inlineChat.showGutterIcon';
private static readonly GUTTER_ICON_OPAQUE_CLASSNAME = 'codicon-inline-chat-opaque';
private static readonly GUTTER_ICON_TRANSPARENT_CLASSNAME = 'codicon-inline-chat-transparent';
constructor(
private readonly _editor: ICodeEditor,
@IContextKeyService _contextKeyService: IContextKeyService,
@IInlineChatService private readonly _inlineChatService: IInlineChatService,
@IInlineChatSessionService private readonly _inlineChatSessionService: IInlineChatSessionService,
@IConfigurationService private readonly _configurationService: IConfigurationService,
@IKeybindingService private readonly _keybindingService: IKeybindingService,
@IDebugService private readonly _debugService: IDebugService
) {
super();
this._gutterDecorationTransparent = this._registerGutterDecoration(true);
this._gutterDecorationOpaque = this._registerGutterDecoration(false);
this._register(this._configurationService.onDidChangeConfiguration((e: IConfigurationChangeEvent) => {
if (!e.affectsConfiguration(InlineChatDecorationsContribution.GUTTER_SETTING_ID)) {
return;
}
this._onEnablementOrModelChanged();
}));
this._register(this._inlineChatSessionService.onWillStartSession((e) => {
if (e === this._editor) {
this._hasInlineChatSession = true;
this._onEnablementOrModelChanged();
}
}));
this._register(this._inlineChatSessionService.onDidEndSession((e) => {
if (e === this._editor) {
this._hasInlineChatSession = false;
this._onEnablementOrModelChanged();
}
}));
this._register(this._debugService.onDidNewSession((session) => {
this._debugSessions.add(session);
if (!this._hasActiveDebugSession) {
this._hasActiveDebugSession = true;
this._onEnablementOrModelChanged();
}
}));
this._register(this._debugService.onDidEndSession(({ session }) => {
this._debugSessions.delete(session);
if (this._debugSessions.size === 0) {
this._hasActiveDebugSession = false;
this._onEnablementOrModelChanged();
}
}));
this._register(this._inlineChatService.onDidChangeProviders(() => this._onEnablementOrModelChanged()));
this._register(this._editor.onDidChangeModel(() => this._onEnablementOrModelChanged()));
this._register(this._keybindingService.onDidUpdateKeybindings(() => {
this._updateDecorationHover();
this._onEnablementOrModelChanged();
}));
this._updateDecorationHover();
this._onEnablementOrModelChanged();
}
private _registerGutterDecoration(isTransparent: boolean): ModelDecorationOptions {
return ModelDecorationOptions.register({
description: 'inline-chat-decoration',
glyphMarginClassName: ThemeIcon.asClassName(isTransparent ? GUTTER_INLINE_CHAT_TRANSPARENT_ICON : GUTTER_INLINE_CHAT_OPAQUE_ICON),
glyphMargin: { position: GlyphMarginLane.Left },
stickiness: TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges,
});
}
private _updateDecorationHover(): void {
const keybinding = this._keybindingService.lookupKeybinding('inlineChat.start')?.getLabel() ?? undefined;
if (this._inlineChatKeybinding === keybinding) {
return;
}
this._inlineChatKeybinding = keybinding;
const hoverMessage = new MarkdownString(keybinding ? localize('runWithKeybinding', 'Start Inline Chat ({0})', keybinding) : LOCALIZED_START_INLINE_CHAT_STRING);
this._gutterDecorationTransparent.glyphMarginHoverMessage = hoverMessage;
this._gutterDecorationOpaque.glyphMarginHoverMessage = hoverMessage;
}
private _updateCurrentBreakpoints(uri: URI) {
this._currentBreakpoints = this._debugService.getModel().getBreakpoints({ uri });
}
private _onEnablementOrModelChanged(): void {
// cancels the scheduler, removes editor listeners / removes decoration
this._localToDispose.clear();
if (!this._editor.hasModel() || this._hasActiveDebugSession || this._hasInlineChatSession || this._showGutterIconMode() === ShowGutterIcon.Never || !this._hasProvider()) {
return;
}
const editor = this._editor;
const decorationUpdateScheduler = new RunOnceScheduler(() => this._onSelectionOrContentChanged(editor), 100);
this._localToDispose.add(decorationUpdateScheduler);
this._localToDispose.add(this._debugService.getModel().onDidChangeBreakpoints(() => {
this._updateCurrentBreakpoints(editor.getModel().uri);
decorationUpdateScheduler.schedule();
}));
this._localToDispose.add(this._editor.onDidChangeCursorSelection(() => decorationUpdateScheduler.schedule()));
this._localToDispose.add(this._editor.onDidChangeModelContent(() => decorationUpdateScheduler.schedule()));
this._localToDispose.add(this._editor.onMouseDown(async (e: IEditorMouseEvent) => {
const showGutterIconMode = this._showGutterIconMode();
const gutterDecorationClassName = showGutterIconMode === ShowGutterIcon.Always ?
InlineChatDecorationsContribution.GUTTER_ICON_OPAQUE_CLASSNAME :
(showGutterIconMode === ShowGutterIcon.MouseOver ?
InlineChatDecorationsContribution.GUTTER_ICON_TRANSPARENT_CLASSNAME : undefined);
if (!gutterDecorationClassName || !e.target.element?.classList.contains(gutterDecorationClassName)) {
return;
}
InlineChatController.get(this._editor)?.run();
}));
this._localToDispose.add({
dispose: () => {
if (this._gutterDecorationID) {
this._removeGutterDecoration(this._gutterDecorationID);
}
}
});
this._updateCurrentBreakpoints(editor.getModel().uri);
decorationUpdateScheduler.schedule();
}
private _onSelectionOrContentChanged(editor: IActiveCodeEditor): void {
const selection = editor.getSelection();
const startLineNumber = selection.startLineNumber;
const model = editor.getModel();
let isEnabled = false;
const hasBreakpoint = this._currentBreakpoints.some(bp => bp.lineNumber === startLineNumber);
if (!hasBreakpoint) {
const selectionIsEmpty = selection.isEmpty();
if (selectionIsEmpty) {
if (/^\s*$/g.test(model.getLineContent(startLineNumber))) {
isEnabled = true;
}
} else {
const startPosition = selection.getStartPosition();
const endPosition = selection.getEndPosition();
const startWord = model.getWordAtPosition(startPosition);
const endWord = model.getWordAtPosition(endPosition);
const isFirstWordCoveredOrNull = !!startWord ? startPosition.column <= startWord.startColumn : true;
const isLastWordCoveredOrNull = !!endWord ? endPosition.column >= endWord.endColumn : true;
isEnabled = isFirstWordCoveredOrNull && isLastWordCoveredOrNull;
}
}
if (isEnabled) {
if (this._gutterDecorationID === undefined) {
this._addGutterDecoration(startLineNumber);
} else {
const decorationRange = model.getDecorationRange(this._gutterDecorationID);
if (decorationRange?.startLineNumber !== startLineNumber) {
this._updateGutterDecoration(this._gutterDecorationID, startLineNumber);
}
}
} else if (this._gutterDecorationID) {
this._removeGutterDecoration(this._gutterDecorationID);
}
}
private _showGutterIconMode(): ShowGutterIcon {
return this._configurationService.getValue<ShowGutterIcon>(InlineChatDecorationsContribution.GUTTER_SETTING_ID);
}
private _hasProvider(): boolean {
return !Iterable.isEmpty(this._inlineChatService.getAllProvider());
}
private _addGutterDecoration(lineNumber: number) {
this._editor.changeDecorations((accessor: IModelDecorationsChangeAccessor) => {
const showGutterIconMode = this._showGutterIconMode();
if (showGutterIconMode === ShowGutterIcon.Never) {
return;
}
this._gutterDecorationID = accessor.addDecoration(new Range(lineNumber, 0, lineNumber, 0), showGutterIconMode === ShowGutterIcon.Always ? this._gutterDecorationOpaque : this._gutterDecorationTransparent);
});
}
private _removeGutterDecoration(decorationId: string) {
this._editor.changeDecorations((accessor: IModelDecorationsChangeAccessor) => {
accessor.removeDecoration(decorationId);
});
this._gutterDecorationID = undefined;
}
private _updateGutterDecoration(decorationId: string, lineNumber: number) {
this._editor.changeDecorations((accessor: IModelDecorationsChangeAccessor) => {
accessor.changeDecoration(decorationId, new Range(lineNumber, 0, lineNumber, 0));
});
}
override dispose() {
super.dispose();
this._localToDispose.dispose();
}
}
GutterActionsRegistry.registerGutterActionsGenerator(({ lineNumber, editor, accessor }, result) => {
const inlineChatService = accessor.get(IInlineChatService);
const noProviders = Iterable.isEmpty(inlineChatService.getAllProvider());
if (noProviders) {
return;
}
const preferencesService = accessor.get(IPreferencesService);
result.push(new Action(
'inlineChat.configureShowGutterIcon',
localize('configureShowGutterIcon', "Configure Inline Chat Icon"),
undefined,
true,
() => { preferencesService.openUserSettings({ query: 'inlineChat.showGutterIcon' }); }
));
});
@@ -130,7 +130,6 @@ export interface IInlineChatService {
export const INLINE_CHAT_ID = 'interactiveEditor';
export const INTERACTIVE_EDITOR_ACCESSIBILITY_HELP_ID = 'interactiveEditorAccessiblityHelp';
export const INLINE_CHAT_DECORATIONS_ID = 'interactiveEditorDecorations';
export const CTX_INLINE_CHAT_HAS_PROVIDER = new RawContextKey<boolean>('inlineChatHasProvider', false, localize('inlineChatHasProvider', "Whether a provider for interactive editors exists"));
export const CTX_INLINE_CHAT_VISIBLE = new RawContextKey<boolean>('inlineChatVisible', false, localize('inlineChatVisible', "Whether the interactive editor input is visible"));
@@ -155,7 +154,6 @@ export const CTX_INLINE_CHAT_DOCUMENT_CHANGED = new RawContextKey<boolean>('inli
export const CTX_INLINE_CHAT_CHANGE_HAS_DIFF = new RawContextKey<boolean>('inlineChatChangeHasDiff', false, localize('inlineChatChangeHasDiff', "Whether the current change supports showing a diff"));
export const CTX_INLINE_CHAT_CHANGE_SHOWS_DIFF = new RawContextKey<boolean>('inlineChatChangeShowsDiff', false, localize('inlineChatChangeShowsDiff', "Whether the current change showing a diff"));
export const CTX_INLINE_CHAT_EDIT_MODE = new RawContextKey<EditMode>('config.inlineChat.mode', EditMode.Live);
export const CTX_INLINE_CHAT_TOOLBAR_ICON_ENABLED = new RawContextKey<boolean>('config.inlineChat.showToolbarIcon', false);
// --- (select) action identifier
@@ -196,12 +194,6 @@ export const enum EditMode {
Preview = 'preview'
}
export const enum ShowGutterIcon {
Always = 'always',
MouseOver = 'mouseover',
Never = 'never'
}
Registry.as<IConfigurationMigrationRegistry>(ExtensionsMigration.ConfigurationMigration).registerConfigurationMigrations(
[{
key: 'interactiveEditor.editMode', migrateFn: (value: any) => {
@@ -228,22 +220,6 @@ Registry.as<IConfigurationRegistry>(Extensions.Configuration).registerConfigurat
description: localize('showDiff', "Enable/disable showing the diff when edits are generated. Works only with inlineChat.mode equal to live or livePreview."),
default: true,
type: 'boolean'
},
'inlineChat.showGutterIcon': {
description: localize('showGutterIcon', "Controls when the gutter icon for spawning inline chat is shown."),
default: ShowGutterIcon.Never,
type: 'string',
enum: [ShowGutterIcon.Always, ShowGutterIcon.MouseOver, ShowGutterIcon.Never],
markdownEnumDescriptions: [
localize('showGutterIcon.always', "Always show the gutter icon."),
localize('showGutterIcon.mouseover', "Show the gutter icon when the mouse is over the icon."),
localize('showGutterIcon.never', "Never show the gutter icon."),
]
},
'inlineChat.showToolbarIcon': {
description: localize('showToolbarIcon', "Controls whether the toolbar icon spawning the inline chat is enabled."),
default: false,
type: 'boolean'
}
}
});