11import * as vscode from "vscode"
2- import { GhostSuggestionsState } from "./GhostSuggestions"
2+ import { FillInAtCursorSuggestion , GhostSuggestionsState } from "./GhostSuggestions"
33import { extractPrefixSuffix } from "./types"
44
5+ const MAX_SUGGESTIONS_HISTORY = 20
6+
7+ /**
8+ * Find a matching suggestion from the history based on current prefix and suffix
9+ * @param prefix - The text before the cursor position
10+ * @param suffix - The text after the cursor position
11+ * @param suggestionsHistory - Array of previous suggestions (most recent last)
12+ * @returns The matching suggestion text, or null if no match found
13+ */
14+ export function findMatchingSuggestion (
15+ prefix : string ,
16+ suffix : string ,
17+ suggestionsHistory : FillInAtCursorSuggestion [ ] ,
18+ ) : string | null {
19+ // Search from most recent to least recent
20+ for ( let i = suggestionsHistory . length - 1 ; i >= 0 ; i -- ) {
21+ const fillInAtCursor = suggestionsHistory [ i ]
22+
23+ // First, try exact prefix/suffix match
24+ if ( prefix === fillInAtCursor . prefix && suffix === fillInAtCursor . suffix ) {
25+ return fillInAtCursor . text
26+ }
27+
28+ // If no exact match, check for partial typing
29+ // The user may have started typing the suggested text
30+ if ( prefix . startsWith ( fillInAtCursor . prefix ) && suffix === fillInAtCursor . suffix ) {
31+ // Extract what the user has typed between the original prefix and current position
32+ const typedContent = prefix . substring ( fillInAtCursor . prefix . length )
33+
34+ // Check if the typed content matches the beginning of the suggestion
35+ if ( fillInAtCursor . text . startsWith ( typedContent ) ) {
36+ // Return the remaining part of the suggestion (with already-typed portion removed)
37+ return fillInAtCursor . text . substring ( typedContent . length )
38+ }
39+ }
40+ }
41+
42+ return null
43+ }
44+
545export class GhostInlineCompletionProvider implements vscode . InlineCompletionItemProvider {
6- private suggestions : GhostSuggestionsState | null = null
46+ private suggestionsHistory : FillInAtCursorSuggestion [ ] = [ ]
747
8- public updateSuggestions ( suggestions : GhostSuggestionsState | null ) : void {
9- this . suggestions = suggestions
48+ public updateSuggestions ( suggestions : GhostSuggestionsState ) : void {
49+ const fillInAtCursor = suggestions . getFillInAtCursor ( )
50+
51+ if ( ! fillInAtCursor ) {
52+ return
53+ }
54+
55+ const isDuplicate = this . suggestionsHistory . some (
56+ ( existing ) =>
57+ existing . text === fillInAtCursor . text &&
58+ existing . prefix === fillInAtCursor . prefix &&
59+ existing . suffix === fillInAtCursor . suffix ,
60+ )
61+
62+ if ( isDuplicate ) {
63+ return
64+ }
65+
66+ // Add to the end of the array (most recent)
67+ this . suggestionsHistory . push ( fillInAtCursor )
68+
69+ // Remove oldest if we exceed the limit
70+ if ( this . suggestionsHistory . length > MAX_SUGGESTIONS_HISTORY ) {
71+ this . suggestionsHistory . shift ( )
72+ }
1073 }
1174
1275 public provideInlineCompletionItems (
@@ -17,16 +80,16 @@ export class GhostInlineCompletionProvider implements vscode.InlineCompletionIte
1780 ) : vscode . ProviderResult < vscode . InlineCompletionItem [ ] | vscode . InlineCompletionList > {
1881 const { prefix, suffix } = extractPrefixSuffix ( document , position )
1982
20- const fillInAtCursor = this . suggestions ?. getFillInAtCursor ( )
21- if ( ! fillInAtCursor || prefix !== fillInAtCursor . prefix || suffix !== fillInAtCursor . suffix ) {
22- return [ ]
23- }
83+ const matchingText = findMatchingSuggestion ( prefix , suffix , this . suggestionsHistory )
2484
25- const item : vscode . InlineCompletionItem = {
26- insertText : fillInAtCursor . text ,
27- range : new vscode . Range ( position , position ) ,
85+ if ( matchingText !== null ) {
86+ const item : vscode . InlineCompletionItem = {
87+ insertText : matchingText ,
88+ range : new vscode . Range ( position , position ) ,
89+ }
90+ return [ item ]
2891 }
2992
30- return [ item ]
93+ return [ ]
3194 }
3295}
0 commit comments