Apply edit via LSP. Fix maven changes

This commit is contained in:
aboyko
2024-10-03 16:50:45 -04:00
parent 31497084cd
commit 084d3a9ad7
5 changed files with 75 additions and 88 deletions

View File

@@ -161,17 +161,10 @@ public class ORDocUtils {
WorkspaceEdit we = new WorkspaceEdit();
we.setDocumentChanges(new ArrayList<>());
for (Result result : results) {
if (result.getBefore() == null) {
String docUri = result.getAfter().getSourcePath().toUri().toASCIIString();
createNewFileEdit(docUri, result.getAfter().printAll(), changeAnnotationId, we);
} else if (result.getAfter() == null) {
String docUri = result.getBefore().getSourcePath().toUri().toASCIIString();
createDeleteFileEdit(docUri, we);
} else {
String docUri = result.getBefore().getSourcePath().toUri().toASCIIString();
createUpdateFileEdit(documents, docUri, result.getBefore().printAll(), result.getAfter().printAll(), changeAnnotationId, we);
}
String docUri = result.getBefore() == null ? result.getAfter().getSourcePath().toUri().toASCIIString() : result.getBefore().getSourcePath().toUri().toASCIIString();
String oldContent = result.getBefore() == null ? null : result.getBefore().printAll();
String newContent = result.getAfter() == null ? null : result.getAfter().printAll();
createWorkspaceEdit(documents, docUri, oldContent, newContent, changeAnnotationId, we);
}
return Optional.of(we);
}
@@ -180,7 +173,7 @@ public class ORDocUtils {
if(oldContent == null) {
createNewFileEdit(docUri, newContent, changeAnnotationId, we);
} else if (newContent == null) {
createDeleteFileEdit(docUri, we);
createDeleteFileEdit(docUri, changeAnnotationId, we);
} else {
createUpdateFileEdit(documents, docUri, oldContent, newContent, changeAnnotationId, we);
}
@@ -190,6 +183,7 @@ public class ORDocUtils {
WorkspaceEdit we) {
CreateFile ro = new CreateFile();
ro.setUri(docUri);
ro.setAnnotationId(changeAnnotationId);
we.getDocumentChanges().add(Either.forRight(ro));
TextDocumentEdit te = new TextDocumentEdit();
@@ -199,8 +193,10 @@ public class ORDocUtils {
we.getDocumentChanges().add(Either.forLeft(te));
}
private static void createDeleteFileEdit(String docUri, WorkspaceEdit we) {
we.getDocumentChanges().add(Either.forRight(new DeleteFile(docUri)));
private static void createDeleteFileEdit(String docUri, String changeAnnotationId, WorkspaceEdit we) {
DeleteFile ro = new DeleteFile(docUri);
ro.setAnnotationId(changeAnnotationId);
we.getDocumentChanges().add(Either.forRight(ro));
}
private static void createUpdateFileEdit(SimpleTextDocumentService documents, String docUri, String oldContent,

View File

@@ -1,10 +1,23 @@
/*******************************************************************************
* Copyright (c) 2024 Broadcom, Inc.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Broadcom, Inc. - initial API and implementation
*******************************************************************************/
package org.springframework.ide.vscode.boot.java.copilot;
import java.io.IOException;
import java.nio.file.Paths;
import java.util.List;
import java.util.UUID;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CompletionException;
import org.eclipse.lsp4j.ApplyWorkspaceEditParams;
import org.eclipse.lsp4j.ExecuteCommandParams;
import org.eclipse.lsp4j.TextDocumentIdentifier;
import org.eclipse.lsp4j.WorkspaceEdit;
@@ -12,6 +25,7 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.ide.vscode.boot.java.copilot.util.ResponseModifier;
import org.springframework.ide.vscode.commons.java.IJavaProject;
import org.springframework.ide.vscode.commons.languageserver.IndefiniteProgressTask;
import org.springframework.ide.vscode.commons.languageserver.java.JavaProjectFinder;
import org.springframework.ide.vscode.commons.languageserver.util.SimpleLanguageServer;
@@ -41,15 +55,27 @@ public class CopilotAgentCommandHandler {
server.onCommand(CMD_COPILOT_AGENT_ENHANCERESPONSE, (params) -> {
return enhanceResponseHandler(params);
});
log.info("Registered command handler: {}", CMD_COPILOT_AGENT_ENHANCERESPONSE);
server.onCommand(CMD_COPILOT_AGENT_LSPEDITS, params -> {
try {
return createLspEdits(params);
} catch (IOException e) {
log.error(e.getMessage());
}
return null;
final IndefiniteProgressTask progressTask = server.getProgressService().createIndefiniteProgressTask(UUID.randomUUID().toString(), "Applying GenAI Response", "Computing changes...");
return CompletableFuture.supplyAsync(() -> {
try {
return createLspEdits(params);
} catch (IOException e) {
throw new CompletionException(e);
}
}).thenCompose(we -> {
if (progressTask != null) {
progressTask.progressEvent("Applying document changes...");
}
return server.getClient().applyEdit(new ApplyWorkspaceEditParams(we, "Apply GenAI Response")).thenCompose(res -> {
if (res.isApplied()) {
return CompletableFuture.completedFuture("success");
} else {
return CompletableFuture.completedFuture(null);
}
});
}).whenComplete((o,t) -> progressTask.done());
});
}
@@ -60,7 +86,7 @@ public class CopilotAgentCommandHandler {
return CompletableFuture.completedFuture(modifiedResp);
}
private CompletableFuture<WorkspaceEdit> createLspEdits(ExecuteCommandParams params) throws IOException {
private WorkspaceEdit createLspEdits(ExecuteCommandParams params) throws IOException {
log.info("Command Handler for lsp edits: ");
String docURI = ((JsonElement) params.getArguments().get(0)).getAsString();
String content = ((JsonElement) params.getArguments().get(1)).getAsString();
@@ -69,8 +95,7 @@ public class CopilotAgentCommandHandler {
List<ProjectArtifact> projectArtifacts = computeProjectArtifacts(content);
ProjectArtifactEditGenerator editGenerator = new ProjectArtifactEditGenerator(server.getTextDocumentService(),
projectArtifacts, Paths.get(project.getLocationUri()), docURI);
WorkspaceEdit we = editGenerator.process().getResult();
return CompletableFuture.completedFuture(we);
return editGenerator.process().getResult();
}
List<ProjectArtifact> computeProjectArtifacts(String response) {

View File

@@ -77,8 +77,7 @@ public class InjectMavenActionHandler extends AbstractInjectMavenActionHandler {
for (InjectMavenBuildPlugin p : buildPlugins) {
List<Xml.Document> xmlDocuments = parseToXml(p.getText());
for (Xml.Document xmlDocument : xmlDocuments) {
MavenPluginMetadata pm = findMavenPluginTags(xmlDocument);
if (pm != null) {
for (MavenPluginMetadata pm : findMavenPluginTags(xmlDocument)) {
AddPlugin addPlugin = new AddPlugin(pm.groupId(), pm.artifactId(), pm.version(), pm.configuration(),
pm.dependencies(), pm.executions(), pm.filePattern());
aggregateRecipe.getRecipeList().add(addPlugin);
@@ -88,8 +87,7 @@ public class InjectMavenActionHandler extends AbstractInjectMavenActionHandler {
for (InjectMavenRepository r : repositories) {
List<Xml.Document> xmlDocuments = parseToXml(r.getText());
for (Xml.Document xmlDocument : xmlDocuments) {
MavenRepositoryMetadata rm = findRepositoryTags(xmlDocument);
if (rm != null) {
for (MavenRepositoryMetadata rm : findRepositoryTags(xmlDocument)) {
AddRepository addRepository = new AddRepository(rm.id(), rm.url(), rm.repoName(), null,
rm.snapshotsEnabled(), null, null, rm.releasesEnabled(), null, null, null);
aggregateRecipe.getRecipeList().add(addRepository);
@@ -99,8 +97,7 @@ public class InjectMavenActionHandler extends AbstractInjectMavenActionHandler {
for (InjectMavenDependencyManagement dm : dependencyManagements) {
List<Xml.Document> xmlDocuments = parseToXml(dm.getText());
for (Xml.Document xmlDocument : xmlDocuments) {
MavenDependencyMetadata mdm = findMavenDependencyTags(xmlDocument);
if (mdm != null) {
for (MavenDependencyMetadata mdm : findMavenDependencyTags(xmlDocument)) {
AddManagedDependency addManagedDependency = new AddManagedDependency(mdm.groupId(), mdm.artifactId(),
mdm.version(), mdm.scope(), null, mdm.classifier(), null, null, null, null);
aggregateRecipe.getRecipeList().add(addManagedDependency);
@@ -118,8 +115,9 @@ public class InjectMavenActionHandler extends AbstractInjectMavenActionHandler {
return xmlDocuments;
}
public MavenDependencyMetadata findMavenDependencyTags(Xml.Document xmlDocument) {
public List<MavenDependencyMetadata> findMavenDependencyTags(Xml.Document xmlDocument) {
Set<Tag> dependencyTags = FindTags.find(xmlDocument, "//dependency");
List<MavenDependencyMetadata> deps = new ArrayList<>(dependencyTags.size());
for (Tag dependencyTag : dependencyTags) {
String groupId = dependencyTag.getChildValue("groupId").orElse(null);
String artifactId = dependencyTag.getChildValue("artifactId").orElse(null);
@@ -127,16 +125,16 @@ public class InjectMavenActionHandler extends AbstractInjectMavenActionHandler {
String scope = dependencyTag.getChildValue("scope").orElse(null);
String type = dependencyTag.getChildValue("type").orElse(null);
String classifier = dependencyTag.getChildValue("classifier").orElse(null);
if (groupId != null && artifactId != null && version != null)
return new MavenDependencyMetadata(groupId, artifactId, version, scope, type, classifier);
if (groupId != null && artifactId != null && version != null) {
deps.add(new MavenDependencyMetadata(groupId, artifactId, version, scope, type, classifier));
}
}
return null;
return deps;
}
public MavenPluginMetadata findMavenPluginTags(Xml.Document xmlDocument) {
public List<MavenPluginMetadata> findMavenPluginTags(Xml.Document xmlDocument) {
Set<Tag> pluginTags = FindTags.find(xmlDocument, "//plugin");
List<MavenPluginMetadata> plugins = new ArrayList<>(pluginTags.size());
for (Tag pluginTag : pluginTags) {
String groupId = pluginTag.getChildValue("groupId").orElse(null);
String artifactId = pluginTag.getChildValue("artifactId").orElse(null);
@@ -146,16 +144,17 @@ public class InjectMavenActionHandler extends AbstractInjectMavenActionHandler {
String executions = pluginTag.getChildValue("executions").orElse(null);
String filePattern = pluginTag.getChildValue("filePattern").orElse(null);
if (groupId != null && artifactId != null && version != null)
return new MavenPluginMetadata(groupId, artifactId, version, configuration, dependencies, executions,
filePattern);
if (groupId != null && artifactId != null && version != null) {
plugins.add(new MavenPluginMetadata(groupId, artifactId, version, configuration, dependencies, executions,
filePattern));
}
}
return null;
return plugins;
}
private MavenRepositoryMetadata findRepositoryTags(Document xmlDocument) {
private List<MavenRepositoryMetadata> findRepositoryTags(Document xmlDocument) {
Set<Tag> repoTags = FindTags.find(xmlDocument, "//plugin");
List<MavenRepositoryMetadata> repos = new ArrayList<>(repoTags.size());
for (Tag repoTag : repoTags) {
String id = repoTag.getChildValue("id").orElse(null);
String url = repoTag.getChildValue("url").orElse(null);
@@ -163,10 +162,11 @@ public class InjectMavenActionHandler extends AbstractInjectMavenActionHandler {
boolean snapshotsEnabled = Boolean.parseBoolean(repoTag.getChildValue("snapshotsEnabled").orElse(null));
boolean releasesEnabled = Boolean.parseBoolean(repoTag.getChildValue("releasesEnabled").orElse(null));
if (id != null && url != null)
return new MavenRepositoryMetadata(id, url, repoName, snapshotsEnabled, releasesEnabled);
if (id != null && url != null) {
repos.add(new MavenRepositoryMetadata(id, url, repoName, snapshotsEnabled, releasesEnabled));
}
}
return null;
return repos;
}
}

View File

@@ -135,8 +135,9 @@ public class ProjectArtifactEditGenerator {
// Move the parsing to injectMavenActionHandler
List<Xml.Document> xmlDocuments = injectMavenActionHandler.parseToXml(projectArtifact.getText());
for (Xml.Document xmlDocument : xmlDocuments) {
MavenDependencyMetadata dep = injectMavenActionHandler.findMavenDependencyTags(xmlDocument);
injectMavenActionHandler.injectDependency(dep);
for (MavenDependencyMetadata dep : injectMavenActionHandler.findMavenDependencyTags(xmlDocument)) {
injectMavenActionHandler.injectDependency(dep);
}
}
List<Result> res = injectMavenActionHandler.run().getChangeset().getAllResults();

View File

@@ -1,45 +1,10 @@
import { Uri, workspace, window, commands, ProgressLocation } from "vscode";
import { Uri, commands } from "vscode";
import { getTargetGuideMardown, readResponseFromFile } from "./util";
import { createConverter } from "vscode-languageclient/lib/common/protocolConverter";
import fs from "fs";
import path from "path";
const CONVERTER = createConverter(undefined, true, true);
const CANCELLED = "Cancelled";
export async function applyLspEdit(uri: Uri) {
try {
if (!uri) {
uri = await getTargetGuideMardown();
}
window.withProgress({
location: ProgressLocation.Window,
title: "Copilot agent",
cancellable: true
}, async (progress, cancellation) => {
progress.report({ message: "applying edits..." });
const fileContent = (await readResponseFromFile(uri)).toString();
const lspEdit = await commands.executeCommand("sts/copilot/agent/lspEdits", uri.toString(), fileContent);
const workspaceEdit = await CONVERTER.asWorkspaceEdit(lspEdit);
await Promise.all(workspaceEdit.entries().map(async ([uri, edits]) => {
console.log(edits);
if (fs.existsSync(uri.fsPath)) {
const doc = await workspace.openTextDocument(uri.fsPath);
await window.showTextDocument(doc);
}
}));
return await workspace.applyEdit(workspaceEdit, {
isRefactoring: true
});
});
} catch (error) {
if (error !== CANCELLED) {
window.showErrorMessage(error);
}
if (!uri) {
uri = await getTargetGuideMardown();
}
const fileContent = (await readResponseFromFile(uri)).toString();
await commands.executeCommand("sts/copilot/agent/lspEdits", uri.toString(), fileContent);
}