Skip to content

Commit 6bb7802

Browse files
committed
feat: apply fix command
1 parent 529d605 commit 6bb7802

6 files changed

Lines changed: 156 additions & 60 deletions

File tree

plugin/src/main/java/io/snyk/eclipse/plugin/html/BaseHtmlProvider.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -119,9 +119,10 @@ public String replaceCssVariables(String html) {
119119
getColorAsHex("org.eclipse.ui.workbench.INACTIVE_TAB_BG_START", "#F0F0F0"));
120120
htmlStyled = htmlStyled.replace("var(--circle-color)",
121121
getColorAsHex("org.eclipse.ui.workbench.INACTIVE_TAB_BG_START", "#F0F0F0"));
122-
123122
htmlStyled = htmlStyled.replace("var(--border-color)",
124123
getColorAsHex("org.eclipse.ui.workbench.ACTIVE_TAB_OUTER_KEYLINE_COLOR", "#CCCCCC"));
124+
htmlStyled = htmlStyled.replace("var(--input-border)",
125+
getColorAsHex("org.eclipse.ui.workbench.ACTIVE_TAB_OUTER_KEYLINE_COLOR", "#CCCCCC"));
125126
htmlStyled = htmlStyled.replace("var(--link-color)", getColorAsHex("ACTIVE_HYPERLINK_COLOR", "#0000FF"));
126127
htmlStyled = htmlStyled.replace("var(--horizontal-border-color)",
127128
getColorAsHex("org.eclipse.ui.workbench.ACTIVE_TAB_OUTER_KEYLINE_COLOR", "#CCCCCC"));

plugin/src/main/java/io/snyk/eclipse/plugin/html/CodeHtmlProvider.java

Lines changed: 78 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
import io.snyk.eclipse.plugin.preferences.Preferences;
44

55
public class CodeHtmlProvider extends BaseHtmlProvider {
6-
private static CodeHtmlProvider instance = new CodeHtmlProvider();
6+
private static CodeHtmlProvider instance = new CodeHtmlProvider();
77

88
public static CodeHtmlProvider getInstance() {
99
synchronized (CodeHtmlProvider.class) {
@@ -16,61 +16,85 @@ public static CodeHtmlProvider getInstance() {
1616
return instance;
1717
}
1818

19-
@Override
20-
public String getInitScript() {
21-
String themeScript = getThemeScript();
22-
String initScript = super.getInitScript();
23-
return initScript + "\n" + """
24-
function navigateToIssue(e, target) {
25-
e.preventDefault();
26-
var filePath = target.getAttribute('file-path');
27-
var startLine = target.getAttribute('start-line');
28-
var endLine = target.getAttribute('end-line');
29-
var startCharacter = target.getAttribute('start-character');
30-
var endCharacter = target.getAttribute('end-character');
31-
window.openInEditor(filePath, startLine, endLine, startCharacter, endCharacter);
32-
}
33-
var navigatableLines = document.getElementsByClassName('data-flow-clickable-row');
34-
for(var i = 0; i < navigatableLines.length; i++) {
35-
navigatableLines[i].onclick = function(e) {
36-
navigateToIssue(e, this);
37-
return false;
38-
};
39-
}
40-
if(document.getElementById('position-line')) {
41-
document.getElementById('position-line').onclick = function(e) {
42-
var target = navigatableLines[0];
43-
if(target) {
44-
navigateToIssue(e, target);
45-
}
46-
}
47-
}
48-
// Disable AIfix
49-
if(document.getElementById('ai-fix-wrapper') && document.getElementById('no-ai-fix-wrapper')){
50-
document.getElementById('ai-fix-wrapper').className = 'hidden';
51-
document.getElementById('no-ai-fix-wrapper').className = '';
52-
}
53-
""" + themeScript;
54-
}
19+
@Override
20+
public String getInitScript() {
21+
String themeScript = getThemeScript();
22+
String initScript = super.getInitScript();
23+
return initScript + "\n" + """
24+
function navigateToIssue(e, target) {
25+
e.preventDefault();
26+
var filePath = target.getAttribute('file-path');
27+
var startLine = target.getAttribute('start-line');
28+
var endLine = target.getAttribute('end-line');
29+
var startCharacter = target.getAttribute('start-character');
30+
var endCharacter = target.getAttribute('end-character');
31+
window.openInEditor(filePath, startLine, endLine, startCharacter, endCharacter);
32+
}
33+
var navigatableLines = document.getElementsByClassName('data-flow-clickable-row');
34+
for(var i = 0; i < navigatableLines.length; i++) {
35+
navigatableLines[i].onclick = function(e) {
36+
navigateToIssue(e, this);
37+
return false;
38+
};
39+
}
40+
if(document.getElementById('position-line')) {
41+
document.getElementById('position-line').onclick = function(e) {
42+
var target = navigatableLines[0];
43+
if(target) {
44+
navigateToIssue(e, target);
45+
}
46+
}
47+
}
48+
""" + themeScript;
49+
}
50+
51+
private String getThemeScript() {
52+
if (Preferences.getInstance().isTest()) {
53+
return "";
54+
}
55+
56+
String themeScript = "var isDarkTheme = " + isDarkTheme() + ";\n"
57+
+ "document.body.classList.add(isDarkTheme ? 'dark' : 'light');";
58+
return themeScript;
59+
}
60+
61+
@Override
62+
public String replaceCssVariables(String html) {
63+
String htmlStyled = super.replaceCssVariables(html);
64+
65+
// Replace CSS variables with actual color values
66+
htmlStyled = htmlStyled.replace("var(--example-line-removed-color)",
67+
super.getColorAsHex("DELETION_COLOR", "#ff0000"));
68+
htmlStyled = htmlStyled.replace("var(--example-line-added-color)",
69+
super.getColorAsHex("ADDITION_COLOR", "#00ff00"));
70+
htmlStyled = htmlStyled.replace("var(--generated-ai-fix-button-background-color)",
71+
// super.getColorAsHex("org.eclipse.ui.workbench.INACTIVE_TAB_BG_START", "#F0F0F0"));
72+
super.getColorAsHex("ADDITION_COLOR", "#00ff00"));
73+
htmlStyled = htmlStyled.replace("var(--disabled-background-color)",
74+
super.getColorAsHex("ADDITION_COLOR", "#00ff00"));
5575

56-
private String getThemeScript() {
57-
if(Preferences.getInstance().isTest()) {
58-
return "";
59-
}
76+
String htmlWithScripts = getReplaceAIFixScripts(htmlStyled);
6077

61-
String themeScript = "var isDarkTheme = " + isDarkTheme() + ";\n" +
62-
"document.body.classList.add(isDarkTheme ? 'dark' : 'light');";
63-
return themeScript;
64-
}
78+
return htmlWithScripts;
79+
}
80+
81+
private String getReplaceAIFixScripts(String html) {
82+
String htmlWithGenerateFunc = html.replace("${ideGenerateAIFix}", getGenerateAiFixScript());
83+
String htmlWithApplyFunc = htmlWithGenerateFunc.replace("${ideApplyAIFix}", getApplyAiFixScript());
84+
85+
return htmlWithApplyFunc;
86+
}
6587

66-
@Override
67-
public String replaceCssVariables(String html) {
68-
String htmlStyled = super.replaceCssVariables(html);
69-
70-
// Replace CSS variables with actual color values
71-
htmlStyled = htmlStyled.replace("var(--example-line-removed-color)", super.getColorAsHex("DELETION_COLOR", "#ff0000"));
72-
htmlStyled = htmlStyled.replace("var(--example-line-added-color)", super.getColorAsHex("ADDITION_COLOR", "#00ff00"));
88+
private String getGenerateAiFixScript() {
89+
// TODO this script is broken, does not trigger a generate
90+
return "const issueId = generateAIFixButton.getAttribute('issue-id');\n"
91+
+ "const folderPath = generateAIFixButton.getAttribute('folder-path');\n"
92+
+ "const filePath = generateAIFixButton.getAttribute('file-path');\n" + "console.log(filePath);\n"
93+
+ "window.generateAIFix(folderPath + \"@|@\" + filePath + \"@|@\" + issueId);";
94+
}
95+
96+
private String getApplyAiFixScript() {
97+
return "window.applyAIFix(fixId + '|@' + filePath + '|@' + patch);\n";
98+
}
7399

74-
return htmlStyled;
75-
}
76100
}

plugin/src/main/java/io/snyk/eclipse/plugin/views/snyktoolview/BrowserHandler.java

Lines changed: 54 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import static org.apache.commons.lang3.StringUtils.isEmpty;
44

55
import java.nio.file.Paths;
6+
import java.util.List;
67
import java.util.concurrent.CompletableFuture;
78

89
import org.eclipse.core.commands.common.CommandException;
@@ -31,6 +32,8 @@
3132
import io.snyk.eclipse.plugin.utils.SnykLogger;
3233
import io.snyk.eclipse.plugin.views.snyktoolview.handlers.IHandlerCommands;
3334
import io.snyk.eclipse.plugin.wizards.SnykWizard;
35+
import io.snyk.languageserver.protocolextension.SnykExtendedLanguageClient;
36+
import io.snyk.languageserver.protocolextension.messageObjects.Fix;
3437

3538
@SuppressWarnings("restriction")
3639
public class BrowserHandler {
@@ -84,13 +87,45 @@ public Object function(Object[] arguments) {
8487
new BrowserFunction(browser, "stopScan") {
8588
@Override
8689
public Object function(Object[] arguments) {
87-
IHandlerService handlerService =
88-
(IHandlerService) PlatformUI.getWorkbench().getService(IHandlerService.class);
90+
IHandlerService handlerService = (IHandlerService) PlatformUI.getWorkbench()
91+
.getService(IHandlerService.class);
92+
8993
try {
9094
handlerService.executeCommand(IHandlerCommands.STOP_SCAN, null);
9195
} catch (CommandException e) {
9296
SnykLogger.logError(e);
93-
}
97+
}
98+
return null;
99+
}
100+
};
101+
102+
new BrowserFunction(browser, "generateAIFix") {
103+
@Override
104+
public Object function(Object[] arguments) {
105+
browser.execute("debugger;"); // Triggers a breakpoint for debugging
106+
System.out.println("generateAIFix");
107+
SnykLogger.logInfo("generateAIFix");
108+
109+
String folderURI = (String) arguments[0];
110+
String fileURI = (String) arguments[1];
111+
String issueID = (String) arguments[2];
112+
113+
// Do we want to capture and do something with the responseDiffs here?
114+
List<Fix> responseDiffs = SnykExtendedLanguageClient.getInstance().sendCodeFixDiffsCommand(folderURI,
115+
fileURI, issueID);
116+
117+
return null;
118+
}
119+
};
120+
121+
new BrowserFunction(browser, "applyAIFix") {
122+
@Override
123+
public Object function(Object[] arguments) {
124+
System.out.println("applyAIFix");
125+
SnykLogger.logInfo("applyAIFix");
126+
127+
String fixId = (String) arguments[0];
128+
SnykExtendedLanguageClient.getInstance().sendCodeApplyAiFixEditCommand(fixId);
94129
return null;
95130
}
96131
};
@@ -158,7 +193,20 @@ public CompletableFuture<Void> updateBrowserContent(TreeNode node) {
158193
}
159194

160195
final var browserContent = htmlProvider.replaceCssVariables(htmlContent);
161-
196+
197+
// String[] lines = browserContent.split("\n");
198+
// for (String line : lines) {
199+
// if (line.contains("window.generateAIFix")) {
200+
// System.out.println(line);
201+
// } else if (line.contains("applyAIFix")) {
202+
// System.out.println(line);
203+
// } else if (line.contains("issue-id")) {
204+
// System.out.println(line);
205+
// } else if (line.contains("folder-path")) {
206+
// System.out.println(line);
207+
// }
208+
// }
209+
162210
Display.getDefault().syncExec(() -> {
163211
browser.setText(browserContent);
164212
});
@@ -191,7 +239,8 @@ public String generateHtmlContent(String text) {
191239
}
192240

193241
public void setDefaultBrowserText() {
194-
// If we are not authenticated, show the welcome page, else show the issue placeholder.
242+
// If we are not authenticated, show the welcome page, else show the issue
243+
// placeholder.
195244
if (Preferences.getInstance().getAuthToken().isBlank()) {
196245
browser.setText(StaticPageHtmlProvider.getInstance().getInitHtml());
197246
} else {

plugin/src/main/java/io/snyk/languageserver/LsConstants.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ private LsConstants() {
1717
public static final String COMMAND_REPORT_ANALYTICS = "snyk.reportAnalytics";
1818
public static final String COMMAND_GET_FEATURE_FLAG_STATUS = "snyk.getFeatureFlagStatus";
1919
public static final String COMMAND_CODE_FIX_DIFFS = "snyk.code.fixDiffs";
20+
public static final String COMMAND_CODE_FIX_APPLY_AI_EDIT = "$/snyk.code.fixApplyEdit";
2021
public static final String COMMAND_CODE_SUBMIT_FIX_FEEDBACK = "snyk.code.submitFixFeedback";
2122
public static final String COMMAND_SNYK_CLI = "snyk.executeCLI";
2223
public static final String SNYK_HAS_AUTHENTICATED = "$/snyk.hasAuthenticated";

plugin/src/main/java/io/snyk/languageserver/protocolextension/SnykExtendedLanguageClient.java

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,7 @@
9696
import io.snyk.languageserver.SnykLanguageServer;
9797
import io.snyk.languageserver.protocolextension.messageObjects.Diagnostic316;
9898
import io.snyk.languageserver.protocolextension.messageObjects.FeatureFlagStatus;
99+
import io.snyk.languageserver.protocolextension.messageObjects.Fix;
99100
import io.snyk.languageserver.protocolextension.messageObjects.FolderConfig;
100101
import io.snyk.languageserver.protocolextension.messageObjects.FolderConfigsParam;
101102
import io.snyk.languageserver.protocolextension.messageObjects.HasAuthenticatedParam;
@@ -869,4 +870,13 @@ public void setLs(LanguageServer ls) {
869870
this.ls = ls;
870871
}
871872

873+
public List<Fix> sendCodeFixDiffsCommand(String folderURI, String fileURI, String issueID) {
874+
// TODO: capture and return results
875+
executeCommand(LsConstants.COMMAND_CODE_FIX_DIFFS, List.of(folderURI, fileURI, issueID));
876+
return null;
877+
}
878+
879+
public void sendCodeApplyAiFixEditCommand(String fixId) {
880+
executeCommand(LsConstants.COMMAND_CODE_FIX_APPLY_AI_EDIT, List.of(fixId));
881+
}
872882
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
package io.snyk.languageserver.protocolextension.messageObjects;
2+
3+
import java.util.Map;
4+
5+
import com.google.gson.annotations.SerializedName;
6+
7+
public record Fix(
8+
@SerializedName("fixId") String fixId,
9+
@SerializedName("unifiedDiffsPerFile") Map<String, String> unifiedDiffsPerFile) {
10+
// no-arg constructor is generated automatically by Java compiler
11+
}

0 commit comments

Comments
 (0)