Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
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
15 changes: 15 additions & 0 deletions CodeReferenceActionListener.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package co.bito.intellij.codeCompletion.toolwindow

import com.intellij.openapi.editor.RangeMarker
import co.bito.intellij.codeCompletion.model.InvocationContext
import co.bito.intellij.codeCompletion.model.SessionContext
import co.bito.intellij.codeCompletion.popup.UserActionListener

class CodeReferenceActionListener : UserActionListener {
override fun afterAccept(states: InvocationContext, sessionContext: SessionContext, rangeMarker: RangeMarker) {
val (project, editor) = states.requestContext
val manager = CodeReferenceManager.getInstance(project)
manager.insertCodeReference(states, sessionContext.selectedIndex)

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bito Code Review Agent Run #0911d8 - 06/28/2024, 10:10 am

🔴 High importance
Issue: The method 'insertCodeReference' is called without checking if 'manager' is null. If 'CodeReferenceManager.getInstance(project)' returns null, this will lead to a NullPointerException.
Fix: Add a null check for 'manager' before calling 'insertCodeReference' and 'addListeners' methods.
Code suggestion
 @@ -11,6 +11,10 @@
      val manager = CodeReferenceManager.getInstance(project)
 +    if (manager != null) {
      manager.insertCodeReference(states, sessionContext.selectedIndex)
      manager.addListeners(editor)
 +    } else {
 +        // Handle the case where manager is null, possibly log an error or throw an exception
 +    }

manager.addListeners(editor)
}
}
154 changes: 154 additions & 0 deletions CodeReferenceComponents.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,154 @@
package co.bito.intellij.codeCompletion.toolwindow

import com.intellij.ide.BrowserUtil
import com.intellij.openapi.editor.colors.EditorColorsManager
import com.intellij.openapi.options.ShowSettingsUtil
import com.intellij.openapi.project.Project
import com.intellij.ui.components.ActionLink
import software.amazon.awssdk.services.codewhispererruntime.model.Reference
// import software.aws.toolkits.jetbrains.core.credentials.ToolkitConnection
// import software.aws.toolkits.jetbrains.core.credentials.ToolkitConnectionManagerListener
import co.bito.intellij.codeCompletion.credentials.CodeWhispererLoginType
import co.bito.intellij.codeCompletion.explorer.CodeWhispererExplorerActionManager
import co.bito.intellij.codeCompletion.layout.CodeWhispererLayoutConfig.addHorizontalGlue
import co.bito.intellij.codeCompletion.layout.CodeWhispererLayoutConfig.addVerticalGlue
import co.bito.intellij.codeCompletion.layout.CodeWhispererLayoutConfig.horizontalPanelConstraints
import co.bito.intellij.codeCompletion.layout.CodeWhispererLayoutConfig.inlineLabelConstraints
import co.bito.intellij.codeCompletion.service.CodeWhispererLicenseInfoManager
import co.bito.intellij.codeCompletion.settings.CodeWhispererConfigurable
import co.bito.intellij.codeCompletion.util.CodeWhispererColorUtil.TOOLWINDOW_BACKGROUND
import co.bito.intellij.codeCompletion.util.CodeWhispererColorUtil.TOOLWINDOW_CODE
import software.aws.toolkits.resources.message
import java.awt.Font
import java.awt.GridBagLayout
import java.time.LocalTime
import java.time.format.DateTimeFormatter
import javax.swing.BorderFactory
import javax.swing.JComponent
import javax.swing.JLabel
import javax.swing.JPanel

class CodeWhispererCodeReferenceComponents(private val project: Project) {
// private val settingsLabelPrefixText = JLabel().apply {
// text = message("codewhisperer.toolwindow.settings.prefix")
// }.asCodeReferencePanelFont()

// private val settingsLabelLink = ActionLink().apply {
// text = message("codewhisperer.toolwindow.settings")
// addActionListener {
// ShowSettingsUtil.getInstance().showSettingsDialog(project, CodeWhispererConfigurable::class.java)
// }
// }.asCodeReferencePanelFont()

// private val settingsPanel = JPanel(GridBagLayout()).apply {
// background = TOOLWINDOW_BACKGROUND
// border = BorderFactory.createEmptyBorder(0, 0, 17, 0)
// add(settingsLabelPrefixText, inlineLabelConstraints)
// add(settingsLabelLink, inlineLabelConstraints)
// add(JLabel("."), inlineLabelConstraints)
// addHorizontalGlue()
// }
val contentPanel = JPanel(GridBagLayout()).apply {
background = TOOLWINDOW_BACKGROUND
border = BorderFactory.createEmptyBorder(7, 14, 0, 0)
// add(settingsPanel, horizontalPanelConstraints)
addVerticalGlue()
}

private val codeReferenceTimeFormatter = DateTimeFormatter.ofPattern("HH:mm:ss")
private val acceptRecommendationPrefixText
get() = JLabel().apply {
text = message("codewhisperer.toolwindow.entry.prefix", LocalTime.now().format(codeReferenceTimeFormatter))
}.asCodeReferencePanelFont()

init {
repaint(project)

// set the reference panel text different for SSO users vs AWS Builder ID / Accless users
// project.messageBus.connect().subscribe(
// ToolkitConnectionManagerListener.TOPIC,
// object : ToolkitConnectionManagerListener {
// override fun activeConnectionChanged(newConnection: ToolkitConnection?) {
// repaint(project)
// }
// }
// )
}

// TODO: figure out how to have a different view for SSO user in a cleaner way, maybe have 2 sets of components stored in [ReferenceManager]?
private fun repaint(project: Project) {
// val loginType = CodeWhispererExplorerActionManager.getInstance().checkActiveCodeWhispererConnectionType(project)
// settingsLabelPrefixText as JLabel
// settingsLabelLink as ActionLink
// if (loginType == CodeWhispererLoginType.SSO) {
// settingsLabelPrefixText.text = message("codewhisperer.toolwindow.settings.prefix_sso")
// settingsLabelLink.isVisible = false
// } else {
// settingsLabelPrefixText.text = message("codewhisperer.toolwindow.settings.prefix")
// settingsLabelLink.isVisible = true
// }
}

private fun licenseNameLink(licenseName: String) = ActionLink(licenseName) {
BrowserUtil.browse(CodeWhispererLicenseInfoManager.getInstance().getLicenseLink(licenseName))
}.asCodeReferencePanelFont()

private fun repoNameLink(repo: String, url: String) = ActionLink(repo) {
BrowserUtil.browse(url)
}.asCodeReferencePanelFont()

private fun acceptRecommendationSuffixText(path: String?, line: String) = JLabel().apply {
val choice = if (path != null) 1 else 0
text = message("codewhisperer.toolwindow.entry.suffix", path ?: "", choice, line)
}.asCodeReferencePanelFont()

fun codeReferenceRecordPanel(ref: Reference, relativePath: String?, lineNums: String) = JPanel(GridBagLayout()).apply {
background = EditorColorsManager.getInstance().globalScheme.defaultBackground
border = BorderFactory.createEmptyBorder(5, 0, 0, 0)
add(acceptRecommendationPrefixText, inlineLabelConstraints)

// if url to source package/repo is missing, the UX remains the same as we have for now
// if url to source package/repo is present, the url pointing to the source will be present and remove the hyperlink to SPDX
if (ref.url().isNullOrEmpty()) {
add(
licenseNameLink(ref.licenseName()).apply {
font = font.deriveFont(Font.ITALIC + Font.BOLD)
},
inlineLabelConstraints
)
add(JLabel(" from ").asCodeReferencePanelFont(), inlineLabelConstraints)
add(JLabel(ref.repository()), inlineLabelConstraints)
} else {
add(
JLabel(ref.licenseName()).apply {
font = font.deriveFont(Font.ITALIC + Font.BOLD)
},
inlineLabelConstraints
)
add(JLabel(" from ").asCodeReferencePanelFont(), inlineLabelConstraints)
add(repoNameLink(ref.repository(), ref.url()), inlineLabelConstraints)
}

add(acceptRecommendationSuffixText(relativePath, lineNums), inlineLabelConstraints)
addHorizontalGlue()
}

fun codeContentLine(line: String) = JLabel(line).apply {
foreground = TOOLWINDOW_CODE
}.asCodeReferencePanelFont()

fun codeContentPanel(line: String) = JPanel(GridBagLayout()).apply {
background = EditorColorsManager.getInstance().globalScheme.defaultBackground
if (line == "") {
add(codeContentLine(" "), inlineLabelConstraints)
} else {
add(codeContentLine(line), inlineLabelConstraints)
}
addHorizontalGlue()
}

private fun JComponent.asCodeReferencePanelFont(): JComponent {
font = Font("JetBrains mono", font.style, font.size)
return this
}
}
Empty file added CodeReferenceManager.kt
Empty file.