diff --git a/build.sbt b/build.sbt index db026ebb026..df46543c6e7 100644 --- a/build.sbt +++ b/build.sbt @@ -1,5 +1,9 @@ inThisBuild( List( + version ~= { old => + if (sys.env.contains("CI")) old + else "0.1-SNAPSHOT" // to avoid manually updating extension.js + }, scalaVersion := "2.12.3", organization := "org.scalameta", licenses := Seq( diff --git a/languageserver/src/main/scala/langserver/core/LanguageServer.scala b/languageserver/src/main/scala/langserver/core/LanguageServer.scala index ced6e3465eb..bc3d60881c0 100644 --- a/languageserver/src/main/scala/langserver/core/LanguageServer.scala +++ b/languageserver/src/main/scala/langserver/core/LanguageServer.scala @@ -30,7 +30,7 @@ class LanguageServer(inStream: InputStream, outStream: OutputStream) extends Laz case (_, Shutdown()) => shutdown() - ShutdownResult(0) // the value is a dummy, because Play Json needs to serialize something + ShutdownResult() case c => logger.error(s"Unknown command $c") sys.error("Unknown command") @@ -40,6 +40,7 @@ class LanguageServer(inStream: InputStream, outStream: OutputStream) extends Laz protected val documentManager = new TextDocumentManager(connection) connection.notificationHandlers += { + case Exit() => onExit() case DidOpenTextDocumentParams(td) => onOpenTextDocument(td) case DidChangeTextDocumentParams(td, changes) => onChangeTextDocument(td, changes) case DidSaveTextDocumentParams(td) => onSaveTextDocument(td) @@ -52,6 +53,12 @@ class LanguageServer(inStream: InputStream, outStream: OutputStream) extends Laz connection.start() } + def onExit(): Unit = { + logger.debug("exit") + // TODO: should exit with success code 0 if the shutdown request has been received before; otherwise with error code 1 + sys.exit(0) + } + def onOpenTextDocument(td: TextDocumentItem) = { logger.debug(s"openTextDocuemnt $td") } @@ -82,9 +89,7 @@ class LanguageServer(inStream: InputStream, outStream: OutputStream) extends Laz CompletionList(isIncomplete = false, Nil) } - def shutdown(): Unit = { - - } + def shutdown(): Unit = {} def gotoDefinitionRequest(textDocument: TextDocumentIdentifier, position: Position): DefinitionResult = { DefinitionResult(Seq.empty[Location]) diff --git a/languageserver/src/main/scala/langserver/messages/Commands.scala b/languageserver/src/main/scala/langserver/messages/Commands.scala index 13a47196606..1ce543281ef 100644 --- a/languageserver/src/main/scala/langserver/messages/Commands.scala +++ b/languageserver/src/main/scala/langserver/messages/Commands.scala @@ -141,13 +141,13 @@ object CompletionList { case class InitializeResult(capabilities: ServerCapabilities) extends ResultResponse case class Shutdown() extends ServerCommand -object Shutdown { - implicit val format: Format[Shutdown] = OFormat( - Reads(jsValue => JsSuccess(Shutdown())), - OWrites[Shutdown](s => Json.obj())) -} -case class ShutdownResult(dummy: Int) extends ResultResponse +case class ShutdownResult() extends ResultResponse +object ShutdownResult { + implicit val format: Format[ShutdownResult] = OFormat( + Reads(jsValue => JsSuccess(ShutdownResult())), + OWrites[ShutdownResult](s => Json.obj())) +} case class ShowMessageRequestParams( /** @@ -193,13 +193,20 @@ object ServerCommand extends CommandCompanion[ServerCommand] { override val CommandFormats = Message.MessageFormats( "initialize" -> Json.format[InitializeParams], - "shutdown" -> Shutdown.format, "textDocument/completion" -> valueFormat(TextDocumentCompletionRequest)(_.params), "textDocument/definition" -> valueFormat(TextDocumentDefinitionRequest)(_.params), "textDocument/hover" -> valueFormat(TextDocumentHoverRequest)(_.params), "textDocument/documentSymbol" -> Json.format[DocumentSymbolParams], "textDocument/formatting" -> valueFormat(TextDocumentFormattingRequest)(_.params) ) + + // NOTE: this is a workaround to read `shutdown` request which doesn't have parameters (scala-json-rpc requires parameters for all requests) + override def read(jsonRpcRequestMessage: JsonRpcRequestMessage): JsResult[_ <: ServerCommand] = { + jsonRpcRequestMessage.method match { + case "shutdown" => JsSuccess(Shutdown()) + case _ => super.read(jsonRpcRequestMessage) + } + } } object ClientCommand extends CommandCompanion[ClientCommand] { @@ -217,7 +224,8 @@ case class PublishDiagnostics(uri: String, diagnostics: Seq[Diagnostic]) extends // from client to server -case class ExitNotification() extends Notification +case class Exit() extends Notification + case class DidOpenTextDocumentParams(textDocument: TextDocumentItem) extends Notification case class DidChangeTextDocumentParams( textDocument: VersionedTextDocumentIdentifier, @@ -259,6 +267,14 @@ object Notification extends NotificationCompanion[Notification] { "initialized" -> Initialized.format, "$/cancelRequest" -> Json.format[CancelRequest] ) + + // NOTE: this is a workaround to read `exit` notification which doesn't have parameters (scala-json-rpc requires parameters for all notifications) + override def read(jsonRpcNotificationMessage: JsonRpcNotificationMessage): JsResult[_ <: Notification] = { + jsonRpcNotificationMessage.method match { + case "exit" => JsSuccess(Exit()) + case _ => super.read(jsonRpcNotificationMessage) + } + } } case class DocumentSymbolResult(params: Seq[SymbolInformation]) extends ResultResponse @@ -275,5 +291,6 @@ object ResultResponse extends ResponseCompanion[Any] { "textDocument/hover" -> Json.format[Hover], "textDocument/documentSymbol" -> valueFormat(DocumentSymbolResult)(_.params), "textDocument/formatting" -> valueFormat(DocumentFormattingResult)(_.params), - "shutdown" -> Json.format[ShutdownResult]) + "shutdown" -> ShutdownResult.format + ) } diff --git a/metaserver/src/main/scala/scala/meta/languageserver/ScalametaLanguageServer.scala b/metaserver/src/main/scala/scala/meta/languageserver/ScalametaLanguageServer.scala index c64157b29bb..884f78e821c 100644 --- a/metaserver/src/main/scala/scala/meta/languageserver/ScalametaLanguageServer.scala +++ b/metaserver/src/main/scala/scala/meta/languageserver/ScalametaLanguageServer.scala @@ -155,27 +155,20 @@ class ScalametaLanguageServer( td: TextDocumentIdentifier, options: FormattingOptions ): List[TextEdit] = { - try { - val path = Uri.toPath(td.uri).get - val contents = buffers.read(path) - val fullDocumentRange = Range( - start = Position(0, 0), - end = Position(Int.MaxValue, Int.MaxValue) - ) - val config = cwd.resolve(".scalafmt.conf") - if (Files.isRegularFile(config.toNIO)) { - val formattedContent = - scalafmt.format(contents, path.toString(), config) - List(TextEdit(fullDocumentRange, formattedContent)) - } else { - connection.showMessage(MessageType.Info, s"Missing $config") - Nil - } - } catch { - case NonFatal(e) => - connection.showMessage(MessageType.Error, e.getMessage) - logger.error(e.getMessage, e) - Nil + val path = Uri.toPath(td.uri).get + val contents = buffers.read(path) + val fullDocumentRange = Range( + start = Position(0, 0), + end = Position(Int.MaxValue, Int.MaxValue) + ) + val config = cwd.resolve(".scalafmt.conf") + if (Files.isRegularFile(config.toNIO)) { + val formattedContent = + scalafmt.format(contents, path.toString(), config) + List(TextEdit(fullDocumentRange, formattedContent)) + } else { + connection.showMessage(MessageType.Info, s"Missing $config") + Nil } } @@ -263,27 +256,21 @@ class ScalametaLanguageServer( td: TextDocumentIdentifier, position: Position ): ResultResponse = { - try { - val completions = compiler.autocomplete( - Uri.toPath(td.uri).get, - position.line, - position.character - ) - CompletionList( - isIncomplete = false, - items = completions.map { - case (signature, name) => - CompletionItem( - label = name, - detail = Some(signature) - ) - } - ) - } catch { - case NonFatal(e) => - onError(e) - ShutdownResult(-1) - } + val completions = compiler.autocomplete( + Uri.toPath(td.uri).get, + position.line, + position.character + ) + CompletionList( + isIncomplete = false, + items = completions.map { + case (signature, name) => + CompletionItem( + label = name, + detail = Some(signature) + ) + } + ) } override def hoverRequest(