@@ -41,9 +41,11 @@ import com.intellij.ui.popup.AbstractPopup
4141import com.intellij.ui.popup.PopupFactoryImpl
4242import com.intellij.util.messages.Topic
4343import com.intellij.util.ui.UIUtil
44+ import kotlinx.coroutines.sync.Semaphore
4445import software.amazon.awssdk.services.codewhispererruntime.model.Import
4546import software.amazon.awssdk.services.codewhispererruntime.model.Reference
4647import software.aws.toolkits.core.utils.debug
48+ import software.aws.toolkits.core.utils.error
4749import software.aws.toolkits.core.utils.getLogger
4850import software.aws.toolkits.jetbrains.services.codewhisperer.editor.CodeWhispererEditorManager
4951import software.aws.toolkits.jetbrains.services.codewhisperer.layout.CodeWhispererLayoutConfig.addHorizontalGlue
@@ -85,7 +87,8 @@ import javax.swing.JLabel
8587class CodeWhispererPopupManager {
8688 val popupComponents = CodeWhispererPopupComponents ()
8789
88- var shouldListenerCancelPopup: Boolean = true
90+ // Act like a semaphore: one increment only corresponds to one decrement
91+ var allowEditsDuringSuggestionPreview = Semaphore (MAX_EDIT_SOURCE_DURING_SUGGESTION_PREVIEW )
8992 var sessionContext = SessionContext ()
9093 private set
9194
@@ -245,12 +248,20 @@ class CodeWhispererPopupManager {
245248 }
246249 }
247250
251+ // Don't want to block or throw any kinds of exceptions here if it can continue to provide suggestions
248252 fun dontClosePopupAndRun (runnable : () -> Unit ) {
249- try {
250- shouldListenerCancelPopup = false
251- runnable()
252- } finally {
253- shouldListenerCancelPopup = true
253+ if (allowEditsDuringSuggestionPreview.tryAcquire()) {
254+ try {
255+ runnable()
256+ } finally {
257+ try {
258+ allowEditsDuringSuggestionPreview.release()
259+ } catch (e: Exception ) {
260+ LOG .error(e) { " Failed to release allowEditsDuringSuggestionPreview semaphore" }
261+ }
262+ }
263+ } else {
264+ LOG .error { " Failed to acquire allowEditsDuringSuggestionPreview semaphore" }
254265 }
255266 }
256267
@@ -496,7 +507,7 @@ class CodeWhispererPopupManager {
496507 val editor = states.requestContext.editor
497508 val codewhispererSelectionListener: SelectionListener = object : SelectionListener {
498509 override fun selectionChanged (event : SelectionEvent ) {
499- if (shouldListenerCancelPopup ) {
510+ if (allowEditsDuringSuggestionPreview.availablePermits == MAX_EDIT_SOURCE_DURING_SUGGESTION_PREVIEW ) {
500511 cancelPopup(states.popup)
501512 }
502513 super .selectionChanged(event)
@@ -512,7 +523,7 @@ class CodeWhispererPopupManager {
512523 if (! delete) return
513524 if (editor.caretModel.offset == event.offset) {
514525 changeStates(states, 0 )
515- } else if (shouldListenerCancelPopup ) {
526+ } else if (allowEditsDuringSuggestionPreview.availablePermits == MAX_EDIT_SOURCE_DURING_SUGGESTION_PREVIEW ) {
516527 cancelPopup(states.popup)
517528 }
518529 }
@@ -521,7 +532,7 @@ class CodeWhispererPopupManager {
521532
522533 val codewhispererCaretListener: CaretListener = object : CaretListener {
523534 override fun caretPositionChanged (event : CaretEvent ) {
524- if (shouldListenerCancelPopup ) {
535+ if (allowEditsDuringSuggestionPreview.availablePermits == MAX_EDIT_SOURCE_DURING_SUGGESTION_PREVIEW ) {
525536 cancelPopup(states.popup)
526537 }
527538 super .caretPositionChanged(event)
@@ -702,6 +713,7 @@ class CodeWhispererPopupManager {
702713 " CodeWhisperer user action performed" ,
703714 CodeWhispererUserActionListener ::class .java
704715 )
716+ const val MAX_EDIT_SOURCE_DURING_SUGGESTION_PREVIEW = 2
705717 }
706718}
707719
0 commit comments