Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"type" : "removal",
"description" : "The Amazon Q inline suggestion popup goes back to being under the suggestions and is always showing."
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@

import com.intellij.codeInsight.hint.ParameterInfoController
import com.intellij.codeInsight.lookup.LookupManager
import com.intellij.codeInsight.lookup.LookupManagerListener
import com.intellij.idea.AppMode
import com.intellij.openapi.actionSystem.IdeActions.ACTION_EDITOR_ENTER
import com.intellij.openapi.actionSystem.IdeActions.ACTION_EDITOR_ESCAPE
Expand All @@ -26,8 +25,6 @@
import com.intellij.openapi.editor.event.CaretListener
import com.intellij.openapi.editor.event.DocumentEvent
import com.intellij.openapi.editor.event.DocumentListener
import com.intellij.openapi.editor.event.EditorMouseEvent
import com.intellij.openapi.editor.event.EditorMouseMotionListener
import com.intellij.openapi.editor.event.SelectionEvent
import com.intellij.openapi.editor.event.SelectionListener
import com.intellij.openapi.fileEditor.FileEditorManager
Expand Down Expand Up @@ -65,10 +62,8 @@
import software.aws.toolkits.jetbrains.services.codewhisperer.popup.listeners.CodeWhispererAcceptButtonActionListener
import software.aws.toolkits.jetbrains.services.codewhisperer.popup.listeners.CodeWhispererActionListener
import software.aws.toolkits.jetbrains.services.codewhisperer.popup.listeners.CodeWhispererNextButtonActionListener
import software.aws.toolkits.jetbrains.services.codewhisperer.popup.listeners.CodeWhispererPopupIntelliSenseAcceptListener
import software.aws.toolkits.jetbrains.services.codewhisperer.popup.listeners.CodeWhispererPrevButtonActionListener
import software.aws.toolkits.jetbrains.services.codewhisperer.popup.listeners.CodeWhispererScrollListener
import software.aws.toolkits.jetbrains.services.codewhisperer.popup.listeners.addIntelliSenseAcceptListener
import software.aws.toolkits.jetbrains.services.codewhisperer.service.CodeWhispererInvocationStatus
import software.aws.toolkits.jetbrains.services.codewhisperer.telemetry.CodeWhispererTelemetryService
import software.aws.toolkits.jetbrains.services.codewhisperer.toolwindow.CodeWhispererCodeReferenceManager
Expand Down Expand Up @@ -224,6 +219,7 @@
fun render(
states: InvocationContext,
sessionContext: SessionContext,
overlappingLinesCount: Int,
isRecommendationAdded: Boolean,
) {
updatePopupPanel(states, sessionContext)
Expand All @@ -246,7 +242,7 @@
states.requestContext.latencyContext.getPerceivedLatency(states.requestContext.triggerTypeInfo.triggerType)
}
if (!isRecommendationAdded) {
showPopup(states, sessionContext, states.popup, visible = sessionContext.isPopupShowing)
showPopup(states, sessionContext, states.popup, overlappingLinesCount)
}
}

Expand Down Expand Up @@ -285,32 +281,30 @@
states: InvocationContext,
sessionContext: SessionContext,
popup: JBPopup,
visible: Boolean = false,
overlappingLinesCount: Int,
) {
val caretPoint = states.requestContext.editor.offsetToXY(states.requestContext.caretPosition.offset)
val editor = states.requestContext.editor
val detailContexts = states.recommendationContext.details
val userInputOriginal = states.recommendationContext.userInputOriginal
val userInput = states.recommendationContext.userInputSinceInvocation
val selectedIndex = sessionContext.selectedIndex
val typeaheadOriginal = sessionContext.typeaheadOriginal
val typeahead = sessionContext.typeahead
val userInputLines = userInputOriginal.split("\n").size - 1
val lineCount = getReformattedRecommendation(detailContexts[selectedIndex], userInput).split("\n").size
val additionalLines = typeaheadOriginal.split("\n").size - typeahead.split("\n").size
val popupSize = (popup as AbstractPopup).preferredContentSize
val yBelowLastLine = caretPoint.y + (lineCount + additionalLines + userInputLines - overlappingLinesCount) * editor.lineHeight
val yAboveFirstLine = caretPoint.y - popupSize.height + (additionalLines + userInputLines) * editor.lineHeight
val editorRect = editor.scrollingModel.visibleArea
val popupRect = Rectangle(caretPoint.x, yAboveFirstLine, popupSize.width, popupSize.height)
var popupRect = Rectangle(caretPoint.x, yBelowLastLine, popupSize.width, popupSize.height)
var noEnoughSpaceForPopup = false

CodeWhispererInvocationStatus.getInstance().setDisplaySessionActive(true)

if (!editorRect.contains(popupRect)) {
// popup location above first line don't work, so don't show the popup
noEnoughSpaceForPopup = true
}

// Check if the current editor still has focus. If not, don't show the popup.
val isSameEditorAsTrigger = if (!AppMode.isRemoteDevHost()) {

Check warning on line 307 in plugins/amazonq/codewhisperer/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codewhisperer/popup/CodeWhispererPopupManager.kt

View workflow job for this annotation

GitHub Actions / qodana

Unstable API Usage

'isRemoteDevHost()' is declared in unstable class 'com.intellij.idea.AppMode' marked with @ApiStatus.Internal
editor.contentComponent.isFocusOwner
} else {
FileEditorManager.getInstance(states.requestContext.project).selectedTextEditorWithRemotes.firstOrNull() == editor
Expand All @@ -321,8 +315,25 @@
return
}

// popup to always display above the current editing line
val popupLocation = Point(caretPoint.x, yAboveFirstLine)
val popupLocation =
if (!editorRect.contains(popupRect)) {
popupRect = Rectangle(caretPoint.x, yAboveFirstLine, popupSize.width, popupSize.height)
if (!editorRect.contains(popupRect)) {
// both popup location (below last line and above first line) don't work, so don't show the popup
noEnoughSpaceForPopup = true
}
LOG.debug {
"Show popup above the first line of recommendation. " +
"Editor position: $editorRect, popup position: $popupRect"
}
Point(caretPoint.x, yAboveFirstLine)
} else {
LOG.debug {
"Show popup below the last line of recommendation. " +
"Editor position: $editorRect, popup position: $popupRect"
}
Point(caretPoint.x, yBelowLastLine)
}

val relativePopupLocationToEditor = RelativePoint(editor.contentComponent, popupLocation)

Expand All @@ -334,13 +345,10 @@
popup.size = popup.preferredContentSize
}
} else {
if (!AppMode.isRemoteDevHost()) {

Check warning on line 348 in plugins/amazonq/codewhisperer/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codewhisperer/popup/CodeWhispererPopupManager.kt

View workflow job for this annotation

GitHub Actions / qodana

Unstable API Usage

'com.intellij.idea.AppMode' is marked unstable with @ApiStatus.Internal
if (visible && !noEnoughSpaceForPopup) {
// TODO: will move to a keybinding listener once I found one
popupComponents.prevButton.text = popupComponents.prevButtonText()
popupComponents.nextButton.text = popupComponents.nextButtonText()
popup.show(relativePopupLocationToEditor)
}
popupComponents.prevButton.text = popupComponents.prevButtonText()
popupComponents.nextButton.text = popupComponents.nextButtonText()
popup.show(relativePopupLocationToEditor)
} else {
// TODO: For now, the popup will always display below the suggestions, without checking
// if the location the popup is about to show at stays in the editor window or not, due to
Expand Down Expand Up @@ -369,27 +377,14 @@
}
}

bringSuggestionInlayToFront(editor, popup, sessionContext, !visible)
}

// opposite == false: show Q, hide IntelliSense
// opposite == true: show IntelliSense, hide Q
fun bringSuggestionInlayToFront(
editor: Editor,
popup: JBPopup?,
sessionContext: SessionContext,
opposite: Boolean = false,
) {
val qInlinePopupAlpha = if (opposite) 1f else 0.1f
val intelliSensePopupAlpha = if (opposite) 0f else 0.8f

(popup as AbstractPopup?)?.popupWindow?.let {
WindowManager.getInstance().setAlphaModeRatio(it, qInlinePopupAlpha)
}
ComponentUtil.getWindow(LookupManager.getActiveLookup(editor)?.component)?.let {
WindowManager.getInstance().setAlphaModeRatio(it, intelliSensePopupAlpha)
// popup.popupWindow is null in remote host
if (!AppMode.isRemoteDevHost()) {
if (noEnoughSpaceForPopup) {
WindowManager.getInstance().setAlphaModeRatio(popup.popupWindow, 1f)
} else {
WindowManager.getInstance().setAlphaModeRatio(popup.popupWindow, 0.1f)
}
}
sessionContext.isPopupShowing = !opposite
}

fun initPopup(): JBPopup = JBPopupFactory.getInstance()
Expand Down Expand Up @@ -458,13 +453,6 @@
}
}
)
states.requestContext.project.messageBus.connect(states).subscribe(
LookupManagerListener.TOPIC,
CodeWhispererPopupIntelliSenseAcceptListener(states)
)
LookupManager.getActiveLookup(states.requestContext.editor)?.let {
addIntelliSenseAcceptListener(it, states)
}
}

private fun addButtonActionListeners(states: InvocationContext) {
Expand Down Expand Up @@ -556,18 +544,6 @@
window?.addComponentListener(windowListener)
Disposer.register(states) { window?.removeComponentListener(windowListener) }
}

val suggestionHoverEnterListener: EditorMouseMotionListener = object : EditorMouseMotionListener {
override fun mouseMoved(e: EditorMouseEvent) {
if (e.inlay != null) {
showPopup(states, sessionContext, states.popup, visible = true)
} else {
bringSuggestionInlayToFront(editor, states.popup, sessionContext, opposite = true)
}
super.mouseMoved(e)
}
}
editor.addEditorMouseMotionListener(suggestionHoverEnterListener, states)
}

private fun updateSelectedRecommendationLabelText(validSelectedIndex: Int, validCount: Int) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -91,14 +91,39 @@ class CodeWhispererUIChangeListener : CodeWhispererPopupStateChangeListener {
CodeWhispererPopupManager.getInstance().render(
states,
sessionContext,
overlappingLinesCount,
isRecommendationAdded = false
)
}

override fun scrolled(states: InvocationContext, sessionContext: SessionContext) {
if (states.popup.isDisposed) return
val editor = states.requestContext.editor
val editorManager = CodeWhispererEditorManager.getInstance()
val selectedIndex = sessionContext.selectedIndex
val typeahead = sessionContext.typeahead
val detail = states.recommendationContext.details[selectedIndex]

// get matching brackets from recommendations to the brackets after caret position
val remaining = CodeWhispererPopupManager.getInstance().getReformattedRecommendation(
detail,
states.recommendationContext.userInputSinceInvocation
).substring(typeahead.length)

val remainingLines = remaining.split("\n")
val otherLinesOfRemaining = remainingLines.drop(1)

// process other lines inlays, where we do tail-head matching as much as possible
val overlappingLinesCount = editorManager.findOverLappingLines(
editor,
otherLinesOfRemaining,
detail.isTruncatedOnRight,
sessionContext
)
CodeWhispererPopupManager.getInstance().render(
states,
sessionContext,
overlappingLinesCount,
isRecommendationAdded = false
)
}
Expand All @@ -107,6 +132,7 @@ class CodeWhispererUIChangeListener : CodeWhispererPopupStateChangeListener {
CodeWhispererPopupManager.getInstance().render(
states,
sessionContext,
0,
isRecommendationAdded = true
)
}
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -699,7 +699,7 @@ class CodeWhispererService(private val cs: CoroutineScope) : Disposable {
recommendationContext: RecommendationContext,
popup: JBPopup,
): InvocationContext {
addPopupChildDisposables(requestContext.project, requestContext.editor, popup)
addPopupChildDisposables(popup)
// Creating a disposable for managing all listeners lifecycle attached to the popup.
// previously(before pagination) we use popup as the parent disposable.
// After pagination, listeners need to be updated as states are updated, for the same popup,
Expand All @@ -711,25 +711,12 @@ class CodeWhispererService(private val cs: CoroutineScope) : Disposable {
return states
}

private fun addPopupChildDisposables(project: Project, editor: Editor, popup: JBPopup) {
private fun addPopupChildDisposables(popup: JBPopup) {
codeInsightSettingsFacade.disableCodeInsightUntil(popup)

Disposer.register(popup) {
CodeWhispererPopupManager.getInstance().reset()
}
project.messageBus.connect(popup).subscribe(
CodeWhispererServiceNew.CODEWHISPERER_INTELLISENSE_POPUP_ON_HOVER,
object : CodeWhispererIntelliSenseOnHoverListener {
override fun onEnter() {
CodeWhispererPopupManager.getInstance().bringSuggestionInlayToFront(
editor,
popup,
CodeWhispererPopupManager.getInstance().sessionContext,
opposite = true
)
}
}
)
}

private fun logServiceInvocation(
Expand Down
Loading