mirror of
https://github.com/microsoft/vscode.git
synced 2025-12-28 06:31:58 +00:00
Merge branch 'main' into dev/dmitriv/go-to-column
This commit is contained in:
commit
296108389a
@ -274,18 +274,10 @@ export default tseslint.config(
|
||||
'src/vs/workbench/contrib/chat/browser/chatInlineAnchorWidget.ts',
|
||||
'src/vs/workbench/contrib/chat/browser/chatResponseAccessibleView.ts',
|
||||
'src/vs/workbench/contrib/chat/browser/contrib/chatInputCompletions.ts',
|
||||
'src/vs/workbench/contrib/chat/common/annotations.ts',
|
||||
'src/vs/workbench/contrib/chat/common/chat.ts',
|
||||
'src/vs/workbench/contrib/chat/common/chatAgents.ts',
|
||||
'src/vs/workbench/contrib/chat/common/chatModel.ts',
|
||||
'src/vs/workbench/contrib/chat/common/chatService.ts',
|
||||
'src/vs/workbench/contrib/chat/common/chatServiceImpl.ts',
|
||||
'src/vs/workbench/contrib/chat/common/codeBlockModelCollection.ts',
|
||||
'src/vs/workbench/contrib/chat/test/common/chatModel.test.ts',
|
||||
'src/vs/workbench/contrib/chat/test/common/promptSyntax/testUtils/mockFilesystem.test.ts',
|
||||
'src/vs/workbench/contrib/chat/test/common/promptSyntax/testUtils/mockFilesystem.ts',
|
||||
'src/vs/workbench/contrib/chat/test/common/tools/manageTodoListTool.test.ts',
|
||||
'src/vs/workbench/contrib/debug/browser/breakpointsView.ts',
|
||||
'src/vs/workbench/contrib/debug/browser/debugAdapterManager.ts',
|
||||
'src/vs/workbench/contrib/debug/browser/variablesView.ts',
|
||||
'src/vs/workbench/contrib/debug/browser/watchExpressionsView.ts',
|
||||
|
||||
@ -1128,6 +1128,7 @@
|
||||
{
|
||||
"command": "git.repositories.openWorktreeInNewWindow",
|
||||
"title": "%command.openWorktreeInNewWindow2%",
|
||||
"icon": "$(folder-opened)",
|
||||
"category": "Git",
|
||||
"enablement": "!operationInProgress"
|
||||
},
|
||||
@ -2116,7 +2117,7 @@
|
||||
"when": "scmProvider == git && (scmArtifactGroupId == branches || scmArtifactGroupId == tags)"
|
||||
},
|
||||
{
|
||||
"command": "git.repositories.openWorktree",
|
||||
"command": "git.repositories.openWorktreeInNewWindow",
|
||||
"group": "inline@1",
|
||||
"when": "scmProvider == git && scmArtifactGroupId == worktrees"
|
||||
},
|
||||
|
||||
@ -578,11 +578,7 @@ export class MainThreadChatSessions extends Disposable implements MainThreadChat
|
||||
|
||||
this._sessionTypeToHandle.set(chatSessionScheme, handle);
|
||||
this._contentProvidersRegistrations.set(handle, this._chatSessionsService.registerChatSessionContentProvider(chatSessionScheme, provider));
|
||||
this._proxy.$provideChatSessionProviderOptions(handle, CancellationToken.None).then(options => {
|
||||
if (options?.optionGroups && options.optionGroups.length) {
|
||||
this._chatSessionsService.setOptionGroupsForSessionType(chatSessionScheme, handle, options.optionGroups);
|
||||
}
|
||||
}).catch(err => this._logService.error('Error fetching chat session options', err));
|
||||
this._refreshProviderOptions(handle, chatSessionScheme);
|
||||
}
|
||||
|
||||
$unregisterChatSessionContentProvider(handle: number): void {
|
||||
@ -634,6 +630,31 @@ export class MainThreadChatSessions extends Disposable implements MainThreadChat
|
||||
// throw new Error('Method not implemented.');
|
||||
}
|
||||
|
||||
$onDidChangeChatSessionProviderOptions(handle: number): void {
|
||||
let sessionType: string | undefined;
|
||||
for (const [type, h] of this._sessionTypeToHandle) {
|
||||
if (h === handle) {
|
||||
sessionType = type;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!sessionType) {
|
||||
this._logService.warn(`No session type found for chat session content provider handle ${handle} when refreshing provider options`);
|
||||
return;
|
||||
}
|
||||
|
||||
this._refreshProviderOptions(handle, sessionType);
|
||||
}
|
||||
|
||||
private _refreshProviderOptions(handle: number, chatSessionScheme: string): void {
|
||||
this._proxy.$provideChatSessionProviderOptions(handle, CancellationToken.None).then(options => {
|
||||
if (options?.optionGroups && options.optionGroups.length) {
|
||||
this._chatSessionsService.setOptionGroupsForSessionType(chatSessionScheme, handle, options.optionGroups);
|
||||
}
|
||||
}).catch(err => this._logService.error('Error fetching chat session options', err));
|
||||
}
|
||||
|
||||
override dispose(): void {
|
||||
for (const session of this._activeSessions.values()) {
|
||||
session.dispose();
|
||||
|
||||
@ -3305,6 +3305,7 @@ export interface MainThreadChatSessionsShape extends IDisposable {
|
||||
$registerChatSessionContentProvider(handle: number, chatSessionScheme: string): void;
|
||||
$unregisterChatSessionContentProvider(handle: number): void;
|
||||
$onDidChangeChatSessionOptions(handle: number, sessionResource: UriComponents, updates: ReadonlyArray<ChatSessionOptionUpdateDto2>): void;
|
||||
$onDidChangeChatSessionProviderOptions(handle: number): void;
|
||||
|
||||
$handleProgressChunk(handle: number, sessionResource: UriComponents, requestId: string, chunks: (IChatProgressDto | [IChatProgressDto, number])[]): Promise<void>;
|
||||
$handleAnchorResolve(handle: number, sessionResource: UriComponents, requestId: string, requestHandle: string, anchor: Dto<IChatContentInlineReference>): void;
|
||||
|
||||
@ -151,6 +151,12 @@ export class ExtHostChatSessions extends Disposable implements ExtHostChatSessio
|
||||
}));
|
||||
}
|
||||
|
||||
if (provider.onDidChangeChatSessionProviderOptions) {
|
||||
disposables.add(provider.onDidChangeChatSessionProviderOptions(() => {
|
||||
this._proxy.$onDidChangeChatSessionProviderOptions(handle);
|
||||
}));
|
||||
}
|
||||
|
||||
return new extHostTypes.Disposable(() => {
|
||||
this._chatSessionContentProviders.delete(handle);
|
||||
disposables.dispose();
|
||||
|
||||
@ -1125,6 +1125,9 @@ export class ExtHostSCM implements ExtHostSCMShape {
|
||||
|
||||
$setSelectedSourceControl(selectedSourceControlHandle: number | undefined): Promise<void> {
|
||||
this.logService.trace('ExtHostSCM#$setSelectedSourceControl', selectedSourceControlHandle);
|
||||
if (this._selectedSourceControlHandle === selectedSourceControlHandle) {
|
||||
return Promise.resolve(undefined);
|
||||
}
|
||||
|
||||
if (selectedSourceControlHandle !== undefined) {
|
||||
this._sourceControls.get(selectedSourceControlHandle)?.setSelectionState(true);
|
||||
|
||||
@ -19,7 +19,7 @@ import { ILogService, NullLogService } from '../../../../platform/log/common/log
|
||||
import { ChatSessionsService } from '../../../contrib/chat/browser/chatSessions.contribution.js';
|
||||
import { IChatAgentRequest } from '../../../contrib/chat/common/chatAgents.js';
|
||||
import { IChatProgress, IChatProgressMessage, IChatService } from '../../../contrib/chat/common/chatService.js';
|
||||
import { IChatSessionItem, IChatSessionsService } from '../../../contrib/chat/common/chatSessionsService.js';
|
||||
import { IChatSessionItem, IChatSessionProviderOptionGroup, IChatSessionsService } from '../../../contrib/chat/common/chatSessionsService.js';
|
||||
import { LocalChatSessionUri } from '../../../contrib/chat/common/chatUri.js';
|
||||
import { ChatAgentLocation } from '../../../contrib/chat/common/constants.js';
|
||||
import { IEditorService } from '../../../services/editor/common/editorService.js';
|
||||
@ -517,4 +517,43 @@ suite('MainThreadChatSessions', function () {
|
||||
|
||||
mainThread.$unregisterChatSessionContentProvider(1);
|
||||
});
|
||||
|
||||
test('$onDidChangeChatSessionProviderOptions refreshes option groups', async function () {
|
||||
const sessionScheme = 'test-session-type';
|
||||
const handle = 1;
|
||||
|
||||
const optionGroups1: IChatSessionProviderOptionGroup[] = [{
|
||||
id: 'models',
|
||||
name: 'Models',
|
||||
items: [{ id: 'modelA', name: 'Model A' }]
|
||||
}];
|
||||
const optionGroups2: IChatSessionProviderOptionGroup[] = [{
|
||||
id: 'models',
|
||||
name: 'Models',
|
||||
items: [{ id: 'modelB', name: 'Model B' }]
|
||||
}];
|
||||
|
||||
const provideOptionsStub = proxy.$provideChatSessionProviderOptions as sinon.SinonStub;
|
||||
provideOptionsStub.onFirstCall().resolves({ optionGroups: optionGroups1 } as IChatSessionProviderOptions);
|
||||
provideOptionsStub.onSecondCall().resolves({ optionGroups: optionGroups2 } as IChatSessionProviderOptions);
|
||||
|
||||
mainThread.$registerChatSessionContentProvider(handle, sessionScheme);
|
||||
|
||||
// Wait for initial options fetch triggered on registration
|
||||
await new Promise(resolve => setTimeout(resolve, 0));
|
||||
|
||||
let storedGroups = chatSessionsService.getOptionGroupsForSessionType(sessionScheme);
|
||||
assert.ok(storedGroups);
|
||||
assert.strictEqual(storedGroups![0].items[0].id, 'modelA');
|
||||
|
||||
// Simulate extension signaling that provider options have changed
|
||||
mainThread.$onDidChangeChatSessionProviderOptions(handle);
|
||||
await new Promise(resolve => setTimeout(resolve, 0));
|
||||
|
||||
storedGroups = chatSessionsService.getOptionGroupsForSessionType(sessionScheme);
|
||||
assert.ok(storedGroups);
|
||||
assert.strictEqual(storedGroups![0].items[0].id, 'modelB');
|
||||
|
||||
mainThread.$unregisterChatSessionContentProvider(handle);
|
||||
});
|
||||
});
|
||||
|
||||
@ -96,8 +96,7 @@ export class ChatEditorInput extends EditorInput implements IEditorCloseHandler
|
||||
|
||||
// Check if we already have a custom title for this session
|
||||
const hasExistingCustomTitle = this._sessionResource && (
|
||||
this.chatService.getSession(this._sessionResource)?.title ||
|
||||
this.chatService.getPersistedSessionTitle(this._sessionResource)?.trim()
|
||||
this.chatService.getSessionTitle(this._sessionResource)?.trim()
|
||||
);
|
||||
|
||||
this.hasCustomTitle = Boolean(hasExistingCustomTitle);
|
||||
@ -184,7 +183,7 @@ export class ChatEditorInput extends EditorInput implements IEditorCloseHandler
|
||||
}
|
||||
|
||||
// If not in active registry, try persisted session data
|
||||
const persistedTitle = this.chatService.getPersistedSessionTitle(this._sessionResource);
|
||||
const persistedTitle = this.chatService.getSessionTitle(this._sessionResource);
|
||||
if (persistedTitle && persistedTitle.trim()) { // Only use non-empty persisted titles
|
||||
return persistedTitle;
|
||||
}
|
||||
|
||||
@ -1476,7 +1476,6 @@ export class ChatInputPart extends Disposable implements IHistoryNavigationWidge
|
||||
|
||||
this.tryUpdateWidgetController();
|
||||
|
||||
this.renderAttachedContext();
|
||||
this._register(this._attachmentModel.onDidChange((e) => {
|
||||
if (e.added.length > 0) {
|
||||
this._indexOfLastAttachedContextDeletedWithKeyboard = -1;
|
||||
@ -1759,6 +1758,7 @@ export class ChatInputPart extends Disposable implements IHistoryNavigationWidge
|
||||
this._onDidChangeHeight.fire();
|
||||
}
|
||||
}));
|
||||
this.renderAttachedContext();
|
||||
}
|
||||
|
||||
public toggleChatInputOverlay(editing: boolean): void {
|
||||
|
||||
@ -7,6 +7,7 @@ import { MarkdownString } from '../../../../base/common/htmlContent.js';
|
||||
import { basename } from '../../../../base/common/resources.js';
|
||||
import { URI } from '../../../../base/common/uri.js';
|
||||
import { IRange } from '../../../../editor/common/core/range.js';
|
||||
import { isLocation } from '../../../../editor/common/languages.js';
|
||||
import { IChatProgressRenderableResponseContent, IChatProgressResponseContent, appendMarkdownString, canMergeMarkdownStrings } from './chatModel.js';
|
||||
import { IChatAgentVulnerabilityDetails, IChatMarkdownContent } from './chatService.js';
|
||||
|
||||
@ -24,10 +25,10 @@ export function annotateSpecialMarkdownContent(response: Iterable<IChatProgressR
|
||||
if (!label) {
|
||||
if (URI.isUri(item.inlineReference)) {
|
||||
label = basename(item.inlineReference);
|
||||
} else if ('name' in item.inlineReference) {
|
||||
label = item.inlineReference.name;
|
||||
} else {
|
||||
} else if (isLocation(item.inlineReference)) {
|
||||
label = basename(item.inlineReference.uri);
|
||||
} else {
|
||||
label = item.inlineReference.name;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -6,7 +6,7 @@
|
||||
import { ResourceSet } from '../../../../base/common/map.js';
|
||||
import { chatEditingSessionIsReady } from './chatEditingService.js';
|
||||
import { IChatModel } from './chatModel.js';
|
||||
import type { IChatSessionStats, IChatTerminalToolInvocationData, ILegacyChatTerminalToolInvocationData } from './chatService.js';
|
||||
import { isLegacyChatTerminalToolInvocationData, type IChatSessionStats, type IChatTerminalToolInvocationData, type ILegacyChatTerminalToolInvocationData } from './chatService.js';
|
||||
import { ChatModeKind } from './constants.js';
|
||||
|
||||
export function checkModeOption(mode: ChatModeKind, option: boolean | ((mode: ChatModeKind) => boolean) | undefined): boolean | undefined {
|
||||
@ -24,7 +24,7 @@ export function checkModeOption(mode: ChatModeKind, option: boolean | ((mode: Ch
|
||||
* we don't break existing chats
|
||||
*/
|
||||
export function migrateLegacyTerminalToolSpecificData(data: IChatTerminalToolInvocationData | ILegacyChatTerminalToolInvocationData): IChatTerminalToolInvocationData {
|
||||
if ('command' in data) {
|
||||
if (isLegacyChatTerminalToolInvocationData(data)) {
|
||||
data = {
|
||||
kind: 'terminal',
|
||||
commandLine: {
|
||||
|
||||
@ -743,8 +743,12 @@ interface IOldSerializedChatAgentData extends Omit<ISerializableChatAgentData, '
|
||||
extensionPublisher?: string;
|
||||
}
|
||||
|
||||
function isSerializableChatAgentData(obj: ISerializableChatAgentData | IOldSerializedChatAgentData): obj is ISerializableChatAgentData {
|
||||
return (obj as ISerializableChatAgentData).name !== undefined;
|
||||
}
|
||||
|
||||
export function reviveSerializedAgent(raw: ISerializableChatAgentData | IOldSerializedChatAgentData): IChatAgentData {
|
||||
const normalized: ISerializableChatAgentData = 'name' in raw ?
|
||||
const normalized: ISerializableChatAgentData = isSerializableChatAgentData(raw) ?
|
||||
raw :
|
||||
{
|
||||
...raw,
|
||||
|
||||
@ -104,6 +104,12 @@ export interface IChatContentVariableReference {
|
||||
value?: URI | Location;
|
||||
}
|
||||
|
||||
export function isChatContentVariableReference(obj: unknown): obj is IChatContentVariableReference {
|
||||
return !!obj &&
|
||||
typeof obj === 'object' &&
|
||||
typeof (obj as IChatContentVariableReference).variableName === 'string';
|
||||
}
|
||||
|
||||
export enum ChatResponseReferencePartStatusKind {
|
||||
Complete = 1,
|
||||
Partial = 2,
|
||||
@ -402,6 +408,10 @@ export interface ILegacyChatTerminalToolInvocationData {
|
||||
language: string;
|
||||
}
|
||||
|
||||
export function isLegacyChatTerminalToolInvocationData(data: unknown): data is ILegacyChatTerminalToolInvocationData {
|
||||
return !!data && typeof data === 'object' && 'command' in data;
|
||||
}
|
||||
|
||||
export interface IChatToolInputInvocationData {
|
||||
kind: 'input';
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
@ -604,7 +614,7 @@ export namespace IChatToolInvocation {
|
||||
}
|
||||
|
||||
export function isComplete(invocation: IChatToolInvocation | IChatToolInvocationSerialized, reader?: IReader): boolean {
|
||||
if ('isComplete' in invocation) { // serialized
|
||||
if (invocation.kind === 'toolInvocationSerialized') {
|
||||
return true; // always cancelled or complete
|
||||
}
|
||||
|
||||
@ -1024,8 +1034,7 @@ export interface IChatService {
|
||||
getActiveSessionReference(sessionResource: URI): IChatModelReference | undefined;
|
||||
|
||||
getOrRestoreSession(sessionResource: URI): Promise<IChatModelReference | undefined>;
|
||||
getPersistedSessionTitle(sessionResource: URI): string | undefined;
|
||||
isPersistedSessionEmpty(sessionResource: URI): boolean;
|
||||
getSessionTitle(sessionResource: URI): string | undefined;
|
||||
loadSessionFromContent(data: IExportableChatData | ISerializableChatData | URI): IChatModelReference | undefined;
|
||||
loadSessionForResource(resource: URI, location: ChatAgentLocation, token: CancellationToken): Promise<IChatModelReference | undefined>;
|
||||
readonly editingSessions: IChatEditingSession[];
|
||||
|
||||
@ -76,7 +76,6 @@ export class ChatService extends Disposable implements IChatService {
|
||||
|
||||
private readonly _sessionModels: ChatModelStore;
|
||||
private readonly _pendingRequests = this._register(new DisposableResourceMap<CancellableRequest>());
|
||||
private _persistedSessions: ISerializableChatsData;
|
||||
private _saveModelsEnabled = true;
|
||||
|
||||
private _transferredSessionResource: URI | undefined;
|
||||
@ -125,7 +124,7 @@ export class ChatService extends Disposable implements IChatService {
|
||||
}
|
||||
|
||||
constructor(
|
||||
@IStorageService storageService: IStorageService,
|
||||
@IStorageService private readonly storageService: IStorageService,
|
||||
@ILogService private readonly logService: ILogService,
|
||||
@IExtensionService private readonly extensionService: IExtensionService,
|
||||
@IInstantiationService private readonly instantiationService: IInstantiationService,
|
||||
@ -160,20 +159,8 @@ export class ChatService extends Disposable implements IChatService {
|
||||
}));
|
||||
|
||||
this._chatServiceTelemetry = this.instantiationService.createInstance(ChatServiceTelemetry);
|
||||
|
||||
const sessionData = storageService.get(serializedChatKey, this.isEmptyWindow ? StorageScope.APPLICATION : StorageScope.WORKSPACE, '');
|
||||
if (sessionData) {
|
||||
this._persistedSessions = this.deserializeChats(sessionData);
|
||||
const countsForLog = Object.keys(this._persistedSessions).length;
|
||||
if (countsForLog > 0) {
|
||||
this.trace('constructor', `Restored ${countsForLog} persisted sessions`);
|
||||
}
|
||||
} else {
|
||||
this._persistedSessions = {};
|
||||
}
|
||||
|
||||
this._chatSessionStore = this._register(this.instantiationService.createInstance(ChatSessionStore));
|
||||
this._chatSessionStore.migrateDataIfNeeded(() => this._persistedSessions);
|
||||
this._chatSessionStore.migrateDataIfNeeded(() => this.migrateData());
|
||||
|
||||
const transferredData = this._chatSessionStore.getTransferredSessionData();
|
||||
if (transferredData) {
|
||||
@ -181,11 +168,7 @@ export class ChatService extends Disposable implements IChatService {
|
||||
this._transferredSessionResource = transferredData;
|
||||
}
|
||||
|
||||
// When using file storage, populate _persistedSessions with session metadata from the index
|
||||
// This ensures that getPersistedSessionTitle() can find titles for inactive sessions
|
||||
this.initializePersistedSessionsFromFileStorage().then(() => {
|
||||
this.reviveSessionsWithEdits();
|
||||
});
|
||||
this.reviveSessionsWithEdits();
|
||||
|
||||
this._register(storageService.onWillSaveState(() => this.saveState()));
|
||||
|
||||
@ -205,6 +188,21 @@ export class ChatService extends Disposable implements IChatService {
|
||||
return this.chatAgentService.getContributedDefaultAgent(location) !== undefined;
|
||||
}
|
||||
|
||||
private migrateData(): ISerializableChatsData | undefined {
|
||||
const sessionData = this.storageService.get(serializedChatKey, this.isEmptyWindow ? StorageScope.APPLICATION : StorageScope.WORKSPACE, '');
|
||||
if (sessionData) {
|
||||
const persistedSessions = this.deserializeChats(sessionData);
|
||||
const countsForLog = Object.keys(persistedSessions).length;
|
||||
if (countsForLog > 0) {
|
||||
this.info('migrateData', `Restored ${countsForLog} persisted sessions`);
|
||||
}
|
||||
|
||||
return persistedSessions;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
private saveState(): void {
|
||||
if (!this._saveModelsEnabled) {
|
||||
return;
|
||||
@ -264,6 +262,14 @@ export class ChatService extends Disposable implements IChatService {
|
||||
}
|
||||
}
|
||||
|
||||
private info(method: string, message?: string): void {
|
||||
if (message) {
|
||||
this.logService.info(`ChatService#${method}: ${message}`);
|
||||
} else {
|
||||
this.logService.info(`ChatService#${method}`);
|
||||
}
|
||||
}
|
||||
|
||||
private error(method: string, message: string): void {
|
||||
this.logService.error(`ChatService#${method} ${message}`);
|
||||
}
|
||||
@ -304,7 +310,8 @@ export class ChatService extends Disposable implements IChatService {
|
||||
* todo@connor4312 This will be cleaned up with the globalization of edits.
|
||||
*/
|
||||
private async reviveSessionsWithEdits(): Promise<void> {
|
||||
await Promise.all(Object.values(this._persistedSessions).map(async session => {
|
||||
const idx = await this._chatSessionStore.getIndex();
|
||||
await Promise.all(Object.values(idx).map(async session => {
|
||||
if (!session.hasPendingEdits) {
|
||||
return;
|
||||
}
|
||||
@ -319,34 +326,6 @@ export class ChatService extends Disposable implements IChatService {
|
||||
}));
|
||||
}
|
||||
|
||||
private async initializePersistedSessionsFromFileStorage(): Promise<void> {
|
||||
|
||||
const index = await this._chatSessionStore.getIndex();
|
||||
const sessionIds = Object.keys(index);
|
||||
|
||||
for (const sessionId of sessionIds) {
|
||||
const metadata = index[sessionId];
|
||||
if (metadata && !this._persistedSessions[sessionId]) {
|
||||
// Create a minimal session entry with the title information
|
||||
// This allows getPersistedSessionTitle() to find the title without loading the full session
|
||||
const minimalSession: ISerializableChatData = {
|
||||
version: 3,
|
||||
sessionId: sessionId,
|
||||
customTitle: metadata.title,
|
||||
creationDate: Date.now(), // Use current time as fallback
|
||||
lastMessageDate: metadata.lastMessageDate,
|
||||
initialLocation: metadata.initialLocation,
|
||||
requests: [], // Empty requests array - this is just for title lookup
|
||||
responderUsername: '',
|
||||
responderAvatarIconUri: undefined,
|
||||
hasPendingEdits: metadata.hasPendingEdits,
|
||||
};
|
||||
|
||||
this._persistedSessions[sessionId] = minimalSession;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an array of chat details for all persisted chat sessions that have at least one request.
|
||||
* Chat sessions that have already been loaded into the chat view are excluded from the result.
|
||||
@ -536,55 +515,20 @@ export class ChatService extends Disposable implements IChatService {
|
||||
return sessionRef;
|
||||
}
|
||||
|
||||
/**
|
||||
* This is really just for migrating data from the edit session location to the panel.
|
||||
*/
|
||||
isPersistedSessionEmpty(sessionResource: URI): boolean {
|
||||
const sessionId = LocalChatSessionUri.parseLocalSessionId(sessionResource);
|
||||
if (!sessionId) {
|
||||
throw new Error(`Cannot restore non-local session ${sessionResource}`);
|
||||
}
|
||||
|
||||
const session = this._persistedSessions[sessionId];
|
||||
if (session) {
|
||||
return session.requests.length === 0;
|
||||
}
|
||||
|
||||
return this._chatSessionStore.isSessionEmpty(sessionId);
|
||||
}
|
||||
|
||||
getPersistedSessionTitle(sessionResource: URI): string | undefined {
|
||||
// There are some cases where this returns a real string. What happens if it doesn't?
|
||||
// This had titles restored from the index, so just return titles from index instead, sync.
|
||||
getSessionTitle(sessionResource: URI): string | undefined {
|
||||
const sessionId = LocalChatSessionUri.parseLocalSessionId(sessionResource);
|
||||
if (!sessionId) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
// First check the memory cache (_persistedSessions)
|
||||
const session = this._persistedSessions[sessionId];
|
||||
if (session) {
|
||||
const title = session.customTitle || ChatModel.getDefaultTitle(session.requests);
|
||||
return title;
|
||||
}
|
||||
|
||||
// Try to read directly from file storage index
|
||||
// This handles the case where getName() is called before initialization completes
|
||||
// Access the internal synchronous index method via reflection
|
||||
// This is a workaround for the timing issue where initialization hasn't completed
|
||||
// eslint-disable-next-line local/code-no-any-casts, @typescript-eslint/no-explicit-any
|
||||
const internalGetIndex = (this._chatSessionStore as any).internalGetIndex;
|
||||
if (typeof internalGetIndex === 'function') {
|
||||
const indexData = internalGetIndex.call(this._chatSessionStore);
|
||||
const metadata = indexData.entries[sessionId];
|
||||
if (metadata && metadata.title) {
|
||||
return metadata.title;
|
||||
}
|
||||
}
|
||||
|
||||
return undefined;
|
||||
return this._sessionModels.get(sessionResource)?.title ??
|
||||
this._chatSessionStore.getMetadataForSessionSync(sessionResource)?.title;
|
||||
}
|
||||
|
||||
loadSessionFromContent(data: IExportableChatData | ISerializableChatData): IChatModelReference | undefined {
|
||||
const sessionId = 'sessionId' in data && data.sessionId ? data.sessionId : generateUuid();
|
||||
const sessionId = (data as ISerializableChatData).sessionId ?? generateUuid();
|
||||
const sessionResource = LocalChatSessionUri.forSession(sessionId);
|
||||
return this._sessionModels.acquireOrCreate({
|
||||
initialData: data,
|
||||
@ -844,9 +788,9 @@ export class ChatService extends Disposable implements IChatService {
|
||||
private _sendRequestAsync(model: ChatModel, sessionResource: URI, parsedRequest: IParsedChatRequest, attempt: number, enableCommandDetection: boolean, defaultAgent: IChatAgentData, location: ChatAgentLocation, options?: IChatSendRequestOptions): IChatSendRequestResponseState {
|
||||
const followupsCancelToken = this.refreshFollowupsCancellationToken(sessionResource);
|
||||
let request: ChatRequestModel;
|
||||
const agentPart = 'kind' in parsedRequest ? undefined : parsedRequest.parts.find((r): r is ChatRequestAgentPart => r instanceof ChatRequestAgentPart);
|
||||
const agentSlashCommandPart = 'kind' in parsedRequest ? undefined : parsedRequest.parts.find((r): r is ChatRequestAgentSubcommandPart => r instanceof ChatRequestAgentSubcommandPart);
|
||||
const commandPart = 'kind' in parsedRequest ? undefined : parsedRequest.parts.find((r): r is ChatRequestSlashCommandPart => r instanceof ChatRequestSlashCommandPart);
|
||||
const agentPart = parsedRequest.parts.find((r): r is ChatRequestAgentPart => r instanceof ChatRequestAgentPart);
|
||||
const agentSlashCommandPart = parsedRequest.parts.find((r): r is ChatRequestAgentSubcommandPart => r instanceof ChatRequestAgentSubcommandPart);
|
||||
const commandPart = parsedRequest.parts.find((r): r is ChatRequestSlashCommandPart => r instanceof ChatRequestSlashCommandPart);
|
||||
const requests = [...model.getRequests()];
|
||||
const requestTelemetry = this.instantiationService.createInstance(ChatRequestTelemetry, {
|
||||
agent: agentPart?.agent ?? defaultAgent,
|
||||
|
||||
@ -419,6 +419,16 @@ export class ChatSessionStore extends Disposable {
|
||||
});
|
||||
}
|
||||
|
||||
getMetadataForSessionSync(sessionResource: URI): IChatSessionEntryMetadata | undefined {
|
||||
const index = this.internalGetIndex();
|
||||
return index.entries[this.getIndexKey(sessionResource)];
|
||||
}
|
||||
|
||||
private getIndexKey(sessionResource: URI): string {
|
||||
const sessionId = LocalChatSessionUri.parseLocalSessionId(sessionResource);
|
||||
return sessionId ?? sessionResource.toString();
|
||||
}
|
||||
|
||||
logIndex(): void {
|
||||
const data = this.storageService.get(ChatIndexStorageKey, this.getIndexStorageScope(), undefined);
|
||||
this.logService.info('ChatSessionStore index: ', data);
|
||||
|
||||
@ -14,6 +14,7 @@ import { PLAINTEXT_LANGUAGE_ID } from '../../../../editor/common/languages/modes
|
||||
import { EndOfLinePreference, ITextModel } from '../../../../editor/common/model.js';
|
||||
import { IResolvedTextEditorModel, ITextModelService } from '../../../../editor/common/services/resolverService.js';
|
||||
import { extractCodeblockUrisFromText, extractVulnerabilitiesFromText, IMarkdownVulnerability } from './annotations.js';
|
||||
import { isChatContentVariableReference } from './chatService.js';
|
||||
import { IChatRequestViewModel, IChatResponseViewModel, isResponseVM } from './chatViewModel.js';
|
||||
|
||||
|
||||
@ -240,7 +241,7 @@ export class CodeBlockModelCollection extends Disposable {
|
||||
return;
|
||||
}
|
||||
|
||||
const uriOrLocation = 'variableName' in ref.reference ?
|
||||
const uriOrLocation = isChatContentVariableReference(ref.reference) ?
|
||||
ref.reference.value :
|
||||
ref.reference;
|
||||
if (!uriOrLocation) {
|
||||
|
||||
@ -92,7 +92,7 @@ class MockChatService implements IChatService {
|
||||
throw new Error('Method not implemented.');
|
||||
}
|
||||
|
||||
getPersistedSessionTitle(_sessionResource: URI): string | undefined {
|
||||
getSessionTitle(_sessionResource: URI): string | undefined {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
@ -158,10 +158,6 @@ class MockChatService implements IChatService {
|
||||
|
||||
logChatIndex(): void { }
|
||||
|
||||
isPersistedSessionEmpty(_sessionResource: URI): boolean {
|
||||
return false;
|
||||
}
|
||||
|
||||
activateDefaultAgent(_location: ChatAgentLocation): Promise<void> {
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
@ -263,7 +263,6 @@ suite('normalizeSerializableChatData', () => {
|
||||
assert.strictEqual(newData.creationDate, v1Data.creationDate);
|
||||
assert.strictEqual(newData.lastMessageDate, v1Data.creationDate);
|
||||
assert.strictEqual(newData.version, 3);
|
||||
assert.ok('customTitle' in newData);
|
||||
});
|
||||
|
||||
test('v2', () => {
|
||||
|
||||
@ -49,7 +49,7 @@ export class MockChatService implements IChatService {
|
||||
async getOrRestoreSession(sessionResource: URI): Promise<IChatModelReference | undefined> {
|
||||
throw new Error('Method not implemented.');
|
||||
}
|
||||
getPersistedSessionTitle(sessionResource: URI): string | undefined {
|
||||
getSessionTitle(sessionResource: URI): string | undefined {
|
||||
throw new Error('Method not implemented.');
|
||||
}
|
||||
loadSessionFromContent(data: ISerializableChatData): IChatModelReference | undefined {
|
||||
@ -124,10 +124,6 @@ export class MockChatService implements IChatService {
|
||||
throw new Error('Method not implemented.');
|
||||
}
|
||||
|
||||
isPersistedSessionEmpty(sessionResource: URI): boolean {
|
||||
throw new Error('Method not implemented.');
|
||||
}
|
||||
|
||||
activateDefaultAgent(location: ChatAgentLocation): Promise<void> {
|
||||
throw new Error('Method not implemented.');
|
||||
}
|
||||
|
||||
@ -7,16 +7,17 @@ import assert from 'assert';
|
||||
import { ensureNoDisposablesAreLeakedInTestSuite } from '../../../../../../base/test/common/utils.js';
|
||||
import { createManageTodoListToolData } from '../../../common/tools/manageTodoListTool.js';
|
||||
import { IToolData } from '../../../common/languageModelToolsService.js';
|
||||
import { IJSONSchema } from '../../../../../../base/common/jsonSchema.js';
|
||||
|
||||
suite('ManageTodoListTool Description Field Setting', () => {
|
||||
ensureNoDisposablesAreLeakedInTestSuite();
|
||||
|
||||
function getSchemaProperties(toolData: IToolData): { properties: any; required: string[] } {
|
||||
assert.ok(toolData.inputSchema);
|
||||
// eslint-disable-next-line local/code-no-any-casts
|
||||
const schema = toolData.inputSchema as any;
|
||||
const properties = schema?.properties?.todoList?.items?.properties;
|
||||
const required = schema?.properties?.todoList?.items?.required;
|
||||
const schema = toolData.inputSchema;
|
||||
const todolistItems = schema?.properties?.todoList?.items as IJSONSchema | undefined;
|
||||
const properties = todolistItems?.properties;
|
||||
const required = todolistItems?.required;
|
||||
|
||||
assert.ok(properties, 'Schema properties should be defined');
|
||||
assert.ok(required, 'Schema required fields should be defined');
|
||||
|
||||
@ -60,6 +60,7 @@ import { DisassemblyViewInput } from '../common/disassemblyViewInput.js';
|
||||
import * as icons from './debugIcons.js';
|
||||
import { DisassemblyView } from './disassemblyView.js';
|
||||
import { equals } from '../../../../base/common/arrays.js';
|
||||
import { hasKey } from '../../../../base/common/types.js';
|
||||
|
||||
const $ = dom.$;
|
||||
|
||||
@ -1823,7 +1824,7 @@ export function getBreakpointMessageAndIcon(state: State, breakpointsActivated:
|
||||
}
|
||||
|
||||
const appendMessage = (text: string): string => {
|
||||
return ('message' in breakpoint && breakpoint.message) ? text.concat(', ' + breakpoint.message) : text;
|
||||
return breakpoint.message ? text.concat(', ' + breakpoint.message) : text;
|
||||
};
|
||||
|
||||
if (debugActive && breakpoint instanceof Breakpoint && breakpoint.pending) {
|
||||
@ -1835,7 +1836,7 @@ export function getBreakpointMessageAndIcon(state: State, breakpointsActivated:
|
||||
if (debugActive && !breakpoint.verified) {
|
||||
return {
|
||||
icon: breakpointIcon.unverified,
|
||||
message: ('message' in breakpoint && breakpoint.message) ? breakpoint.message : (breakpoint.logMessage ? localize('unverifiedLogpoint', "Unverified Logpoint") : localize('unverifiedBreakpoint', "Unverified Breakpoint")),
|
||||
message: breakpoint.message ? breakpoint.message : (breakpoint.logMessage ? localize('unverifiedLogpoint', "Unverified Logpoint") : localize('unverifiedBreakpoint', "Unverified Breakpoint")),
|
||||
showAdapterUnverifiedMessage: true
|
||||
};
|
||||
}
|
||||
@ -1935,7 +1936,7 @@ export function getBreakpointMessageAndIcon(state: State, breakpointsActivated:
|
||||
};
|
||||
}
|
||||
|
||||
const message = ('message' in breakpoint && breakpoint.message) ? breakpoint.message : breakpoint instanceof Breakpoint && labelService ? labelService.getUriLabel(breakpoint.uri) : localize('breakpoint', "Breakpoint");
|
||||
const message = breakpoint.message ? breakpoint.message : breakpoint instanceof Breakpoint && labelService ? labelService.getUriLabel(breakpoint.uri) : localize('breakpoint', "Breakpoint");
|
||||
return {
|
||||
icon: breakpointIcon.regular,
|
||||
message
|
||||
@ -2047,7 +2048,7 @@ abstract class MemoryBreakpointAction extends Action2 {
|
||||
}));
|
||||
disposables.add(input.onDidAccept(() => {
|
||||
const r = this.parseAddress(input.value, true);
|
||||
if ('error' in r) {
|
||||
if (hasKey(r, { error: true })) {
|
||||
input.validationMessage = r.error;
|
||||
} else {
|
||||
resolve(r);
|
||||
|
||||
@ -16,34 +16,6 @@
|
||||
z-index: 0;
|
||||
}
|
||||
|
||||
.monaco-workbench .terminal-resize-overlay {
|
||||
position: absolute;
|
||||
left: 50%;
|
||||
top: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
padding: 4px 10px;
|
||||
border-radius: 4px;
|
||||
background-color: var(--vscode-editorWidget-background);
|
||||
color: var(--vscode-editorWidget-foreground);
|
||||
border: 1px solid var(--vscode-editorWidget-border);
|
||||
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.5);
|
||||
pointer-events: none;
|
||||
opacity: 0;
|
||||
transition: opacity 80ms ease-out;
|
||||
z-index: 35;
|
||||
font-size: 11px;
|
||||
}
|
||||
|
||||
.monaco-workbench.hc-black .terminal-resize-overlay,
|
||||
.monaco-workbench.hc-light .terminal-resize-overlay {
|
||||
box-shadow: none;
|
||||
border-color: var(--vscode-contrastBorder);
|
||||
}
|
||||
|
||||
.monaco-workbench .terminal-resize-overlay.visible {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.terminal-command-decoration.hide {
|
||||
visibility: hidden;
|
||||
}
|
||||
|
||||
@ -94,7 +94,6 @@ import { refreshShellIntegrationInfoStatus } from './terminalTooltip.js';
|
||||
import { generateUuid } from '../../../../base/common/uuid.js';
|
||||
import { PromptInputState } from '../../../../platform/terminal/common/capabilities/commandDetection/promptInputModel.js';
|
||||
import { hasKey, isNumber, isString } from '../../../../base/common/types.js';
|
||||
import { TerminalResizeDimensionsOverlay } from './terminalResizeDimensionsOverlay.js';
|
||||
|
||||
const enum Constants {
|
||||
/**
|
||||
@ -203,7 +202,6 @@ export class TerminalInstance extends Disposable implements ITerminalInstance {
|
||||
private _lineDataEventAddon: LineDataEventAddon | undefined;
|
||||
private readonly _scopedContextKeyService: IContextKeyService;
|
||||
private _resizeDebouncer?: TerminalResizeDebouncer;
|
||||
private readonly _terminalResizeDimensionsOverlay: MutableDisposable<IDisposable> = this._register(new MutableDisposable());
|
||||
|
||||
readonly capabilities = this._register(new TerminalCapabilityStoreMultiplexer());
|
||||
readonly statusList: ITerminalStatusList;
|
||||
@ -1182,17 +1180,6 @@ export class TerminalInstance extends Disposable implements ITerminalInstance {
|
||||
}
|
||||
this.updateConfig();
|
||||
|
||||
// Initialize resize dimensions overlay
|
||||
this.processReady.then(() => {
|
||||
// Wait a second to avoid resize events during startup like when opening a terminal or
|
||||
// when a terminal reconnects. Ideally we'd have an actual event to listen to here.
|
||||
timeout(1000).then(() => {
|
||||
if (!this._store.isDisposed) {
|
||||
this._terminalResizeDimensionsOverlay.value = new TerminalResizeDimensionsOverlay(this._wrapperElement, xterm);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// If IShellLaunchConfig.waitOnExit was true and the process finished before the terminal
|
||||
// panel was initialized.
|
||||
if (xterm.raw.options.disableStdin) {
|
||||
|
||||
@ -28,6 +28,7 @@ import '../terminalContrib/stickyScroll/browser/terminal.stickyScroll.contributi
|
||||
import '../terminalContrib/quickAccess/browser/terminal.quickAccess.contribution.js';
|
||||
import '../terminalContrib/quickFix/browser/terminal.quickFix.contribution.js';
|
||||
import '../terminalContrib/typeAhead/browser/terminal.typeAhead.contribution.js';
|
||||
import '../terminalContrib/resizeDimensionsOverlay/browser/terminal.resizeDimensionsOverlay.contribution.js';
|
||||
import '../terminalContrib/sendSequence/browser/terminal.sendSequence.contribution.js';
|
||||
import '../terminalContrib/sendSignal/browser/terminal.sendSignal.contribution.js';
|
||||
import '../terminalContrib/suggest/browser/terminal.suggest.contribution.js';
|
||||
|
||||
@ -379,16 +379,10 @@ registerAction2(class ShowChatTerminalsAction extends Action2 {
|
||||
const chatSessionId = terminalChatService.getChatSessionIdForInstance(instance);
|
||||
let chatSessionTitle: string | undefined;
|
||||
if (chatSessionId) {
|
||||
const sessionUri = LocalChatSessionUri.forSession(chatSessionId);
|
||||
// Try to get title from active session first, then fall back to persisted title
|
||||
chatSessionTitle = chatService.getSession(sessionUri)?.title || chatService.getPersistedSessionTitle(sessionUri);
|
||||
}
|
||||
|
||||
let description: string | undefined;
|
||||
if (chatSessionTitle) {
|
||||
description = `${chatSessionTitle}`;
|
||||
chatSessionTitle = chatService.getSessionTitle(LocalChatSessionUri.forSession(chatSessionId));
|
||||
}
|
||||
|
||||
const description = chatSessionTitle;
|
||||
let detail: string | undefined;
|
||||
let tooltip: string | IMarkdownString | undefined;
|
||||
if (lastCommand) {
|
||||
|
||||
@ -271,7 +271,7 @@ export const terminalChatAgentToolsConfiguration: IStringDictionary<IConfigurati
|
||||
// while processing the input.
|
||||
// - `-f`/`--file`: Add the commands contained in the file script-file to the set of
|
||||
// commands to be run while processing the input.
|
||||
// - `-i`/`--in-place`: This option specifies that files are to be edited in-place.
|
||||
// - `-i`/`-I`/`--in-place`: This option specifies that files are to be edited in-place.
|
||||
// - `w`/`W` commands: Write to files (blocked by `-i` check + agent typically won't use).
|
||||
// - `s///e` flag: Executes substitution result as shell command
|
||||
// - `s///w` flag: Write substitution result to file
|
||||
@ -279,7 +279,7 @@ export const terminalChatAgentToolsConfiguration: IStringDictionary<IConfigurati
|
||||
// - Note that `--sandbox` exists which blocks unsafe commands that could potentially be
|
||||
// leveraged to auto approve
|
||||
sed: true,
|
||||
'/^sed\\b.*(-[a-zA-Z]*(e|i|f)[a-zA-Z]*|--expression|--file|--in-place)\\b/': false,
|
||||
'/^sed\\b.*(-[a-zA-Z]*(e|i|I|f)[a-zA-Z]*|--expression|--file|--in-place)\\b/': false,
|
||||
'/^sed\\b.*(\/e|\/w|;W)/': false,
|
||||
|
||||
// sort
|
||||
|
||||
@ -304,6 +304,7 @@ suite('RunInTerminalTool', () => {
|
||||
'rg --hostname-bin hostname pattern .',
|
||||
'sed -i "s/foo/bar/g" file.txt',
|
||||
'sed -i.bak "s/foo/bar/" file.txt',
|
||||
'sed -Ibak "s/foo/bar/" file.txt',
|
||||
'sed --in-place "s/foo/bar/" file.txt',
|
||||
'sed -e "s/a/b/" file.txt',
|
||||
'sed -f script.sed file.txt',
|
||||
|
||||
@ -0,0 +1,32 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
.monaco-workbench .terminal-resize-overlay {
|
||||
position: absolute;
|
||||
left: 50%;
|
||||
top: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
padding: 4px 10px;
|
||||
border-radius: 4px;
|
||||
background-color: var(--vscode-editorWidget-background);
|
||||
color: var(--vscode-editorWidget-foreground);
|
||||
border: 1px solid var(--vscode-editorWidget-border);
|
||||
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.5);
|
||||
pointer-events: none;
|
||||
opacity: 0;
|
||||
transition: opacity 80ms ease-out;
|
||||
z-index: 35;
|
||||
font-size: 11px;
|
||||
}
|
||||
|
||||
.monaco-workbench.hc-black .terminal-resize-overlay,
|
||||
.monaco-workbench.hc-light .terminal-resize-overlay {
|
||||
box-shadow: none;
|
||||
border-color: var(--vscode-contrastBorder);
|
||||
}
|
||||
|
||||
.monaco-workbench .terminal-resize-overlay.visible {
|
||||
opacity: 1;
|
||||
}
|
||||
@ -0,0 +1,37 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import type { Terminal as RawXtermTerminal } from '@xterm/xterm';
|
||||
import { Disposable, MutableDisposable, type IDisposable } from '../../../../../base/common/lifecycle.js';
|
||||
import type { ITerminalContribution, IXtermTerminal } from '../../../terminal/browser/terminal.js';
|
||||
import { registerTerminalContribution, type ITerminalContributionContext } from '../../../terminal/browser/terminalExtensions.js';
|
||||
import { timeout } from '../../../../../base/common/async.js';
|
||||
import { TerminalResizeDimensionsOverlay } from './terminalResizeDimensionsOverlay.js';
|
||||
|
||||
class TerminalResizeDimensionsOverlayContribution extends Disposable implements ITerminalContribution {
|
||||
static readonly ID = 'terminal.resizeDimensionsOverlay';
|
||||
|
||||
private readonly _overlay: MutableDisposable<IDisposable> = this._register(new MutableDisposable());
|
||||
|
||||
constructor(
|
||||
private readonly _ctx: ITerminalContributionContext,
|
||||
) {
|
||||
super();
|
||||
}
|
||||
|
||||
xtermOpen(xterm: IXtermTerminal & { raw: RawXtermTerminal }): void {
|
||||
// Initialize resize dimensions overlay
|
||||
this._ctx.processManager.ptyProcessReady.then(() => {
|
||||
// Wait a second to avoid resize events during startup like when opening a terminal or
|
||||
// when a terminal reconnects. Ideally we'd have an actual event to listen to here.
|
||||
timeout(1000).then(() => {
|
||||
if (!this._store.isDisposed) {
|
||||
this._overlay.value = new TerminalResizeDimensionsOverlay(this._ctx.instance.domElement, xterm);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
registerTerminalContribution(TerminalResizeDimensionsOverlayContribution.ID, TerminalResizeDimensionsOverlayContribution);
|
||||
@ -3,10 +3,13 @@
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { $ } from '../../../../base/browser/dom.js';
|
||||
import { disposableTimeout } from '../../../../base/common/async.js';
|
||||
import { Disposable, MutableDisposable, toDisposable, type IDisposable } from '../../../../base/common/lifecycle.js';
|
||||
import type { XtermTerminal } from './xterm/xtermTerminal.js';
|
||||
|
||||
import './media/terminalResizeDimensionsOverlay.css';
|
||||
import { $ } from '../../../../../base/browser/dom.js';
|
||||
import { disposableTimeout } from '../../../../../base/common/async.js';
|
||||
import { Disposable, MutableDisposable, toDisposable, type IDisposable } from '../../../../../base/common/lifecycle.js';
|
||||
import type { IXtermTerminal } from '../../../terminal/browser/terminal.js';
|
||||
import type { XtermTerminal } from '../../../terminal/browser/xterm/xtermTerminal.js';
|
||||
|
||||
const enum Constants {
|
||||
ResizeOverlayHideDelay = 500,
|
||||
@ -20,11 +23,11 @@ export class TerminalResizeDimensionsOverlay extends Disposable {
|
||||
|
||||
constructor(
|
||||
private readonly _container: HTMLElement,
|
||||
xterm: XtermTerminal,
|
||||
xterm: IXtermTerminal,
|
||||
) {
|
||||
super();
|
||||
|
||||
this._register(xterm.raw.onResize(dims => this._handleDimensionsChanged(dims)));
|
||||
this._register((xterm as XtermTerminal).raw.onResize(dims => this._handleDimensionsChanged(dims)));
|
||||
this._register(toDisposable(() => {
|
||||
this._resizeOverlay?.remove();
|
||||
this._resizeOverlay = undefined;
|
||||
@ -241,6 +241,14 @@ declare module 'vscode' {
|
||||
*/
|
||||
readonly onDidChangeChatSessionOptions?: Event<ChatSessionOptionChangeEvent>;
|
||||
|
||||
/**
|
||||
* Event that the provider can fire to signal that the available provider options have changed.
|
||||
*
|
||||
* When fired, the editor will re-query {@link ChatSessionContentProvider.provideChatSessionProviderOptions}
|
||||
* and update the UI to reflect the new option groups.
|
||||
*/
|
||||
readonly onDidChangeChatSessionProviderOptions?: Event<void>;
|
||||
|
||||
/**
|
||||
* Provides the chat session content for a given uri.
|
||||
*
|
||||
|
||||
Loading…
Reference in New Issue
Block a user