blob: b880ccdee8f6d90d806e7066081e11c57b3191c1 [file] [log] [blame]
Ben Rohlfs4deb8df52024-05-10 12:53:19 +02001/**
2 * @license
3 * Copyright 2024 Google LLC
4 * SPDX-License-Identifier: Apache-2.0
5 */
Ben Rohlfsdd88cd92024-05-08 13:29:39 +02006export interface AutocompletionContext {
7 draftContent: string;
8 draftContentLength?: number;
9 commentCompletion: string;
10 commentCompletionLength?: number;
11
12 isFullCommentPrediction?: boolean;
13 draftInSyncWithSuggestionLength?: number;
14 modelVersion?: string;
Ben Rohlfs8b0e91a2024-05-23 14:42:23 +020015 outcome?: number;
Ben Rohlfsdd88cd92024-05-08 13:29:39 +020016 requestDurationMs?: number;
17
18 commentId?: string;
19 commentNumber?: number;
20 filePath?: string;
21 fileExtension?: string;
22
23 similarCharacters?: number;
24 maxSimilarCharacters?: number;
25 acceptedSuggestionsCount?: number;
26 totalAcceptedCharacters?: number;
27 savedDraftLength?: number;
Ben Rohlfs40f41af2024-05-22 12:57:34 +020028
29 hasDraftChanged?: boolean;
Ben Rohlfs4deb8df52024-05-10 12:53:19 +020030}
31
32/**
33 * Caching for autocompleting text, e.g. comments.
34 *
35 * If the user continues typing text that matches the completion hint, then keep the hint.
36 *
37 * If the user backspaces, then continue using previous hint.
38 */
39export class AutocompleteCache {
40 /**
41 * We are using an ordered list instead of a map here, because we want to evict the oldest
42 * entries, if the capacity is exceeded. And we want to prefer newer entries over older
43 * entries, if both match the criteria for being reused.
44 */
Ben Rohlfsdd88cd92024-05-08 13:29:39 +020045 private cache: AutocompletionContext[] = [];
Ben Rohlfs4deb8df52024-05-10 12:53:19 +020046
47 constructor(private readonly capacity = 10) {}
48
Ben Rohlfsdd88cd92024-05-08 13:29:39 +020049 get(content: string): AutocompletionContext | undefined {
Ben Rohlfs4deb8df52024-05-10 12:53:19 +020050 if (content === '') return undefined;
51 for (let i = this.cache.length - 1; i >= 0; i--) {
Ben Rohlfsdd88cd92024-05-08 13:29:39 +020052 const cachedContext = this.cache[i];
53 const completionContent = cachedContext.draftContent;
54 const completionHint = cachedContext.commentCompletion;
Ben Rohlfs4deb8df52024-05-10 12:53:19 +020055 const completionFull = completionContent + completionHint;
56 if (completionContent.length > content.length) continue;
57 if (!completionFull.startsWith(content)) continue;
58 if (completionFull === content) continue;
Ben Rohlfsdd88cd92024-05-08 13:29:39 +020059 const hint = completionFull.substring(content.length);
60 return {
61 ...cachedContext,
62 draftContent: content,
63 commentCompletion: hint,
64 draftInSyncWithSuggestionLength:
65 content.length - completionContent.length,
66 };
Ben Rohlfs4deb8df52024-05-10 12:53:19 +020067 }
68 return undefined;
69 }
70
Ben Rohlfsdd88cd92024-05-08 13:29:39 +020071 set(context: AutocompletionContext) {
72 const index = this.cache.findIndex(
73 c => c.draftContent === context.draftContent
74 );
Ben Rohlfs4deb8df52024-05-10 12:53:19 +020075 if (index !== -1) {
76 this.cache.splice(index, 1);
77 } else if (this.cache.length >= this.capacity) {
78 this.cache.shift();
79 }
Ben Rohlfsdd88cd92024-05-08 13:29:39 +020080 this.cache.push(context);
Ben Rohlfs4deb8df52024-05-10 12:53:19 +020081 }
82}