@@ -15,6 +15,7 @@ import com.intellij.util.gist.GistManager
1515import com.intellij.util.io.DataExternalizer
1616import kotlinx.coroutines.TimeoutCancellationException
1717import kotlinx.coroutines.async
18+ import kotlinx.coroutines.awaitAll
1819import kotlinx.coroutines.runBlocking
1920import kotlinx.coroutines.withContext
2021import kotlinx.coroutines.withTimeout
@@ -38,6 +39,7 @@ import software.aws.toolkits.jetbrains.services.codewhisperer.language.programmi
3839import software.aws.toolkits.jetbrains.services.codewhisperer.model.Chunk
3940import software.aws.toolkits.jetbrains.services.codewhisperer.model.FileContextInfo
4041import software.aws.toolkits.jetbrains.services.codewhisperer.model.SupplementalContextInfo
42+ import software.aws.toolkits.jetbrains.services.codewhisperer.util.CodeWhispererConstants.SUPPLEMETAL_CONTEXT_BUFFER
4143import java.io.DataInput
4244import java.io.DataOutput
4345import java.util.Collections
@@ -117,54 +119,55 @@ class DefaultCodeWhispererFileContextProvider(private val project: Project) : Fi
117119 val startFetchingTimestamp = System .currentTimeMillis()
118120 val isTst = readAction { isTestFile(psiFile) }
119121 return try {
120- withTimeout(timeout) {
121- val language = targetContext.programmingLanguage
122-
123- val supplementalContext = if (isTst) {
124- when (shouldFetchUtgContext(language)) {
125- true -> extractSupplementalFileContextForTst(psiFile, targetContext)
126- false -> SupplementalContextInfo .emptyUtgFileContextInfo(targetContext.filename)
127- null -> {
128- LOG .debug { " UTG is not supporting ${targetContext.programmingLanguage.languageId} " }
129- null
130- }
122+ val language = targetContext.programmingLanguage
123+
124+ val supplementalContext = if (isTst) {
125+ when (shouldFetchUtgContext(language)) {
126+ true -> withTimeout(timeout) { extractSupplementalFileContextForTst(psiFile, targetContext) }
127+ false -> SupplementalContextInfo .emptyUtgFileContextInfo(targetContext.filename)
128+ null -> {
129+ LOG .debug { " UTG is not supporting ${targetContext.programmingLanguage.languageId} " }
130+ null
131131 }
132- } else {
133- when (shouldFetchCrossfileContext(language)) {
134- true -> extractSupplementalFileContextForSrc(psiFile, targetContext)
135- false -> SupplementalContextInfo .emptyCrossFileContextInfo(targetContext.filename)
136- null -> {
137- LOG .debug { " Crossfile is not supporting ${targetContext.programmingLanguage.languageId} " }
138- null
139- }
132+ }
133+ } else {
134+ when (shouldFetchCrossfileContext(language)) {
135+ // we need this buffer 10ms as when project context timeout by 50ms,
136+ // the entire [extractSupplementalFileContextForSrc] call will time out and not even return openTabsContext
137+ true -> withTimeout(timeout + SUPPLEMETAL_CONTEXT_BUFFER ) { extractSupplementalFileContextForSrc(psiFile, targetContext) }
138+ false -> SupplementalContextInfo .emptyCrossFileContextInfo(targetContext.filename)
139+ null -> {
140+ LOG .debug { " Crossfile is not supporting ${targetContext.programmingLanguage.languageId} " }
141+ null
140142 }
141143 }
144+ }
142145
143- return @withTimeout supplementalContext?.let {
144- if (it.contents.isNotEmpty()) {
145- val logStr = buildString {
146- append(" Successfully fetched supplemental context with strategy ${it.strategy} with ${it.latency} ms" )
147- it.contents.forEachIndexed { index, chunk ->
148- append(
149- """
146+ return supplementalContext?.let {
147+ if (it.contents.isNotEmpty()) {
148+ val logStr = buildString {
149+ append(" Successfully fetched supplemental context with strategy ${it.strategy} with ${it.latency} ms" )
150+ it.contents.forEachIndexed { index, chunk ->
151+ append(
152+ """
150153 |
151154 | Chunk ${index + 1 } :
152155 | path = ${chunk.path} ,
153156 | score = ${chunk.score} ,
154157 | contentLength = ${chunk.content.length}
155158 |
156- """ .trimMargin()
157- )
158- }
159+ """ .trimMargin()
160+ )
159161 }
160-
161- LOG .info { logStr }
162- } else {
163- LOG .warn { " Failed to fetch supplemental context, empty list." }
164162 }
165163
166- it.copy(latency = System .currentTimeMillis() - startFetchingTimestamp)
164+ LOG .info { logStr }
165+ } else {
166+ LOG .warn { " Failed to fetch supplemental context, empty list." }
167167 }
168+
169+ // TODO: fix this latency
170+ it.copy(latency = System .currentTimeMillis() - startFetchingTimestamp)
168171 }
169172 } catch (e: TimeoutCancellationException ) {
170173 LOG .debug {
@@ -215,47 +218,60 @@ class DefaultCodeWhispererFileContextProvider(private val project: Project) : Fi
215218
216219 val query = generateQuery(targetContext)
217220
218- val projectContextDeferred = if ( CodeWhispererFeatureConfigService .getInstance().getInlineCompletion() ) {
219- withContext(coroutineContext ) {
221+ val contexts = withContext(coroutineContext ) {
222+ val projectContextDeferred1 = if ( CodeWhispererFeatureConfigService .getInstance().getInlineCompletion() ) {
220223 async {
221224 val t0 = System .currentTimeMillis()
222225 val r = fetchProjectContext(query, psiFile, targetContext)
223226 val t1 = System .currentTimeMillis()
224- LOG .debug { " fetchProjectContext cost ${t1 - t0} ms" }
227+ LOG .debug {
228+ buildString {
229+ append(" time elapse for fetching project context=${t1 - t0} ms; " )
230+ append(" numberOfChunks=${r.contents.size} ; " )
231+ append(" totalLength=${r.contentLength} " )
232+ }
233+ }
225234
226235 r
227236 }
237+ } else {
238+ null
228239 }
229- } else {
230- null
231- }
232240
233- val openTabsContextDeferred = withContext(coroutineContext) {
234- async {
241+ val openTabsContextDeferred1 = async {
235242 val t0 = System .currentTimeMillis()
236243 val r = fetchOpenTabsContext(query, psiFile, targetContext)
237244 val t1 = System .currentTimeMillis()
238- LOG .debug { " fetchOpenTabsContext cost ${t1 - t0} ms" }
245+ LOG .debug {
246+ buildString {
247+ append(" time elapse for open tabs context=${t1 - t0} ms; " )
248+ append(" numberOfChunks=${r.contents.size} ; " )
249+ append(" totalLength=${r.contentLength} " )
250+ }
251+ }
239252
240253 r
241254 }
242- }
243255
244- if (projectContextDeferred == null ) {
245- return openTabsContextDeferred.await()
246- } else {
247- val projectContext = projectContextDeferred.await()
248- return if (projectContext.contents.isNotEmpty()) {
249- projectContext
256+ if (projectContextDeferred1 != null ) {
257+ awaitAll(projectContextDeferred1, openTabsContextDeferred1)
250258 } else {
251- val openTabsContext = openTabsContextDeferred.await()
252- openTabsContext
259+ awaitAll(openTabsContextDeferred1)
253260 }
254261 }
262+
263+ val projectContext = contexts.find { it.strategy == CrossFileStrategy .ProjectContext }
264+ val openTabsContext = contexts.find { it.strategy == CrossFileStrategy .OpenTabsBM25 }
265+
266+ return if (projectContext != null && projectContext.contents.isNotEmpty()) {
267+ projectContext
268+ } else {
269+ openTabsContext ? : SupplementalContextInfo .emptyCrossFileContextInfo(targetContext.filename)
270+ }
255271 }
256272
257273 @VisibleForTesting
258- fun fetchProjectContext (query : String , psiFile : PsiFile , targetContext : FileContextInfo ): SupplementalContextInfo {
274+ suspend fun fetchProjectContext (query : String , psiFile : PsiFile , targetContext : FileContextInfo ): SupplementalContextInfo {
259275 val response = ProjectContextController .getInstance(project).queryInline(query, psiFile.virtualFile?.path ? : " " )
260276
261277 return SupplementalContextInfo (
0 commit comments