Skip to content

Commit

Permalink
Merge remote-tracking branch 'upstream/main'
Browse files Browse the repository at this point in the history
  • Loading branch information
dabreadman committed Oct 12, 2023
2 parents 63fc0c9 + 88fc434 commit d6e2a1d
Show file tree
Hide file tree
Showing 65 changed files with 1,527 additions and 311 deletions.
4 changes: 2 additions & 2 deletions build/lib/compilation.js

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion build/lib/compilation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -277,7 +277,7 @@ function generateApiProposalNames() {
eol = os.EOL;
}

const pattern = /vscode\.proposed\.([a-zA-Z]+)\.d\.ts$/;
const pattern = /vscode\.proposed\.([a-zA-Z\d]+)\.d\.ts$/;
const proposalNames = new Set<string>();

const input = es.through();
Expand Down
4 changes: 4 additions & 0 deletions build/lib/i18n.resources.json
Original file line number Diff line number Diff line change
Expand Up @@ -214,6 +214,10 @@
"name": "vs/workbench/contrib/tags",
"project": "vscode-workbench"
},
{
"name": "vs/workbench/contrib/speech",
"project": "vscode-workbench"
},
{
"name": "vs/workbench/contrib/surveys",
"project": "vscode-workbench"
Expand Down
8 changes: 7 additions & 1 deletion src/vs/code/electron-main/app.ts
Original file line number Diff line number Diff line change
Expand Up @@ -797,7 +797,13 @@ export class CodeApplication extends Disposable {
}

if (checkboxChecked) {
windowsMainService.sendToOpeningWindow('vscode:disablePromptForProtocolHandling', uri.authority === Schemas.file ? 'local' : 'remote');
// Due to https://github.com/microsoft/vscode/issues/195436, we can only
// update settings from within a window. But we do not know if a window
// is about to open or can already handle the request, so we have to send
// to any current window and any newly opening window.
const request = { channel: 'vscode:disablePromptForProtocolHandling', args: uri.authority === Schemas.file ? 'local' : 'remote' };
windowsMainService.sendToFocused(request.channel, request.args);
windowsMainService.sendToOpeningWindow(request.channel, request.args);
}

return false; // not blocked by user choice
Expand Down
7 changes: 6 additions & 1 deletion src/vs/editor/common/services/getIconClasses.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,13 @@ export function getIconClasses(modelService: IModelService, languageService: ILa
}
}

// Root Folders
if (fileKind === FileKind.ROOT_FOLDER) {
classes.push(`${name}-root-name-folder-icon`);
}

// Folders
if (fileKind === FileKind.FOLDER) {
else if (fileKind === FileKind.FOLDER) {
classes.push(`${name}-name-folder-icon`);
}

Expand Down
1 change: 1 addition & 0 deletions src/vs/platform/actions/common/actions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,7 @@ export class MenuId {
static readonly SCMResourceFolderContext = new MenuId('SCMResourceFolderContext');
static readonly SCMResourceGroupContext = new MenuId('SCMResourceGroupContext');
static readonly SCMSourceControl = new MenuId('SCMSourceControl');
static readonly SCMInputBox = new MenuId('SCMInputBox');
static readonly SCMTitle = new MenuId('SCMTitle');
static readonly SearchContext = new MenuId('SearchContext');
static readonly SearchActionMenu = new MenuId('SearchActionContext');
Expand Down
10 changes: 9 additions & 1 deletion src/vs/platform/quickinput/browser/quickInputController.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,8 @@ export class QuickInputController extends Disposable {
private previousFocusElement?: HTMLElement;

constructor(private options: IQuickInputOptions,
private readonly themeService: IThemeService) {
private readonly themeService: IThemeService,
private readonly layoutService: ILayoutService) {
super();
this.idPrefix = options.idPrefix;
this.parentElement = options.container;
Expand All @@ -72,6 +73,13 @@ export class QuickInputController extends Disposable {

private getUI() {
if (this.ui) {
// In order to support aux windows, re-parent the controller if the original event is
// from a different document
if (this.parentElement.ownerDocument !== this.layoutService.activeContainer.ownerDocument) {
this.parentElement = this.layoutService.activeContainer;
dom.append(this.parentElement, this.ui.container);
}

return this.ui;
}

Expand Down
3 changes: 2 additions & 1 deletion src/vs/platform/quickinput/browser/quickInputService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,8 @@ export class QuickInputService extends Themable implements IQuickInputService {
...defaultOptions,
...options
},
this.themeService));
this.themeService,
this.layoutService));

controller.layout(host.dimension, host.offset.quickPickTop);

Expand Down
3 changes: 2 additions & 1 deletion src/vs/platform/quickinput/test/browser/quickinput.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,8 @@ suite('QuickInput', () => { // https://github.com/microsoft/vscode/issues/147543
}
}
},
new TestThemeService()));
new TestThemeService(),
{ activeContainer: fixture } as any));

// initial layout
controller.layout({ height: 20, width: 40 }, 0);
Expand Down
8 changes: 7 additions & 1 deletion src/vs/platform/windows/electron-main/windowsMainService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1129,7 +1129,13 @@ export class WindowsMainService extends Disposable implements IWindowsMainServic
addUNCHostToAllowlist(uri.authority);

if (checkboxChecked) {
this.sendToOpeningWindow('vscode:configureAllowedUNCHost', uri.authority);
// Due to https://github.com/microsoft/vscode/issues/195436, we can only
// update settings from within a window. But we do not know if a window
// is about to open or can already handle the request, so we have to send
// to any current window and any newly opening window.
const request = { channel: 'vscode:configureAllowedUNCHost', args: uri.authority };
this.sendToFocused(request.channel, request.args);
this.sendToOpeningWindow(request.channel, request.args);
}

return this.doResolveFilePath(path, options, true /* do not handle UNC error again */);
Expand Down
2 changes: 2 additions & 0 deletions src/vs/workbench/api/browser/extensionHost.contribution.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import './mainThreadLocalization';
import './mainThreadBulkEdits';
import './mainThreadChatProvider';
import './mainThreadChatAgents';
import './mainThreadChatAgents2';
import './mainThreadChatVariables';
import './mainThreadCodeInsets';
import './mainThreadCLICommands';
Expand Down Expand Up @@ -53,6 +54,7 @@ import './mainThreadQuickDiff';
import './mainThreadQuickOpen';
import './mainThreadRemoteConnectionData';
import './mainThreadSaveParticipant';
import './mainThreadSpeech';
import './mainThreadEditSessionIdentityParticipant';
import './mainThreadSCM';
import './mainThreadSearch';
Expand Down
3 changes: 3 additions & 0 deletions src/vs/workbench/api/browser/mainThreadChat.ts
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,9 @@ export class MainThreadChat extends Disposable implements MainThreadChatShape {
provideWelcomeMessage: (token) => {
return this._proxy.$provideWelcomeMessage(handle, token);
},
provideSampleQuestions: (token) => {
return this._proxy.$provideSampleQuestions(handle, token);
},
provideSlashCommands: (session, token) => {
return this._proxy.$provideSlashCommands(handle, session.id, token);
},
Expand Down
49 changes: 29 additions & 20 deletions src/vs/workbench/api/browser/mainThreadChatAgents.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@ import { DisposableMap } from 'vs/base/common/lifecycle';
import { revive } from 'vs/base/common/marshalling';
import { IProgress } from 'vs/platform/progress/common/progress';
import { ExtHostChatAgentsShape, ExtHostContext, MainContext, MainThreadChatAgentsShape } from 'vs/workbench/api/common/extHost.protocol';
import { IChatAgentMetadata, IChatAgentService } from 'vs/workbench/contrib/chat/common/chatAgents';
import { IChatAgentCommand, IChatAgentMetadata, IChatAgentService } from 'vs/workbench/contrib/chat/common/chatAgents';
import { IChatProgress } from 'vs/workbench/contrib/chat/common/chatService';
import { IChatSlashFragment } from 'vs/workbench/contrib/chat/common/chatSlashCommands';
import { IExtHostContext, extHostNamedCustomer } from 'vs/workbench/services/extensions/common/extHostCustomers';

Expand All @@ -16,7 +17,7 @@ import { IExtHostContext, extHostNamedCustomer } from 'vs/workbench/services/ext
export class MainThreadChatAgents implements MainThreadChatAgentsShape {

private readonly _agents = new DisposableMap<number>;
private readonly _pendingProgress = new Map<number, IProgress<IChatSlashFragment>>();
private readonly _pendingProgress = new Map<number, IProgress<IChatProgress>>();
private readonly _proxy: ExtHostChatAgentsShape;

constructor(
Expand All @@ -34,29 +35,37 @@ export class MainThreadChatAgents implements MainThreadChatAgentsShape {
this._agents.clearAndDisposeAll();
}

$registerAgent(handle: number, name: string, metadata: IChatAgentMetadata): void {
if (!this._chatAgentService.hasAgent(name)) {
// dynamic!
this._chatAgentService.registerAgentData({
id: name,
metadata: revive(metadata)
});
}

const d = this._chatAgentService.registerAgentCallback(name, async (prompt, progress, history, token) => {
const requestId = Math.random();
this._pendingProgress.set(requestId, progress);
try {
return await this._proxy.$invokeAgent(handle, requestId, prompt, { history }, token);
} finally {
this._pendingProgress.delete(requestId);
}
$registerAgent(handle: number, name: string, metadata: IChatAgentMetadata & { subCommands: IChatAgentCommand[] }): void {
const d = this._chatAgentService.registerAgent({
id: name,
metadata: revive(metadata),
invoke: async (request, progress, history, token) => {
const requestId = Math.random();
this._pendingProgress.set(requestId, progress);
try {
const result = await this._proxy.$invokeAgent(handle, requestId, request.message, { history }, token);
return {
followUp: result?.followUp ?? [],
};
} finally {
this._pendingProgress.delete(requestId);
}
},
async provideSlashCommands() {
return metadata.subCommands;
},
});
this._agents.set(handle, d);
}

async $handleProgressChunk(requestId: number, chunk: IChatSlashFragment): Promise<void> {
this._pendingProgress.get(requestId)?.report(revive(chunk));
// An extra step because TS really struggles with type inference in the Revived generic parameter?
const revived = revive<IChatSlashFragment>(chunk);
if (typeof revived.content === 'string') {
this._pendingProgress.get(requestId)?.report({ content: revived.content });
} else {
this._pendingProgress.get(requestId)?.report(revived.content);
}
}

$unregisterCommand(handle: number): void {
Expand Down
80 changes: 80 additions & 0 deletions src/vs/workbench/api/browser/mainThreadChatAgents2.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/

import { DisposableMap, IDisposable } from 'vs/base/common/lifecycle';
import { revive } from 'vs/base/common/marshalling';
import { IProgress } from 'vs/platform/progress/common/progress';
import { ExtHostChatAgentsShape2, ExtHostContext, IChatResponseProgressDto, IExtensionChatAgentMetadata, MainContext, MainThreadChatAgentsShape2 } from 'vs/workbench/api/common/extHost.protocol';
import { IChatAgentService } from 'vs/workbench/contrib/chat/common/chatAgents';
import { IChatProgress } from 'vs/workbench/contrib/chat/common/chatService';
import { IExtHostContext, extHostNamedCustomer } from 'vs/workbench/services/extensions/common/extHostCustomers';


type AgentData = {
dispose: () => void;
name: string;
hasSlashCommands?: boolean;
hasFollowups?: boolean;
};

@extHostNamedCustomer(MainContext.MainThreadChatAgents2)
export class MainThreadChatAgents implements MainThreadChatAgentsShape2, IDisposable {

private readonly _agents = new DisposableMap<number, AgentData>;
private readonly _pendingProgress = new Map<number, IProgress<IChatProgress>>();
private readonly _proxy: ExtHostChatAgentsShape2;

constructor(
extHostContext: IExtHostContext,
@IChatAgentService private readonly _chatAgentService: IChatAgentService
) {
this._proxy = extHostContext.getProxy(ExtHostContext.ExtHostChatAgents2);
}

$unregisterAgent(handle: number): void {
this._agents.deleteAndDispose(handle);
}

dispose(): void {
this._agents.clearAndDisposeAll();
}

$registerAgent(handle: number, name: string, metadata: IExtensionChatAgentMetadata): void {
const d = this._chatAgentService.registerAgent({
id: name,
metadata: revive(metadata),
invoke: async (request, progress, history, token) => {
const requestId = Math.random(); // Make this a guid
this._pendingProgress.set(requestId, progress);
try {
return await this._proxy.$invokeAgent(handle, requestId, request, { history }, token) ?? {};
} finally {
this._pendingProgress.delete(requestId);
}
},
provideSlashCommands: async (token) => {
if (!this._agents.get(handle)?.hasSlashCommands) {
return []; // safe an IPC call
}
return this._proxy.$provideSlashCommands(handle, token);
}
});
this._agents.set(handle, { name, dispose: d.dispose, hasSlashCommands: metadata.hasSlashCommands });
}

$updateAgent(handle: number, metadataUpdate: IExtensionChatAgentMetadata): void {
const data = this._agents.get(handle);
if (!data) {
throw new Error(`No agent with handle ${handle} registered`);
}
data.hasSlashCommands = metadataUpdate.hasSlashCommands;
this._chatAgentService.updateAgent(data.name, revive(metadataUpdate));
}

async $handleProgressChunk(requestId: number, chunk: IChatResponseProgressDto): Promise<void> {
// TODO copy/move $acceptResponseProgress from MainThreadChat
this._pendingProgress.get(requestId)?.report(revive(chunk) as any);
}
}
81 changes: 81 additions & 0 deletions src/vs/workbench/api/browser/mainThreadSpeech.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/

import { CancellationTokenSource } from 'vs/base/common/cancellation';
import { Emitter } from 'vs/base/common/event';
import { Disposable, IDisposable } from 'vs/base/common/lifecycle';
import { ILogService } from 'vs/platform/log/common/log';
import { ExtHostContext, ExtHostSpeechShape, MainContext, MainThreadSpeechShape } from 'vs/workbench/api/common/extHost.protocol';
import { ISpeechProviderMetadata, ISpeechService, ISpeechToTextEvent } from 'vs/workbench/contrib/speech/common/speechService';
import { IExtHostContext, extHostNamedCustomer } from 'vs/workbench/services/extensions/common/extHostCustomers';

type SpeechToTextSession = {
readonly onDidChange: Emitter<ISpeechToTextEvent>;
};

@extHostNamedCustomer(MainContext.MainThreadSpeech)
export class MainThreadSpeech extends Disposable implements MainThreadSpeechShape {

private readonly proxy: ExtHostSpeechShape;

private readonly providerRegistrations = new Map<number, IDisposable>();
private readonly providerSessions = new Map<number, SpeechToTextSession>();

constructor(
extHostContext: IExtHostContext,
@ISpeechService private readonly speechService: ISpeechService,
@ILogService private readonly logService: ILogService
) {
super();

this.proxy = extHostContext.getProxy(ExtHostContext.ExtHostSpeech);
}

$registerProvider(handle: number, identifier: string, metadata: ISpeechProviderMetadata): void {
this.logService.trace('[Speech] extension registered provider', metadata.extension.value);

const registration = this.speechService.registerSpeechProvider(identifier, {
metadata,
createSpeechToTextSession: token => {
const cts = new CancellationTokenSource(token);
const session = Math.random();

this.proxy.$createSpeechToTextSession(handle, session, cts.token);

const onDidChange = new Emitter<ISpeechToTextEvent>();
this.providerSessions.set(session, { onDidChange });

return {
onDidChange: onDidChange.event,
dispose: () => {
cts.dispose(true);
onDidChange.dispose();
this.providerSessions.delete(session);
}
};
}
});
this.providerRegistrations.set(handle, {
dispose: () => {
registration.dispose();
}
});
}

$unregisterProvider(handle: number): void {
const registration = this.providerRegistrations.get(handle);
if (registration) {
registration.dispose();
this.providerRegistrations.delete(handle);
}
}

$emitSpeechToTextEvent(session: number, event: ISpeechToTextEvent): void {
const providerSession = this.providerSessions.get(session);
if (providerSession) {
providerSession.onDidChange.fire(event);
}
}
}
Loading

0 comments on commit d6e2a1d

Please sign in to comment.