@@ -5,7 +5,6 @@ package software.aws.toolkits.jetbrains.services.codewhisperer.popup
55
66import com.intellij.codeInsight.hint.ParameterInfoController
77import com.intellij.codeInsight.lookup.LookupManager
8- import com.intellij.codeInsight.lookup.LookupManagerListener
98import com.intellij.idea.AppMode
109import com.intellij.openapi.actionSystem.IdeActions.ACTION_EDITOR_ENTER
1110import com.intellij.openapi.actionSystem.IdeActions.ACTION_EDITOR_ESCAPE
@@ -26,8 +25,6 @@ import com.intellij.openapi.editor.event.CaretEvent
2625import com.intellij.openapi.editor.event.CaretListener
2726import com.intellij.openapi.editor.event.DocumentEvent
2827import com.intellij.openapi.editor.event.DocumentListener
29- import com.intellij.openapi.editor.event.EditorMouseEvent
30- import com.intellij.openapi.editor.event.EditorMouseMotionListener
3128import com.intellij.openapi.editor.event.SelectionEvent
3229import com.intellij.openapi.editor.event.SelectionListener
3330import com.intellij.openapi.fileEditor.FileEditorManager
@@ -65,10 +62,8 @@ import software.aws.toolkits.jetbrains.services.codewhisperer.popup.handlers.Cod
6562import software.aws.toolkits.jetbrains.services.codewhisperer.popup.listeners.CodeWhispererAcceptButtonActionListener
6663import software.aws.toolkits.jetbrains.services.codewhisperer.popup.listeners.CodeWhispererActionListener
6764import software.aws.toolkits.jetbrains.services.codewhisperer.popup.listeners.CodeWhispererNextButtonActionListener
68- import software.aws.toolkits.jetbrains.services.codewhisperer.popup.listeners.CodeWhispererPopupIntelliSenseAcceptListener
6965import software.aws.toolkits.jetbrains.services.codewhisperer.popup.listeners.CodeWhispererPrevButtonActionListener
7066import software.aws.toolkits.jetbrains.services.codewhisperer.popup.listeners.CodeWhispererScrollListener
71- import software.aws.toolkits.jetbrains.services.codewhisperer.popup.listeners.addIntelliSenseAcceptListener
7267import software.aws.toolkits.jetbrains.services.codewhisperer.service.CodeWhispererInvocationStatus
7368import software.aws.toolkits.jetbrains.services.codewhisperer.telemetry.CodeWhispererTelemetryService
7469import software.aws.toolkits.jetbrains.services.codewhisperer.toolwindow.CodeWhispererCodeReferenceManager
@@ -224,6 +219,7 @@ class CodeWhispererPopupManager {
224219 fun render (
225220 states : InvocationContext ,
226221 sessionContext : SessionContext ,
222+ overlappingLinesCount : Int ,
227223 isRecommendationAdded : Boolean ,
228224 ) {
229225 updatePopupPanel(states, sessionContext)
@@ -246,7 +242,7 @@ class CodeWhispererPopupManager {
246242 states.requestContext.latencyContext.getPerceivedLatency(states.requestContext.triggerTypeInfo.triggerType)
247243 }
248244 if (! isRecommendationAdded) {
249- showPopup(states, sessionContext, states.popup, visible = sessionContext.isPopupShowing )
245+ showPopup(states, sessionContext, states.popup, overlappingLinesCount )
250246 }
251247 }
252248
@@ -285,30 +281,28 @@ class CodeWhispererPopupManager {
285281 states : InvocationContext ,
286282 sessionContext : SessionContext ,
287283 popup : JBPopup ,
288- visible : Boolean = false ,
284+ overlappingLinesCount : Int ,
289285 ) {
290286 val caretPoint = states.requestContext.editor.offsetToXY(states.requestContext.caretPosition.offset)
291287 val editor = states.requestContext.editor
292288 val detailContexts = states.recommendationContext.details
293289 val userInputOriginal = states.recommendationContext.userInputOriginal
290+ val userInput = states.recommendationContext.userInputSinceInvocation
294291 val selectedIndex = sessionContext.selectedIndex
295292 val typeaheadOriginal = sessionContext.typeaheadOriginal
296293 val typeahead = sessionContext.typeahead
297294 val userInputLines = userInputOriginal.split(" \n " ).size - 1
295+ val lineCount = getReformattedRecommendation(detailContexts[selectedIndex], userInput).split(" \n " ).size
298296 val additionalLines = typeaheadOriginal.split(" \n " ).size - typeahead.split(" \n " ).size
299297 val popupSize = (popup as AbstractPopup ).preferredContentSize
298+ val yBelowLastLine = caretPoint.y + (lineCount + additionalLines + userInputLines - overlappingLinesCount) * editor.lineHeight
300299 val yAboveFirstLine = caretPoint.y - popupSize.height + (additionalLines + userInputLines) * editor.lineHeight
301300 val editorRect = editor.scrollingModel.visibleArea
302- val popupRect = Rectangle (caretPoint.x, yAboveFirstLine , popupSize.width, popupSize.height)
301+ var popupRect = Rectangle (caretPoint.x, yBelowLastLine , popupSize.width, popupSize.height)
303302 var noEnoughSpaceForPopup = false
304303
305304 CodeWhispererInvocationStatus .getInstance().setDisplaySessionActive(true )
306305
307- if (! editorRect.contains(popupRect)) {
308- // popup location above first line don't work, so don't show the popup
309- noEnoughSpaceForPopup = true
310- }
311-
312306 // Check if the current editor still has focus. If not, don't show the popup.
313307 val isSameEditorAsTrigger = if (! AppMode .isRemoteDevHost()) {
314308 editor.contentComponent.isFocusOwner
@@ -321,8 +315,25 @@ class CodeWhispererPopupManager {
321315 return
322316 }
323317
324- // popup to always display above the current editing line
325- val popupLocation = Point (caretPoint.x, yAboveFirstLine)
318+ val popupLocation =
319+ if (! editorRect.contains(popupRect)) {
320+ popupRect = Rectangle (caretPoint.x, yAboveFirstLine, popupSize.width, popupSize.height)
321+ if (! editorRect.contains(popupRect)) {
322+ // both popup location (below last line and above first line) don't work, so don't show the popup
323+ noEnoughSpaceForPopup = true
324+ }
325+ LOG .debug {
326+ " Show popup above the first line of recommendation. " +
327+ " Editor position: $editorRect , popup position: $popupRect "
328+ }
329+ Point (caretPoint.x, yAboveFirstLine)
330+ } else {
331+ LOG .debug {
332+ " Show popup below the last line of recommendation. " +
333+ " Editor position: $editorRect , popup position: $popupRect "
334+ }
335+ Point (caretPoint.x, yBelowLastLine)
336+ }
326337
327338 val relativePopupLocationToEditor = RelativePoint (editor.contentComponent, popupLocation)
328339
@@ -335,12 +346,9 @@ class CodeWhispererPopupManager {
335346 }
336347 } else {
337348 if (! AppMode .isRemoteDevHost()) {
338- if (visible && ! noEnoughSpaceForPopup) {
339- // TODO: will move to a keybinding listener once I found one
340- popupComponents.prevButton.text = popupComponents.prevButtonText()
341- popupComponents.nextButton.text = popupComponents.nextButtonText()
342- popup.show(relativePopupLocationToEditor)
343- }
349+ popupComponents.prevButton.text = popupComponents.prevButtonText()
350+ popupComponents.nextButton.text = popupComponents.nextButtonText()
351+ popup.show(relativePopupLocationToEditor)
344352 } else {
345353 // TODO: For now, the popup will always display below the suggestions, without checking
346354 // if the location the popup is about to show at stays in the editor window or not, due to
@@ -369,27 +377,14 @@ class CodeWhispererPopupManager {
369377 }
370378 }
371379
372- bringSuggestionInlayToFront(editor, popup, sessionContext, ! visible)
373- }
374-
375- // opposite == false: show Q, hide IntelliSense
376- // opposite == true: show IntelliSense, hide Q
377- fun bringSuggestionInlayToFront (
378- editor : Editor ,
379- popup : JBPopup ? ,
380- sessionContext : SessionContext ,
381- opposite : Boolean = false,
382- ) {
383- val qInlinePopupAlpha = if (opposite) 1f else 0.1f
384- val intelliSensePopupAlpha = if (opposite) 0f else 0.8f
385-
386- (popup as AbstractPopup ? )?.popupWindow?.let {
387- WindowManager .getInstance().setAlphaModeRatio(it, qInlinePopupAlpha)
388- }
389- ComponentUtil .getWindow(LookupManager .getActiveLookup(editor)?.component)?.let {
390- WindowManager .getInstance().setAlphaModeRatio(it, intelliSensePopupAlpha)
380+ // popup.popupWindow is null in remote host
381+ if (! AppMode .isRemoteDevHost()) {
382+ if (noEnoughSpaceForPopup) {
383+ WindowManager .getInstance().setAlphaModeRatio(popup.popupWindow, 1f )
384+ } else {
385+ WindowManager .getInstance().setAlphaModeRatio(popup.popupWindow, 0.1f )
386+ }
391387 }
392- sessionContext.isPopupShowing = ! opposite
393388 }
394389
395390 fun initPopup (): JBPopup = JBPopupFactory .getInstance()
@@ -458,13 +453,6 @@ class CodeWhispererPopupManager {
458453 }
459454 }
460455 )
461- states.requestContext.project.messageBus.connect(states).subscribe(
462- LookupManagerListener .TOPIC ,
463- CodeWhispererPopupIntelliSenseAcceptListener (states)
464- )
465- LookupManager .getActiveLookup(states.requestContext.editor)?.let {
466- addIntelliSenseAcceptListener(it, states)
467- }
468456 }
469457
470458 private fun addButtonActionListeners (states : InvocationContext ) {
@@ -556,18 +544,6 @@ class CodeWhispererPopupManager {
556544 window?.addComponentListener(windowListener)
557545 Disposer .register(states) { window?.removeComponentListener(windowListener) }
558546 }
559-
560- val suggestionHoverEnterListener: EditorMouseMotionListener = object : EditorMouseMotionListener {
561- override fun mouseMoved (e : EditorMouseEvent ) {
562- if (e.inlay != null ) {
563- showPopup(states, sessionContext, states.popup, visible = true )
564- } else {
565- bringSuggestionInlayToFront(editor, states.popup, sessionContext, opposite = true )
566- }
567- super .mouseMoved(e)
568- }
569- }
570- editor.addEditorMouseMotionListener(suggestionHoverEnterListener, states)
571547 }
572548
573549 private fun updateSelectedRecommendationLabelText (validSelectedIndex : Int , validCount : Int ) {
0 commit comments