Skip to content

Commit 1cad4eb

Browse files
committed
remove all the ctrl+c logic
1 parent 48801f9 commit 1cad4eb

4 files changed

Lines changed: 81 additions & 214 deletions

File tree

com.microsoft.copilot.eclipse.terminal.api/src/com/microsoft/copilot/eclipse/terminal/api/TerminalCommandProcessor.java

Lines changed: 9 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -104,49 +104,37 @@ public static String prepareOutputForModel(String output) {
104104
* Attempts to complete a command using shell integration markers.
105105
*
106106
* @param output terminal output buffer
107-
* @param activeCommand command currently being executed
108-
* @param skipCompletion whether to skip the next completed command region
109107
* @return the completion check result
110108
*/
111-
public static CompletionCheckResult tryCompleteWithMarker(StringBuilder output, String activeCommand,
112-
boolean skipCompletion) {
113-
MarkerRange commandFinishMarkerRange = findCommandFinishMarker(output);
109+
public static CompletionCheckResult tryCompleteWithMarker(StringBuilder output) {
110+
MarkerRange commandFinishMarkerRange = findMarker(output, COMMAND_FINISH_MARKER_PATTERN, 0);
114111
if (commandFinishMarkerRange == null) {
115112
// Startup or idle prompts can arrive before a command runs. Keep the visible prompt text, but remove marker
116113
// bytes so later command output cleanup does not have to handle stale prompt boundaries.
117114
removePromptMarkers(output);
118115
return CompletionCheckResult.incomplete();
119116
}
120117

121-
// The command-finished marker is emitted before the next prompt. Wait for prompt end so the returned output keeps
122-
// the prompt line, which gives the language model the terminal's current working directory.
118+
// A complete marker command is the command finish marker followed by the next prompt end. Waiting for B keeps the
119+
// prompt line in the returned output, which gives the language model the terminal's current working directory.
123120
MarkerRange promptEndMarkerRange = findMarker(output, PROMPT_END_MARKER_PATTERN, commandFinishMarkerRange.endIndex);
124121
if (promptEndMarkerRange == null) {
125122
return CompletionCheckResult.incomplete();
126123
}
127124

128-
// Keep command output plus the next prompt, but remove the command-finished marker itself, including exit code.
125+
// Keep terminal output plus the next prompt, but exclude command finish markers.
129126
String completedOutput = output.substring(0, commandFinishMarkerRange.startIndex)
130127
+ output.substring(commandFinishMarkerRange.endIndex, promptEndMarkerRange.endIndex);
131-
if (shouldSkipCompletion(completedOutput, activeCommand, skipCompletion)) {
132-
// This region belongs to a command that was interrupted by Ctrl+C. Drop it so it cannot complete the next
133-
// foreground command that may already be listening on the same terminal output buffer.
134-
output.delete(0, promptEndMarkerRange.endIndex);
135-
return CompletionCheckResult.skipped();
136-
}
137-
return CompletionCheckResult.completed(cleanCommandOutput(completedOutput, activeCommand));
128+
return CompletionCheckResult.completed(cleanCommandOutput(completedOutput));
138129
}
139130

140131
/**
141132
* Attempts to complete a command by detecting a shell prompt.
142133
*
143134
* @param output terminal output buffer
144-
* @param activeCommand command currently being executed
145-
* @param skipCompletion whether to skip the next completed command region
146135
* @return the completion check result
147136
*/
148-
public static CompletionCheckResult tryCompleteWithPrompt(StringBuilder output, String activeCommand,
149-
boolean skipCompletion) {
137+
public static CompletionCheckResult tryCompleteWithPrompt(StringBuilder output) {
150138
String terminalOutput = output.toString().trim();
151139
int lastNewLineIndex = terminalOutput.lastIndexOf('\n');
152140
if (lastNewLineIndex <= 0) {
@@ -164,11 +152,6 @@ public static CompletionCheckResult tryCompleteWithPrompt(StringBuilder output,
164152
return CompletionCheckResult.incomplete();
165153
}
166154

167-
if (shouldSkipCompletion(terminalOutput, activeCommand, skipCompletion)) {
168-
output.setLength(0);
169-
return CompletionCheckResult.skipped();
170-
}
171-
172155
String contentWithoutLastPrompt = terminalOutput.substring(0, lastNewLineIndex);
173156
int promptStartIndex = contentWithoutLastPrompt.indexOf(lastLine);
174157
if (promptStartIndex == -1) {
@@ -183,17 +166,6 @@ public static CompletionCheckResult tryCompleteWithPrompt(StringBuilder output,
183166
return CompletionCheckResult.completed(contentWithoutLastPrompt.substring(promptStartIndex).trim());
184167
}
185168

186-
private static boolean shouldSkipCompletion(String completedRegion, String activeCommand, boolean skipCompletion) {
187-
if (!skipCompletion) {
188-
return false;
189-
}
190-
String normalizedCommand = normalizeLineEndings(activeCommand == null ? "" : activeCommand).trim();
191-
if (normalizedCommand.isBlank()) {
192-
return true;
193-
}
194-
return !normalizeLineEndings(completedRegion).contains(normalizedCommand);
195-
}
196-
197169
private static String removeBracketedPasteMarkers(String output) {
198170
return output.replace(BRACKETED_PASTE_START, "").replace(BRACKETED_PASTE_END, "");
199171
}
@@ -217,10 +189,6 @@ private static String removeTrailingLineEndings(String value) {
217189
return value.substring(0, endIndex);
218190
}
219191

220-
private static MarkerRange findCommandFinishMarker(StringBuilder output) {
221-
return findMarker(output, COMMAND_FINISH_MARKER_PATTERN, 0);
222-
}
223-
224192
private static MarkerRange findMarker(StringBuilder output, Pattern markerPattern, int startIndex) {
225193
Matcher matcher = markerPattern.matcher(output);
226194
if (!matcher.find(startIndex)) {
@@ -248,18 +216,10 @@ private static Pattern buildMarkerPattern(String markerKind, boolean includeExit
248216
+ exitCodePattern + "(?:\u0007|\u001B\\\\)?");
249217
}
250218

251-
private static String cleanCommandOutput(String output, String activeCommand) {
219+
private static String cleanCommandOutput(String output) {
252220
String normalizedOutput = normalizeLineEndings(output);
253221
normalizedOutput = removeShellIntegrationMarkers(normalizedOutput);
254222
normalizedOutput = removeBracketedPasteMarkers(normalizedOutput);
255-
String normalizedCommand = normalizeLineEndings(activeCommand == null ? "" : activeCommand).trim();
256-
if (normalizedCommand.isBlank()) {
257-
return normalizedOutput.trim();
258-
}
259-
int commandIndex = normalizedOutput.lastIndexOf(normalizedCommand);
260-
if (commandIndex >= 0) {
261-
normalizedOutput = normalizedOutput.substring(commandIndex + normalizedCommand.length());
262-
}
263223
return normalizedOutput.trim();
264224
}
265225

@@ -294,10 +254,6 @@ private static CompletionCheckResult incomplete() {
294254
return new CompletionCheckResult(CompletionCheckState.INCOMPLETE, "");
295255
}
296256

297-
private static CompletionCheckResult skipped() {
298-
return new CompletionCheckResult(CompletionCheckState.SKIPPED, "");
299-
}
300-
301257
private static CompletionCheckResult completed(String output) {
302258
return new CompletionCheckResult(CompletionCheckState.COMPLETED, output);
303259
}
@@ -308,7 +264,6 @@ private static CompletionCheckResult completed(String output) {
308264
*/
309265
public enum CompletionCheckState {
310266
INCOMPLETE,
311-
SKIPPED,
312267
COMPLETED
313268
}
314-
}
269+
}

com.microsoft.copilot.eclipse.ui.terminal.tm/src/com/microsoft/copilot/eclipse/ui/terminal/tm/RunInTerminalTool.java

Lines changed: 29 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,6 @@ public class RunInTerminalTool implements IRunInTerminalTool {
5151
private static final Map<String, StringBuilder> backgroundCommandOutputs = new HashMap<>();
5252
private static final String BACKGROUND_TERMINAL_PREFIX = "Copilot-";
5353
private static final String POWERSHELL_SCRIPT_ENV = "COPILOT_POWERSHELL_INTEGRATION_SCRIPT";
54-
private static final char INTERRUPT_CHARACTER = '\u0003';
5554
private static final String COMMAND_CANCELLED_MESSAGE = "Terminal command cancelled.";
5655
private static final String COMMAND_INTERRUPTED_MESSAGE = "Terminal command interrupted by a new command.";
5756

@@ -68,7 +67,6 @@ public class RunInTerminalTool implements IRunInTerminalTool {
6867
// Output and command state
6968
private StringBuilder sb;
7069
private volatile ForegroundCommand foregroundCommand;
71-
private volatile boolean skipNextCompletionAfterInterrupt;
7270

7371
/**
7472
* Constructor for RunInTerminalTool.
@@ -84,14 +82,12 @@ public CompletableFuture<String> executeCommand(String command, boolean isBackgr
8482
}
8583

8684
if (!isBackground) {
87-
// A new foreground command immediately installs a new future after Ctrl+C, so the interrupted command's
88-
// next prompt-completion marker must be skipped if it arrives after the new command starts listening.
89-
interruptCurrentCommand(COMMAND_INTERRUPTED_MESSAGE, true);
85+
closeRunningForegroundTerminal(COMMAND_INTERRUPTED_MESSAGE);
9086
}
9187

9288
CompletableFuture<String> commandFuture = new CompletableFuture<>();
9389
ForegroundCommand commandState = isBackground ? null
94-
: new ForegroundCommand(commandFuture, command, hasShellIntegrationMarker());
90+
: new ForegroundCommand(commandFuture, hasShellIntegrationMarker());
9591

9692
if (commandState != null) {
9793
foregroundCommand = commandState;
@@ -217,56 +213,48 @@ public StringBuilder getBackgroundCommandOutput(String executionId) {
217213

218214
@Override
219215
public void cancelCurrentCommand() {
220-
// User cancel completes the current future without starting a replacement command. Do not reserve a skip here,
221-
// otherwise a later command could incorrectly skip its own completion if the interrupted prompt was already idle.
222-
interruptCurrentCommand(COMMAND_CANCELLED_MESSAGE, false);
216+
closeRunningForegroundTerminal(COMMAND_CANCELLED_MESSAGE);
223217
}
224218

225-
private void interruptCurrentCommand(String completionMessage, boolean skipInterruptedCompletion) {
226-
ITerminalViewControl terminalViewControl = null;
219+
private void closeRunningForegroundTerminal(String completionMessage) {
220+
ForegroundCommand commandState = foregroundCommand;
221+
if (commandState != null && !commandState.future().isDone()) {
222+
closeCurrentForegroundTerminal(completionMessage);
223+
}
224+
}
225+
226+
private void closeCurrentForegroundTerminal(String completionMessage) {
227227
ForegroundCommand commandState = null;
228+
CTabItem tabItem = null;
228229
synchronized (lock) {
229-
if (!hasRunningForegroundCommand()) {
230-
if (!skipInterruptedCompletion) {
231-
skipNextCompletionAfterInterrupt = false;
232-
}
233-
return;
234-
}
235230
commandState = foregroundCommand;
236231
foregroundCommand = null;
237-
skipNextCompletionAfterInterrupt = skipInterruptedCompletion;
238-
terminalViewControl = persistentTerminalViewControl;
232+
persistentTerminalViewControl = null;
233+
tabItem = copilotTabItem;
234+
copilotTabItem = null;
235+
sb.setLength(0);
239236
}
240237

241-
if (terminalViewControl != null) {
242-
sendInterrupt(terminalViewControl);
238+
if (tabItem != null) {
239+
final CTabItem tabItemToDispose = tabItem;
240+
// Keep this synchronous so a new foreground command cannot open before the old terminal tab is disposed.
241+
Display.getDefault().syncExec(() -> {
242+
if (!tabItemToDispose.isDisposed()) {
243+
tabItemToDispose.dispose();
244+
}
245+
});
243246
}
244247
if (commandState != null && !commandState.future().isDone()) {
245248
commandState.future().complete(completionMessage);
246249
}
247250
}
248251

249-
private boolean hasRunningForegroundCommand() {
250-
ForegroundCommand commandState = foregroundCommand;
251-
return commandState != null && !commandState.future().isDone();
252-
}
253-
254252
private void clearForegroundCommand(ForegroundCommand commandState) {
255253
if (commandState != null && foregroundCommand == commandState) {
256254
foregroundCommand = null;
257255
}
258256
}
259257

260-
private void sendInterrupt(ITerminalViewControl terminalViewControl) {
261-
Display display = terminalViewControl.getControl().getDisplay();
262-
// Ctrl+C must be delivered before the next foreground command is pasted into the reused terminal.
263-
display.syncExec(() -> {
264-
if (!terminalViewControl.isDisposed()) {
265-
terminalViewControl.sendKey(INTERRUPT_CHARACTER);
266-
}
267-
});
268-
}
269-
270258
private void sendCommand(ITerminalViewControl terminalViewControl, String command) {
271259
terminalViewControl.pasteString(command);
272260
}
@@ -363,16 +351,10 @@ private ITerminalServiceOutputStreamMonitorListener buildOutputStreamMonitorList
363351
// Detect completion based on platform strategy
364352
ForegroundCommand commandState = foregroundCommand;
365353
if (!isBackground && commandState != null && !commandState.future().isDone()) {
366-
CompletionCheckResult completionResult;
367-
do {
368-
completionResult = commandState.useMarker()
369-
? TerminalCommandProcessor.tryCompleteWithMarker(output, commandState.command(),
370-
skipNextCompletionAfterInterrupt)
371-
: TerminalCommandProcessor.tryCompleteWithPrompt(output, commandState.command(),
372-
skipNextCompletionAfterInterrupt);
373-
handleCompletionResult(commandState, completionResult);
374-
} while (completionResult.state() == CompletionCheckState.SKIPPED
375-
&& foregroundCommand == commandState && !commandState.future().isDone());
354+
CompletionCheckResult completionResult = commandState.useMarker()
355+
? TerminalCommandProcessor.tryCompleteWithMarker(output)
356+
: TerminalCommandProcessor.tryCompleteWithPrompt(output);
357+
handleCompletionResult(commandState, completionResult);
376358
}
377359
};
378360
}
@@ -381,10 +363,6 @@ private void handleCompletionResult(ForegroundCommand commandState, CompletionCh
381363
if (completionResult.state() == CompletionCheckState.INCOMPLETE) {
382364
return;
383365
}
384-
if (completionResult.state() == CompletionCheckState.SKIPPED) {
385-
skipNextCompletionAfterInterrupt = false;
386-
return;
387-
}
388366
if (foregroundCommand == commandState) {
389367
foregroundCommand = null;
390368
}
@@ -436,7 +414,7 @@ private String buildBackgroundTerminalTitle(String executionId) {
436414
return BACKGROUND_TERMINAL_PREFIX + executionId;
437415
}
438416

439-
private record ForegroundCommand(CompletableFuture<String> future, String command, boolean useMarker) {
417+
private record ForegroundCommand(CompletableFuture<String> future, boolean useMarker) {
440418
}
441419

442420
/**

0 commit comments

Comments
 (0)