mirror of
https://github.com/microsoft/vscode.git
synced 2026-02-14 23:18:36 +00:00
ensure command id defined for non copilot terminals (#274954)
This commit is contained in:
@@ -276,12 +276,6 @@ export interface IHandleCommandOptions {
|
||||
* Properties for the mark
|
||||
*/
|
||||
markProperties?: IMarkProperties;
|
||||
|
||||
/**
|
||||
* An optional predefined command ID. When provided, this ID will be used instead of
|
||||
* generating a new one, allowing commands to be linked across renderer and ptyHost.
|
||||
*/
|
||||
commandId?: string;
|
||||
}
|
||||
|
||||
export interface INaiveCwdDetectionCapability {
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
import { IMarkProperties, ISerializedTerminalCommand, ITerminalCommand } from '../capabilities.js';
|
||||
import { ITerminalOutputMatcher, ITerminalOutputMatch } from '../../terminal.js';
|
||||
import type { IBuffer, IBufferLine, IMarker, Terminal } from '@xterm/headless';
|
||||
import { generateUuid } from '../../../../../base/common/uuid.js';
|
||||
|
||||
export interface ITerminalCommandProperties {
|
||||
command: string;
|
||||
@@ -284,7 +285,7 @@ export class PartialTerminalCommand implements ICurrentPartialCommand {
|
||||
private readonly _xterm: Terminal,
|
||||
id?: string
|
||||
) {
|
||||
this.id = id;
|
||||
this.id = id ?? generateUuid();
|
||||
}
|
||||
|
||||
serialize(cwd: string | undefined): ISerializedTerminalCommand | undefined {
|
||||
|
||||
@@ -7,13 +7,13 @@ import { RunOnceScheduler } from '../../../../base/common/async.js';
|
||||
import { debounce } from '../../../../base/common/decorators.js';
|
||||
import { Emitter } from '../../../../base/common/event.js';
|
||||
import { Disposable, MandatoryMutableDisposable, MutableDisposable } from '../../../../base/common/lifecycle.js';
|
||||
import { generateUuid } from '../../../../base/common/uuid.js';
|
||||
import { ILogService } from '../../../log/common/log.js';
|
||||
import { CommandInvalidationReason, ICommandDetectionCapability, ICommandInvalidationRequest, IHandleCommandOptions, ISerializedCommandDetectionCapability, ISerializedTerminalCommand, ITerminalCommand, TerminalCapability } from './capabilities.js';
|
||||
import { ITerminalOutputMatcher } from '../terminal.js';
|
||||
import { ICurrentPartialCommand, PartialTerminalCommand, TerminalCommand } from './commandDetection/terminalCommand.js';
|
||||
import { PromptInputModel, type IPromptInputModel } from './commandDetection/promptInputModel.js';
|
||||
import type { IBuffer, IDisposable, IMarker, Terminal } from '@xterm/headless';
|
||||
import { isString } from '../../../../base/common/types.js';
|
||||
|
||||
interface ITerminalDimensions {
|
||||
cols: number;
|
||||
@@ -365,20 +365,7 @@ export class CommandDetectionCapability extends Disposable implements ICommandDe
|
||||
if (!this._currentCommand.commandExecutedMarker) {
|
||||
this.handleCommandExecuted();
|
||||
}
|
||||
// If a custom command ID is provided, use it for the current command
|
||||
// Otherwise, check if there's a pending next command ID
|
||||
if (options?.commandId) {
|
||||
this._currentCommand.id = options.commandId;
|
||||
this._nextCommandId = undefined; // Clear the pending ID
|
||||
} else if (
|
||||
this._nextCommandId &&
|
||||
isString(this.currentCommand.command) &&
|
||||
isString(this._nextCommandId.command) &&
|
||||
this.currentCommand.command.trim() === this._nextCommandId.command.trim()
|
||||
) {
|
||||
this._currentCommand.id = this._nextCommandId.commandId;
|
||||
this._nextCommandId = undefined; // Clear after use
|
||||
}
|
||||
this._ensureCurrentCommandId(this._currentCommand.command ?? this._currentCommand.extractCommandLine());
|
||||
this._currentCommand.markFinishedTime();
|
||||
this._ptyHeuristics.value.preHandleCommandFinished?.();
|
||||
|
||||
@@ -415,12 +402,25 @@ export class CommandDetectionCapability extends Disposable implements ICommandDe
|
||||
this._logService.debug('CommandDetectionCapability#onCommandFinished', newCommand);
|
||||
this._onCommandFinished.fire(newCommand);
|
||||
}
|
||||
// Create new command for next execution, preserving command ID if one was specified
|
||||
const nextCommandId = this._handleCommandStartOptions?.commandId;
|
||||
this._currentCommand = new PartialTerminalCommand(this._terminal, nextCommandId);
|
||||
// Create new command for next execution
|
||||
this._currentCommand = new PartialTerminalCommand(this._terminal);
|
||||
this._handleCommandStartOptions = undefined;
|
||||
}
|
||||
|
||||
private _ensureCurrentCommandId(commandLine: string | undefined): void {
|
||||
if (this._nextCommandId?.commandId && typeof commandLine === 'string' && commandLine.trim() === this._nextCommandId.command.trim()) {
|
||||
if (this._currentCommand.id !== this._nextCommandId.commandId) {
|
||||
this._currentCommand.id = this._nextCommandId.commandId;
|
||||
}
|
||||
this._nextCommandId = undefined;
|
||||
return;
|
||||
}
|
||||
|
||||
if (!this._currentCommand.id) {
|
||||
this._currentCommand.id = generateUuid();
|
||||
}
|
||||
}
|
||||
|
||||
setCommandLine(commandLine: string, isTrusted: boolean) {
|
||||
this._logService.debug('CommandDetectionCapability#setCommandLine', commandLine, isTrusted);
|
||||
this._currentCommand.command = commandLine;
|
||||
|
||||
@@ -33,6 +33,7 @@ import { IInstantiationService } from '../../../../../platform/instantiation/com
|
||||
import { TerminalContext } from '../../../chat/browser/actions/chatContext.js';
|
||||
import { getTerminalUri, parseTerminalUri } from '../terminalUri.js';
|
||||
import { URI } from '../../../../../base/common/uri.js';
|
||||
import { ChatAgentLocation } from '../../../chat/common/constants.js';
|
||||
|
||||
interface IDisposableDecoration { decoration: IDecoration; disposables: IDisposable[]; exitCode?: number; markProperties?: IMarkProperties }
|
||||
|
||||
@@ -526,12 +527,13 @@ export class DecorationAddon extends Disposable implements ITerminalAddon, IDeco
|
||||
return {
|
||||
class: undefined, tooltip: labelAttachToChat, id: 'terminal.attachToChat', label: labelAttachToChat, enabled: true,
|
||||
run: async () => {
|
||||
const widget = this._chatWidgetService.lastFocusedWidget;
|
||||
const widget = this._chatWidgetService.lastFocusedWidget ?? this._chatWidgetService.getWidgetsByLocations(ChatAgentLocation.Chat)?.[0];
|
||||
let terminalContext: TerminalContext | undefined;
|
||||
if (this._resource) {
|
||||
const parsedUri = parseTerminalUri(this._resource);
|
||||
terminalContext = this._instantiationService.createInstance(TerminalContext, getTerminalUri(parsedUri.workspaceId, parsedUri.instanceId!, undefined, command.id));
|
||||
}
|
||||
|
||||
if (terminalContext && widget && widget.attachmentCapabilities.supportsTerminalAttachments) {
|
||||
try {
|
||||
const attachment = await terminalContext.asAttachment(widget);
|
||||
|
||||
@@ -35,6 +35,7 @@ suite('CommandDetectionCapability', () => {
|
||||
// Ensure timestamps are set and were captured recently
|
||||
for (const command of capability.commands) {
|
||||
ok(Math.abs(Date.now() - command.timestamp) < 2000);
|
||||
ok(command.id, 'Expected command to have an assigned id');
|
||||
}
|
||||
deepStrictEqual(addEvents, capability.commands);
|
||||
// Clear the commands to avoid re-asserting past commands
|
||||
|
||||
Reference in New Issue
Block a user