Skip to content

Commit 084d3a9

Browse files
committed
Apply edit via LSP. Fix maven changes
1 parent 3149708 commit 084d3a9

File tree

5 files changed

+75
-88
lines changed

5 files changed

+75
-88
lines changed

headless-services/commons/commons-rewrite/src/main/java/org/springframework/ide/vscode/commons/rewrite/ORDocUtils.java

Lines changed: 10 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -161,17 +161,10 @@ public static Optional<WorkspaceEdit> createWorkspaceEdit(SimpleTextDocumentServ
161161
WorkspaceEdit we = new WorkspaceEdit();
162162
we.setDocumentChanges(new ArrayList<>());
163163
for (Result result : results) {
164-
if (result.getBefore() == null) {
165-
String docUri = result.getAfter().getSourcePath().toUri().toASCIIString();
166-
createNewFileEdit(docUri, result.getAfter().printAll(), changeAnnotationId, we);
167-
} else if (result.getAfter() == null) {
168-
String docUri = result.getBefore().getSourcePath().toUri().toASCIIString();
169-
createDeleteFileEdit(docUri, we);
170-
} else {
171-
String docUri = result.getBefore().getSourcePath().toUri().toASCIIString();
172-
createUpdateFileEdit(documents, docUri, result.getBefore().printAll(), result.getAfter().printAll(), changeAnnotationId, we);
173-
}
174-
164+
String docUri = result.getBefore() == null ? result.getAfter().getSourcePath().toUri().toASCIIString() : result.getBefore().getSourcePath().toUri().toASCIIString();
165+
String oldContent = result.getBefore() == null ? null : result.getBefore().printAll();
166+
String newContent = result.getAfter() == null ? null : result.getAfter().printAll();
167+
createWorkspaceEdit(documents, docUri, oldContent, newContent, changeAnnotationId, we);
175168
}
176169
return Optional.of(we);
177170
}
@@ -180,7 +173,7 @@ public static void createWorkspaceEdit(SimpleTextDocumentService documents, Stri
180173
if(oldContent == null) {
181174
createNewFileEdit(docUri, newContent, changeAnnotationId, we);
182175
} else if (newContent == null) {
183-
createDeleteFileEdit(docUri, we);
176+
createDeleteFileEdit(docUri, changeAnnotationId, we);
184177
} else {
185178
createUpdateFileEdit(documents, docUri, oldContent, newContent, changeAnnotationId, we);
186179
}
@@ -190,6 +183,7 @@ private static void createNewFileEdit(String docUri, String newContent, String c
190183
WorkspaceEdit we) {
191184
CreateFile ro = new CreateFile();
192185
ro.setUri(docUri);
186+
ro.setAnnotationId(changeAnnotationId);
193187
we.getDocumentChanges().add(Either.forRight(ro));
194188

195189
TextDocumentEdit te = new TextDocumentEdit();
@@ -199,8 +193,10 @@ private static void createNewFileEdit(String docUri, String newContent, String c
199193
we.getDocumentChanges().add(Either.forLeft(te));
200194
}
201195

202-
private static void createDeleteFileEdit(String docUri, WorkspaceEdit we) {
203-
we.getDocumentChanges().add(Either.forRight(new DeleteFile(docUri)));
196+
private static void createDeleteFileEdit(String docUri, String changeAnnotationId, WorkspaceEdit we) {
197+
DeleteFile ro = new DeleteFile(docUri);
198+
ro.setAnnotationId(changeAnnotationId);
199+
we.getDocumentChanges().add(Either.forRight(ro));
204200
}
205201

206202
private static void createUpdateFileEdit(SimpleTextDocumentService documents, String docUri, String oldContent,

headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/copilot/CopilotAgentCommandHandler.java

Lines changed: 35 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,31 @@
1+
/*******************************************************************************
2+
* Copyright (c) 2024 Broadcom, Inc.
3+
* All rights reserved. This program and the accompanying materials
4+
* are made available under the terms of the Eclipse Public License v1.0
5+
* which accompanies this distribution, and is available at
6+
* https://www.eclipse.org/legal/epl-v10.html
7+
*
8+
* Contributors:
9+
* Broadcom, Inc. - initial API and implementation
10+
*******************************************************************************/
111
package org.springframework.ide.vscode.boot.java.copilot;
212

313
import java.io.IOException;
414
import java.nio.file.Paths;
515
import java.util.List;
16+
import java.util.UUID;
617
import java.util.concurrent.CompletableFuture;
18+
import java.util.concurrent.CompletionException;
719

20+
import org.eclipse.lsp4j.ApplyWorkspaceEditParams;
821
import org.eclipse.lsp4j.ExecuteCommandParams;
922
import org.eclipse.lsp4j.TextDocumentIdentifier;
1023
import org.eclipse.lsp4j.WorkspaceEdit;
1124
import org.slf4j.Logger;
1225
import org.slf4j.LoggerFactory;
1326
import org.springframework.ide.vscode.boot.java.copilot.util.ResponseModifier;
1427
import org.springframework.ide.vscode.commons.java.IJavaProject;
28+
import org.springframework.ide.vscode.commons.languageserver.IndefiniteProgressTask;
1529
import org.springframework.ide.vscode.commons.languageserver.java.JavaProjectFinder;
1630
import org.springframework.ide.vscode.commons.languageserver.util.SimpleLanguageServer;
1731

@@ -41,15 +55,27 @@ private void registerCommands() {
4155
server.onCommand(CMD_COPILOT_AGENT_ENHANCERESPONSE, (params) -> {
4256
return enhanceResponseHandler(params);
4357
});
44-
log.info("Registered command handler: {}", CMD_COPILOT_AGENT_ENHANCERESPONSE);
4558

4659
server.onCommand(CMD_COPILOT_AGENT_LSPEDITS, params -> {
47-
try {
48-
return createLspEdits(params);
49-
} catch (IOException e) {
50-
log.error(e.getMessage());
51-
}
52-
return null;
60+
final IndefiniteProgressTask progressTask = server.getProgressService().createIndefiniteProgressTask(UUID.randomUUID().toString(), "Applying GenAI Response", "Computing changes...");
61+
return CompletableFuture.supplyAsync(() -> {
62+
try {
63+
return createLspEdits(params);
64+
} catch (IOException e) {
65+
throw new CompletionException(e);
66+
}
67+
}).thenCompose(we -> {
68+
if (progressTask != null) {
69+
progressTask.progressEvent("Applying document changes...");
70+
}
71+
return server.getClient().applyEdit(new ApplyWorkspaceEditParams(we, "Apply GenAI Response")).thenCompose(res -> {
72+
if (res.isApplied()) {
73+
return CompletableFuture.completedFuture("success");
74+
} else {
75+
return CompletableFuture.completedFuture(null);
76+
}
77+
});
78+
}).whenComplete((o,t) -> progressTask.done());
5379
});
5480
}
5581

@@ -60,7 +86,7 @@ private CompletableFuture<Object> enhanceResponseHandler(ExecuteCommandParams pa
6086
return CompletableFuture.completedFuture(modifiedResp);
6187
}
6288

63-
private CompletableFuture<WorkspaceEdit> createLspEdits(ExecuteCommandParams params) throws IOException {
89+
private WorkspaceEdit createLspEdits(ExecuteCommandParams params) throws IOException {
6490
log.info("Command Handler for lsp edits: ");
6591
String docURI = ((JsonElement) params.getArguments().get(0)).getAsString();
6692
String content = ((JsonElement) params.getArguments().get(1)).getAsString();
@@ -69,8 +95,7 @@ private CompletableFuture<WorkspaceEdit> createLspEdits(ExecuteCommandParams par
6995
List<ProjectArtifact> projectArtifacts = computeProjectArtifacts(content);
7096
ProjectArtifactEditGenerator editGenerator = new ProjectArtifactEditGenerator(server.getTextDocumentService(),
7197
projectArtifacts, Paths.get(project.getLocationUri()), docURI);
72-
WorkspaceEdit we = editGenerator.process().getResult();
73-
return CompletableFuture.completedFuture(we);
98+
return editGenerator.process().getResult();
7499
}
75100

76101
List<ProjectArtifact> computeProjectArtifacts(String response) {

headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/copilot/InjectMavenActionHandler.java

Lines changed: 22 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -77,8 +77,7 @@ protected Recipe createRecipe() {
7777
for (InjectMavenBuildPlugin p : buildPlugins) {
7878
List<Xml.Document> xmlDocuments = parseToXml(p.getText());
7979
for (Xml.Document xmlDocument : xmlDocuments) {
80-
MavenPluginMetadata pm = findMavenPluginTags(xmlDocument);
81-
if (pm != null) {
80+
for (MavenPluginMetadata pm : findMavenPluginTags(xmlDocument)) {
8281
AddPlugin addPlugin = new AddPlugin(pm.groupId(), pm.artifactId(), pm.version(), pm.configuration(),
8382
pm.dependencies(), pm.executions(), pm.filePattern());
8483
aggregateRecipe.getRecipeList().add(addPlugin);
@@ -88,8 +87,7 @@ protected Recipe createRecipe() {
8887
for (InjectMavenRepository r : repositories) {
8988
List<Xml.Document> xmlDocuments = parseToXml(r.getText());
9089
for (Xml.Document xmlDocument : xmlDocuments) {
91-
MavenRepositoryMetadata rm = findRepositoryTags(xmlDocument);
92-
if (rm != null) {
90+
for (MavenRepositoryMetadata rm : findRepositoryTags(xmlDocument)) {
9391
AddRepository addRepository = new AddRepository(rm.id(), rm.url(), rm.repoName(), null,
9492
rm.snapshotsEnabled(), null, null, rm.releasesEnabled(), null, null, null);
9593
aggregateRecipe.getRecipeList().add(addRepository);
@@ -99,8 +97,7 @@ protected Recipe createRecipe() {
9997
for (InjectMavenDependencyManagement dm : dependencyManagements) {
10098
List<Xml.Document> xmlDocuments = parseToXml(dm.getText());
10199
for (Xml.Document xmlDocument : xmlDocuments) {
102-
MavenDependencyMetadata mdm = findMavenDependencyTags(xmlDocument);
103-
if (mdm != null) {
100+
for (MavenDependencyMetadata mdm : findMavenDependencyTags(xmlDocument)) {
104101
AddManagedDependency addManagedDependency = new AddManagedDependency(mdm.groupId(), mdm.artifactId(),
105102
mdm.version(), mdm.scope(), null, mdm.classifier(), null, null, null, null);
106103
aggregateRecipe.getRecipeList().add(addManagedDependency);
@@ -118,25 +115,26 @@ public List<Xml.Document> parseToXml(String content) {
118115
return xmlDocuments;
119116
}
120117

121-
public MavenDependencyMetadata findMavenDependencyTags(Xml.Document xmlDocument) {
118+
public List<MavenDependencyMetadata> findMavenDependencyTags(Xml.Document xmlDocument) {
122119
Set<Tag> dependencyTags = FindTags.find(xmlDocument, "//dependency");
120+
List<MavenDependencyMetadata> deps = new ArrayList<>(dependencyTags.size());
123121
for (Tag dependencyTag : dependencyTags) {
124122
String groupId = dependencyTag.getChildValue("groupId").orElse(null);
125123
String artifactId = dependencyTag.getChildValue("artifactId").orElse(null);
126124
String version = dependencyTag.getChildValue("version").orElse("latest");
127125
String scope = dependencyTag.getChildValue("scope").orElse(null);
128126
String type = dependencyTag.getChildValue("type").orElse(null);
129127
String classifier = dependencyTag.getChildValue("classifier").orElse(null);
130-
if (groupId != null && artifactId != null && version != null)
131-
return new MavenDependencyMetadata(groupId, artifactId, version, scope, type, classifier);
132-
128+
if (groupId != null && artifactId != null && version != null) {
129+
deps.add(new MavenDependencyMetadata(groupId, artifactId, version, scope, type, classifier));
130+
}
133131
}
134-
return null;
132+
return deps;
135133
}
136134

137-
public MavenPluginMetadata findMavenPluginTags(Xml.Document xmlDocument) {
135+
public List<MavenPluginMetadata> findMavenPluginTags(Xml.Document xmlDocument) {
138136
Set<Tag> pluginTags = FindTags.find(xmlDocument, "//plugin");
139-
137+
List<MavenPluginMetadata> plugins = new ArrayList<>(pluginTags.size());
140138
for (Tag pluginTag : pluginTags) {
141139
String groupId = pluginTag.getChildValue("groupId").orElse(null);
142140
String artifactId = pluginTag.getChildValue("artifactId").orElse(null);
@@ -146,27 +144,29 @@ public MavenPluginMetadata findMavenPluginTags(Xml.Document xmlDocument) {
146144
String executions = pluginTag.getChildValue("executions").orElse(null);
147145
String filePattern = pluginTag.getChildValue("filePattern").orElse(null);
148146

149-
if (groupId != null && artifactId != null && version != null)
150-
return new MavenPluginMetadata(groupId, artifactId, version, configuration, dependencies, executions,
151-
filePattern);
147+
if (groupId != null && artifactId != null && version != null) {
148+
plugins.add(new MavenPluginMetadata(groupId, artifactId, version, configuration, dependencies, executions,
149+
filePattern));
150+
}
152151
}
153-
return null;
152+
return plugins;
154153
}
155154

156-
private MavenRepositoryMetadata findRepositoryTags(Document xmlDocument) {
155+
private List<MavenRepositoryMetadata> findRepositoryTags(Document xmlDocument) {
157156
Set<Tag> repoTags = FindTags.find(xmlDocument, "//plugin");
158-
157+
List<MavenRepositoryMetadata> repos = new ArrayList<>(repoTags.size());
159158
for (Tag repoTag : repoTags) {
160159
String id = repoTag.getChildValue("id").orElse(null);
161160
String url = repoTag.getChildValue("url").orElse(null);
162161
String repoName = repoTag.getChildValue("repoName").orElse("latest");
163162
boolean snapshotsEnabled = Boolean.parseBoolean(repoTag.getChildValue("snapshotsEnabled").orElse(null));
164163
boolean releasesEnabled = Boolean.parseBoolean(repoTag.getChildValue("releasesEnabled").orElse(null));
165164

166-
if (id != null && url != null)
167-
return new MavenRepositoryMetadata(id, url, repoName, snapshotsEnabled, releasesEnabled);
165+
if (id != null && url != null) {
166+
repos.add(new MavenRepositoryMetadata(id, url, repoName, snapshotsEnabled, releasesEnabled));
167+
}
168168
}
169-
return null;
169+
return repos;
170170
}
171171

172172
}

headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/copilot/ProjectArtifactEditGenerator.java

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -135,8 +135,9 @@ private void writeMavenDependencies(ProjectArtifact projectArtifact, Path projec
135135
// Move the parsing to injectMavenActionHandler
136136
List<Xml.Document> xmlDocuments = injectMavenActionHandler.parseToXml(projectArtifact.getText());
137137
for (Xml.Document xmlDocument : xmlDocuments) {
138-
MavenDependencyMetadata dep = injectMavenActionHandler.findMavenDependencyTags(xmlDocument);
139-
injectMavenActionHandler.injectDependency(dep);
138+
for (MavenDependencyMetadata dep : injectMavenActionHandler.findMavenDependencyTags(xmlDocument)) {
139+
injectMavenActionHandler.injectDependency(dep);
140+
}
140141
}
141142

142143
List<Result> res = injectMavenActionHandler.run().getChangeset().getAllResults();
Lines changed: 5 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -1,45 +1,10 @@
1-
import { Uri, workspace, window, commands, ProgressLocation } from "vscode";
1+
import { Uri, commands } from "vscode";
22
import { getTargetGuideMardown, readResponseFromFile } from "./util";
3-
import { createConverter } from "vscode-languageclient/lib/common/protocolConverter";
4-
import fs from "fs";
5-
import path from "path";
6-
7-
8-
const CONVERTER = createConverter(undefined, true, true);
9-
const CANCELLED = "Cancelled";
103

114
export async function applyLspEdit(uri: Uri) {
12-
try {
13-
if (!uri) {
14-
uri = await getTargetGuideMardown();
15-
}
16-
17-
window.withProgress({
18-
location: ProgressLocation.Window,
19-
title: "Copilot agent",
20-
cancellable: true
21-
}, async (progress, cancellation) => {
22-
progress.report({ message: "applying edits..." });
23-
const fileContent = (await readResponseFromFile(uri)).toString();
24-
const lspEdit = await commands.executeCommand("sts/copilot/agent/lspEdits", uri.toString(), fileContent);
25-
const workspaceEdit = await CONVERTER.asWorkspaceEdit(lspEdit);
26-
27-
28-
await Promise.all(workspaceEdit.entries().map(async ([uri, edits]) => {
29-
console.log(edits);
30-
if (fs.existsSync(uri.fsPath)) {
31-
const doc = await workspace.openTextDocument(uri.fsPath);
32-
await window.showTextDocument(doc);
33-
}
34-
}));
35-
36-
return await workspace.applyEdit(workspaceEdit, {
37-
isRefactoring: true
38-
});
39-
});
40-
} catch (error) {
41-
if (error !== CANCELLED) {
42-
window.showErrorMessage(error);
43-
}
5+
if (!uri) {
6+
uri = await getTargetGuideMardown();
447
}
8+
const fileContent = (await readResponseFromFile(uri)).toString();
9+
await commands.executeCommand("sts/copilot/agent/lspEdits", uri.toString(), fileContent);
4510
}

0 commit comments

Comments
 (0)