Skip to content

Commit 8ca009c

Browse files
committed
fix(amazonq) Previous and subsequent cells are used as context for completion in a Jupyter notebook
1 parent d457022 commit 8ca009c

File tree

2 files changed

+114
-3
lines changed

2 files changed

+114
-3
lines changed
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
{
2+
"type": "Bug Fix",
3+
"description": "Previous and subsequent cells are used as context for completion in a Jupyter notebook"
4+
}

packages/core/src/codewhisperer/util/editorContext.ts

Lines changed: 110 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,19 +22,87 @@ import { AuthUtil } from './authUtil'
2222

2323
let tabSize: number = getTabSizeSetting()
2424

25+
const languageCommentChars: Record<string, string> = {
26+
python: '# ',
27+
java: '// ',
28+
}
29+
30+
export function extractSingleCellContext(cell: vscode.NotebookCell, commentPrefix: string): string {
31+
const cellText = cell.document.getText()
32+
if (cell.kind === vscode.NotebookCellKind.Markup) {
33+
// Converting markdown to a comment block is language dependent.
34+
// If a commentPrefix is specified, add it to each line of markdown.
35+
// Otherwise, just return the text as is.
36+
if (commentPrefix === '') {
37+
return cellText
38+
}
39+
return cell.document
40+
.getText()
41+
.split('\n')
42+
.map((line) => `${commentPrefix}${line}`)
43+
.join('\n')
44+
}
45+
return cellText
46+
}
47+
48+
export function extractPrefixCellsContext(
49+
cells: vscode.NotebookCell[],
50+
maxLength: number,
51+
commentPrefix: string
52+
): string {
53+
const output: string[] = []
54+
for (let i = cells.length - 1; i >= 0; i--) {
55+
let cellText = extractSingleCellContext(cells[i], commentPrefix)
56+
if (cellText.length > 0) {
57+
if (!cellText.endsWith('\n')) {
58+
cellText += '\n'
59+
}
60+
if (cellText.length >= maxLength) {
61+
output.unshift(cellText.substring(cellText.length - maxLength))
62+
break
63+
}
64+
output.unshift(cellText)
65+
maxLength -= cellText.length
66+
}
67+
}
68+
return output.join('')
69+
}
70+
71+
export function extractSuffixCellsContext(
72+
cells: vscode.NotebookCell[],
73+
maxLength: number,
74+
commentPrefix: string
75+
): string {
76+
const output: string[] = []
77+
for (let i = 0; i < cells.length; i++) {
78+
let cellText = extractSingleCellContext(cells[i], commentPrefix)
79+
if (cellText.length > 0) {
80+
if (!cellText.endsWith('\n')) {
81+
cellText += '\n'
82+
}
83+
if (cellText.length >= maxLength) {
84+
output.push(cellText.substring(0, maxLength))
85+
break
86+
}
87+
output.push(cellText)
88+
maxLength -= cellText.length
89+
}
90+
}
91+
return output.join('')
92+
}
93+
2594
export function extractContextForCodeWhisperer(editor: vscode.TextEditor): codewhispererClient.FileContext {
2695
const document = editor.document
2796
const curPos = editor.selection.active
2897
const offset = document.offsetAt(curPos)
2998

30-
const caretLeftFileContext = editor.document.getText(
99+
let caretLeftFileContext = editor.document.getText(
31100
new vscode.Range(
32101
document.positionAt(offset - CodeWhispererConstants.charactersLimit),
33102
document.positionAt(offset)
34103
)
35104
)
36-
37-
const caretRightFileContext = editor.document.getText(
105+
let caretRightFileContext = editor.document.getText(
38106
new vscode.Range(
39107
document.positionAt(offset),
40108
document.positionAt(offset + CodeWhispererConstants.charactersLimit)
@@ -45,6 +113,45 @@ export function extractContextForCodeWhisperer(editor: vscode.TextEditor): codew
45113
languageName =
46114
runtimeLanguageContext.normalizeLanguage(editor.document.languageId) ?? editor.document.languageId
47115
}
116+
if (editor.document.uri.scheme === 'vscode-notebook-cell') {
117+
// For notebook cells, first find the existing notebook with a cell that matches the current editor.
118+
const notebook = vscode.workspace.notebookDocuments.find(
119+
(nb) =>
120+
nb.notebookType === 'jupyter-notebook' &&
121+
nb.getCells().some((cell) => cell.document === editor.document)
122+
)
123+
if (notebook) {
124+
const allCells = notebook.getCells()
125+
const cellIndex = allCells.findIndex((cell) => cell.document === editor.document)
126+
127+
// Add appropriate comment string at beginning of each line if language is recognized
128+
const commentPrefix = languageCommentChars[languageName] ?? ''
129+
130+
// Extract text from prior cells if there is enough room in left file context
131+
if (caretLeftFileContext.length < CodeWhispererConstants.charactersLimit - 1) {
132+
const leftCellsText = extractPrefixCellsContext(
133+
allCells.slice(0, cellIndex),
134+
CodeWhispererConstants.charactersLimit - (caretLeftFileContext.length + 1),
135+
commentPrefix
136+
)
137+
if (leftCellsText.length > 0) {
138+
caretLeftFileContext = leftCellsText + '\n' + caretLeftFileContext
139+
}
140+
}
141+
// Extract text from subsequent cells if there is enough room in right file context
142+
if (caretRightFileContext.length < CodeWhispererConstants.charactersLimit - 1) {
143+
const rightCellsText = extractSuffixCellsContext(
144+
allCells.slice(cellIndex + 1),
145+
CodeWhispererConstants.charactersLimit - (caretRightFileContext.length + 1),
146+
commentPrefix
147+
)
148+
if (rightCellsText.length > 0) {
149+
caretRightFileContext = caretRightFileContext + '\n' + rightCellsText
150+
}
151+
}
152+
}
153+
}
154+
48155
return {
49156
filename: getFileRelativePath(editor),
50157
programmingLanguage: {

0 commit comments

Comments
 (0)