diff --git a/src/main/kotlin/b/language/server/App.kt b/src/main/kotlin/b/language/server/App.kt index 75b38eab50ef0fd2cc5085067083c92d9958d914..014cb395c7398e42d9f1ac5f07ef89818d3175ef 100644 --- a/src/main/kotlin/b/language/server/App.kt +++ b/src/main/kotlin/b/language/server/App.kt @@ -16,6 +16,7 @@ fun startServer(inputStream: InputStream, outputStream: OutputStream){ val server = Server() val launcher : Launcher<LanguageClient> = LSPLauncher.createServerLauncher(server, inputStream, outputStream) val startListing : Future<*> = launcher.startListening() + server.setRemoteProxy(launcher.remoteProxy) startListing.get() } diff --git a/src/main/kotlin/b/language/server/BDocumentService.kt b/src/main/kotlin/b/language/server/BDocumentService.kt index 2448022e4b4826e5c9cba71300f87777334620ef..a855090740691543bec38bacb84f537a00497c52 100644 --- a/src/main/kotlin/b/language/server/BDocumentService.kt +++ b/src/main/kotlin/b/language/server/BDocumentService.kt @@ -1,5 +1,6 @@ package b.language.server +import b.language.server.communication.CommunicatorInterface import b.language.server.proBMangement.CommandCouldNotBeExecutedException import b.language.server.proBMangement.PathCouldNotBeCreatedException import b.language.server.proBMangement.ProBCommandLineAccess @@ -8,7 +9,7 @@ import org.eclipse.lsp4j.* import org.eclipse.lsp4j.services.TextDocumentService import java.util.concurrent.ConcurrentHashMap -class BDocumentService(private val server: Server) : TextDocumentService { +class BDocumentService(private val server: Server, private val communicator: CommunicatorInterface) : TextDocumentService { private val documents = ConcurrentHashMap<String, String>() private val issueTracker : ConcurrentHashMap<String, Set<String>> = ConcurrentHashMap() @@ -33,45 +34,47 @@ class BDocumentService(private val server: Server) : TextDocumentService { */ override fun didSave(params: DidSaveTextDocumentParams?) { - // server.languageClient.showMessage(MessageParams(MessageType.Log,"Penis")) - - val currentUri = params!!.textDocument.uri - checkUri(currentUri) + communicator.sendDebugMessage("document ${params!!.textDocument.uri} was saved", MessageType.Info) + val currentUri = params.textDocument.uri + checkDocument(currentUri) } /** - * + * checks a document via prob an the set options * @param the uri to perform actions on */ - fun checkUri(currentUri : String){ - val clientSettings = server.getDocumentSettings(currentUri) + fun checkDocument(currentUri : String){ - // server.languageClient.showMessage(MessageParams(MessageType.Log,clientSettings.toString())) + val clientSettings = server.getDocumentSettings(currentUri) + communicator.sendDebugMessage("waiting for document settings", MessageType.Info) clientSettings.thenAccept{ settings -> - val prob : ProBInterface = ProBCommandLineAccess() - // server.languageClient.showMessage(MessageParams(MessageType.Log,settings.toString())) + communicator.setDebugMode(settings.debugMode) + val prob : ProBInterface = ProBCommandLineAccess(communicator) + communicator.sendDebugMessage("settings are $settings", MessageType.Info) try{ val diagnostics: List<Diagnostic> = prob.checkDocument(currentUri, settings) - - server.languageClient.publishDiagnostics(PublishDiagnosticsParams(currentUri, diagnostics)) + communicator.sendDebugMessage("created diagnostics $diagnostics", MessageType.Info) + communicator.publishDiagnostics(PublishDiagnosticsParams(currentUri, diagnostics)) val filesWithProblems = diagnostics.map { diagnostic -> diagnostic.source } - calculateToInvalidate(currentUri, filesWithProblems) - .forEach{uri -> server.languageClient.publishDiagnostics(PublishDiagnosticsParams(uri, listOf()))} + val invalidFiles = calculateToInvalidate(currentUri, filesWithProblems) + invalidFiles.forEach{uri -> communicator.publishDiagnostics(PublishDiagnosticsParams(uri, listOf()))} + communicator.sendDebugMessage("invalidating old files $invalidFiles", MessageType.Info) issueTracker[currentUri] = filesWithProblems.toSet() }catch (e : PathCouldNotBeCreatedException ){ - server.languageClient.showMessage(MessageParams(MessageType.Error, e.message)) + communicator.showMessage(e.message!!, MessageType.Error) }catch (e : CommandCouldNotBeExecutedException){ - server.languageClient.showMessage(MessageParams(MessageType.Error, e.message)) + communicator.showMessage(e.message!!, MessageType.Error) } } + } /** * Gets all uris that are no longer contain problems - * @param currentUri the uri of the current main file + * @param currentUri the uri of the curre nt main file * @param filesWithProblems uris of files containing problems */ fun calculateToInvalidate(currentUri : String, filesWithProblems : List<String>) : List<String>{ @@ -88,7 +91,8 @@ class BDocumentService(private val server: Server) : TextDocumentService { * Registration Options: TextDocumentRegistrationOptions */ override fun didClose(params: DidCloseTextDocumentParams?) { - server.documentSettings.remove(params!!.textDocument.uri) + communicator.sendDebugMessage("document ${params!!.textDocument.uri} was closed - removing meta data", MessageType.Info) + server.documentSettings.remove(params.textDocument.uri) } /** @@ -98,8 +102,9 @@ class BDocumentService(private val server: Server) : TextDocumentService { * Registration Options: TextDocumentChangeRegistrationOptions */ override fun didChange(params: DidChangeTextDocumentParams?) { - val currentUri = params!!.textDocument.uri - checkUri(currentUri) + communicator.sendDebugMessage("document ${params!!.textDocument.uri} was changed", MessageType.Info) + val currentUri = params.textDocument.uri + checkDocument(currentUri) } } \ No newline at end of file diff --git a/src/main/kotlin/b/language/server/Server.kt b/src/main/kotlin/b/language/server/Server.kt index d1b11c312d27fdbc716e80d5ade78ba0c26b0343..ab657f7c99974307a9b5b55651ceb8be1b754ac6 100644 --- a/src/main/kotlin/b/language/server/Server.kt +++ b/src/main/kotlin/b/language/server/Server.kt @@ -1,30 +1,31 @@ package b.language.server +import b.language.server.communication.Communicator import b.language.server.dataStorage.Settings import com.google.gson.JsonObject import org.eclipse.lsp4j.* import org.eclipse.lsp4j.jsonrpc.messages.Either -import org.eclipse.lsp4j.services.LanguageClient -import org.eclipse.lsp4j.services.LanguageServer -import org.eclipse.lsp4j.services.TextDocumentService -import org.eclipse.lsp4j.services.WorkspaceService +import org.eclipse.lsp4j.jsonrpc.services.JsonNotification +import org.eclipse.lsp4j.services.* import java.util.concurrent.CompletableFuture import kotlin.collections.HashMap import kotlin.system.exitProcess -class Server : LanguageServer { +class Server : LanguageServer{ private val textDocumentService : TextDocumentService private val bWorkspaceService : WorkspaceService - lateinit var languageClient : LanguageClient + lateinit var languageClient : LanguageClient var globalSettings : Settings = Settings() val documentSettings : HashMap<String, CompletableFuture<Settings>> = HashMap() var configurationAbility : Boolean = true + init { - textDocumentService = BDocumentService(this) + textDocumentService = BDocumentService(this, Communicator) bWorkspaceService = BWorkspaceService(this) + } @@ -74,6 +75,7 @@ class Server : LanguageServer { fun setRemoteProxy(remoteProxy: LanguageClient) { this.languageClient = remoteProxy + Communicator.client = remoteProxy } @@ -84,6 +86,7 @@ class Server : LanguageServer { * @return settings of the document requested */ fun getDocumentSettings(uri : String) : CompletableFuture<Settings> { + Communicator.sendDebugMessage("received configuration Data of the document $uri", MessageType.Info) if(!configurationAbility){ val returnValue = CompletableFuture<Settings>() returnValue.complete(globalSettings) @@ -104,4 +107,6 @@ class Server : LanguageServer { documentSettings[uri]!! } } + + } \ No newline at end of file diff --git a/src/main/kotlin/b/language/server/Util.kt b/src/main/kotlin/b/language/server/Util.kt index a42106ee353348e5875acf2b05fc0cb6b955da75..d1d0d31b76ce89079e892db531bb2af48ba965b4 100644 --- a/src/main/kotlin/b/language/server/Util.kt +++ b/src/main/kotlin/b/language/server/Util.kt @@ -17,5 +17,6 @@ fun castJsonToSetting(json : JsonObject) : Settings { Gson().fromJson(json.get("wdChecks"), Boolean::class.java), Gson().fromJson(json.get("strictChecks"), Boolean::class.java), Gson().fromJson(json.get("performanceHints"), Boolean::class.java), - File(Gson().fromJson(json.get("probHome"), String::class.java))) + File(Gson().fromJson(json.get("probHome"), String::class.java)), + Gson().fromJson(json.get("debugMode"), Boolean::class.java)) } diff --git a/src/main/kotlin/b/language/server/communication/Communicator.kt b/src/main/kotlin/b/language/server/communication/Communicator.kt new file mode 100644 index 0000000000000000000000000000000000000000..7b8f5912b1abfdb1d4cd4b0c6b9bbcb3e06bd0d8 --- /dev/null +++ b/src/main/kotlin/b/language/server/communication/Communicator.kt @@ -0,0 +1,60 @@ +package b.language.server.communication + +import org.eclipse.lsp4j.MessageParams +import org.eclipse.lsp4j.MessageType +import org.eclipse.lsp4j.PublishDiagnosticsParams +import org.eclipse.lsp4j.services.LanguageClient + + +object Communicator : CommunicatorInterface { + + + /** + * Will be set in the server an encapsulates the client + */ + lateinit var client : LanguageClient + + private var debugMode : Boolean = true + + /** + * Sends the diagnostics + * + * @param diagnostics object containing the Diagnostics + */ + override fun publishDiagnostics(diagnostics: PublishDiagnosticsParams) { + client.publishDiagnostics(diagnostics) + } + + /** + * Sends a debug message resulting in a output channel message + * + * @param message the message to send + * @param severity the Severity of the message (Error/Info/Warning) + */ + override fun sendDebugMessage(message: String, severity: MessageType) { + if(debugMode) { + client.logMessage(MessageParams(severity, message)) + } + + } + + /** + * Sends a popup message resulting in a popup message + * + * @param message the message to send + * @param severity the Severity of the message (Error/Info/Warning) + */ + override fun showMessage(message: String, severity: MessageType) { + client.showMessage(MessageParams(severity, message)) + } + + + /** + * To enable/disable debug mode + * + * @param mode the new state of the debug mode + */ + override fun setDebugMode(mode : Boolean){ + debugMode = mode + } +} \ No newline at end of file diff --git a/src/main/kotlin/b/language/server/communication/CommunicatorInterface.kt b/src/main/kotlin/b/language/server/communication/CommunicatorInterface.kt new file mode 100644 index 0000000000000000000000000000000000000000..b9096f08c5bf4872ac83fc822690fd03e6566388 --- /dev/null +++ b/src/main/kotlin/b/language/server/communication/CommunicatorInterface.kt @@ -0,0 +1,41 @@ +package b.language.server.communication + +import org.eclipse.lsp4j.MessageType +import org.eclipse.lsp4j.PublishDiagnosticsParams + +/** + * Describes the basic functions used to communicate with the outside world + */ +interface CommunicatorInterface { + + /** + * Sends the diagnostics + * + * @param diagnostics object containing the Diagnostics + */ + fun publishDiagnostics(diagnostics : PublishDiagnosticsParams) + + /** + * Sends a debug message resulting in a output channel message + * + * @param message the message to send + * @param severity the Severity of the message (Error/Info/Warning) + */ + fun sendDebugMessage(message: String, severity: MessageType) + + + /** + * Sends a popup message resulting in a popup message + * + * @param message the message to send + * @param severity the Severity of the message (Error/Info/Warning) + */ + fun showMessage(message : String, severity : MessageType) + + /** + * To enable/disable debug mode + * + * @param mode the new state of the debug mode + */ + fun setDebugMode(mode : Boolean) +} \ No newline at end of file diff --git a/src/main/kotlin/b/language/server/dataStorage/Settings.kt b/src/main/kotlin/b/language/server/dataStorage/Settings.kt index 9a2ca6fd1fea92559a7cc3221c33671c486daf26..0cc9534412823959507dd82add8b6a6137d66d34 100644 --- a/src/main/kotlin/b/language/server/dataStorage/Settings.kt +++ b/src/main/kotlin/b/language/server/dataStorage/Settings.kt @@ -3,4 +3,5 @@ package b.language.server.dataStorage import java.io.File data class Settings(val maxNumberOfProblem : Int = 1000, val strictChecks : Boolean = true, val wdChecks : Boolean = true, - val performanceHints : Boolean = true , val probHome : File = File("~/prob_prolog/probcli.sh")) + val performanceHints : Boolean = true , val probHome : File = File("~/prob_prolog/probcli.sh"), + val debugMode : Boolean = true) diff --git a/src/main/kotlin/b/language/server/proBMangement/ProBCommandLineAccess.kt b/src/main/kotlin/b/language/server/proBMangement/ProBCommandLineAccess.kt index 35af31f6a651c1d5e20ce5888a1c997d7c7f97d8..bd34568fadb8db891f9b5272cabf28f770deb028 100644 --- a/src/main/kotlin/b/language/server/proBMangement/ProBCommandLineAccess.kt +++ b/src/main/kotlin/b/language/server/proBMangement/ProBCommandLineAccess.kt @@ -1,5 +1,7 @@ package b.language.server.proBMangement +import b.language.server.communication.Communicator +import b.language.server.communication.CommunicatorInterface import b.language.server.dataStorage.Problem import b.language.server.dataStorage.Settings import com.google.gson.Gson @@ -11,13 +13,14 @@ import java.net.URI /** * Access ProB via command line */ -class ProBCommandLineAccess : ProBInterface{ +class ProBCommandLineAccess(val communicator : CommunicatorInterface) : ProBInterface{ /** * Checks the given document with the help of ProB; Will setup all needed steps to ensure a clean process * @param uri the source to check * @return a list of all problems found */ override fun checkDocument(uri : String, settings: Settings): List<Diagnostic> { + communicator.sendDebugMessage("checking document ($uri) with proB", MessageType.Info ) val realUri = URI(uri) val path = File(realUri.path) val errorPath = File(path.parent + "/tmp/_error.json") @@ -27,11 +30,14 @@ class ProBCommandLineAccess : ProBInterface{ if(!result){ throw PathCouldNotBeCreatedException("The Path leading to $errorPath has not been created due some issue.") } + communicator.sendDebugMessage("creation successful", MessageType.Info) val command = buildCommand(settings, path, errorPath) + communicator.sendDebugMessage("sending command <$command> to proB", MessageType.Info) performActionOnDocument(command) val problems = readProblems(errorPath.path) + communicator.sendDebugMessage("found the following problems: $problems", MessageType.Info) return transformProblems(problems) } @@ -84,6 +90,7 @@ class ProBCommandLineAccess : ProBInterface{ * @return success of the action */ fun createFolder(errorDict : File, errorPath: File) : Boolean{ + communicator.sendDebugMessage("creating errorDict $errorDict and errorFile $errorPath", MessageType.Info) errorDict.mkdirs() FileWriter(errorPath, false).close() return errorDict.exists() && errorPath.exists()