Skip to content

Commit 9dead72

Browse files
authored
Merge pull request #2456 from KJ7LNW/fix-misc-terminal-issues
Terminal improvements: command delay, PowerShell counter, and ZSH EOL mark
2 parents e70954f + ae0ab56 commit 9dead72

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

48 files changed

+1105
-46
lines changed

src/core/webview/ClineProvider.ts

Lines changed: 41 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -352,10 +352,29 @@ export class ClineProvider extends EventEmitter<ClineProviderEvents> implements
352352
}
353353

354354
// Initialize out-of-scope variables that need to recieve persistent global state values
355-
this.getState().then(({ soundEnabled, terminalShellIntegrationTimeout }) => {
356-
setSoundEnabled(soundEnabled ?? false)
357-
Terminal.setShellIntegrationTimeout(terminalShellIntegrationTimeout ?? TERMINAL_SHELL_INTEGRATION_TIMEOUT)
358-
})
355+
this.getState().then(
356+
({
357+
soundEnabled,
358+
terminalShellIntegrationTimeout,
359+
terminalCommandDelay,
360+
terminalZshClearEolMark,
361+
terminalZshOhMy,
362+
terminalZshP10k,
363+
terminalPowershellCounter,
364+
terminalZdotdir,
365+
}) => {
366+
setSoundEnabled(soundEnabled ?? false)
367+
Terminal.setShellIntegrationTimeout(
368+
terminalShellIntegrationTimeout ?? TERMINAL_SHELL_INTEGRATION_TIMEOUT,
369+
)
370+
Terminal.setCommandDelay(terminalCommandDelay ?? 0)
371+
Terminal.setTerminalZshClearEolMark(terminalZshClearEolMark ?? true)
372+
Terminal.setTerminalZshOhMy(terminalZshOhMy ?? false)
373+
Terminal.setTerminalZshP10k(terminalZshP10k ?? false)
374+
Terminal.setPowershellCounter(terminalPowershellCounter ?? false)
375+
Terminal.setTerminalZdotdir(terminalZdotdir ?? false)
376+
},
377+
)
359378

360379
// Initialize tts enabled state
361380
this.getState().then(({ ttsEnabled }) => {
@@ -1017,6 +1036,12 @@ export class ClineProvider extends EventEmitter<ClineProviderEvents> implements
10171036
writeDelayMs,
10181037
terminalOutputLineLimit,
10191038
terminalShellIntegrationTimeout,
1039+
terminalCommandDelay,
1040+
terminalPowershellCounter,
1041+
terminalZshClearEolMark,
1042+
terminalZshOhMy,
1043+
terminalZshP10k,
1044+
terminalZdotdir,
10201045
fuzzyMatchThreshold,
10211046
mcpEnabled,
10221047
enableMcpServerCreation,
@@ -1084,6 +1109,12 @@ export class ClineProvider extends EventEmitter<ClineProviderEvents> implements
10841109
writeDelayMs: writeDelayMs ?? 1000,
10851110
terminalOutputLineLimit: terminalOutputLineLimit ?? 500,
10861111
terminalShellIntegrationTimeout: terminalShellIntegrationTimeout ?? TERMINAL_SHELL_INTEGRATION_TIMEOUT,
1112+
terminalCommandDelay: terminalCommandDelay ?? 0,
1113+
terminalPowershellCounter: terminalPowershellCounter ?? false,
1114+
terminalZshClearEolMark: terminalZshClearEolMark ?? true,
1115+
terminalZshOhMy: terminalZshOhMy ?? false,
1116+
terminalZshP10k: terminalZshP10k ?? false,
1117+
terminalZdotdir: terminalZdotdir ?? false,
10871118
fuzzyMatchThreshold: fuzzyMatchThreshold ?? 1.0,
10881119
mcpEnabled: mcpEnabled ?? true,
10891120
enableMcpServerCreation: enableMcpServerCreation ?? true,
@@ -1170,6 +1201,12 @@ export class ClineProvider extends EventEmitter<ClineProviderEvents> implements
11701201
terminalOutputLineLimit: stateValues.terminalOutputLineLimit ?? 500,
11711202
terminalShellIntegrationTimeout:
11721203
stateValues.terminalShellIntegrationTimeout ?? TERMINAL_SHELL_INTEGRATION_TIMEOUT,
1204+
terminalCommandDelay: stateValues.terminalCommandDelay ?? 0,
1205+
terminalPowershellCounter: stateValues.terminalPowershellCounter ?? false,
1206+
terminalZshClearEolMark: stateValues.terminalZshClearEolMark ?? true,
1207+
terminalZshOhMy: stateValues.terminalZshOhMy ?? false,
1208+
terminalZshP10k: stateValues.terminalZshP10k ?? false,
1209+
terminalZdotdir: stateValues.terminalZdotdir ?? false,
11731210
mode: stateValues.mode ?? defaultModeSlug,
11741211
language: stateValues.language ?? formatLanguage(vscode.env.language),
11751212
mcpEnabled: stateValues.mcpEnabled ?? true,

src/core/webview/webviewMessageHandler.ts

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -736,6 +736,48 @@ export const webviewMessageHandler = async (provider: ClineProvider, message: We
736736
Terminal.setShellIntegrationTimeout(message.value)
737737
}
738738
break
739+
case "terminalCommandDelay":
740+
await updateGlobalState("terminalCommandDelay", message.value)
741+
await provider.postStateToWebview()
742+
if (message.value !== undefined) {
743+
Terminal.setCommandDelay(message.value)
744+
}
745+
break
746+
case "terminalPowershellCounter":
747+
await updateGlobalState("terminalPowershellCounter", message.bool)
748+
await provider.postStateToWebview()
749+
if (message.bool !== undefined) {
750+
Terminal.setPowershellCounter(message.bool)
751+
}
752+
break
753+
case "terminalZshClearEolMark":
754+
await updateGlobalState("terminalZshClearEolMark", message.bool)
755+
await provider.postStateToWebview()
756+
if (message.bool !== undefined) {
757+
Terminal.setTerminalZshClearEolMark(message.bool)
758+
}
759+
break
760+
case "terminalZshOhMy":
761+
await updateGlobalState("terminalZshOhMy", message.bool)
762+
await provider.postStateToWebview()
763+
if (message.bool !== undefined) {
764+
Terminal.setTerminalZshOhMy(message.bool)
765+
}
766+
break
767+
case "terminalZshP10k":
768+
await updateGlobalState("terminalZshP10k", message.bool)
769+
await provider.postStateToWebview()
770+
if (message.bool !== undefined) {
771+
Terminal.setTerminalZshP10k(message.bool)
772+
}
773+
break
774+
case "terminalZdotdir":
775+
await updateGlobalState("terminalZdotdir", message.bool)
776+
await provider.postStateToWebview()
777+
if (message.bool !== undefined) {
778+
Terminal.setTerminalZdotdir(message.bool)
779+
}
780+
break
739781
case "mode":
740782
await provider.handleModeSwitch(message.text as Mode)
741783
break

src/exports/roo-code.d.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -266,6 +266,12 @@ type GlobalSettings = {
266266
maxReadFileLine?: number | undefined
267267
terminalOutputLineLimit?: number | undefined
268268
terminalShellIntegrationTimeout?: number | undefined
269+
terminalCommandDelay?: number | undefined
270+
terminalPowershellCounter?: boolean | undefined
271+
terminalZshClearEolMark?: boolean | undefined
272+
terminalZshOhMy?: boolean | undefined
273+
terminalZshP10k?: boolean | undefined
274+
terminalZdotdir?: boolean | undefined
269275
rateLimitSeconds?: number | undefined
270276
diffEnabled?: boolean | undefined
271277
fuzzyMatchThreshold?: number | undefined

src/exports/types.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -269,6 +269,12 @@ type GlobalSettings = {
269269
maxReadFileLine?: number | undefined
270270
terminalOutputLineLimit?: number | undefined
271271
terminalShellIntegrationTimeout?: number | undefined
272+
terminalCommandDelay?: number | undefined
273+
terminalPowershellCounter?: boolean | undefined
274+
terminalZshClearEolMark?: boolean | undefined
275+
terminalZshOhMy?: boolean | undefined
276+
terminalZshP10k?: boolean | undefined
277+
terminalZdotdir?: boolean | undefined
272278
rateLimitSeconds?: number | undefined
273279
diffEnabled?: boolean | undefined
274280
fuzzyMatchThreshold?: number | undefined

src/integrations/terminal/Terminal.ts

Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,19 @@ import * as vscode from "vscode"
22
import pWaitFor from "p-wait-for"
33
import { ExitCodeDetails, mergePromise, TerminalProcess, TerminalProcessResultPromise } from "./TerminalProcess"
44
import { truncateOutput, applyRunLengthEncoding } from "../misc/extract-text"
5+
// Import TerminalRegistry here to avoid circular dependencies
6+
const { TerminalRegistry } = require("./TerminalRegistry")
57

68
export const TERMINAL_SHELL_INTEGRATION_TIMEOUT = 5000
79

810
export class Terminal {
911
private static shellIntegrationTimeout: number = TERMINAL_SHELL_INTEGRATION_TIMEOUT
12+
private static commandDelay: number = 0
13+
private static powershellCounter: boolean = false
14+
private static terminalZshClearEolMark: boolean = true
15+
private static terminalZshOhMy: boolean = false
16+
private static terminalZshP10k: boolean = false
17+
private static terminalZdotdir: boolean = false
1018

1119
public terminal: vscode.Terminal
1220
public busy: boolean
@@ -180,10 +188,16 @@ export class Terminal {
180188
// Wait for shell integration before executing the command
181189
pWaitFor(() => this.terminal.shellIntegration !== undefined, { timeout: Terminal.shellIntegrationTimeout })
182190
.then(() => {
191+
// Clean up temporary directory if shell integration is available, zsh did its job:
192+
TerminalRegistry.zshCleanupTmpDir(this.id)
193+
194+
// Run the command in the terminal
183195
process.run(command)
184196
})
185197
.catch(() => {
186198
console.log(`[Terminal ${this.id}] Shell integration not available. Command execution aborted.`)
199+
// Clean up temporary directory if shell integration is not available
200+
TerminalRegistry.zshCleanupTmpDir(this.id)
187201
process.emit(
188202
"no_shell_integration",
189203
`Shell integration initialization sequence '\\x1b]633;A' was not received within ${Terminal.shellIntegrationTimeout / 1000}s. Shell integration has been disabled for this terminal instance. Increase the timeout in the settings if necessary.`,
@@ -256,7 +270,107 @@ export class Terminal {
256270
Terminal.shellIntegrationTimeout = timeoutMs
257271
}
258272

273+
public static getShellIntegrationTimeout(): number {
274+
return Terminal.shellIntegrationTimeout
275+
}
276+
277+
/**
278+
* Sets the command delay in milliseconds
279+
* @param delayMs The delay in milliseconds
280+
*/
281+
public static setCommandDelay(delayMs: number): void {
282+
Terminal.commandDelay = delayMs
283+
}
284+
285+
/**
286+
* Gets the command delay in milliseconds
287+
* @returns The command delay in milliseconds
288+
*/
289+
public static getCommandDelay(): number {
290+
return Terminal.commandDelay
291+
}
292+
293+
/**
294+
* Sets whether to use the PowerShell counter workaround
295+
* @param enabled Whether to enable the PowerShell counter workaround
296+
*/
297+
public static setPowershellCounter(enabled: boolean): void {
298+
Terminal.powershellCounter = enabled
299+
}
300+
301+
/**
302+
* Gets whether to use the PowerShell counter workaround
303+
* @returns Whether the PowerShell counter workaround is enabled
304+
*/
305+
public static getPowershellCounter(): boolean {
306+
return Terminal.powershellCounter
307+
}
308+
309+
/**
310+
* Sets whether to clear the ZSH EOL mark
311+
* @param enabled Whether to clear the ZSH EOL mark
312+
*/
313+
public static setTerminalZshClearEolMark(enabled: boolean): void {
314+
Terminal.terminalZshClearEolMark = enabled
315+
}
316+
317+
/**
318+
* Gets whether to clear the ZSH EOL mark
319+
* @returns Whether the ZSH EOL mark clearing is enabled
320+
*/
321+
public static getTerminalZshClearEolMark(): boolean {
322+
return Terminal.terminalZshClearEolMark
323+
}
324+
325+
/**
326+
* Sets whether to enable Oh My Zsh shell integration
327+
* @param enabled Whether to enable Oh My Zsh shell integration
328+
*/
329+
public static setTerminalZshOhMy(enabled: boolean): void {
330+
Terminal.terminalZshOhMy = enabled
331+
}
332+
333+
/**
334+
* Gets whether Oh My Zsh shell integration is enabled
335+
* @returns Whether Oh My Zsh shell integration is enabled
336+
*/
337+
public static getTerminalZshOhMy(): boolean {
338+
return Terminal.terminalZshOhMy
339+
}
340+
341+
/**
342+
* Sets whether to enable Powerlevel10k shell integration
343+
* @param enabled Whether to enable Powerlevel10k shell integration
344+
*/
345+
public static setTerminalZshP10k(enabled: boolean): void {
346+
Terminal.terminalZshP10k = enabled
347+
}
348+
349+
/**
350+
* Gets whether Powerlevel10k shell integration is enabled
351+
* @returns Whether Powerlevel10k shell integration is enabled
352+
*/
353+
public static getTerminalZshP10k(): boolean {
354+
return Terminal.terminalZshP10k
355+
}
356+
259357
public static compressTerminalOutput(input: string, lineLimit: number): string {
260358
return truncateOutput(applyRunLengthEncoding(input), lineLimit)
261359
}
360+
361+
/**
362+
* Sets whether to enable ZDOTDIR handling for zsh
363+
* @param enabled Whether to enable ZDOTDIR handling
364+
*/
365+
public static setTerminalZdotdir(enabled: boolean): void {
366+
Terminal.terminalZdotdir = enabled
367+
}
368+
369+
/**
370+
* Gets whether ZDOTDIR handling is enabled
371+
* @returns Whether ZDOTDIR handling is enabled
372+
*/
373+
public static getTerminalZdotdir(): boolean {
374+
return Terminal.terminalZdotdir
375+
}
262376
}

src/integrations/terminal/TerminalProcess.ts

Lines changed: 24 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,6 @@ export interface ExitCodeDetails {
9595
coreDumpPossible?: boolean
9696
}
9797
import { Terminal } from "./Terminal"
98-
import { TerminalRegistry } from "./TerminalRegistry"
9998

10099
export interface TerminalProcessEvents {
101100
line: [line: string]
@@ -140,7 +139,10 @@ export class TerminalProcess extends EventEmitter<TerminalProcessEvents> {
140139
this.once("no_shell_integration", () => {
141140
if (this.terminalInfo) {
142141
console.log(`no_shell_integration received for terminal ${this.terminalInfo.id}`)
143-
TerminalRegistry.removeTerminal(this.terminalInfo.id)
142+
this.emit("completed", "<no shell integration>")
143+
this.terminalInfo.busy = false
144+
this.terminalInfo.setActiveStream(undefined)
145+
this.continue()
144146
}
145147
})
146148
}
@@ -254,12 +256,16 @@ export class TerminalProcess extends EventEmitter<TerminalProcessEvents> {
254256
// Emit no_shell_integration event with descriptive message
255257
this.emit(
256258
"no_shell_integration",
257-
"VSCE shell integration stream did not start within 3 seconds. Terminal problem?",
259+
`VSCE shell integration stream did not start within ${Terminal.getShellIntegrationTimeout() / 1000} seconds. Terminal problem?`,
258260
)
259261

260262
// Reject with descriptive error
261-
reject(new Error("VSCE shell integration stream did not start within 3 seconds."))
262-
}, 3000)
263+
reject(
264+
new Error(
265+
`VSCE shell integration stream did not start within ${Terminal.getShellIntegrationTimeout() / 1000} seconds.`,
266+
),
267+
)
268+
}, Terminal.getShellIntegrationTimeout())
263269

264270
// Clean up timeout if stream becomes available
265271
this.once("stream_available", (stream: AsyncIterable<string>) => {
@@ -284,9 +290,19 @@ export class TerminalProcess extends EventEmitter<TerminalProcessEvents> {
284290
(defaultWindowsShellProfile === null ||
285291
(defaultWindowsShellProfile as string)?.toLowerCase().includes("powershell"))
286292
if (isPowerShell) {
287-
terminal.shellIntegration.executeCommand(
288-
`${command} ; "(Roo/PS Workaround: ${this.terminalInfo.cmdCounter++})" > $null; start-sleep -milliseconds 150`,
289-
)
293+
let commandToExecute = command
294+
295+
// Only add the PowerShell counter workaround if enabled
296+
if (Terminal.getPowershellCounter()) {
297+
commandToExecute += ` ; "(Roo/PS Workaround: ${this.terminalInfo.cmdCounter++})" > $null`
298+
}
299+
300+
// Only add the sleep command if the command delay is greater than 0
301+
if (Terminal.getCommandDelay() > 0) {
302+
commandToExecute += ` ; start-sleep -milliseconds ${Terminal.getCommandDelay()}`
303+
}
304+
305+
terminal.shellIntegration.executeCommand(commandToExecute)
290306
} else {
291307
terminal.shellIntegration.executeCommand(command)
292308
}

0 commit comments

Comments
 (0)