Skip to content

Commit e413835

Browse files
authored
feat(codewhisperer): ignore whitespace in right context #3255
* do not trim if there is no overlap * do not trim suggestion * update right context range
1 parent d5c4d40 commit e413835

File tree

3 files changed

+69
-7
lines changed

3 files changed

+69
-7
lines changed
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
{
2+
"type": "Feature",
3+
"description": "CodeWhisperer improves right context handling"
4+
}

src/codewhisperer/service/inlineCompletionService.ts

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -88,16 +88,18 @@ export class CWInlineCompletionItemProvider implements vscode.InlineCompletionIt
8888
}
8989

9090
truncateOverlapWithRightContext(document: vscode.TextDocument, suggestion: string): string {
91-
let rightContextRange: vscode.Range | undefined = undefined
91+
const trimmedSuggestion = suggestion.trim()
9292
const pos = vscode.window.activeTextEditor?.selection.active || RecommendationHandler.instance.startPos
93-
if (suggestion.split(/\r?\n/).length > 1) {
94-
rightContextRange = new vscode.Range(pos, document.positionAt(document.offsetAt(pos) + suggestion.length))
93+
// limit of 5000 for right context matching
94+
const rightContext = document.getText(new vscode.Range(pos, document.positionAt(document.offsetAt(pos) + 5000)))
95+
const overlap = getPrefixSuffixOverlap(trimmedSuggestion, rightContext.trim())
96+
const overlapIndex = suggestion.lastIndexOf(overlap)
97+
if (overlapIndex >= 0) {
98+
const truncated = suggestion.slice(0, overlapIndex)
99+
return truncated.trim().length ? truncated : ''
95100
} else {
96-
rightContextRange = new vscode.Range(pos, document.lineAt(pos).range.end)
101+
return suggestion
97102
}
98-
const rightContext = document.getText(rightContextRange)
99-
const overlap = getPrefixSuffixOverlap(suggestion, rightContext)
100-
return suggestion.slice(0, suggestion.length - overlap.length)
101103
}
102104

103105
getInlineCompletionItem(

src/test/codewhisperer/service/inlineCompletionService.test.ts

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,62 @@ describe('inlineCompletionService', function () {
101101
})
102102
})
103103

104+
describe('truncateOverlapWithRightContext', function () {
105+
const fileName = 'test.py'
106+
const language = 'python'
107+
let rightContext = 'return target\n'
108+
const doc = `import math\ndef two_sum(nums, target):\n`
109+
const provider = new CWInlineCompletionItemProvider(0, 0)
110+
111+
it('removes overlap with right context from suggestion', async function () {
112+
const mockSuggestion = 'return target\n'
113+
const mockEditor = createMockTextEditor(`${doc}${rightContext}`, fileName, language)
114+
const result = provider.truncateOverlapWithRightContext(mockEditor.document, mockSuggestion)
115+
assert.strictEqual(result, '')
116+
})
117+
118+
it('only removes the overlap part from suggestion', async function () {
119+
const mockSuggestion = 'print(nums)\nreturn target\n'
120+
const mockEditor = createMockTextEditor(`${doc}${rightContext}`, fileName, language)
121+
const result = provider.truncateOverlapWithRightContext(mockEditor.document, mockSuggestion)
122+
assert.strictEqual(result, 'print(nums)\n')
123+
})
124+
125+
it('only removes the last overlap pattern from suggestion', async function () {
126+
const mockSuggestion = 'return target\nprint(nums)\nreturn target\n'
127+
const mockEditor = createMockTextEditor(`${doc}${rightContext}`, fileName, language)
128+
const result = provider.truncateOverlapWithRightContext(mockEditor.document, mockSuggestion)
129+
assert.strictEqual(result, 'return target\nprint(nums)\n')
130+
})
131+
132+
it('returns empty string if the remaining suggestion only contains white space', async function () {
133+
const mockSuggestion = 'return target\n '
134+
const mockEditor = createMockTextEditor(`${doc}${rightContext}`, fileName, language)
135+
const result = provider.truncateOverlapWithRightContext(mockEditor.document, mockSuggestion)
136+
assert.strictEqual(result, '')
137+
})
138+
139+
it('returns the original suggestion if no match found', async function () {
140+
const mockSuggestion = 'import numpy\n'
141+
const mockEditor = createMockTextEditor(`${doc}${rightContext}`, fileName, language)
142+
const result = provider.truncateOverlapWithRightContext(mockEditor.document, mockSuggestion)
143+
assert.strictEqual(result, 'import numpy\n')
144+
})
145+
it('ignores the space at the end of recommendation', async function () {
146+
const mockSuggestion = 'return target\n\n\n\n\n'
147+
const mockEditor = createMockTextEditor(`${doc}${rightContext}`, fileName, language)
148+
const result = provider.truncateOverlapWithRightContext(mockEditor.document, mockSuggestion)
149+
assert.strictEqual(result, '')
150+
})
151+
it('ignores the space at the start of right context', async function () {
152+
rightContext = '\n\n\n\nreturn target'
153+
const mockEditor = createMockTextEditor(`${doc}${rightContext}`, fileName, language)
154+
const mockSuggestion = 'return target\n'
155+
const result = provider.truncateOverlapWithRightContext(mockEditor.document, mockSuggestion)
156+
assert.strictEqual(result, '')
157+
})
158+
})
159+
104160
describe('on event change', async function () {
105161
beforeEach(function () {
106162
const fakeReferences = [

0 commit comments

Comments
 (0)