diff --git a/build/lib/stylelint/vscode-known-variables.json b/build/lib/stylelint/vscode-known-variables.json index 17778581978..a2f1696f372 100644 --- a/build/lib/stylelint/vscode-known-variables.json +++ b/build/lib/stylelint/vscode-known-variables.json @@ -999,7 +999,8 @@ "--comment-thread-state-color", "--comment-thread-state-background-color", "--inline-edit-border-radius", - "--chat-subagent-last-item-height" + "--chat-subagent-last-item-height", + "--vscode-inline-chat-affordance-height" ], "sizes": [ "--vscode-bodyFontSize", diff --git a/src/vs/workbench/contrib/inlineChat/browser/inlineChatAffordance.ts b/src/vs/workbench/contrib/inlineChat/browser/inlineChatAffordance.ts index 5b8a4bba6f7..fba6cf4cf6f 100644 --- a/src/vs/workbench/contrib/inlineChat/browser/inlineChatAffordance.ts +++ b/src/vs/workbench/contrib/inlineChat/browser/inlineChatAffordance.ts @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import { Disposable } from '../../../../base/common/lifecycle.js'; -import { autorun, debouncedObservable, derived, observableValue } from '../../../../base/common/observable.js'; +import { autorun, debouncedObservable, derived, observableValue, runOnChange } from '../../../../base/common/observable.js'; import { ICodeEditor } from '../../../../editor/browser/editorBrowser.js'; import { observableCodeEditor } from '../../../../editor/browser/observableCodeEditor.js'; import { IInstantiationService } from '../../../../platform/instantiation/common/instantiation.js'; @@ -18,6 +18,7 @@ import { InlineChatGutterAffordance } from './inlineChatGutterAffordance.js'; import { Selection, SelectionDirection } from '../../../../editor/common/core/selection.js'; import { assertType } from '../../../../base/common/types.js'; import { Event } from '../../../../base/common/event.js'; +import { CursorChangeReason } from '../../../../editor/common/cursorEvents.js'; export class InlineChatAffordance extends Disposable { @@ -45,41 +46,41 @@ export class InlineChatAffordance extends Disposable { const debouncedSelection = debouncedObservable(editorObs.cursorSelection, 500); - const selection = observableValue(this, undefined); + const selectionData = observableValue(this, undefined); - this._store.add(autorun(r => { - const value = editorObs.cursorSelection.read(r); - if (!value || value.isEmpty()) { - selection.set(undefined, undefined); + let explicitSelection = false; + + this._store.add(runOnChange(editorObs.selections, (value, _prev, events) => { + explicitSelection = events.every(e => e.reason === CursorChangeReason.Explicit); + if (!value || value.length !== 1 || value[0].isEmpty() || !explicitSelection) { + selectionData.set(undefined, undefined); } })); + this._store.add(autorun(r => { + const value = debouncedSelection.read(r); + if (!value || value.isEmpty() || !explicitSelection) { + selectionData.set(undefined, undefined); + return; + } + selectionData.set(value, undefined); + })); this._store.add(autorun(r => { if (chatEntiteldService.sentimentObs.read(r).hidden) { - selection.set(undefined, undefined); - return; + selectionData.set(undefined, undefined); } if (suppressGutter.read(r)) { - selection.set(undefined, undefined); - return; + selectionData.set(undefined, undefined); } - const value = debouncedSelection.read(r); - if (!value || value.isEmpty()) { - selection.set(undefined, undefined); - return; - } - selection.set(value, undefined); })); - - // Instantiate the gutter indicator this._store.add(this._instantiationService.createInstance( InlineChatGutterAffordance, editorObs, - derived(r => affordance.read(r) === 'gutter' ? selection.read(r) : undefined), + derived(r => affordance.read(r) === 'gutter' ? selectionData.read(r) : undefined), suppressGutter, this._menuData )); @@ -88,7 +89,7 @@ export class InlineChatAffordance extends Disposable { this._store.add(this._instantiationService.createInstance( InlineChatEditorAffordance, this._editor, - derived(r => affordance.read(r) === 'editor' ? selection.read(r) : undefined), + derived(r => affordance.read(r) === 'editor' ? selectionData.read(r) : undefined), suppressGutter, this._menuData )); diff --git a/src/vs/workbench/contrib/inlineChat/browser/inlineChatEditorAffordance.ts b/src/vs/workbench/contrib/inlineChat/browser/inlineChatEditorAffordance.ts index 9fa3043f0fb..3ed19bbfa6b 100644 --- a/src/vs/workbench/contrib/inlineChat/browser/inlineChatEditorAffordance.ts +++ b/src/vs/workbench/contrib/inlineChat/browser/inlineChatEditorAffordance.ts @@ -4,11 +4,13 @@ *--------------------------------------------------------------------------------------------*/ import './media/inlineChatEditorAffordance.css'; +import { IDimension } from '../../../../base/browser/dom.js'; import * as dom from '../../../../base/browser/dom.js'; import { Codicon } from '../../../../base/common/codicons.js'; import { Disposable } from '../../../../base/common/lifecycle.js'; import { ThemeIcon } from '../../../../base/common/themables.js'; import { ContentWidgetPositionPreference, ICodeEditor, IContentWidget, IContentWidgetPosition } from '../../../../editor/browser/editorBrowser.js'; +import { EditorOption } from '../../../../editor/common/config/editorOptions.js'; import { Selection, SelectionDirection } from '../../../../editor/common/core/selection.js'; import { autorun, IObservable, ISettableObservable } from '../../../../base/common/observable.js'; import { assertType } from '../../../../base/common/types.js'; @@ -42,7 +44,7 @@ export class InlineChatEditorAffordance extends Disposable implements IContentWi // Add sparkle icon const icon = dom.append(this._domNode, dom.$('.icon')); - icon.classList.add(...ThemeIcon.asClassNameArray(Codicon.sparkle)); + icon.classList.add(...ThemeIcon.asClassNameArray(Codicon.sparkleFilled)); // Handle click to show overlay widget this._store.add(dom.addDisposableListener(this._domNode, dom.EventType.CLICK, (e) => { @@ -126,6 +128,15 @@ export class InlineChatEditorAffordance extends Disposable implements IContentWi return this._position; } + beforeRender(): IDimension | null { + const position = this._editor.getPosition(); + const lineHeight = position ? this._editor.getLineHeightForPosition(position) : this._editor.getOption(EditorOption.lineHeight); + + this._domNode.style.setProperty('--vscode-inline-chat-affordance-height', `${lineHeight}px`); + + return null; + } + override dispose(): void { if (this._isVisible) { this._editor.removeContentWidget(this); diff --git a/src/vs/workbench/contrib/inlineChat/browser/media/inlineChatEditorAffordance.css b/src/vs/workbench/contrib/inlineChat/browser/media/inlineChatEditorAffordance.css index 81a039d9d5c..5eaa356dcfa 100644 --- a/src/vs/workbench/contrib/inlineChat/browser/media/inlineChatEditorAffordance.css +++ b/src/vs/workbench/contrib/inlineChat/browser/media/inlineChatEditorAffordance.css @@ -4,25 +4,19 @@ *--------------------------------------------------------------------------------------------*/ .inline-chat-content-widget { - box-shadow: 0 0 8px 2px var(--vscode-widget-shadow); - border: 1px solid var(--vscode-widget-border, transparent); - border-radius: 4px; - color: var(--vscode-button-foreground); - background-color: var(--vscode-button-background); - display: flex; - height: 16px; - width: 16px; - align-items: center; - justify-content: center; - cursor: pointer; + background-color: var(--vscode-editor-background); padding: 2px; -} - -.inline-chat-content-widget:hover { - background-color: var(--vscode-button-hoverBackground); + border-radius: 8px; + display: flex; + align-items: center; + box-shadow: 0 4px 8px var(--vscode-widget-shadow); + cursor: pointer; + min-width: var(--vscode-inline-chat-affordance-height); + min-height: var(--vscode-inline-chat-affordance-height); + line-height: var(--vscode-inline-chat-affordance-height); } .inline-chat-content-widget .icon.codicon { margin: 0; - color: var(--vscode-button-foreground); + color: var(--vscode-editorLightBulb-foreground); }