Revert "Merge pull request #250670 from microsoft/copilot/fix-250669"

This reverts commit aa095f877e, reversing
changes made to 13ff4544a7.
This commit is contained in:
Daniel Imms
2025-06-06 09:49:55 -07:00
parent a76a1c4650
commit 95c9166d0b
6 changed files with 66 additions and 57 deletions
@@ -121,49 +121,20 @@ export async function getCwdForSplit(
}
export const terminalSendSequenceCommand = async (accessor: ServicesAccessor, args: unknown) => {
const configurationResolverService = accessor.get(IConfigurationResolverService);
const historyService = accessor.get(IHistoryService);
const quickInputService = accessor.get(IQuickInputService);
const terminalService = accessor.get(ITerminalService);
const workspaceContextService = accessor.get(IWorkspaceContextService);
const instance = terminalService.activeInstance || await terminalService.getActiveOrCreateInstance();
if (!instance) {
return;
}
let text = isObject(args) && 'text' in args ? toOptionalString(args.text) : undefined;
// If no text provided, prompt user for input
if (!text) {
text = await quickInputService.input({
value: '',
placeHolder: 'Enter sequence to send (supports \\n, \\r, \\x escape sequences)',
prompt: localize('workbench.action.terminal.sendSequence.prompt', "Enter sequence to send to the terminal"),
});
const instance = accessor.get(ITerminalService).activeInstance;
if (instance) {
const text = isObject(args) && 'text' in args ? toOptionalString(args.text) : undefined;
if (!text) {
return;
}
const configurationResolverService = accessor.get(IConfigurationResolverService);
const workspaceContextService = accessor.get(IWorkspaceContextService);
const historyService = accessor.get(IHistoryService);
const activeWorkspaceRootUri = historyService.getLastActiveWorkspaceRoot(instance.isRemote ? Schemas.vscodeRemote : Schemas.file);
const lastActiveWorkspaceRoot = activeWorkspaceRootUri ? workspaceContextService.getWorkspaceFolder(activeWorkspaceRootUri) ?? undefined : undefined;
const resolvedText = await configurationResolverService.resolveAsync(lastActiveWorkspaceRoot, text);
instance.sendText(resolvedText, false);
}
// Process escape sequences
let processedText = text
.replace(/\\n/g, '\n')
.replace(/\\r/g, '\r');
// Process hex escape sequences (\xNN)
while (true) {
const match = processedText.match(/\\x([0-9a-fA-F]{2})/);
if (match === null || match.index === undefined || match.length < 2) {
break;
}
processedText = processedText.slice(0, match.index) + String.fromCharCode(parseInt(match[1], 16)) + processedText.slice(match.index + 4);
}
const activeWorkspaceRootUri = historyService.getLastActiveWorkspaceRoot(instance.isRemote ? Schemas.vscodeRemote : Schemas.file);
const lastActiveWorkspaceRoot = activeWorkspaceRootUri ? workspaceContextService.getWorkspaceFolder(activeWorkspaceRootUri) ?? undefined : undefined;
const resolvedText = await configurationResolverService.resolveAsync(lastActiveWorkspaceRoot, processedText);
instance.sendText(resolvedText, false);
};
export const terminalSendSignalCommand = async (accessor: ServicesAccessor, args: unknown) => {
@@ -1036,13 +1007,14 @@ export function registerTerminalActions() {
registerTerminalAction({
id: TerminalCommandId.SendSequence,
title: terminalStrings.sendSequence,
f1: true,
f1: false,
metadata: {
description: terminalStrings.sendSequence.value,
args: [{
name: 'args',
schema: {
type: 'object',
required: ['text'],
properties: {
text: {
description: localize('sendSequence', "The sequence of text to send to the terminal"),
@@ -17,11 +17,12 @@ import { IConfigurationService } from '../../../../../platform/configuration/com
import { ContextKeyExpr } from '../../../../../platform/contextkey/common/contextkey.js';
import { IFileService } from '../../../../../platform/files/common/files.js';
import { IOpenerService } from '../../../../../platform/opener/common/opener.js';
import { IQuickInputService } from '../../../../../platform/quickinput/common/quickInput.js';
import { ITerminalCommand, TerminalCapability } from '../../../../../platform/terminal/common/capabilities/capabilities.js';
import { ITerminalLogService, TerminalSettingId } from '../../../../../platform/terminal/common/terminal.js';
import { IWorkspaceContextService } from '../../../../../platform/workspace/common/workspace.js';
import { IStatusbarService, StatusbarAlignment, type IStatusbarEntry } from '../../../../services/statusbar/browser/statusbar.js';
import { ITerminalContribution, ITerminalInstance, IXtermTerminal } from '../../../terminal/browser/terminal.js';
import { IInternalXtermTerminal, ITerminalContribution, ITerminalInstance, IXtermTerminal } from '../../../terminal/browser/terminal.js';
import { registerTerminalAction } from '../../../terminal/browser/terminalActions.js';
import { registerTerminalContribution, type ITerminalContributionContext } from '../../../terminal/browser/terminalExtensions.js';
import { TerminalContextKeys } from '../../../terminal/common/terminalContextKey.js';
@@ -60,6 +61,41 @@ registerTerminalAction({
}
});
registerTerminalAction({
id: TerminalDeveloperCommandId.WriteDataToTerminal,
title: localize2('workbench.action.terminal.writeDataToTerminal', 'Write Data to Terminal'),
category: Categories.Developer,
run: async (c, accessor) => {
const quickInputService = accessor.get(IQuickInputService);
const instance = await c.service.getActiveOrCreateInstance();
await c.service.revealActiveTerminal();
await instance.processReady;
if (!instance.xterm) {
throw new Error('Cannot write data to terminal if xterm isn\'t initialized');
}
const data = await quickInputService.input({
value: '',
placeHolder: 'Enter data, use \\x to escape',
prompt: localize('workbench.action.terminal.writeDataToTerminal.prompt', "Enter data to write directly to the terminal, bypassing the pty"),
});
if (!data) {
return;
}
let escapedData = data
.replace(/\\n/g, '\n')
.replace(/\\r/g, '\r');
while (true) {
const match = escapedData.match(/\\x([0-9a-fA-F]{2})/);
if (match === null || match.index === undefined || match.length < 2) {
break;
}
escapedData = escapedData.slice(0, match.index) + String.fromCharCode(parseInt(match[1], 16)) + escapedData.slice(match.index + 4);
}
const xterm = instance.xterm as any as IInternalXtermTerminal;
xterm._writeText(escapedData);
}
});
registerTerminalAction({
id: TerminalDeveloperCommandId.RecordSession,
title: localize2('workbench.action.terminal.recordSession', 'Record Terminal Session'),
@@ -4,6 +4,7 @@
*--------------------------------------------------------------------------------------------*/
export const enum TerminalDeveloperCommandId {
WriteDataToTerminal = 'workbench.action.terminal.writeDataToTerminal',
RecordSession = 'workbench.action.terminal.recordSession',
ShowTextureAtlas = 'workbench.action.terminal.showTextureAtlas',
RestartPtyHost = 'workbench.action.terminal.restartPtyHost',
+4 -4
View File
@@ -41,7 +41,7 @@ export enum TerminalCommandIdWithValue {
NewWithProfile = 'workbench.action.terminal.newWithProfile',
SelectDefaultProfile = 'workbench.action.terminal.selectDefaultShell',
AttachToSession = 'workbench.action.terminal.attachToSession',
SendSequence = 'workbench.action.terminal.sendSequence'
WriteDataToTerminal = 'workbench.action.terminal.writeDataToTerminal'
}
/**
@@ -156,7 +156,7 @@ export class Terminal {
/**
* Creates an empty terminal by opening a regular terminal and resetting its state such that it
* essentially acts like an Pseudoterminal extension API-based terminal. This can then be paired
* with `TerminalCommandIdWithValue.SendSequence` to make more reliable tests.
* with `TerminalCommandIdWithValue.WriteDataToTerminal` to make more reliable tests.
*/
async createEmptyTerminal(expectedLocation?: 'editor' | 'panel'): Promise<void> {
await this.createTerminal(expectedLocation);
@@ -167,11 +167,11 @@ export class Terminal {
await this.waitForTerminalText(buffer => buffer.some(line => line.startsWith('initialized')));
// Erase all content and reset cursor to top
await this.runCommandWithValue(TerminalCommandIdWithValue.SendSequence, `${csi('2J')}${csi('H')}`);
await this.runCommandWithValue(TerminalCommandIdWithValue.WriteDataToTerminal, `${csi('2J')}${csi('H')}`);
// Force windows pty mode off; assume all sequences are rendered in correct position
if (process.platform === 'win32') {
await this.runCommandWithValue(TerminalCommandIdWithValue.SendSequence, `${vsc('P;IsWindows=False')}`);
await this.runCommandWithValue(TerminalCommandIdWithValue.WriteDataToTerminal, `${vsc('P;IsWindows=False')}`);
}
}
@@ -98,33 +98,33 @@ export function setup(options?: { skipSuite: boolean }) {
// Use the simplest profile to get as little process interaction as possible
await terminal.createEmptyTerminal();
// Erase all content and reset cursor to top
await terminal.runCommandWithValue(TerminalCommandIdWithValue.SendSequence, `${csi('2J')}${csi('H')}`);
await terminal.runCommandWithValue(TerminalCommandIdWithValue.WriteDataToTerminal, `${csi('2J')}${csi('H')}`);
});
describe('VS Code sequences', () => {
it('should handle the simple case', async () => {
await terminal.runCommandWithValue(TerminalCommandIdWithValue.SendSequence, `${vsc('A')}Prompt> ${vsc('B')}exitcode 0`);
await terminal.runCommandWithValue(TerminalCommandIdWithValue.WriteDataToTerminal, `${vsc('A')}Prompt> ${vsc('B')}exitcode 0`);
await terminal.assertCommandDecorations({ placeholder: 1, success: 0, error: 0 });
await terminal.runCommandWithValue(TerminalCommandIdWithValue.SendSequence, `\\r\\n${vsc('C')}Success\\r\\n${vsc('D;0')}`);
await terminal.runCommandWithValue(TerminalCommandIdWithValue.WriteDataToTerminal, `\\r\\n${vsc('C')}Success\\r\\n${vsc('D;0')}`);
await terminal.assertCommandDecorations({ placeholder: 0, success: 1, error: 0 });
await terminal.runCommandWithValue(TerminalCommandIdWithValue.SendSequence, `${vsc('A')}Prompt> ${vsc('B')}exitcode 1`);
await terminal.runCommandWithValue(TerminalCommandIdWithValue.WriteDataToTerminal, `${vsc('A')}Prompt> ${vsc('B')}exitcode 1`);
await terminal.assertCommandDecorations({ placeholder: 1, success: 1, error: 0 });
await terminal.runCommandWithValue(TerminalCommandIdWithValue.SendSequence, `\\r\\n${vsc('C')}Failure\\r\\n${vsc('D;1')}`);
await terminal.runCommandWithValue(TerminalCommandIdWithValue.WriteDataToTerminal, `\\r\\n${vsc('C')}Failure\\r\\n${vsc('D;1')}`);
await terminal.assertCommandDecorations({ placeholder: 0, success: 1, error: 1 });
await terminal.runCommandWithValue(TerminalCommandIdWithValue.SendSequence, `${vsc('A')}Prompt> ${vsc('B')}`);
await terminal.runCommandWithValue(TerminalCommandIdWithValue.WriteDataToTerminal, `${vsc('A')}Prompt> ${vsc('B')}`);
await terminal.assertCommandDecorations({ placeholder: 1, success: 1, error: 1 });
});
});
describe('Final Term sequences', () => {
it('should handle the simple case', async () => {
await terminal.runCommandWithValue(TerminalCommandIdWithValue.SendSequence, `${ft('A')}Prompt> ${ft('B')}exitcode 0`);
await terminal.runCommandWithValue(TerminalCommandIdWithValue.WriteDataToTerminal, `${ft('A')}Prompt> ${ft('B')}exitcode 0`);
await terminal.assertCommandDecorations({ placeholder: 1, success: 0, error: 0 });
await terminal.runCommandWithValue(TerminalCommandIdWithValue.SendSequence, `\\r\\n${ft('C')}Success\\r\\n${ft('D;0')}`);
await terminal.runCommandWithValue(TerminalCommandIdWithValue.WriteDataToTerminal, `\\r\\n${ft('C')}Success\\r\\n${ft('D;0')}`);
await terminal.assertCommandDecorations({ placeholder: 0, success: 1, error: 0 });
await terminal.runCommandWithValue(TerminalCommandIdWithValue.SendSequence, `${ft('A')}Prompt> ${ft('B')}exitcode 1`);
await terminal.runCommandWithValue(TerminalCommandIdWithValue.WriteDataToTerminal, `${ft('A')}Prompt> ${ft('B')}exitcode 1`);
await terminal.assertCommandDecorations({ placeholder: 1, success: 1, error: 0 });
await terminal.runCommandWithValue(TerminalCommandIdWithValue.SendSequence, `\\r\\n${ft('C')}Failure\\r\\n${ft('D;1')}`);
await terminal.runCommandWithValue(TerminalCommandIdWithValue.WriteDataToTerminal, `\\r\\n${ft('C')}Failure\\r\\n${ft('D;1')}`);
await terminal.assertCommandDecorations({ placeholder: 0, success: 1, error: 1 });
await terminal.runCommandWithValue(TerminalCommandIdWithValue.SendSequence, `${ft('A')}Prompt> ${ft('B')}exitcode 1`);
await terminal.runCommandWithValue(TerminalCommandIdWithValue.WriteDataToTerminal, `${ft('A')}Prompt> ${ft('B')}exitcode 1`);
await terminal.assertCommandDecorations({ placeholder: 1, success: 1, error: 1 });
});
});
@@ -35,7 +35,7 @@ export function setup(options?: { skipSuite: boolean }) {
expectedLineCount: number = 1
): Promise<void> {
const data = generateCommandAndOutput(prompt, command, exitCode);
await terminal.runCommandWithValue(TerminalCommandIdWithValue.SendSequence, data);
await terminal.runCommandWithValue(TerminalCommandIdWithValue.WriteDataToTerminal, data);
// Verify line count
await app.code.waitForElements('.terminal-sticky-scroll .xterm-rows > *', true, e => e.length === expectedLineCount);
// Verify content