Skip to content

Commit ff0c307

Browse files
committed
Refactors AI feedback context handling for changelog docs
Centralizes management of AI feedback context and changelog document URIs into a dedicated provider, improving modularity and cleanup. Updates relevant usages to access changelog feedback context through the new provider, removing redundant context management logic from command files. Simplifies resource cleanup on document close and ensures consistent context availability for AI-related features. (#4449, #4480)
1 parent 91f9b4a commit ff0c307

File tree

5 files changed

+82
-50
lines changed

5 files changed

+82
-50
lines changed

src/commands/aiFeedback.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ const uriResponses = new UriMap<AIFeedbackEvent['sentiment']>();
4949
let _updateContextDebounced: Deferrable<() => void> | undefined;
5050

5151
async function sendFeedback(container: Container, uri: Uri, sentiment: AIFeedbackEvent['sentiment']): Promise<void> {
52-
const context = extractAIResultContext(uri);
52+
const context = extractAIResultContext(container, uri);
5353
if (!context) return;
5454

5555
try {

src/commands/generateChangelog.ts

Lines changed: 3 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,15 @@
1-
import type { CancellationToken, ProgressOptions, Uri } from 'vscode';
1+
import type { CancellationToken, ProgressOptions } from 'vscode';
22
import { ProgressLocation, window, workspace } from 'vscode';
33
import type { Source } from '../constants.telemetry';
44
import type { Container } from '../container';
55
import type { GitReference } from '../git/models/reference';
66
import { getChangesForChangelog } from '../git/utils/-webview/log.utils';
77
import { createRevisionRange, shortenRevision } from '../git/utils/revision.utils';
88
import { showGenericErrorMessage } from '../messages';
9-
import type { AIGenerateChangelogChanges, AIResultContext } from '../plus/ai/aiProviderService';
9+
import type { AIGenerateChangelogChanges } from '../plus/ai/aiProviderService';
1010
import { getAIResultContext } from '../plus/ai/utils/-webview/ai.utils';
1111
import { showComparisonPicker } from '../quickpicks/comparisonPicker';
1212
import { command } from '../system/-webview/command';
13-
import { setContext } from '../system/-webview/context';
14-
import type { Deferrable } from '../system/function/debounce';
15-
import { debounce } from '../system/function/debounce';
1613
import type { Lazy } from '../system/lazy';
1714
import { lazy } from '../system/lazy';
1815
import { Logger } from '../system/logger';
@@ -25,36 +22,6 @@ export interface GenerateChangelogCommandArgs {
2522
source?: Source;
2623
}
2724

28-
// Storage for AI feedback context associated with changelog documents
29-
const changelogFeedbackContexts = new Map<string, AIResultContext>();
30-
export function getChangelogFeedbackContext(documentUri: string): AIResultContext | undefined {
31-
return changelogFeedbackContexts.get(documentUri);
32-
}
33-
function setChangelogFeedbackContext(documentUri: string, context: AIResultContext): void {
34-
changelogFeedbackContexts.set(documentUri, context);
35-
}
36-
function clearChangelogFeedbackContext(documentUri: string): void {
37-
changelogFeedbackContexts.delete(documentUri);
38-
}
39-
40-
// Storage for changelog document URIs
41-
const changelogUris = new Set<Uri>();
42-
let _updateChangelogContextDebounced: Deferrable<() => void> | undefined;
43-
function updateChangelogContext(): void {
44-
_updateChangelogContextDebounced ??= debounce(() => {
45-
void setContext('gitlens:tabs:ai:changelog', [...changelogUris]);
46-
}, 100);
47-
_updateChangelogContextDebounced();
48-
}
49-
function addChangelogUri(uri: Uri): void {
50-
changelogUris.add(uri);
51-
updateChangelogContext();
52-
}
53-
function removeChangelogUri(uri: Uri): void {
54-
changelogUris.delete(uri);
55-
updateChangelogContext();
56-
}
57-
5825
@command()
5926
export class GenerateChangelogCommand extends GlCommandBase {
6027
constructor(private readonly container: Container) {
@@ -158,17 +125,7 @@ export async function generateChangelogAndOpenMarkdownDocument(
158125
const document = await workspace.openTextDocument({ language: 'markdown', content: content });
159126
if (feedbackContext) {
160127
// Store feedback context for this document
161-
setChangelogFeedbackContext(document.uri.toString(), feedbackContext);
162-
// Add to changelog URIs context even for no-results documents
163-
addChangelogUri(document.uri);
164-
// Clean up context when document is closed
165-
const disposable = workspace.onDidCloseTextDocument(closedDoc => {
166-
if (closedDoc.uri.toString() === document.uri.toString()) {
167-
clearChangelogFeedbackContext(document.uri.toString());
168-
removeChangelogUri(document.uri);
169-
disposable.dispose();
170-
}
171-
});
128+
container.aiFeedback.addChangelogDocument(document.uri, feedbackContext);
172129
}
173130
await window.showTextDocument(document);
174131
}

src/container.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ import type { Storage } from './system/-webview/storage';
5757
import { memoize } from './system/decorators/-webview/memoize';
5858
import { log } from './system/decorators/log';
5959
import { Logger } from './system/logger';
60+
import { AIFeedbackProvider } from './telemetry/aiFeedbackProvider';
6061
import { TelemetryService } from './telemetry/telemetry';
6162
import { UsageTracker } from './telemetry/usageTracker';
6263
import { isWalkthroughSupported, WalkthroughStateProvider } from './telemetry/walkthroughStateProvider';
@@ -365,6 +366,14 @@ export class Container {
365366
return this._ai;
366367
}
367368

369+
private _aiFeedback: AIFeedbackProvider | undefined;
370+
get aiFeedback(): AIFeedbackProvider {
371+
if (this._aiFeedback == null) {
372+
this._disposables.push((this._aiFeedback = new AIFeedbackProvider()));
373+
}
374+
return this._aiFeedback;
375+
}
376+
368377
private _autolinks: AutolinksProvider | undefined;
369378
get autolinks(): AutolinksProvider {
370379
if (this._autolinks == null) {

src/plus/ai/utils/-webview/ai.utils.ts

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
import type { Disposable, QuickInputButton } from 'vscode';
22
import { env, ThemeIcon, Uri, window } from 'vscode';
3-
import { getChangelogFeedbackContext } from '../../../../commands/generateChangelog';
43
import { Schemes } from '../../../../constants';
54
import type { AIProviders } from '../../../../constants.ai';
65
import type { Container } from '../../../../container';
@@ -283,7 +282,7 @@ export function getAIResultContext(result: AIResult): AIResultContext {
283282
};
284283
}
285284

286-
export function extractAIResultContext(uri: Uri | undefined): AIResultContext | undefined {
285+
export function extractAIResultContext(container: Container, uri: Uri | undefined): AIResultContext | undefined {
287286
if (uri?.scheme === Schemes.GitLensAIMarkdown) {
288287
const { authority } = uri;
289288
if (!authority) return undefined;
@@ -300,7 +299,7 @@ export function extractAIResultContext(uri: Uri | undefined): AIResultContext |
300299
// Check for untitled documents with stored changelog feedback context
301300
if (uri?.scheme === 'untitled') {
302301
try {
303-
return getChangelogFeedbackContext(uri.toString());
302+
return container.aiFeedback.getChangelogFeedback(uri.toString());
304303
} catch {
305304
return undefined;
306305
}

src/telemetry/aiFeedbackProvider.ts

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
import type { Disposable, Uri } from 'vscode';
2+
import { workspace } from 'vscode';
3+
import type { AIResultContext } from '../plus/ai/aiProviderService';
4+
import { setContext } from '../system/-webview/context';
5+
import type { Deferrable } from '../system/function/debounce';
6+
import { debounce } from '../system/function/debounce';
7+
8+
export class AIFeedbackProvider implements Disposable {
9+
constructor() {
10+
// Listen for document close events to clean up contexts
11+
this._disposables.push(
12+
workspace.onDidCloseTextDocument(document => this.removeChangelogDocument(document.uri)),
13+
);
14+
}
15+
16+
public addChangelogDocument(uri: Uri, context: AIResultContext): void {
17+
this.setChangelogFeedback(uri.toString(), context);
18+
this.addChangelogUri(uri);
19+
}
20+
21+
private removeChangelogDocument(uri: Uri): void {
22+
this.deleteChangelogFeedback(uri.toString());
23+
this.removeChangelogUri(uri);
24+
}
25+
26+
private readonly _disposables: Disposable[] = [];
27+
dispose(): void {
28+
this._disposables.forEach(d => void d.dispose());
29+
this._changelogFeedbacks.clear();
30+
this._changelogUris.clear();
31+
this._updateChangelogContextDebounced = undefined;
32+
}
33+
34+
// Storage for changelog document URIs
35+
private readonly _changelogUris = new Set<Uri>();
36+
private _updateChangelogContextDebounced: Deferrable<() => void> | undefined;
37+
private updateChangelogContext(): void {
38+
this._updateChangelogContextDebounced ??= debounce(() => {
39+
void setContext('gitlens:tabs:ai:changelog', [...this._changelogUris]);
40+
}, 100);
41+
this._updateChangelogContextDebounced();
42+
}
43+
private addChangelogUri(uri: Uri): void {
44+
if (!this._changelogUris.has(uri)) {
45+
this._changelogUris.add(uri);
46+
this.updateChangelogContext();
47+
}
48+
}
49+
private removeChangelogUri(uri: Uri): void {
50+
if (this._changelogUris.has(uri)) {
51+
this._changelogUris.delete(uri);
52+
this.updateChangelogContext();
53+
}
54+
}
55+
56+
// Storage for AI feedback context associated with changelog documents
57+
private readonly _changelogFeedbacks = new Map<string, AIResultContext>();
58+
getChangelogFeedback(documentUri: string): AIResultContext | undefined {
59+
return this._changelogFeedbacks.get(documentUri);
60+
}
61+
private setChangelogFeedback(documentUri: string, context: AIResultContext): void {
62+
this._changelogFeedbacks.set(documentUri, context);
63+
}
64+
private deleteChangelogFeedback(documentUri: string): void {
65+
this._changelogFeedbacks.delete(documentUri);
66+
}
67+
}

0 commit comments

Comments
 (0)