diff --git a/extensions/vscode-api-tests/testWorkspace2/.vscode/settings.json b/extensions/vscode-api-tests/testWorkspace2/.vscode/settings.json deleted file mode 100644 index bcb312b4a28c4..0000000000000 --- a/extensions/vscode-api-tests/testWorkspace2/.vscode/settings.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "editor.minimap.enabled": false, // see https://github.com/microsoft/vscode/issues/115747 - "workbench.editor.languageDetection": false, - "typescript.disableAutomaticTypeAcquisition": true, - "json.schemaDownload.enable": false, - "npm.fetchOnlinePackageInfo": false, - "npm.autoDetect": "off", - "workbench.localHistory.enabled": false -} diff --git a/src/vs/platform/utilityProcess/electron-main/utilityProcess.ts b/src/vs/platform/utilityProcess/electron-main/utilityProcess.ts index e2f88fbf8c0f7..51514a1b9d593 100644 --- a/src/vs/platform/utilityProcess/electron-main/utilityProcess.ts +++ b/src/vs/platform/utilityProcess/electron-main/utilityProcess.ts @@ -234,7 +234,6 @@ export class UtilityProcess extends Disposable { const args = this.configuration.args ?? []; const execArgv = this.configuration.execArgv ?? []; const allowLoadingUnsignedLibraries = this.configuration.allowLoadingUnsignedLibraries; - const respondToAuthRequestsFromMainProcess = this.configuration.respondToAuthRequestsFromMainProcess; const stdio = 'pipe'; const env = this.createEnv(configuration); @@ -246,7 +245,6 @@ export class UtilityProcess extends Disposable { env, execArgv, allowLoadingUnsignedLibraries, - respondToAuthRequestsFromMainProcess, stdio }); diff --git a/src/vs/workbench/contrib/accessibility/browser/accessibilityConfiguration.ts b/src/vs/workbench/contrib/accessibility/browser/accessibilityConfiguration.ts index 9e64c7226d728..7709e2cec6800 100644 --- a/src/vs/workbench/contrib/accessibility/browser/accessibilityConfiguration.ts +++ b/src/vs/workbench/contrib/accessibility/browser/accessibilityConfiguration.ts @@ -789,6 +789,12 @@ export class DynamicSpeechAccessibilityConfiguration extends Disposable implemen 'minimum': 0, 'tags': ['accessibility'] }, + [AccessibilityVoiceSettingId.IgnoreCodeBlocks]: { + 'markdownDescription': localize('voice.ignoreCodeBlocks', "Whether to ignore code snippets from the text to speech in copilot chat."), + 'type': 'boolean', + 'default': true, + 'tags': ['accessibility'] + }, [AccessibilityVoiceSettingId.SpeechLanguage]: { 'markdownDescription': localize('voice.speechLanguage', "The language that text-to-speech and speech-to-text should use. Select `auto` to use the configured display language if possible. Note that not all display languages maybe supported by speech recognition and synthesizers."), 'type': 'string', @@ -804,7 +810,7 @@ export class DynamicSpeechAccessibilityConfiguration extends Disposable implemen 'enumDescriptions': [ localize('accessibility.voice.autoSynthesize.on', "Enable the feature. When a screen reader is enabled, note that this will disable aria updates."), localize('accessibility.voice.autoSynthesize.off', "Disable the feature."), - localize('accessibility.voice.autoSynthesize.auto', "When a screen reader is detected, disable the feature. Otherwise, enable the feature.") + localize('accessibility.voice.autoSynthesize.auto', "When a screen reader is detected, disable the feature. Otherwise, enable the feature."), ], 'markdownDescription': localize('autoSynthesize', "Whether a textual response should automatically be read out aloud when speech was used as input. For example in a chat session, a response is automatically synthesized when voice was used as chat request."), 'default': this.productService.quality !== 'stable' ? 'auto' : 'off', // TODO@bpasero decide on a default diff --git a/src/vs/workbench/contrib/chat/common/chatModel.ts b/src/vs/workbench/contrib/chat/common/chatModel.ts index 14fa03dffa0f7..24f99b76d14bb 100644 --- a/src/vs/workbench/contrib/chat/common/chatModel.ts +++ b/src/vs/workbench/contrib/chat/common/chatModel.ts @@ -567,6 +567,18 @@ export class ChatResponseModel extends Disposable implements IChatResponseModel this.id = restoredId ?? 'response_' + generateUuid(); } + withoutCodeBlocks(): string { + const delimiter = '```'; + let filtered = this._response.toString(); + let start = filtered.indexOf(delimiter); + while (start >= 0) { + const end = filtered.indexOf(delimiter, start + delimiter.length); + filtered = filtered.slice(0, start) + filtered.slice(end + delimiter.length); + start = filtered.indexOf(delimiter); + } + return filtered; + } + /** * Apply a progress update to the actual response content. */ diff --git a/src/vs/workbench/contrib/chat/electron-sandbox/actions/voiceChatActions.ts b/src/vs/workbench/contrib/chat/electron-sandbox/actions/voiceChatActions.ts index 198a49bb8696b..b7eec4e444f08 100644 --- a/src/vs/workbench/contrib/chat/electron-sandbox/actions/voiceChatActions.ts +++ b/src/vs/workbench/contrib/chat/electron-sandbox/actions/voiceChatActions.ts @@ -722,7 +722,8 @@ class ChatSynthesizerSessions { constructor( @ISpeechService private readonly speechService: ISpeechService, - @IInstantiationService private readonly instantiationService: IInstantiationService + @IInstantiationService private readonly instantiationService: IInstantiationService, + @IConfigurationService private readonly configurationService: IConfigurationService ) { } async start(controller: IChatSynthesizerSessionController): Promise { @@ -770,11 +771,13 @@ class ChatSynthesizerSessions { private async *nextChatResponseChunk(response: IChatResponseModel, token: CancellationToken): AsyncIterable { let totalOffset = 0; let complete = false; + let isWithinCodeBlock = false; do { const responseLength = response.response.toString().length; - const { chunk, offset } = this.parseNextChatResponseChunk(response, totalOffset); + const { chunk, offset, codeBlockTerminated } = this.parseNextChatResponseChunk(response, totalOffset, isWithinCodeBlock); totalOffset = offset; complete = response.isComplete; + isWithinCodeBlock = !codeBlockTerminated; if (chunk) { yield chunk; @@ -790,10 +793,38 @@ class ChatSynthesizerSessions { } while (!token.isCancellationRequested && !complete); } - private parseNextChatResponseChunk(response: IChatResponseModel, offset: number): { readonly chunk: string | undefined; readonly offset: number } { - let chunk: string | undefined = undefined; + private withoutCodeBlocks(text: string): [string, boolean] { + const delimiter = '```'; + let start = text.indexOf(delimiter); + while (start >= 0) { + const end = text.indexOf(delimiter, start + delimiter.length); + if (end === -1) { + return [text.substring(0, start), false]; + } + text = text.slice(0, start) + text.slice(end + delimiter.length); + start = text.indexOf(delimiter); + } + return [text, true]; + } - const text = response.response.toString(); + private parseNextChatResponseChunk(response: IChatResponseModel, offset: number, isWithinCodeBlock = false): { readonly chunk: string | undefined; readonly offset: number; readonly codeBlockTerminated: boolean } { + let chunk: string | undefined = undefined; + const ignoreCodeBlocks = this.configurationService.getValue(AccessibilityVoiceSettingId.IgnoreCodeBlocks); + let text = response.response.toString(); + const delimiter = '```'; + let codeBlockTerminates = false; + const firstDelimiterIndex = text.indexOf(delimiter); + + if (ignoreCodeBlocks) { + if (isWithinCodeBlock && firstDelimiterIndex === -1) { + text = ''; + } else if (isWithinCodeBlock && firstDelimiterIndex >= 0) { + text = text.substring(firstDelimiterIndex + 1); + } + const [filteredText, terminated] = this.withoutCodeBlocks(text); + text = filteredText; + codeBlockTerminates = terminated; + } if (response.isComplete) { chunk = text.substring(offset); @@ -806,7 +837,8 @@ class ChatSynthesizerSessions { return { chunk: chunk ? renderStringAsPlaintext({ value: chunk }) : chunk, // convert markdown to plain text - offset + offset, + codeBlockTerminated: codeBlockTerminates }; } diff --git a/src/vs/workbench/contrib/speech/common/speechService.ts b/src/vs/workbench/contrib/speech/common/speechService.ts index 4df439533b5b0..03c9d1a305bd4 100644 --- a/src/vs/workbench/contrib/speech/common/speechService.ts +++ b/src/vs/workbench/contrib/speech/common/speechService.ts @@ -138,6 +138,7 @@ export const enum AccessibilityVoiceSettingId { SpeechTimeout = 'accessibility.voice.speechTimeout', AutoSynthesize = 'accessibility.voice.autoSynthesize', SpeechLanguage = 'accessibility.voice.speechLanguage', + IgnoreCodeBlocks = 'accessibility.voice.ignoreCodeBlocks' } export const SPEECH_LANGUAGE_CONFIG = AccessibilityVoiceSettingId.SpeechLanguage;