mirror of
https://github.com/microsoft/vscode.git
synced 2026-08-29 17:41:32 +01:00
Improve slash command rendering in inline chat (#187769)
* Render inline chat slash commands as blocks * Allow backspace to delete slash command block * Remove unnecessary template string literal
This commit is contained in:
@@ -278,13 +278,20 @@
|
||||
}
|
||||
|
||||
.monaco-editor .inline-chat-slash-command {
|
||||
color: var(--vscode-textLink-foreground)
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
.monaco-editor .inline-chat-slash-command-detail {
|
||||
opacity: 0.5;
|
||||
}
|
||||
|
||||
.monaco-editor .inline-chat-slash-command-content-widget {
|
||||
padding: 0 0.4em;
|
||||
border-radius: 3px;
|
||||
background-color: var(--vscode-textCodeBlock-background);
|
||||
color: var(--vscode-textLink-foreground);
|
||||
}
|
||||
|
||||
/* diff zone */
|
||||
|
||||
.monaco-editor .inline-chat-diff-widget {
|
||||
|
||||
@@ -4,8 +4,8 @@
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import 'vs/css!./inlineChat';
|
||||
import { DisposableStore, MutableDisposable, toDisposable } from 'vs/base/common/lifecycle';
|
||||
import { IActiveCodeEditor, ICodeEditor, IDiffEditorConstructionOptions } from 'vs/editor/browser/editorBrowser';
|
||||
import { Disposable, DisposableStore, MutableDisposable, toDisposable } from 'vs/base/common/lifecycle';
|
||||
import { ContentWidgetPositionPreference, IActiveCodeEditor, ICodeEditor, IContentWidget, IDiffEditorConstructionOptions } from 'vs/editor/browser/editorBrowser';
|
||||
import { EditorLayoutInfo, EditorOption } from 'vs/editor/common/config/editorOptions';
|
||||
import { IRange, Range } from 'vs/editor/common/core/range';
|
||||
import { localize } from 'vs/nls';
|
||||
@@ -49,6 +49,7 @@ import { ExpansionState } from 'vs/workbench/contrib/inlineChat/browser/inlineCh
|
||||
import { IdleValue } from 'vs/base/common/async';
|
||||
import * as aria from 'vs/base/browser/ui/aria/aria';
|
||||
import { IMenuWorkbenchButtonBarOptions, MenuWorkbenchButtonBar } from 'vs/platform/actions/browser/buttonbar';
|
||||
import { KeyCode } from 'vs/base/common/keyCodes';
|
||||
|
||||
const defaultAriaLabel = localize('aria-label', "Inline Chat Input");
|
||||
|
||||
@@ -180,6 +181,8 @@ export class InlineChatWidget {
|
||||
private _preferredExpansionState: ExpansionState | undefined;
|
||||
private _expansionState: ExpansionState = ExpansionState.NOT_CROPPED;
|
||||
|
||||
private _slashCommandContentWidget: SlashCommandContentWidget;
|
||||
|
||||
constructor(
|
||||
private readonly parentEditor: ICodeEditor,
|
||||
@IModelService private readonly _modelService: IModelService,
|
||||
@@ -278,6 +281,11 @@ export class InlineChatWidget {
|
||||
this._store.add(this._inputModel.onDidChangeContent(togglePlaceholder));
|
||||
togglePlaceholder();
|
||||
|
||||
// slash command content widget
|
||||
|
||||
this._slashCommandContentWidget = new SlashCommandContentWidget(this._inputEditor);
|
||||
this._store.add(this._slashCommandContentWidget);
|
||||
|
||||
// toolbars
|
||||
|
||||
const toolbar = this._instantiationService.createInstance(MenuWorkbenchToolBar, this._elements.editorToolbar, MENU_INLINE_CHAT_WIDGET, {
|
||||
@@ -654,6 +662,8 @@ export class InlineChatWidget {
|
||||
const decorations = this._inputEditor.createDecorationsCollection();
|
||||
|
||||
const updateSlashDecorations = () => {
|
||||
this._slashCommandContentWidget.hide();
|
||||
|
||||
const newDecorations: IModelDeltaDecoration[] = [];
|
||||
for (const command of commands) {
|
||||
const withSlash = `/${command.command}`;
|
||||
@@ -664,9 +674,16 @@ export class InlineChatWidget {
|
||||
options: {
|
||||
description: 'inline-chat-slash-command',
|
||||
inlineClassName: 'inline-chat-slash-command',
|
||||
after: {
|
||||
// Force some space between slash command and placeholder
|
||||
content: ' '
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
this._slashCommandContentWidget.setCommandText(command.command);
|
||||
this._slashCommandContentWidget.show();
|
||||
|
||||
// inject detail when otherwise empty
|
||||
if (firstLine === `/${command.command} `) {
|
||||
newDecorations.push({
|
||||
@@ -691,6 +708,57 @@ export class InlineChatWidget {
|
||||
}
|
||||
}
|
||||
|
||||
class SlashCommandContentWidget extends Disposable implements IContentWidget {
|
||||
private _domNode = document.createElement('div');
|
||||
private _lastSlashCommandText: string | undefined;
|
||||
|
||||
constructor(private _editor: ICodeEditor) {
|
||||
super();
|
||||
|
||||
this._domNode.toggleAttribute('hidden', true);
|
||||
this._domNode.classList.add('inline-chat-slash-command-content-widget');
|
||||
|
||||
// If backspace at a slash command boundary, remove the slash command
|
||||
this._register(this._editor.onKeyUp((e) => {
|
||||
if (e.keyCode !== KeyCode.Backspace) {
|
||||
return;
|
||||
}
|
||||
|
||||
const firstLine = this._editor.getModel()?.getLineContent(1);
|
||||
const selection = this._editor.getSelection();
|
||||
const withSlash = `/${this._lastSlashCommandText}`;
|
||||
if (!firstLine?.startsWith(withSlash) || !selection?.isEmpty() || selection?.startLineNumber !== 1 || selection?.startColumn !== withSlash.length + 1) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Allow to undo the backspace
|
||||
this._editor.executeEdits('inline-chat-slash-command', [{
|
||||
range: new Range(1, 1, 1, selection.startColumn),
|
||||
text: null
|
||||
}]);
|
||||
}));
|
||||
}
|
||||
|
||||
show() {
|
||||
this._domNode.toggleAttribute('hidden', false);
|
||||
this._editor.addContentWidget(this);
|
||||
}
|
||||
|
||||
hide() {
|
||||
this._domNode.toggleAttribute('hidden', true);
|
||||
this._editor.removeContentWidget(this);
|
||||
}
|
||||
|
||||
setCommandText(slashCommand: string) {
|
||||
this._domNode.innerText = `${slashCommand} `;
|
||||
this._lastSlashCommandText = slashCommand;
|
||||
}
|
||||
|
||||
getId() { return 'inline-chat-slash-command-content-widget'; }
|
||||
getDomNode() { return this._domNode; }
|
||||
getPosition() { return { position: { lineNumber: 1, column: 1 }, preference: [ContentWidgetPositionPreference.EXACT] }; }
|
||||
}
|
||||
|
||||
export class InlineChatZoneWidget extends ZoneWidget {
|
||||
|
||||
readonly widget: InlineChatWidget;
|
||||
|
||||
Reference in New Issue
Block a user