Skip to content

Commit 4dc6386

Browse files
authored
fix(codewhisperer): support code generation for IaC languages without external plugin extensions (#4181)
* CW: Support IaaC languages with file extension instead of editor language for code generation * Change in test case file * Added change log * minor code changes * Small code fixes * Addressing comments * CW:Change log * Change in text --------- Co-authored-by: Laxman Reddy <[email protected]>
1 parent 79ede19 commit 4dc6386

11 files changed

+87
-22
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": "CodeWhisperer supports code generation for Iac languages without external extensions"
4+
}

src/codewhisperer/commands/onAcceptance.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import { handleExtraBrackets } from '../util/closingBracketUtil'
1414
import { RecommendationHandler } from '../service/recommendationHandler'
1515
import { ReferenceLogViewProvider } from '../service/referenceLogViewProvider'
1616
import { ReferenceHoverProvider } from '../service/referenceHoverProvider'
17+
import path from 'path'
1718

1819
/**
1920
* This function is called when user accepts a intelliSense suggestion or an inline suggestion
@@ -24,7 +25,10 @@ export async function onAcceptance(acceptanceEntry: OnRecommendationAcceptanceEn
2425
* Format document
2526
*/
2627
if (acceptanceEntry.editor) {
27-
const languageContext = runtimeLanguageContext.getLanguageContext(acceptanceEntry.editor.document.languageId)
28+
const languageContext = runtimeLanguageContext.getLanguageContext(
29+
acceptanceEntry.editor.document.languageId,
30+
path.extname(acceptanceEntry.editor.document.fileName)
31+
)
2832
const start = acceptanceEntry.range.start
2933
const end = isCloud9() ? acceptanceEntry.editor.selection.active : acceptanceEntry.range.end
3034

src/codewhisperer/commands/onInlineAcceptance.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ import { ReferenceLogViewProvider } from '../service/referenceLogViewProvider'
2727
import { ReferenceHoverProvider } from '../service/referenceHoverProvider'
2828
import { ImportAdderProvider } from '../service/importAdderProvider'
2929
import { session } from '../util/codeWhispererSession'
30+
import path from 'path'
3031

3132
export const acceptSuggestion = Commands.declare(
3233
'aws.codeWhisperer.accept',
@@ -73,7 +74,10 @@ export async function onInlineAcceptance(
7374

7475
if (acceptanceEntry.editor) {
7576
await sleep(CodeWhispererConstants.vsCodeCursorUpdateDelay)
76-
const languageContext = runtimeLanguageContext.getLanguageContext(acceptanceEntry.editor.document.languageId)
77+
const languageContext = runtimeLanguageContext.getLanguageContext(
78+
acceptanceEntry.editor.document.languageId,
79+
path.extname(acceptanceEntry.editor.document.fileName)
80+
)
7781
const start = acceptanceEntry.range.start
7882
const end = acceptanceEntry.editor.selection.active
7983

src/codewhisperer/commands/startSecurityScan.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ import { isAwsError } from '../../shared/errors'
3333
import { openUrl } from '../../shared/utilities/vsCodeUtils'
3434
import { AuthUtil } from '../util/authUtil'
3535
import { DependencyGraphConstants } from '../util/dependencyGraph/dependencyGraph'
36+
import path from 'path'
3637

3738
const performance = globalThis.performance ?? require('perf_hooks').performance
3839
const securityScanOutputChannel = vscode.window.createOutputChannel('CodeWhisperer Security Scan Logs')
@@ -72,7 +73,10 @@ export async function startSecurityScan(
7273
const codeScanStartTime = performance.now()
7374
let serviceInvocationStartTime = 0
7475
const codeScanTelemetryEntry: CodeScanTelemetryEntry = {
75-
codewhispererLanguage: runtimeLanguageContext.getLanguageContext(editor.document.languageId).language,
76+
codewhispererLanguage: runtimeLanguageContext.getLanguageContext(
77+
editor.document.languageId,
78+
path.extname(editor.document.fileName)
79+
).language,
7680
codewhispererCodeScanSrcPayloadBytes: 0,
7781
codewhispererCodeScanSrcZipFileBytes: 0,
7882
codewhispererCodeScanLines: 0,

src/codewhisperer/service/completionProvider.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import { Recommendation } from '../client/codewhisperer'
1010
import { LicenseUtil } from '../util/licenseUtil'
1111
import { RecommendationHandler } from './recommendationHandler'
1212
import { session } from '../util/codeWhispererSession'
13+
import path from 'path'
1314
/**
1415
* completion provider for intelliSense popup
1516
*/
@@ -41,7 +42,10 @@ export function getCompletionItem(
4142
completionItem.preselect = true
4243
completionItem.sortText = String(recommendationIndex + 1).padStart(10, '0')
4344
completionItem.range = new vscode.Range(start, position)
44-
const languageContext = runtimeLanguageContext.getLanguageContext(document.languageId)
45+
const languageContext = runtimeLanguageContext.getLanguageContext(
46+
document.languageId,
47+
path.extname(document.fileName)
48+
)
4549
let references: typeof recommendationDetail.references
4650
if (recommendationDetail.references !== undefined && recommendationDetail.references.length > 0) {
4751
references = recommendationDetail.references

src/codewhisperer/service/inlineCompletionItemProvider.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import { runtimeLanguageContext } from '../util/runtimeLanguageContext'
1111
import { ReferenceInlineProvider } from './referenceInlineProvider'
1212
import { ImportAdderProvider } from './importAdderProvider'
1313
import { application } from '../util/codeWhispererApplication'
14+
import path from 'path'
1415

1516
export class CWInlineCompletionItemProvider implements vscode.InlineCompletionItemProvider {
1617
private activeItemIndex: number | undefined
@@ -116,7 +117,8 @@ export class CWInlineCompletionItemProvider implements vscode.InlineCompletionIt
116117
session.sessionId,
117118
session.triggerType,
118119
session.getCompletionType(index),
119-
runtimeLanguageContext.getLanguageContext(document.languageId).language,
120+
runtimeLanguageContext.getLanguageContext(document.languageId, path.extname(document.fileName))
121+
.language,
120122
r.references,
121123
],
122124
},

src/codewhisperer/service/recommendationHandler.ts

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ import { CWInlineCompletionItemProvider } from './inlineCompletionItemProvider'
4343
import { application } from '../util/codeWhispererApplication'
4444
import { openUrl } from '../../shared/utilities/vsCodeUtils'
4545
import { indent } from '../../shared/utilities/textUtilities'
46+
import path from 'path'
4647

4748
/**
4849
* This class is for getRecommendation/listRecommendation API calls and its states
@@ -180,7 +181,10 @@ export class RecommendationHandler {
180181
let latency = 0
181182
let nextToken = ''
182183
let shouldRecordServiceInvocation = true
183-
session.language = runtimeLanguageContext.getLanguageContext(editor.document.languageId).language
184+
session.language = runtimeLanguageContext.getLanguageContext(
185+
editor.document.languageId,
186+
path.extname(editor.document.fileName)
187+
).language
184188
session.taskType = await this.getTaskTypeFromEditorFileName(editor.document.fileName)
185189

186190
if (pagination) {
@@ -399,7 +403,10 @@ export class RecommendationHandler {
399403
session.requestIdList,
400404
sessionId,
401405
page,
402-
editor.document.languageId,
406+
runtimeLanguageContext.getLanguageContext(
407+
editor.document.languageId,
408+
path.extname(editor.document.fileName)
409+
).language,
403410
session.requestContext.supplementalMetadata
404411
)
405412
}
@@ -685,7 +692,10 @@ export class RecommendationHandler {
685692
private sendPerceivedLatencyTelemetry() {
686693
if (vscode.window.activeTextEditor) {
687694
const languageContext = runtimeLanguageContext.getLanguageContext(
688-
vscode.window.activeTextEditor.document.languageId
695+
vscode.window.activeTextEditor.document.languageId,
696+
vscode.window.activeTextEditor.document.fileName.substring(
697+
vscode.window.activeTextEditor.document.fileName.lastIndexOf('.') + 1
698+
)
689699
)
690700
telemetry.codewhisperer_perceivedLatency.emit({
691701
codewhispererRequestId: this.requestId,

src/codewhisperer/util/editorContext.ts

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -181,12 +181,14 @@ export async function buildGenerateRecommendationRequest(editor: vscode.TextEdit
181181
export function validateRequest(
182182
req: codewhispererClient.ListRecommendationsRequest | codewhispererClient.GenerateRecommendationsRequest
183183
): boolean {
184-
const isLanguageNameValid = !(
185-
req.fileContext.programmingLanguage.languageName === undefined ||
186-
req.fileContext.programmingLanguage.languageName.length < 1 ||
187-
req.fileContext.programmingLanguage.languageName.length > 128 ||
188-
!runtimeLanguageContext.isLanguageSupported(req.fileContext.programmingLanguage.languageName)
189-
)
184+
const isLanguageNameValid =
185+
req.fileContext.programmingLanguage.languageName !== undefined &&
186+
req.fileContext.programmingLanguage.languageName.length >= 1 &&
187+
req.fileContext.programmingLanguage.languageName.length <= 128 &&
188+
(runtimeLanguageContext.isLanguageSupported(req.fileContext.programmingLanguage.languageName) ||
189+
runtimeLanguageContext.isFileFormatSupported(
190+
req.fileContext.filename.substring(req.fileContext.filename.lastIndexOf('.') + 1)
191+
))
190192
const isFileNameValid = !(req.fileContext.filename === undefined || req.fileContext.filename.length < 1)
191193
const isFileContextValid = !(
192194
req.fileContext.leftFileContent.length > CodeWhispererConstants.charactersLimit ||

src/codewhisperer/util/runtimeLanguageContext.ts

Lines changed: 31 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -158,10 +158,25 @@ export class RuntimeLanguageContext {
158158
}
159159

160160
/**
161-
* @param languageId : vscode language id or codewhisperer language name
161+
* @param languageId : vscode language id or codewhisperer language name, fileExtension: extension of the selected file
162162
* @returns An object with a field language: CodewhispererLanguage, if no corresponding CodewhispererLanguage ID, plaintext is returned
163163
*/
164-
public getLanguageContext(languageId?: string): { language: CodewhispererLanguage } {
164+
public getLanguageContext(languageId?: string, fileExtension?: string): { language: CodewhispererLanguage } {
165+
const extensionToLanguageMap: Record<string, CodewhispererLanguage> = {
166+
tf: 'tf',
167+
hcl: 'tf',
168+
json: 'json',
169+
yaml: 'yaml',
170+
yml: 'yaml',
171+
// Add more mappings if needed
172+
}
173+
174+
if (languageId === 'plaintext' && fileExtension !== undefined) {
175+
const languages = extensionToLanguageMap[fileExtension]
176+
if (languages) {
177+
return { language: languages }
178+
}
179+
}
165180
return { language: this.normalizeLanguage(languageId) ?? 'plaintext' }
166181
}
167182

@@ -177,7 +192,10 @@ export class RuntimeLanguageContext {
177192
const fileContext = request.fileContext
178193
const runtimeLanguage: codewhispererClient.ProgrammingLanguage = {
179194
languageName: this.toRuntimeLanguage(
180-
request.fileContext.programmingLanguage.languageName as CodewhispererLanguage
195+
runtimeLanguageContext.getLanguageContext(
196+
request.fileContext.programmingLanguage.languageName,
197+
request.fileContext.filename.substring(request.fileContext.filename.lastIndexOf('.') + 1)
198+
).language
181199
),
182200
}
183201

@@ -193,12 +211,21 @@ export class RuntimeLanguageContext {
193211
/**
194212
*
195213
* @param languageId: either vscodeLanguageId or CodewhispererLanguage
196-
* @returns ture if the language is supported by CodeWhisperer otherwise false
214+
* @returns true if the language is supported by CodeWhisperer otherwise false
197215
*/
198216
public isLanguageSupported(languageId: string): boolean {
199217
const lang = this.normalizeLanguage(languageId)
200218
return lang !== undefined && this.normalizeLanguage(languageId) !== 'plaintext'
201219
}
220+
/**
221+
*
222+
* @param fileFormat : vscode editor filecontext filename extension
223+
* @returns true if the fileformat is supported by CodeWhisperer otherwise false
224+
*/
225+
public isFileFormatSupported(fileFormat: string): boolean {
226+
const fileformat = this.supportedLanguageExtensionMap.get(fileFormat)
227+
return fileformat !== undefined && this.supportedLanguageExtensionMap.get(fileformat) !== 'txt'
228+
}
202229
}
203230

204231
export const runtimeLanguageContext = new RuntimeLanguageContext()

src/codewhisperer/util/telemetryHelper.ts

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -99,10 +99,9 @@ export class TelemetryHelper {
9999
requestIdList: string[],
100100
sessionId: string,
101101
paginationIndex: number,
102-
languageId: string,
102+
language: CodewhispererLanguage,
103103
supplementalContextMetadata?: Omit<CodeWhispererSupplementalContext, 'supplementalContextItems'> | undefined
104104
) {
105-
const languageContext = runtimeLanguageContext.getLanguageContext(languageId)
106105
telemetry.codewhisperer_userDecision.emit({
107106
codewhispererRequestId: requestIdList[0],
108107
codewhispererSessionId: sessionId ? sessionId : undefined,
@@ -113,7 +112,7 @@ export class TelemetryHelper {
113112
codewhispererSuggestionReferences: undefined,
114113
codewhispererSuggestionReferenceCount: 0,
115114
codewhispererCompletionType: 'Line',
116-
codewhispererLanguage: languageContext.language,
115+
codewhispererLanguage: language,
117116
codewhispererGettingStartedTask: session.taskType,
118117
credentialStartUrl: AuthUtil.instance.startUrl,
119118
codewhispererUserGroup: CodeWhispererUserGroupSettings.getUserGroup().toString(),

0 commit comments

Comments
 (0)