diff --git a/src/main/kotlin/io/snyk/plugin/DiffPatcher.kt b/src/main/kotlin/io/snyk/plugin/DiffPatcher.kt index 5d4e28006..4eb2aee14 100644 --- a/src/main/kotlin/io/snyk/plugin/DiffPatcher.kt +++ b/src/main/kotlin/io/snyk/plugin/DiffPatcher.kt @@ -1,8 +1,24 @@ package io.snyk.plugin -import io.snyk.plugin.ui.jcef.Change -import io.snyk.plugin.ui.jcef.DiffPatch -import io.snyk.plugin.ui.jcef.Hunk +data class DiffPatch( + val originalFile: String, + val fixedFile: String, + val hunks: List +) + +data class Hunk( + val startLineOriginal: Int, + val numLinesOriginal: Int, + val startLineFixed: Int, + val numLinesFixed: Int, + val changes: List +) + +sealed class Change { + data class Addition(val line: String) : Change() + data class Deletion(val line: String) : Change() + data class Context(val line: String) : Change() // Unchanged line for context +} class DiffPatcher { diff --git a/src/main/kotlin/io/snyk/plugin/ui/jcef/ApplyFixHandler.kt b/src/main/kotlin/io/snyk/plugin/ui/jcef/ApplyFixHandler.kt index 952835236..dd26ff6ae 100644 --- a/src/main/kotlin/io/snyk/plugin/ui/jcef/ApplyFixHandler.kt +++ b/src/main/kotlin/io/snyk/plugin/ui/jcef/ApplyFixHandler.kt @@ -2,6 +2,7 @@ package io.snyk.plugin.ui.jcef import com.intellij.openapi.application.ApplicationManager import com.intellij.openapi.command.WriteCommandAction +import com.intellij.openapi.diagnostic.LogLevel import com.intellij.openapi.diagnostic.Logger import com.intellij.openapi.fileEditor.FileDocumentManager import com.intellij.openapi.project.Project @@ -14,34 +15,17 @@ import org.cef.browser.CefFrame import org.cef.handler.CefLoadHandlerAdapter import org.jetbrains.concurrency.runAsync import io.snyk.plugin.ui.SnykBalloonNotificationHelper +import snyk.common.lsp.LanguageServerWrapper import java.io.IOException - -data class DiffPatch( - val originalFile: String, - val fixedFile: String, - val hunks: List -) - -data class Hunk( - val startLineOriginal: Int, - val numLinesOriginal: Int, - val startLineFixed: Int, - val numLinesFixed: Int, - val changes: List -) - -sealed class Change { - data class Addition(val line: String) : Change() - data class Deletion(val line: String) : Change() - data class Context(val line: String) : Change() // Unchanged line for context -} - class ApplyFixHandler(private val project: Project) { - private val enableDebug = Logger.getInstance("Snyk Language Server").isDebugEnabled - private val enableTrace = Logger.getInstance("Snyk Language Server").isTraceEnabled - private val logger = Logger.getInstance(this::class.java) + val logger = Logger.getInstance(this::class.java).apply { + // tie log level to language server log level + val languageServerWrapper = LanguageServerWrapper.getInstance() + if (languageServerWrapper.logger.isDebugEnabled) this.setLevel(LogLevel.DEBUG) + if (languageServerWrapper.logger.isTraceEnabled) this.setLevel(LogLevel.TRACE) + } fun generateApplyFixCommand(jbCefBrowser: JBCefBrowserBase): CefLoadHandlerAdapter { @@ -54,32 +38,30 @@ class ApplyFixHandler(private val project: Project) { // Avoid blocking the UI thread runAsync { - //var success = true val result = try { applyPatchAndSave(project, filePath, patch) } catch (e: IOException) { // Catch specific file-related exceptions - log("Error applying patch to file: $filePath. e:$e") + logger.error("Error applying patch to file: $filePath. e:$e") Result.failure(e) } catch (e: Exception) { - log("Unexpected error applying patch. e:$e") + logger.error("Unexpected error applying patch. e:$e") Result.failure(e) } - ApplicationManager.getApplication().invokeLater { - if (result.isSuccess) { - val script = """ + if (result.isSuccess) { + val script = """ window.receiveApplyFixResponse(true); """.trimIndent() - jbCefBrowser.cefBrowser.executeJavaScript(script, jbCefBrowser.cefBrowser.url, 0) - } else { - val errorMessage = "Error applying fix: ${result.exceptionOrNull()?.message}" - SnykBalloonNotificationHelper.showError(errorMessage, project) - val errorScript = """ + jbCefBrowser.cefBrowser.executeJavaScript(script, jbCefBrowser.cefBrowser.url, 0) + } else { + val errorMessage = "Error applying fix: ${result.exceptionOrNull()?.message}" + SnykBalloonNotificationHelper.showError(errorMessage, project) + val errorScript = """ window.receiveApplyFixResponse(false, "$errorMessage"); """.trimIndent() - jbCefBrowser.cefBrowser.executeJavaScript(errorScript, jbCefBrowser.cefBrowser.url, 0) - } + jbCefBrowser.cefBrowser.executeJavaScript(errorScript, jbCefBrowser.cefBrowser.url, 0) } + } return@addHandler JBCefJSQuery.Response("success") } @@ -105,34 +87,21 @@ class ApplyFixHandler(private val project: Project) { val virtualFile = filePath.toVirtualFile() val patcher = DiffPatcher() - return try { - WriteCommandAction.runWriteCommandAction(project) { - val document = FileDocumentManager.getInstance().getDocument(virtualFile) - if (document != null) { - val originalContent = document.text - val patchedContent = patcher.applyPatch(originalContent, patcher.parseDiff(patch)) - if (originalContent != patchedContent) { - document.setText(patchedContent) - } else { - log("[applyPatchAndSave] Patch did not modify content: $filePath") - } + WriteCommandAction.runWriteCommandAction(project) { + val document = FileDocumentManager.getInstance().getDocument(virtualFile) + if (document != null) { + val originalContent = document.text + val patchedContent = patcher.applyPatch(originalContent, patcher.parseDiff(patch)) + if (originalContent != patchedContent) { + document.setText(patchedContent) } else { - log("[applyPatchAndSave] Failed to find document for: $filePath") - return@runWriteCommandAction + logger.warn("[applyPatchAndSave] Patch did not modify content: $filePath") } + } else { + logger.error("[applyPatchAndSave] Failed to find document for: $filePath") + return@runWriteCommandAction } - Result.success(Unit) - } catch (e: Exception) { - log("[applyPatchAndSave] Error applying patch to: $filePath. e: $e") - Result.failure(e) - } - } - - private fun log(logMessage: String) { - when { - enableDebug -> logger.debug(logMessage) - enableTrace -> logger.trace(logMessage) - else -> logger.error(logMessage) } + return Result.success(Unit) } } diff --git a/src/main/kotlin/snyk/common/lsp/LanguageServerWrapper.kt b/src/main/kotlin/snyk/common/lsp/LanguageServerWrapper.kt index 1bbb72f05..13dbfdffc 100644 --- a/src/main/kotlin/snyk/common/lsp/LanguageServerWrapper.kt +++ b/src/main/kotlin/snyk/common/lsp/LanguageServerWrapper.kt @@ -1,8 +1,6 @@ package snyk.common.lsp import com.google.gson.Gson -import com.google.gson.annotations.SerializedName -import com.google.gson.reflect.TypeToken import com.intellij.openapi.Disposable import com.intellij.openapi.application.ApplicationManager import com.intellij.openapi.components.service @@ -497,11 +495,6 @@ class LanguageServerWrapper( return this.getFeatureFlagStatus("snykCodeConsistentIgnores") } - data class Fix( - @SerializedName("fixId") val fixId: String, - @SerializedName("unifiedDiffsPerFile") val unifiedDiffsPerFile: Map - ) - @Suppress("UNCHECKED_CAST") fun sendCodeFixDiffsCommand(folderURI: String, fileURI: String, issueID: String): List { if (!ensureLanguageServerInitialized()) return emptyList() diff --git a/src/main/kotlin/snyk/common/lsp/Types.kt b/src/main/kotlin/snyk/common/lsp/Types.kt index 3553a3305..fe88f5c35 100644 --- a/src/main/kotlin/snyk/common/lsp/Types.kt +++ b/src/main/kotlin/snyk/common/lsp/Types.kt @@ -337,6 +337,11 @@ data class ExampleCommitFix( @SerializedName("lines") val lines: List, ) +data class Fix( + @SerializedName("fixId") val fixId: String, + @SerializedName("unifiedDiffsPerFile") val unifiedDiffsPerFile: Map +) + data class CommitChangeLine( @SerializedName("line") val line: String, @SerializedName("lineNumber") val lineNumber: Int,