Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 7 additions & 1 deletion extensions/git/src/askpass.ts
Original file line number Diff line number Diff line change
Expand Up @@ -107,8 +107,14 @@ export class Askpass implements IIPCHandler, ITerminalEnvironmentProvider {
// passphrase
if (/passphrase/i.test(request)) {
// Commit signing - Enter passphrase:
// Commit signing - Enter passphrase for '/c/Users/<username>/.ssh/id_ed25519':
// Git operation - Enter passphrase for key '/c/Users/<username>/.ssh/id_ed25519':
const file = extractFilePathFromArgs(argv, 6);
let file: string | undefined = undefined;
if (argv[5] && !/key/i.test(argv[5])) {
file = extractFilePathFromArgs(argv, 5);
} else if (argv[6]) {
file = extractFilePathFromArgs(argv, 6);
}

this.logger.trace(`[Askpass][handleSSHAskpass] request: ${request}, file: ${file}`);

Expand Down
7 changes: 7 additions & 0 deletions src/vs/base/common/lifecycle.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import { groupBy } from './collections.js';
import { SetMap } from './map.js';
import { createSingleCallFunction } from './functional.js';
import { Iterable } from './iterator.js';
import { BugIndicatingError, onUnexpectedError } from './errors.js';

// #region Disposable Tracking

Expand Down Expand Up @@ -486,6 +487,12 @@ export class DisposableStore implements IDisposable {
setParentOfDisposable(o, null);
}
}

public assertNotDisposed(): void {
if (this._isDisposed) {
onUnexpectedError(new BugIndicatingError('Object disposed'));
}
}
}

/**
Expand Down
9 changes: 9 additions & 0 deletions src/vs/editor/common/core/text/textLength.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import { LineRange } from '../ranges/lineRange.js';
import { Position } from '../position.js';
import { Range } from '../range.js';
import { OffsetRange } from '../ranges/offsetRange.js';

/**
* Represents a non-negative length of text in terms of line and column count.
Expand Down Expand Up @@ -53,6 +54,14 @@ export class TextLength {
return new TextLength(line, column);
}

public static ofSubstr(str: string, range: OffsetRange): TextLength {
return TextLength.ofText(range.substring(str));
}

public static sum<T>(fragments: readonly T[], getLength: (f: T) => TextLength): TextLength {
return fragments.reduce((acc, f) => acc.add(getLength(f)), TextLength.zero);
}

constructor(
public readonly lineCount: number,
public readonly columnCount: number
Expand Down
6 changes: 6 additions & 0 deletions src/vs/editor/common/languages.ts
Original file line number Diff line number Diff line change
Expand Up @@ -832,6 +832,11 @@ export interface InlineCompletion {
readonly warning?: InlineCompletionWarning;

readonly displayLocation?: InlineCompletionDisplayLocation;

/**
* Used for telemetry.
*/
readonly correlationId?: string | undefined;
}

export interface InlineCompletionWarning {
Expand Down Expand Up @@ -1000,6 +1005,7 @@ export type InlineCompletionEndOfLifeReason<TInlineCompletion = InlineCompletion

export type LifetimeSummary = {
requestUuid: string;
correlationId: string | undefined;
partiallyAccepted: number;
partiallyAcceptedCountSinceOriginal: number;
partiallyAcceptedRatioSinceOriginal: number;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -242,6 +242,7 @@ function toInlineSuggestData(
inlineCompletion.isInlineEdit ?? false,
requestInfo,
providerRequestInfo,
inlineCompletion.correlationId,
);
}

Expand Down Expand Up @@ -301,6 +302,7 @@ export class InlineSuggestData {

private readonly _requestInfo: InlineSuggestRequestInfo,
private readonly _providerRequestInfo: InlineSuggestProviderRequestInfo,
private readonly _correlationId: string | undefined,
) {
this._viewData = { editorType: _requestInfo.editorType };
}
Expand Down Expand Up @@ -368,6 +370,7 @@ export class InlineSuggestData {
if (this.source.provider.handleEndOfLifetime) {
const summary: LifetimeSummary = {
requestUuid: this.context.requestUuid,
correlationId: this._correlationId,
partiallyAccepted: this._partiallyAcceptedCount,
partiallyAcceptedCountSinceOriginal: this._partiallyAcceptedSinceOriginal.count,
partiallyAcceptedRatioSinceOriginal: this._partiallyAcceptedSinceOriginal.ratio,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,4 +20,9 @@ export class StaticServiceAccessor implements ServicesAccessor {
}
return value;
}

getIfExists<T>(id: ServiceIdentifier<T>): T | undefined {
const value = this.services.get(id);
return value;
}
}
5 changes: 5 additions & 0 deletions src/vs/monaco.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7527,6 +7527,10 @@ declare namespace monaco.languages {
readonly showRange?: IRange;
readonly warning?: InlineCompletionWarning;
readonly displayLocation?: InlineCompletionDisplayLocation;
/**
* Used for telemetry.
*/
readonly correlationId?: string | undefined;
}

export interface InlineCompletionWarning {
Expand Down Expand Up @@ -7633,6 +7637,7 @@ declare namespace monaco.languages {

export type LifetimeSummary = {
requestUuid: string;
correlationId: string | undefined;
partiallyAccepted: number;
partiallyAcceptedCountSinceOriginal: number;
partiallyAcceptedRatioSinceOriginal: number;
Expand Down
1 change: 1 addition & 0 deletions src/vs/platform/instantiation/common/instantiation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ export interface IConstructorSignature<T, Args extends any[] = []> {

export interface ServicesAccessor {
get<T>(id: ServiceIdentifier<T>): T;
getIfExists<T>(id: ServiceIdentifier<T>): T | undefined;
}

export const IInstantiationService = createDecorator<IInstantiationService>('instantiationService');
Expand Down
7 changes: 7 additions & 0 deletions src/vs/platform/instantiation/common/instantiationService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,13 @@ export class InstantiationService implements IInstantiationService {
throw new Error(`[invokeFunction] unknown service '${id}'`);
}
return result;
},
getIfExists: <T>(id: ServiceIdentifier<T>) => {
if (_done) {
throw illegalState('service accessor is only valid during the invocation of its target method');
}
const result = this._getOrCreateServiceInstance(id, _trace);
return result;
}
};
return fn(accessor, ...args);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
import * as sinon from 'sinon';
import { DisposableStore, IDisposable, toDisposable } from '../../../../base/common/lifecycle.js';
import { SyncDescriptor } from '../../common/descriptors.js';
import { ServiceIdentifier } from '../../common/instantiation.js';
import { ServiceIdentifier, ServicesAccessor } from '../../common/instantiation.js';
import { InstantiationService, Trace } from '../../common/instantiationService.js';
import { ServiceCollection } from '../../common/serviceCollection.js';

Expand All @@ -17,7 +17,7 @@ interface IServiceMock<T> {

const isSinonSpyLike = (fn: Function): fn is sinon.SinonSpy => fn && 'callCount' in fn;

export class TestInstantiationService extends InstantiationService implements IDisposable {
export class TestInstantiationService extends InstantiationService implements IDisposable, ServicesAccessor {

private _servciesMap: Map<ServiceIdentifier<any>, any>;

Expand All @@ -31,6 +31,14 @@ export class TestInstantiationService extends InstantiationService implements ID
return super._getOrCreateServiceInstance(service, Trace.traceCreation(false, TestInstantiationService));
}

public getIfExists<T>(service: ServiceIdentifier<T>): T | undefined {
try {
return super._getOrCreateServiceInstance(service, Trace.traceCreation(false, TestInstantiationService));
} catch (e) {
return undefined;
}
}

public set<T>(service: ServiceIdentifier<T>, instance: T): T {
return <T>this._serviceCollection.set(service, instance);
}
Expand Down
3 changes: 3 additions & 0 deletions src/vs/workbench/api/browser/mainThreadLanguageFeatures.ts
Original file line number Diff line number Diff line change
Expand Up @@ -652,6 +652,7 @@ export class MainThreadLanguageFeatures extends Disposable implements MainThread
const endOfLifeSummary: InlineCompletionEndOfLifeEvent = {
id: lifetimeSummary.requestUuid,
opportunityId: lifetimeSummary.requestUuid,
correlationId: lifetimeSummary.correlationId,
shown: lifetimeSummary.shown,
shownDuration: lifetimeSummary.shownDuration,
shownDurationUncollapsed: lifetimeSummary.shownDurationUncollapsed,
Expand Down Expand Up @@ -1315,6 +1316,7 @@ type InlineCompletionEndOfLifeEvent = {
*/
id: string;
opportunityId: string;
correlationId: string | undefined;
extensionId: string;
extensionVersion: string;
shown: boolean;
Expand Down Expand Up @@ -1352,6 +1354,7 @@ type InlineCompletionsEndOfLifeClassification = {
comment: 'Inline completions ended';
id: { classification: 'SystemMetaData'; purpose: 'FeatureInsight'; comment: 'The identifier for the inline completion request' };
opportunityId: { classification: 'SystemMetaData'; purpose: 'FeatureInsight'; comment: 'Unique identifier for an opportunity to show an inline completion or NES' };
correlationId: { classification: 'SystemMetaData'; purpose: 'FeatureInsight'; comment: 'The correlation identifier for the inline completion' };
extensionId: { classification: 'SystemMetaData'; purpose: 'FeatureInsight'; comment: 'The identifier for the extension that contributed the inline completion' };
extensionVersion: { classification: 'SystemMetaData'; purpose: 'FeatureInsight'; comment: 'The version of the extension that contributed the inline completion' };
shown: { classification: 'SystemMetaData'; purpose: 'FeatureInsight'; comment: 'Whether the inline completion was shown to the user' };
Expand Down
1 change: 1 addition & 0 deletions src/vs/workbench/api/common/extHostLanguageFeatures.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1437,6 +1437,7 @@ class InlineCompletionAdapter {
message: typeConvert.MarkdownString.from(item.warning.message),
icon: item.warning.icon ? typeConvert.IconPath.fromThemeIcon(item.warning.icon) : undefined,
} : undefined,
correlationId: this._isAdditionsProposedApiEnabled ? item.correlationId : undefined,
});
}),
commands: commands.map(c => {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/

import { alert } from '../../../../../base/browser/ui/aria/aria.js';
import { localize } from '../../../../../nls.js';
import { Action2, MenuId, registerAction2 } from '../../../../../platform/actions/common/actions.js';
import { ContextKeyExpr } from '../../../../../platform/contextkey/common/contextkey.js';
import { ServicesAccessor } from '../../../../../platform/instantiation/common/instantiation.js';
import { KeybindingWeight } from '../../../../../platform/keybinding/common/keybindingsRegistry.js';
import { KeyCode, KeyMod } from '../../../../../base/common/keyCodes.js';
import { IChatWidgetService } from '../chat.js';
import { ChatContextKeys } from '../../common/chatContextKeys.js';
import { ChatAgentLocation } from '../../common/constants.js';
import { isResponseVM } from '../../common/chatViewModel.js';
import { CONTEXT_ACCESSIBILITY_MODE_ENABLED } from '../../../../../platform/accessibility/common/accessibility.js';

export const ACTION_ID_FOCUS_CHAT_CONFIRMATION = 'workbench.action.chat.focusConfirmation';

class AnnounceChatConfirmationAction extends Action2 {
constructor() {
super({
id: ACTION_ID_FOCUS_CHAT_CONFIRMATION,
title: { value: localize('focusChatConfirmation', 'Focus Chat Confirmation'), original: 'Focus Chat Confirmation' },
category: { value: localize('chat.category', 'Chat'), original: 'Chat' },
f1: true,
keybinding: {
weight: KeybindingWeight.WorkbenchContrib,
primary: KeyMod.Alt | KeyCode.KeyA,
when: ContextKeyExpr.and(
ChatContextKeys.location.isEqualTo(ChatAgentLocation.Panel),
ChatContextKeys.inChatSession,
CONTEXT_ACCESSIBILITY_MODE_ENABLED
)
},
menu: [
{
id: MenuId.ChatConfirmationMenu,
when: ChatContextKeys.inChatSession,
group: '0_main'
}
]
});
}

async run(accessor: ServicesAccessor): Promise<void> {
const chatWidgetService = accessor.get(IChatWidgetService);
const lastFocusedWidget = chatWidgetService.lastFocusedWidget;

if (!lastFocusedWidget) {
alert(localize('noChatSession', 'No active chat session found.'));
return;
}

const viewModel = lastFocusedWidget.viewModel;
if (!viewModel) {
alert(localize('chatNotReady', 'Chat interface not ready.'));
return;
}

// Check for active confirmations in the chat responses
let firstConfirmationElement: HTMLElement | undefined;

const lastResponse = viewModel.getItems()[viewModel.getItems().length - 1];
if (isResponseVM(lastResponse)) {
const confirmationWidgets = lastFocusedWidget.domNode.querySelectorAll('.chat-confirmation-widget-container');
if (confirmationWidgets.length > 0) {
firstConfirmationElement = confirmationWidgets[0] as HTMLElement;
}
}

if (firstConfirmationElement) {
firstConfirmationElement.focus();
} else {
alert(localize('noConfirmationRequired', 'No chat confirmation required'));
}
}
}

export function registerChatAccessibilityActions(): void {
registerAction2(AnnounceChatConfirmationAction);
}
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@ export function getAccessibilityHelpText(type: 'panelChat' | 'inlineChat' | 'qui
content.push(localize('workbench.action.chat.focus', 'To focus the chat request/response list, which can be navigated with up and down arrows, invoke the Focus Chat command{0}.', getChatFocusKeybindingLabel(keybindingService, type, false)));
content.push(localize('workbench.action.chat.focusInput', 'To focus the input box for chat requests, invoke the Focus Chat Input command{0}.', getChatFocusKeybindingLabel(keybindingService, type, true)));
content.push(localize('workbench.action.chat.nextCodeBlock', 'To focus the next code block within a response, invoke the Chat: Next Code Block command{0}.', '<keybinding:workbench.action.chat.nextCodeBlock>'));
content.push(localize('workbench.action.chat.announceConfirmation', 'To focus pending chat confirmation dialogs, invoke the Focus Chat Confirmation Status command{0}.', '<keybinding:workbench.action.chat.focusConfirmation>'));
if (type === 'panelChat') {
content.push(localize('workbench.action.chat.newChat', 'To create a new chat session, invoke the New Chat command{0}.', '<keybinding:workbench.action.chat.new>'));
}
Expand Down
2 changes: 2 additions & 0 deletions src/vs/workbench/contrib/chat/browser/chat.contribution.ts
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ import { LanguageModelToolsExtensionPointHandler } from '../common/tools/languag
import { BuiltinToolsContribution } from '../common/tools/tools.js';
import { IVoiceChatService, VoiceChatService } from '../common/voiceChatService.js';
import { AgentChatAccessibilityHelp, EditsChatAccessibilityHelp, PanelChatAccessibilityHelp, QuickChatAccessibilityHelp } from './actions/chatAccessibilityHelp.js';
import { registerChatAccessibilityActions } from './actions/chatAccessibilityActions.js';
import { ACTION_ID_NEW_CHAT, CopilotTitleBarMenuRendering, registerChatActions } from './actions/chatActions.js';
import { registerNewChatActions } from './actions/chatClearActions.js';
import { CodeBlockActionRendering, registerChatCodeBlockActions, registerChatCodeCompareBlockActions } from './actions/chatCodeblockActions.js';
Expand Down Expand Up @@ -802,6 +803,7 @@ registerWorkbenchContribution2(PromptUrlHandler.ID, PromptUrlHandler, WorkbenchP
registerWorkbenchContribution2(ChatSessionsView.ID, ChatSessionsView, WorkbenchPhase.AfterRestored);

registerChatActions();
registerChatAccessibilityActions();
registerChatCopyActions();
registerChatCodeBlockActions();
registerChatCodeCompareBlockActions();
Expand Down
Loading
Loading