diff --git a/vscode-dotty/package-lock.json b/vscode-dotty/package-lock.json index 25d38e4e4a76..fe381044e733 100644 --- a/vscode-dotty/package-lock.json +++ b/vscode-dotty/package-lock.json @@ -4,6 +4,12 @@ "lockfileVersion": 1, "requires": true, "dependencies": { + "@types/compare-versions": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@types/compare-versions/-/compare-versions-3.0.0.tgz", + "integrity": "sha512-HNXtUQQuW3ThO9DVfTNbdvClVr+8AZlNNa2pxk5qtEvObnT27qh0DdQXTN4h5PuTTGinxwXkRKXsllJxuAzGPw==", + "dev": true + }, "@types/mocha": { "version": "5.2.5", "resolved": "https://registry.npmjs.org/@types/mocha/-/mocha-5.2.5.tgz", @@ -11,9 +17,9 @@ "dev": true }, "@types/node": { - "version": "8.10.28", - "resolved": "https://registry.npmjs.org/@types/node/-/node-8.10.28.tgz", - "integrity": "sha512-iHsAzDg3OLH7JP+wipniUULHoDSWLgEDYOvsar6/mpAkTJd9/n23Ap8ikruMlvRTqMv/LXrflH9v/AfiEqaBGg==", + "version": "8.10.30", + "resolved": "https://registry.npmjs.org/@types/node/-/node-8.10.30.tgz", + "integrity": "sha512-Le8HGMI5gjFSBqcCuKP/wfHC19oURzkU2D+ERIescUoJd+CmNEMYBib9LQ4zj1HHEZOJQWhw2ZTnbD8weASh/Q==", "dev": true }, "ajv": { @@ -276,6 +282,11 @@ "integrity": "sha512-b0553uYA5YAEGgyYIGYROzKQ7X5RAqedkfjiZxwi0kL1g3bOaBNNZfYkzt/CL0umgD5wc9Jec2FbB98CjkMRvQ==", "dev": true }, + "compare-versions": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/compare-versions/-/compare-versions-3.4.0.tgz", + "integrity": "sha512-tK69D7oNXXqUW3ZNo/z7NXTEz22TCF0pTE+YF9cxvaAM9XnkLo1fV621xCLrRR6aevJlKxExkss0vWqUCUpqdg==" + }, "concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", @@ -2068,41 +2079,41 @@ } }, "vscode-jsonrpc": { - "version": "3.6.2", - "resolved": "https://registry.npmjs.org/vscode-jsonrpc/-/vscode-jsonrpc-3.6.2.tgz", - "integrity": "sha512-T24Jb5V48e4VgYliUXMnZ379ItbrXgOimweKaJshD84z+8q7ZOZjJan0MeDe+Ugb+uqERDVV8SBmemaGMSMugA==" + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/vscode-jsonrpc/-/vscode-jsonrpc-4.0.0.tgz", + "integrity": "sha512-perEnXQdQOJMTDFNv+UF3h1Y0z4iSiaN9jIlb0OqIYgosPCZGYh/MCUlkFtV2668PL69lRDO32hmvL2yiidUYg==" }, "vscode-languageclient": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/vscode-languageclient/-/vscode-languageclient-5.0.1.tgz", - "integrity": "sha512-5o4mWbKRrjhgFPc3W1kXSWy9O2HQVacrgLI3gK98RsthKESnpgj9FX+7OQLtLgSvHhaqxJbVVz2xdPfeSDKaZg==", + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/vscode-languageclient/-/vscode-languageclient-5.1.0.tgz", + "integrity": "sha512-Z95Kps8UqD4o17HE3uCkZuvenOsxHVH46dKmaGVpGixEFZigPaVuVxLM/JWeIY9aRenoC0ZD9CK1O7L4jpffKg==", "requires": { "semver": "^5.5.0", - "vscode-languageserver-protocol": "^3.10.3" + "vscode-languageserver-protocol": "3.13.0" } }, "vscode-languageserver": { - "version": "5.0.3", - "resolved": "https://registry.npmjs.org/vscode-languageserver/-/vscode-languageserver-5.0.3.tgz", - "integrity": "sha512-itOImvZfDueQXMhy4pm2SwPKa3AShZvILXFcK/5X3ruiYdZozmx3OeD5Y92dVBt0OzTdbVD9MZcEelH4E7Eu3g==", + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/vscode-languageserver/-/vscode-languageserver-5.1.0.tgz", + "integrity": "sha512-CIsrgx2Y5VHS317g/HwkSTWYBIQmy0DwEyZPmB2pEpVOhYFwVsYpbiJwHIIyLQsQtmRaO4eA2xM8KPjNSdXpBw==", "requires": { - "vscode-languageserver-protocol": "^3.10.3", - "vscode-uri": "^1.0.5" + "vscode-languageserver-protocol": "3.13.0", + "vscode-uri": "^1.0.6" } }, "vscode-languageserver-protocol": { - "version": "3.12.0", - "resolved": "https://registry.npmjs.org/vscode-languageserver-protocol/-/vscode-languageserver-protocol-3.12.0.tgz", - "integrity": "sha512-evY6hmyzLnwQrqlQWPrNBq1z8wrSNjLesmgPzeS6Zv11mVS5UJRel26hbM/DH5tHdn45huNzRW0eFHRmIm8LpA==", + "version": "3.13.0", + "resolved": "https://registry.npmjs.org/vscode-languageserver-protocol/-/vscode-languageserver-protocol-3.13.0.tgz", + "integrity": "sha512-2ZGKwI+P2ovQll2PGAp+2UfJH+FK9eait86VBUdkPd9HRlm8e58aYT9pV/NYanHOcp3pL6x2yTLVCFMcTer0mg==", "requires": { - "vscode-jsonrpc": "^3.6.2", - "vscode-languageserver-types": "^3.12.0" + "vscode-jsonrpc": "^4.0.0", + "vscode-languageserver-types": "3.13.0" } }, "vscode-languageserver-types": { - "version": "3.12.0", - "resolved": "https://registry.npmjs.org/vscode-languageserver-types/-/vscode-languageserver-types-3.12.0.tgz", - "integrity": "sha512-UxqnpzBToPO7Mi2tr/s5JeyPOSKSJtLB8lIdxCg9ZNdvP2cU8wS7iTDtwQKz91Ne4CUmTdf85ddR5SIZKXmMjQ==" + "version": "3.13.0", + "resolved": "https://registry.npmjs.org/vscode-languageserver-types/-/vscode-languageserver-types-3.13.0.tgz", + "integrity": "sha512-BnJIxS+5+8UWiNKCP7W3g9FlE7fErFw0ofP5BXJe7c2tl0VeWh+nNHFbwAS2vmVC4a5kYxHBjRy0UeOtziemVA==" }, "vscode-uri": { "version": "1.0.6", diff --git a/vscode-dotty/package.json b/vscode-dotty/package.json index 09601ac80b2d..1a08ad472c97 100644 --- a/vscode-dotty/package.json +++ b/vscode-dotty/package.json @@ -58,10 +58,12 @@ ], "dependencies": { "child-process-promise": "^2.2.1", - "vscode-languageclient": "^5.0.1", - "vscode-languageserver": "^5.0.3" + "compare-versions": "^3.4.0", + "vscode-languageclient": "^5.1.0", + "vscode-languageserver": "^5.1.0" }, "devDependencies": { + "@types/compare-versions": "^3.0.0", "@types/mocha": "^5.2.5", "@types/node": "^8.10.28", "typescript": "^2.9.2", diff --git a/vscode-dotty/src/compat.ts b/vscode-dotty/src/compat.ts new file mode 100644 index 000000000000..1d11e4236f24 --- /dev/null +++ b/vscode-dotty/src/compat.ts @@ -0,0 +1,46 @@ +import * as vscode from 'vscode'; + +import { HoverRequest } from 'vscode-languageclient'; +import { MarkedString, LanguageClient, LanguageClientOptions, RevealOutputChannelOn, + ServerOptions } from 'vscode-languageclient'; + +// Fix hover functionality when using this version of vscode-dotty with Dotty +// Language Server 0.9 or earlier. +// Without this, the displayed hover would be "[object Object]". +export function enableOldServerWorkaround(client: LanguageClient): void { + client.clientOptions.middleware = { + provideHover: (document, position, token, next) => { + // This code is adapted from HoverFeature#registerLanguageProvider in + // https://github.com/Microsoft/vscode-languageserver-node/blob/master/client/src/client.ts + return client + .sendRequest(HoverRequest.type, + client.code2ProtocolConverter.asTextDocumentPositionParams(document, position), token) + .then( + hover => { + if (!hover) { + return undefined + } + // The server is supposed to return string or { language: string, + // value: string } or an array of those things, but instead it returns + // an array of { value: string }. This used to work but with a recent + // vscode-languageclient the user ends up seeing "[object Object]" as + // the hover information. + // We work around this by manually parsing the array of { value: string } + // into a Hover. + const contents = hover.contents as { value: string }[] + let result: vscode.MarkdownString[] = [] + for (let element of contents) { + let item = new vscode.MarkdownString() + item.appendCodeblock(element.value, "scala") + result.push(item) + } + return new vscode.Hover(result) + }, + error => { + client.logFailedRequest(HoverRequest.type, error) + return Promise.resolve(null) + } + ) + } + } +} diff --git a/vscode-dotty/src/extension.ts b/vscode-dotty/src/extension.ts index 52921936017a..75e2accbbf64 100644 --- a/vscode-dotty/src/extension.ts +++ b/vscode-dotty/src/extension.ts @@ -4,18 +4,20 @@ import * as fs from 'fs'; import * as path from 'path'; import * as cpp from 'child-process-promise'; +import * as compareVersions from 'compare-versions'; import { ExtensionContext } from 'vscode'; import * as vscode from 'vscode'; import { LanguageClient, LanguageClientOptions, RevealOutputChannelOn, ServerOptions } from 'vscode-languageclient'; +import { enableOldServerWorkaround } from './compat' let extensionContext: ExtensionContext let outputChannel: vscode.OutputChannel export function activate(context: ExtensionContext) { extensionContext = context - outputChannel = vscode.window.createOutputChannel('Dotty Language Client'); + outputChannel = vscode.window.createOutputChannel("Dotty"); const sbtArtifact = "org.scala-sbt:sbt-launch:1.2.3" const buildSbtFile = `${vscode.workspace.rootPath}/build.sbt` @@ -36,7 +38,7 @@ export function activate(context: ExtensionContext) { run({ module: context.asAbsolutePath('out/src/passthrough-server.js'), args: [ port.toString() ] - }) + }, false) }) } else { @@ -72,11 +74,13 @@ function runLanguageServer(coursierPath: string, languageServerArtifactFile: str if (err) throw err else { const languageServerArtifact = data.toString().trim() + const languageServerVersion = languageServerArtifact.split(":")[2] + const isOldServer = compareVersions(languageServerVersion, "0.9.x") <= 0 fetchWithCoursier(coursierPath, languageServerArtifact).then((languageServerClasspath) => { run({ command: "java", args: ["-classpath", languageServerClasspath, "dotty.tools.languageserver.Main", "-stdio"] - }) + }, isOldServer) }) } }) @@ -149,7 +153,7 @@ function configureIDE(sbtClasspath: string, languageServerScalaVersion: string, }) } -function run(serverOptions: ServerOptions) { +function run(serverOptions: ServerOptions, isOldServer: boolean) { const clientOptions: LanguageClientOptions = { documentSelector: [ { language: 'scala', scheme: 'file', pattern: '**/*.scala' }, @@ -158,12 +162,13 @@ function run(serverOptions: ServerOptions) { synchronize: { configurationSection: 'dotty' }, + outputChannel: outputChannel, revealOutputChannelOn: RevealOutputChannelOn.Never } - outputChannel.dispose() - - const client = new LanguageClient('dotty', 'Dotty Language Server', serverOptions, clientOptions); + const client = new LanguageClient("dotty", "Dotty", serverOptions, clientOptions) + if (isOldServer) + enableOldServerWorkaround(client) // Push the disposable to the context's subscriptions so that the // client can be deactivated on extension deactivation