diff --git a/src/main/java/Main.java b/src/main/java/Main.java index 9f33fea..b876655 100644 --- a/src/main/java/Main.java +++ b/src/main/java/Main.java @@ -2,7 +2,7 @@ import abstractdebugging.AbstractDebuggingServerLauncher; import abstractdebugging.ResultsService; import analysis.GoblintAnalysis; -import analysis.ShowCFGCommand; +import magpiebridge.ShowCFGCommand; import api.GoblintService; import api.GoblintServiceLauncher; import api.messages.params.Params; @@ -13,6 +13,9 @@ import gobpie.GobPieException; import magpiebridge.core.MagpieServer; import magpiebridge.core.ServerAnalysis; +import magpiebridge.GoblintLanguageExtensionHandler; +import magpiebridge.GoblintMagpieServer; +import magpiebridge.GoblintServerConfiguration; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.eclipse.lsp4j.MessageParams; diff --git a/src/main/java/api/GoblintServiceLauncher.java b/src/main/java/api/GoblintServiceLauncher.java index 7d4df20..7ffefac 100644 --- a/src/main/java/api/GoblintServiceLauncher.java +++ b/src/main/java/api/GoblintServiceLauncher.java @@ -1,8 +1,8 @@ package api; import api.json.GoblintMessageJsonHandler; -import api.json.GoblintSocketMessageConsumer; -import api.json.GoblintSocketMessageProducer; +import api.jsonrpc.GoblintSocketMessageConsumer; +import api.jsonrpc.GoblintSocketMessageProducer; import api.jsonrpc.AutoClosingMessageProcessor; import api.jsonrpc.CloseableEndpoint; import gobpie.GobPieException; diff --git a/src/main/java/api/json/GoblintSocketMessageConsumer.java b/src/main/java/api/jsonrpc/GoblintSocketMessageConsumer.java similarity index 96% rename from src/main/java/api/json/GoblintSocketMessageConsumer.java rename to src/main/java/api/jsonrpc/GoblintSocketMessageConsumer.java index a0bdee9..6f281f2 100644 --- a/src/main/java/api/json/GoblintSocketMessageConsumer.java +++ b/src/main/java/api/jsonrpc/GoblintSocketMessageConsumer.java @@ -1,56 +1,56 @@ -package api.json; - -import org.apache.logging.log4j.LogManager; -import org.apache.logging.log4j.Logger; -import org.eclipse.lsp4j.jsonrpc.JsonRpcException; -import org.eclipse.lsp4j.jsonrpc.MessageConsumer; -import org.eclipse.lsp4j.jsonrpc.json.MessageConstants; -import org.eclipse.lsp4j.jsonrpc.json.MessageJsonHandler; -import org.eclipse.lsp4j.jsonrpc.messages.Message; - -import java.io.IOException; -import java.io.OutputStream; -import java.nio.charset.StandardCharsets; - - -/** - * A message consumer that serializes messages to JSON and sends them to an output stream. - * - * @since 0.0.3 - */ - -public class GoblintSocketMessageConsumer implements MessageConsumer, MessageConstants { - - private final String encoding; - private final MessageJsonHandler jsonHandler; - private final Object outputLock = new Object(); - private final OutputStream output; - - private final Logger log = LogManager.getLogger(GoblintSocketMessageConsumer.class); - - public GoblintSocketMessageConsumer(OutputStream output, MessageJsonHandler jsonHandler) { - this(output, StandardCharsets.UTF_8.name(), jsonHandler); - } - - public GoblintSocketMessageConsumer(OutputStream output, String encoding, MessageJsonHandler jsonHandler) { - this.output = output; - this.encoding = encoding; - this.jsonHandler = jsonHandler; - } - - @Override - public void consume(Message message) { - try { - String content = jsonHandler.serialize(message) + "\n"; - byte[] contentBytes = content.getBytes(encoding); - synchronized (outputLock) { - output.write(contentBytes); - output.flush(); - } - log.debug("WRITTEN: {}", content); - } catch (IOException exception) { - throw new JsonRpcException(exception); - } - } - -} +package api.jsonrpc; + +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.eclipse.lsp4j.jsonrpc.JsonRpcException; +import org.eclipse.lsp4j.jsonrpc.MessageConsumer; +import org.eclipse.lsp4j.jsonrpc.json.MessageConstants; +import org.eclipse.lsp4j.jsonrpc.json.MessageJsonHandler; +import org.eclipse.lsp4j.jsonrpc.messages.Message; + +import java.io.IOException; +import java.io.OutputStream; +import java.nio.charset.StandardCharsets; + + +/** + * A message consumer that serializes messages to JSON and sends them to an output stream. + * + * @since 0.0.3 + */ + +public class GoblintSocketMessageConsumer implements MessageConsumer, MessageConstants { + + private final String encoding; + private final MessageJsonHandler jsonHandler; + private final Object outputLock = new Object(); + private final OutputStream output; + + private final Logger log = LogManager.getLogger(GoblintSocketMessageConsumer.class); + + public GoblintSocketMessageConsumer(OutputStream output, MessageJsonHandler jsonHandler) { + this(output, StandardCharsets.UTF_8.name(), jsonHandler); + } + + public GoblintSocketMessageConsumer(OutputStream output, String encoding, MessageJsonHandler jsonHandler) { + this.output = output; + this.encoding = encoding; + this.jsonHandler = jsonHandler; + } + + @Override + public void consume(Message message) { + try { + String content = jsonHandler.serialize(message) + "\n"; + byte[] contentBytes = content.getBytes(encoding); + synchronized (outputLock) { + output.write(contentBytes); + output.flush(); + } + log.debug("WRITTEN: {}", content); + } catch (IOException exception) { + throw new JsonRpcException(exception); + } + } + +} diff --git a/src/main/java/api/json/GoblintSocketMessageProducer.java b/src/main/java/api/jsonrpc/GoblintSocketMessageProducer.java similarity index 96% rename from src/main/java/api/json/GoblintSocketMessageProducer.java rename to src/main/java/api/jsonrpc/GoblintSocketMessageProducer.java index e94860f..ef38d7a 100644 --- a/src/main/java/api/json/GoblintSocketMessageProducer.java +++ b/src/main/java/api/jsonrpc/GoblintSocketMessageProducer.java @@ -1,133 +1,134 @@ -package api.json; - -import org.apache.logging.log4j.LogManager; -import org.eclipse.lsp4j.jsonrpc.*; -import org.eclipse.lsp4j.jsonrpc.json.MessageConstants; -import org.eclipse.lsp4j.jsonrpc.json.MessageJsonHandler; -import org.eclipse.lsp4j.jsonrpc.json.StreamMessageProducer; -import org.eclipse.lsp4j.jsonrpc.messages.Message; - -import java.io.*; -import java.util.logging.Level; -import java.util.logging.Logger; - -/** - * A message producer that reads from an input stream and parses messages from JSON. - * - * @since 0.0.3 - */ - -public class GoblintSocketMessageProducer implements MessageProducer, Closeable, MessageConstants { - - private static final Logger LOG = Logger.getLogger(StreamMessageProducer.class.getName()); - - private final MessageJsonHandler jsonHandler; - private final MessageIssueHandler issueHandler; - private final BufferedReader inputReader; - - private MessageConsumer callback; - private boolean keepRunning; - - private final org.apache.logging.log4j.Logger log = LogManager.getLogger(GoblintSocketMessageConsumer.class); - - public GoblintSocketMessageProducer(InputStream input, MessageJsonHandler jsonHandler) { - this(input, jsonHandler, null); - } - - public GoblintSocketMessageProducer(InputStream input, MessageJsonHandler jsonHandler, MessageIssueHandler issueHandler) { - this.jsonHandler = jsonHandler; - this.issueHandler = issueHandler; - this.inputReader = new BufferedReader(new InputStreamReader(input)); - } - - @Override - public void listen(MessageConsumer callback) { - if (keepRunning) { - throw new IllegalStateException("This StreamMessageProducer is already running."); - } - this.keepRunning = true; - this.callback = callback; - try { - while (keepRunning) { - boolean result = handleMessage(); - if (!result) - keepRunning = false; - } // while (keepRunning) - } catch (IOException exception) { - if (JsonRpcException.indicatesStreamClosed(exception)) { - // Only log the error if we had intended to keep running - if (keepRunning) - fireStreamClosed(exception); - } else - throw new JsonRpcException(exception); - this.keepRunning = false; - } finally { - this.callback = null; - this.keepRunning = false; - } - } - - /** - * Log an error. - */ - protected void fireError(Throwable error) { - String message = error.getMessage() != null ? error.getMessage() : "An error occurred while processing an incoming message."; - LOG.log(Level.SEVERE, message, error); - } - - /** - * Report that the stream was closed through an exception. - */ - protected void fireStreamClosed(Exception cause) { - String message = cause.getMessage() != null ? cause.getMessage() : "The input stream was closed."; - LOG.log(Level.INFO, message, cause); - } - - - /** - * Read the JSON content part of a message, parse it, and notify the callback. - * - * @return {@code true} if we should continue reading from the input stream, {@code false} if we should stop - */ - protected boolean handleMessage() throws IOException { - if (callback == null) - callback = message -> LOG.log(Level.INFO, "Received message: " + message); - - try { - String content = inputReader.readLine(); - log.debug("READ: {}", content); - try { - if (content != null) { - Message message = jsonHandler.parseMessage(content); - callback.consume(message); - } else { - return false; - } - } catch (MessageIssueException exception) { - // An issue was found while parsing or validating the message - if (issueHandler != null) { - issueHandler.handle(exception.getRpcMessage(), exception.getIssues()); - } else { - fireError(exception); - for (var issue : exception.getIssues()) { - fireError(issue.getCause()); - } - } - return false; - } - } catch (Exception exception) { - // UnsupportedEncodingException can be thrown by String constructor - // JsonParseException can be thrown by jsonHandler - // We also catch arbitrary exceptions that are thrown by message consumers in order to keep this thread alive - fireError(exception); - return false; - } - return true; - } - - @Override - public void close() { - keepRunning = false; - } -} - +package api.jsonrpc; + +import api.jsonrpc.GoblintSocketMessageConsumer; +import org.apache.logging.log4j.LogManager; +import org.eclipse.lsp4j.jsonrpc.*; +import org.eclipse.lsp4j.jsonrpc.json.MessageConstants; +import org.eclipse.lsp4j.jsonrpc.json.MessageJsonHandler; +import org.eclipse.lsp4j.jsonrpc.json.StreamMessageProducer; +import org.eclipse.lsp4j.jsonrpc.messages.Message; + +import java.io.*; +import java.util.logging.Level; +import java.util.logging.Logger; + +/** + * A message producer that reads from an input stream and parses messages from JSON. + * + * @since 0.0.3 + */ + +public class GoblintSocketMessageProducer implements MessageProducer, Closeable, MessageConstants { + + private static final Logger LOG = Logger.getLogger(StreamMessageProducer.class.getName()); + + private final MessageJsonHandler jsonHandler; + private final MessageIssueHandler issueHandler; + private final BufferedReader inputReader; + + private MessageConsumer callback; + private boolean keepRunning; + + private final org.apache.logging.log4j.Logger log = LogManager.getLogger(GoblintSocketMessageConsumer.class); + + public GoblintSocketMessageProducer(InputStream input, MessageJsonHandler jsonHandler) { + this(input, jsonHandler, null); + } + + public GoblintSocketMessageProducer(InputStream input, MessageJsonHandler jsonHandler, MessageIssueHandler issueHandler) { + this.jsonHandler = jsonHandler; + this.issueHandler = issueHandler; + this.inputReader = new BufferedReader(new InputStreamReader(input)); + } + + @Override + public void listen(MessageConsumer callback) { + if (keepRunning) { + throw new IllegalStateException("This StreamMessageProducer is already running."); + } + this.keepRunning = true; + this.callback = callback; + try { + while (keepRunning) { + boolean result = handleMessage(); + if (!result) + keepRunning = false; + } // while (keepRunning) + } catch (IOException exception) { + if (JsonRpcException.indicatesStreamClosed(exception)) { + // Only log the error if we had intended to keep running + if (keepRunning) + fireStreamClosed(exception); + } else + throw new JsonRpcException(exception); + this.keepRunning = false; + } finally { + this.callback = null; + this.keepRunning = false; + } + } + + /** + * Log an error. + */ + protected void fireError(Throwable error) { + String message = error.getMessage() != null ? error.getMessage() : "An error occurred while processing an incoming message."; + LOG.log(Level.SEVERE, message, error); + } + + /** + * Report that the stream was closed through an exception. + */ + protected void fireStreamClosed(Exception cause) { + String message = cause.getMessage() != null ? cause.getMessage() : "The input stream was closed."; + LOG.log(Level.INFO, message, cause); + } + + + /** + * Read the JSON content part of a message, parse it, and notify the callback. + * + * @return {@code true} if we should continue reading from the input stream, {@code false} if we should stop + */ + protected boolean handleMessage() throws IOException { + if (callback == null) + callback = message -> LOG.log(Level.INFO, "Received message: " + message); + + try { + String content = inputReader.readLine(); + log.debug("READ: {}", content); + try { + if (content != null) { + Message message = jsonHandler.parseMessage(content); + callback.consume(message); + } else { + return false; + } + } catch (MessageIssueException exception) { + // An issue was found while parsing or validating the message + if (issueHandler != null) { + issueHandler.handle(exception.getRpcMessage(), exception.getIssues()); + } else { + fireError(exception); + for (var issue : exception.getIssues()) { + fireError(issue.getCause()); + } + } + return false; + } + } catch (Exception exception) { + // UnsupportedEncodingException can be thrown by String constructor + // JsonParseException can be thrown by jsonHandler + // We also catch arbitrary exceptions that are thrown by message consumers in order to keep this thread alive + fireError(exception); + return false; + } + return true; + } + + @Override + public void close() { + keepRunning = false; + } +} + diff --git a/src/main/java/api/messages/GoblintMessagesResult.java b/src/main/java/api/messages/GoblintMessagesResult.java index 0059fa6..d0caa2f 100644 --- a/src/main/java/api/messages/GoblintMessagesResult.java +++ b/src/main/java/api/messages/GoblintMessagesResult.java @@ -58,6 +58,11 @@ public interface MultiPiece { public static class Piece implements MultiPiece { private String text; private GoblintLocation loc; + private context context; + + public static class context { + private Integer tag; + } /** * Converts the Single (Piece type of) Goblint messages from the @@ -70,7 +75,8 @@ public static class Piece implements MultiPiece { */ public List convert(List tags, String severity, boolean explode) { GoblintPosition pos = getLocation(loc); - String msg = joinTags(tags) + " " + text; + String ctx = context == null || context.tag == null ? "" : " in context " + context.tag; + String msg = joinTags(tags) + " " + text + ctx; GoblintMessagesAnalysisResult result = new GoblintMessagesAnalysisResult(pos, msg, severity); return List.of(result); } diff --git a/src/main/java/GoblintLanguageExtensionHandler.java b/src/main/java/magpiebridge/GoblintLanguageExtensionHandler.java similarity index 97% rename from src/main/java/GoblintLanguageExtensionHandler.java rename to src/main/java/magpiebridge/GoblintLanguageExtensionHandler.java index ec62d8f..8cda41e 100644 --- a/src/main/java/GoblintLanguageExtensionHandler.java +++ b/src/main/java/magpiebridge/GoblintLanguageExtensionHandler.java @@ -1,33 +1,35 @@ -import magpiebridge.core.LanguageExtensionHandler; - -import java.util.Set; - -/** - * Custom LanguageExtensionHandler for MagpieBridge that overrides the extensions associated with C to include .h and .i. - * For other languages falls back to the provided fallback LanguageExtensionHandler. - */ -public class GoblintLanguageExtensionHandler implements LanguageExtensionHandler { - - private final LanguageExtensionHandler fallbackLanguageExtensionHandler; - - public GoblintLanguageExtensionHandler(LanguageExtensionHandler fallbackLanguageExtensionHandler) { - this.fallbackLanguageExtensionHandler = fallbackLanguageExtensionHandler; - } - - @Override - public String getLanguageForExtension(String extension) { - if (".c".equals(extension) || ".i".equals(extension) || ".h".equals(extension)) { - return "c"; - } - return fallbackLanguageExtensionHandler.getLanguageForExtension(extension); - } - - @Override - public Set getExtensionsForLanguage(String language) { - if ("c".equals(language)) { - return Set.of(".c", ".i", ".h"); - } - return fallbackLanguageExtensionHandler.getExtensionsForLanguage(language); - } - -} +package magpiebridge; + +import magpiebridge.core.LanguageExtensionHandler; + +import java.util.Set; + +/** + * Custom LanguageExtensionHandler for MagpieBridge that overrides the extensions associated with C to include .h and .i. + * For other languages falls back to the provided fallback LanguageExtensionHandler. + */ +public class GoblintLanguageExtensionHandler implements LanguageExtensionHandler { + + private final LanguageExtensionHandler fallbackLanguageExtensionHandler; + + public GoblintLanguageExtensionHandler(LanguageExtensionHandler fallbackLanguageExtensionHandler) { + this.fallbackLanguageExtensionHandler = fallbackLanguageExtensionHandler; + } + + @Override + public String getLanguageForExtension(String extension) { + if (".c".equals(extension) || ".i".equals(extension) || ".h".equals(extension)) { + return "c"; + } + return fallbackLanguageExtensionHandler.getLanguageForExtension(extension); + } + + @Override + public Set getExtensionsForLanguage(String language) { + if ("c".equals(language)) { + return Set.of(".c", ".i", ".h"); + } + return fallbackLanguageExtensionHandler.getExtensionsForLanguage(language); + } + +} diff --git a/src/main/java/GoblintMagpieServer.java b/src/main/java/magpiebridge/GoblintMagpieServer.java similarity index 97% rename from src/main/java/GoblintMagpieServer.java rename to src/main/java/magpiebridge/GoblintMagpieServer.java index 1bca9e6..5cffc26 100644 --- a/src/main/java/GoblintMagpieServer.java +++ b/src/main/java/magpiebridge/GoblintMagpieServer.java @@ -1,48 +1,50 @@ -import magpiebridge.core.*; -import magpiebridge.file.SourceFileManager; -import org.eclipse.lsp4j.InitializeParams; -import org.eclipse.lsp4j.InitializeResult; -import org.eclipse.lsp4j.jsonrpc.messages.Either; - -import java.util.concurrent.CompletableFuture; - -public class GoblintMagpieServer extends MagpieServer { - - /** - * Future that is completed once the configuration of the server has completed i.e. all analyses have been added. - */ - private final CompletableFuture configurationDoneFuture = new CompletableFuture<>(); - - /** - * Instantiates a new MagpieServer using default {@link MagpieTextDocumentService} and {@link - * MagpieWorkspaceService} with given {@link ServerConfiguration}. - * - * @param config the config - */ - public GoblintMagpieServer(ServerConfiguration config) { - super(config); - } - - /** - * Marks this server instance as fully configured, which allows the initialize request to complete. - * The server will receive no communication other than the initialize request from the client before this is called. - */ - public void configurationDone() { - configurationDoneFuture.complete(null); - } - - @Override - public CompletableFuture initialize(InitializeParams params) { - return configurationDoneFuture.thenCompose(_r -> super.initialize(params)); - } - - @Override - protected void doSingleAnalysis(String language, Either analysis, boolean rerun) { - SourceFileManager fileManager = getSourceFileManager(language); - Analysis a = analysis.isLeft() ? analysis.getLeft() : analysis.getRight(); - if (a != null) { - a.analyze(fileManager.getSourceFileModules().values(), this, rerun); - } - } - -} +package magpiebridge; + +import magpiebridge.core.*; +import magpiebridge.file.SourceFileManager; +import org.eclipse.lsp4j.InitializeParams; +import org.eclipse.lsp4j.InitializeResult; +import org.eclipse.lsp4j.jsonrpc.messages.Either; + +import java.util.concurrent.CompletableFuture; + +public class GoblintMagpieServer extends MagpieServer { + + /** + * Future that is completed once the configuration of the server has completed i.e. all analyses have been added. + */ + private final CompletableFuture configurationDoneFuture = new CompletableFuture<>(); + + /** + * Instantiates a new MagpieServer using default {@link MagpieTextDocumentService} and {@link + * MagpieWorkspaceService} with given {@link ServerConfiguration}. + * + * @param config the config + */ + public GoblintMagpieServer(ServerConfiguration config) { + super(config); + } + + /** + * Marks this server instance as fully configured, which allows the initialize request to complete. + * The server will receive no communication other than the initialize request from the client before this is called. + */ + public void configurationDone() { + configurationDoneFuture.complete(null); + } + + @Override + public CompletableFuture initialize(InitializeParams params) { + return configurationDoneFuture.thenCompose(_r -> super.initialize(params)); + } + + @Override + protected void doSingleAnalysis(String language, Either analysis, boolean rerun) { + SourceFileManager fileManager = getSourceFileManager(language); + Analysis a = analysis.isLeft() ? analysis.getLeft() : analysis.getRight(); + if (a != null) { + a.analyze(fileManager.getSourceFileModules().values(), this, rerun); + } + } + +} diff --git a/src/main/java/GoblintServerConfiguration.java b/src/main/java/magpiebridge/GoblintServerConfiguration.java similarity index 96% rename from src/main/java/GoblintServerConfiguration.java rename to src/main/java/magpiebridge/GoblintServerConfiguration.java index 41f848e..7640269 100644 --- a/src/main/java/GoblintServerConfiguration.java +++ b/src/main/java/magpiebridge/GoblintServerConfiguration.java @@ -1,20 +1,22 @@ -import magpiebridge.core.LanguageExtensionHandler; -import magpiebridge.core.ServerConfiguration; - -/** - * ServerConfiguration subclass that allows setting a custom language extension handler. - */ -public class GoblintServerConfiguration extends ServerConfiguration { - - private LanguageExtensionHandler customLanguageExtensionHandler = null; - - public void setLanguageExtensionHandler(LanguageExtensionHandler languageExtensionHandler) { - customLanguageExtensionHandler = languageExtensionHandler; - } - - @Override - public LanguageExtensionHandler getLanguageExtensionHandler() { - return customLanguageExtensionHandler != null ? customLanguageExtensionHandler : super.getLanguageExtensionHandler(); - } - -} +package magpiebridge; + +import magpiebridge.core.LanguageExtensionHandler; +import magpiebridge.core.ServerConfiguration; + +/** + * ServerConfiguration subclass that allows setting a custom language extension handler. + */ +public class GoblintServerConfiguration extends ServerConfiguration { + + private LanguageExtensionHandler customLanguageExtensionHandler = null; + + public void setLanguageExtensionHandler(LanguageExtensionHandler languageExtensionHandler) { + customLanguageExtensionHandler = languageExtensionHandler; + } + + @Override + public LanguageExtensionHandler getLanguageExtensionHandler() { + return customLanguageExtensionHandler != null ? customLanguageExtensionHandler : super.getLanguageExtensionHandler(); + } + +} diff --git a/src/main/java/analysis/ShowCFGCommand.java b/src/main/java/magpiebridge/ShowCFGCommand.java similarity index 97% rename from src/main/java/analysis/ShowCFGCommand.java rename to src/main/java/magpiebridge/ShowCFGCommand.java index 156a6f3..081b730 100644 --- a/src/main/java/analysis/ShowCFGCommand.java +++ b/src/main/java/magpiebridge/ShowCFGCommand.java @@ -1,97 +1,97 @@ -package analysis; - -import com.google.common.io.CharStreams; -import com.google.gson.JsonPrimitive; -import magpiebridge.core.MagpieClient; -import magpiebridge.core.MagpieServer; -import magpiebridge.core.WorkspaceCommand; -import org.apache.http.HttpResponse; -import org.apache.http.client.methods.HttpPost; -import org.apache.http.entity.ContentType; -import org.apache.http.entity.StringEntity; -import org.apache.http.impl.client.CloseableHttpClient; -import org.apache.http.impl.client.HttpClients; -import org.apache.logging.log4j.LogManager; -import org.apache.logging.log4j.Logger; -import org.eclipse.lsp4j.ExecuteCommandParams; -import org.eclipse.lsp4j.services.LanguageClient; - -import java.io.IOException; -import java.io.InputStreamReader; -import java.nio.charset.StandardCharsets; - -public class ShowCFGCommand implements WorkspaceCommand { - - private final String httpServerAddress; - private final Logger log = LogManager.getLogger(ShowCFGCommand.class); - - public ShowCFGCommand(String httpServerAddress) { - this.httpServerAddress = httpServerAddress; - } - - @Override - public void execute(ExecuteCommandParams params, MagpieServer server, LanguageClient client) { - try { - String funName; - Object uriJson = params.getArguments().get(0); - if (uriJson instanceof JsonPrimitive) { - funName = ((JsonPrimitive) uriJson).getAsString(); - } else { - funName = (String) uriJson; - } - showHTMLinClientOrBrowser(server, client, funName); - } catch (IOException e) { - // Note: Logging the exception using log.error("Error:", e) causes JSON-RPC communication with VS Code to break. - // This is caused by a warning printed to stdout by log4j. See https://github.com/apache/logging-log4j2/issues/1484 for more info. - log.error("Error running showcfg command:"); - e.printStackTrace(); - } - } - - - /** - * Show A HTML page with the given CFG in the client, or in a browser if the client doesn't support this. - * - * @param server The MagpieServer - * @param client The IDE/Editor - * @param funName The name of the function to show the CFG for - * @throws IOException IO exception - */ - - public void showHTMLinClientOrBrowser(MagpieServer server, LanguageClient client, String funName) throws IOException { - if (server.clientSupportShowHTML()) { - if (client instanceof MagpieClient) { - String json = "{\"funName\": \"" + funName + "\"}"; - String content = httpPostJson(httpServerAddress + "cfg/", json); - ((MagpieClient) client).showHTML(content); - } - } /*else { - // TODO: Not tested if this works, probably not? - if (Desktop.isDesktopSupported()) - Desktop.getDesktop().browse(new URI(URIUtils.checkURI(cfg))); - }*/ - } - - - /** - * Sends the request to get the HTML for visualizing the CFG. - * - * @param url The HTTPServer url to post the request to. - * @param json The request body as a JSON. - * @return The response body as a string. - * @throws IOException in case of a problem or the connection was aborted. - */ - - public static String httpPostJson(String url, String json) throws IOException { - CloseableHttpClient httpClient = HttpClients.createDefault(); - HttpPost httpPost = new HttpPost(url); - httpPost.setEntity(new StringEntity(json, ContentType.APPLICATION_JSON)); - HttpResponse response = httpClient.execute(httpPost); - String responseBody = CharStreams.toString(new InputStreamReader(response.getEntity().getContent(), StandardCharsets.UTF_8)); - httpClient.close(); - return responseBody; - } - - -} - +package magpiebridge; + +import com.google.common.io.CharStreams; +import com.google.gson.JsonPrimitive; +import magpiebridge.core.MagpieClient; +import magpiebridge.core.MagpieServer; +import magpiebridge.core.WorkspaceCommand; +import org.apache.http.HttpResponse; +import org.apache.http.client.methods.HttpPost; +import org.apache.http.entity.ContentType; +import org.apache.http.entity.StringEntity; +import org.apache.http.impl.client.CloseableHttpClient; +import org.apache.http.impl.client.HttpClients; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.eclipse.lsp4j.ExecuteCommandParams; +import org.eclipse.lsp4j.services.LanguageClient; + +import java.io.IOException; +import java.io.InputStreamReader; +import java.nio.charset.StandardCharsets; + +public class ShowCFGCommand implements WorkspaceCommand { + + private final String httpServerAddress; + private final Logger log = LogManager.getLogger(ShowCFGCommand.class); + + public ShowCFGCommand(String httpServerAddress) { + this.httpServerAddress = httpServerAddress; + } + + @Override + public void execute(ExecuteCommandParams params, MagpieServer server, LanguageClient client) { + try { + String funName; + Object uriJson = params.getArguments().get(0); + if (uriJson instanceof JsonPrimitive) { + funName = ((JsonPrimitive) uriJson).getAsString(); + } else { + funName = (String) uriJson; + } + showHTMLinClientOrBrowser(server, client, funName); + } catch (IOException e) { + // Note: Logging the exception using log.error("Error:", e) causes JSON-RPC communication with VS Code to break. + // This is caused by a warning printed to stdout by log4j. See https://github.com/apache/logging-log4j2/issues/1484 for more info. + log.error("Error running showcfg command:"); + e.printStackTrace(); + } + } + + + /** + * Show A HTML page with the given CFG in the client, or in a browser if the client doesn't support this. + * + * @param server The MagpieServer + * @param client The IDE/Editor + * @param funName The name of the function to show the CFG for + * @throws IOException IO exception + */ + + public void showHTMLinClientOrBrowser(MagpieServer server, LanguageClient client, String funName) throws IOException { + if (server.clientSupportShowHTML()) { + if (client instanceof MagpieClient) { + String json = "{\"funName\": \"" + funName + "\"}"; + String content = httpPostJson(httpServerAddress + "cfg/", json); + ((MagpieClient) client).showHTML(content); + } + } /*else { + // TODO: Not tested if this works, probably not? + if (Desktop.isDesktopSupported()) + Desktop.getDesktop().browse(new URI(URIUtils.checkURI(cfg))); + }*/ + } + + + /** + * Sends the request to get the HTML for visualizing the CFG. + * + * @param url The HTTPServer url to post the request to. + * @param json The request body as a JSON. + * @return The response body as a string. + * @throws IOException in case of a problem or the connection was aborted. + */ + + public static String httpPostJson(String url, String json) throws IOException { + CloseableHttpClient httpClient = HttpClients.createDefault(); + HttpPost httpPost = new HttpPost(url); + httpPost.setEntity(new StringEntity(json, ContentType.APPLICATION_JSON)); + HttpResponse response = httpClient.execute(httpPost); + String responseBody = CharStreams.toString(new InputStreamReader(response.getEntity().getContent(), StandardCharsets.UTF_8)); + httpClient.close(); + return responseBody; + } + + +} +