TS + Rust Integration

Rust Lang Server reads from stdin
Client invokes the language server and sends requests
It works!
This commit is contained in:
Noah Santschi-Cooney 2020-02-14 23:14:29 +00:00
parent b4a19265f8
commit 17f65ec5cf
No known key found for this signature in database
GPG key ID: 3B22282472C8AE48
9 changed files with 80 additions and 107 deletions

View file

@ -315,9 +315,9 @@
}
},
"https-proxy-agent": {
"version": "2.2.2",
"resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-2.2.2.tgz",
"integrity": "sha512-c8Ndjc9Bkpfx/vCJueCPy0jlP4ccCCSNDp8xwCZzPjKJUm+B+u9WX2x98Qx4n1PiMNTWo3D7KK5ifNV/yJyRzg==",
"version": "2.2.4",
"resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-2.2.4.tgz",
"integrity": "sha512-OmvfoQ53WLjtA9HeYP9RNrWMJzzAz1JGaSFr1nijg0PVR1JaD/xbJq1mdEIIlxGpXp9eSe/O2LgU9DJmTPd0Eg==",
"dev": true,
"requires": {
"agent-base": "^4.3.0",
@ -698,31 +698,39 @@
}
},
"vscode-jsonrpc": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/vscode-jsonrpc/-/vscode-jsonrpc-4.0.0.tgz",
"integrity": "sha512-perEnXQdQOJMTDFNv+UF3h1Y0z4iSiaN9jIlb0OqIYgosPCZGYh/MCUlkFtV2668PL69lRDO32hmvL2yiidUYg=="
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/vscode-jsonrpc/-/vscode-jsonrpc-5.0.1.tgz",
"integrity": "sha512-JvONPptw3GAQGXlVV2utDcHx0BiY34FupW/kI6mZ5x06ER5DdPG/tXWMVHjTNULF5uKPOUUD0SaXg5QaubJL0A=="
},
"vscode-languageclient": {
"version": "4.4.2",
"resolved": "https://registry.npmjs.org/vscode-languageclient/-/vscode-languageclient-4.4.2.tgz",
"integrity": "sha512-9TUzsg1UM6n1UEyPlWbDf7tK1wJAK7UGFRmGDN8sz4KmbbDiVRh6YicaB/5oRSVTpuV47PdJpYlOl3SJ0RiK1Q==",
"version": "6.1.0",
"resolved": "https://registry.npmjs.org/vscode-languageclient/-/vscode-languageclient-6.1.0.tgz",
"integrity": "sha512-Tcp0VoOaa0YzxL4nEfK9tsmcy76Eo8jNLvFQZwh2c8oMm02luL8uGYPLQNAiZ3XGgegfcwiQFZMqbW7DNV0vxA==",
"requires": {
"vscode-languageserver-protocol": "^3.10.3"
"semver": "^6.3.0",
"vscode-languageserver-protocol": "^3.15.2"
},
"dependencies": {
"semver": {
"version": "6.3.0",
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
"integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw=="
}
}
},
"vscode-languageserver-protocol": {
"version": "3.14.1",
"resolved": "https://registry.npmjs.org/vscode-languageserver-protocol/-/vscode-languageserver-protocol-3.14.1.tgz",
"integrity": "sha512-IL66BLb2g20uIKog5Y2dQ0IiigW0XKrvmWiOvc0yXw80z3tMEzEnHjaGAb3ENuU7MnQqgnYJ1Cl2l9RvNgDi4g==",
"version": "3.15.2",
"resolved": "https://registry.npmjs.org/vscode-languageserver-protocol/-/vscode-languageserver-protocol-3.15.2.tgz",
"integrity": "sha512-GdL05JKOgZ76RDg3suiGCl9enESM7iQgGw4x93ibTh4sldvZmakHmTeZ4iUApPPGKf6O3OVBtrsksBXnHYaxNg==",
"requires": {
"vscode-jsonrpc": "^4.0.0",
"vscode-languageserver-types": "3.14.0"
"vscode-jsonrpc": "^5.0.1",
"vscode-languageserver-types": "3.15.1"
}
},
"vscode-languageserver-types": {
"version": "3.14.0",
"resolved": "https://registry.npmjs.org/vscode-languageserver-types/-/vscode-languageserver-types-3.14.0.tgz",
"integrity": "sha512-lTmS6AlAlMHOvPQemVwo3CezxBp0sNB95KNPkqp3Nxd5VFEnuG1ByM0zlRWos0zjO3ZWtkvhal0COgiV1xIA4A=="
"version": "3.15.1",
"resolved": "https://registry.npmjs.org/vscode-languageserver-types/-/vscode-languageserver-types-3.15.1.tgz",
"integrity": "sha512-+a9MPUQrNGRrGU630OGbYVQ+11iOIovjCkqxajPa9w57Sd5ruK8WQNsslzpa0x/QJqC8kRc2DUxWjIFwoNm4ZQ=="
},
"vscode-test": {
"version": "0.4.3",

View file

@ -10,7 +10,7 @@
"url": "https://github.com/Strum355/vscode-mc-shader"
},
"engines": {
"vscode": "^1.37.0"
"vscode": "^1.42.0"
},
"scripts": {
"update-vscode": "vscode-install",
@ -19,7 +19,7 @@
"compile": "tsc -p ./"
},
"dependencies": {
"vscode-languageclient": "^4.4.2"
"vscode-languageclient": "^6.1.0"
},
"devDependencies": {
"vscode": "^1.1.36"

View file

@ -3,34 +3,38 @@ import * as vscode from 'vscode'
import * as vscodeLang from 'vscode-languageclient'
export async function activate(context: vscode.ExtensionContext) {
const serverModule = context.asAbsolutePath(path.join('server', 'out', 'server.js'))
const debugOpts = { execArgv: ['--nolazy', '--inspect=6009']}
const serverOpts: vscodeLang.ServerOptions = {
run: {
module: serverModule, transport: vscodeLang.TransportKind.ipc
},
debug: {
module: serverModule, transport: vscodeLang.TransportKind.ipc, options: debugOpts
}
}
const outputChannel = vscode.window.createOutputChannel('vscode-mc-shader')
const clientOpts: vscodeLang.LanguageClientOptions = {
documentSelector: [{scheme: 'file', language: 'glsl'}],
outputChannel: outputChannel,
outputChannelName: 'vscode-mc-shader',
synchronize: {
configurationSection: 'mcglsl',
fileEvents: vscode.workspace.createFileSystemWatcher('**/*.{fsh,gsh,vsh,glsl}')
}
},
}
const serverOpts: vscodeLang.ServerOptions = {
command: context.asAbsolutePath(path.join('server', 'target', 'debug', 'vscode-mc-shader')),
}
outputChannel.appendLine('starting language server...')
const langServer = new vscodeLang.LanguageClient('vscode-mc-shader', serverOpts, clientOpts)
context.subscriptions.push(langServer.start())
await langServer.onReady()
langServer.onNotification('sampleText', (...nums: number[]) => {
outputChannel.appendLine(`got notif: ${nums.join(' ')}`)
})
langServer.onNotification('update-config', (dir: string) => {
vscode.workspace.getConfiguration().update('mcglsl.glslangValidatorPath', dir, vscode.ConfigurationTarget.Global)
})
outputChannel.appendLine('language server started!')
}

12
package-lock.json generated
View file

@ -466,9 +466,9 @@
}
},
"tree-kill": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/tree-kill/-/tree-kill-1.2.0.tgz",
"integrity": "sha512-DlX6dR0lOIRDFxI0mjL9IYg6OTncLm/Zt+JiBhE5OlFcAR8yc9S7FFXU9so0oda47frdM/JFsk7UjNt9vscKcg==",
"version": "1.2.2",
"resolved": "https://registry.npmjs.org/tree-kill/-/tree-kill-1.2.2.tgz",
"integrity": "sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==",
"dev": true
},
"tslib": {
@ -516,9 +516,9 @@
}
},
"typescript": {
"version": "3.5.3",
"resolved": "https://registry.npmjs.org/typescript/-/typescript-3.5.3.tgz",
"integrity": "sha512-ACzBtm/PhXBDId6a6sDJfroT2pOWt/oOnk4/dElG5G33ZL776N3Y6/6bKZJBFpd+b05F3Ct9qDjMeJmRWtE2/g==",
"version": "3.7.5",
"resolved": "https://registry.npmjs.org/typescript/-/typescript-3.7.5.tgz",
"integrity": "sha512-/P5lkRXkWHNAbcJIiHPfRoKqyd7bsyCma1hZNUGfn20qm64T6ZBlrzprymeu918H+mB/0rIg2gGK/BXkhhYgBw==",
"dev": true
},
"validate-npm-package-license": {

View file

@ -63,14 +63,14 @@
"vscode:prepublish": "cd client && npm run update-vscode && cd .. && npm run compile",
"compile": "tsc -b",
"watch": "tsc -b -w",
"postinstall": "cd client && npm install && cd ../server && npm install && cd ..",
"lint": "tslint -c tslint.json 'server/src/**/*.ts' && tslint -c tslint.json 'client/src/**/*.ts'",
"fix": "tslint -c tslint.json --fix server/src/**/*.ts && tslint -c tslint.json --fix client/src/**/*.ts"
"postinstall": "cd client && npm install",
"lint": "tslint -c tslint.json 'client/src/**/*.ts'",
"fix": "tslint -c tslint.json --fix client/src/**/*.ts"
},
"devDependencies": {
"@types/node": "^10.14.15",
"concurrently": "^3.6.1",
"tslint": "^5.18.0",
"typescript": "^3.5.3"
"typescript": "^3.7.5"
}
}

3
server/.gitignore vendored
View file

@ -1 +1,2 @@
target
target
sample.log

2
server/Cargo.lock generated
View file

@ -129,7 +129,7 @@ dependencies = [
[[package]]
name = "rust_lsp"
version = "0.6.0"
source = "git+https://github.com/Strum355/RustLSP#30d3247d70b8b8bff1cdeafd61cbfc3126ca432e"
source = "git+https://github.com/Strum355/RustLSP#d820d8f604bbfe09657587b0febc3faa3164e8be"
dependencies = [
"languageserver-types 0.54.0 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",

View file

@ -2,53 +2,17 @@ use rust_lsp::lsp::*;
use rust_lsp::ls_types::*;
use rust_lsp::jsonrpc::*;
use rust_lsp::jsonrpc::method_types::*;
use serde_json::Value;
use std::io;
use std::thread;
use std::net::TcpListener;
use std::net::TcpStream;
fn main() {
let listener = TcpListener::bind(("127.0.0.1", 0)).unwrap();
let local_addr = listener.local_addr().unwrap();
let server_listener = thread::spawn(|| {
tcp_server(listener)
});
let stream = TcpStream::connect(local_addr).unwrap();
let out_stream = stream.try_clone().expect("Failed to clone stream");
let mut endpoint = LSPEndpoint::create_lsp_output_with_output_stream(|| { out_stream });
let stdin = std::io::stdin();
let endpoint_output = LSPEndpoint::create_lsp_output_with_output_stream(|| io::stdout());
server_rpc_handle(&mut endpoint);
}
let langserver = MinecraftShaderLanguageServer{endpoint: endpoint_output.clone()};
fn tcp_server(listener: TcpListener) {
for stream in listener.incoming() {
let stream = stream.expect("Failed to open incoming stream");
let conn_handler = thread::spawn(move|| {
handle_connection(stream)
});
// Only listen to first connection, so that this example can be run as a test
conn_handler.join().unwrap();
break;
}
drop(listener);
}
fn handle_connection(stream: TcpStream) {
let out_stream = stream.try_clone().expect("Failed to clone stream");
let endpoint = LSPEndpoint::create_lsp_output_with_output_stream(|| { out_stream });
let ls = MinecraftShaderLanguageServer { endpoint: endpoint.clone() };
let mut input = io::BufReader::new(stream);
LSPEndpoint::run_server_from_input(&mut input, endpoint, ls);
LSPEndpoint::run_server_from_input(&mut stdin.lock(), endpoint_output, langserver);
}
struct MinecraftShaderLanguageServer {
@ -56,16 +20,18 @@ struct MinecraftShaderLanguageServer {
}
impl MinecraftShaderLanguageServer {
pub fn error_not_available<DATA>(data : DATA) -> MethodError<DATA> {
pub fn error_not_available<DATA>(data: DATA) -> MethodError<DATA> {
let msg = "Functionality not implemented.".to_string();
MethodError::<DATA> { code : 1, message : msg, data : data }
MethodError::<DATA> { code: 1, message: msg, data: data }
}
}
impl LanguageServerHandling for MinecraftShaderLanguageServer {
fn initialize(&mut self, _: InitializeParams, completable: MethodCompletable<InitializeResult, InitializeError>) {
let capabilities = ServerCapabilities::default();
completable.complete(Ok(InitializeResult { capabilities : capabilities }))
let mut capabilities = ServerCapabilities::default();
capabilities.hover_provider = Some(true);
completable.complete(Ok(InitializeResult { capabilities: capabilities }))
}
fn shutdown(&mut self, _: (), completable: LSCompletable<()>) {
completable.complete(Ok(()));
@ -88,16 +54,14 @@ impl LanguageServerHandling for MinecraftShaderLanguageServer {
completable.complete(Err(Self::error_not_available(())));
}
fn hover(&mut self, _: TextDocumentPositionParams, completable: LSCompletable<Hover>) {
let mut endpoint = self.endpoint.clone();
thread::spawn(move || {
client_rpc_handle(&mut endpoint).telemetry_event(Value::Null)
.unwrap();
let hover_str = "hover_text".to_string();
let hover = Hover { contents: HoverContents::Array(vec![MarkedString::String(hover_str)]), range: None };
completable.complete(Ok(hover));
});
self.endpoint.send_notification("sampleText", vec![1,2,3]).unwrap();
completable.complete(Ok(Hover{
contents: HoverContents::Markup(MarkupContent{
kind: MarkupKind::Markdown,
value: String::from("# Hello World"),
}),
range: None,
}));
}
fn signature_help(&mut self, _: TextDocumentPositionParams, completable: LSCompletable<SignatureHelp>) {
completable.complete(Err(Self::error_not_available(())));

View file

@ -2,19 +2,15 @@
"compilerOptions": {
"module": "commonjs",
"target": "es6",
"outDir": "out",
"rootDir": "src",
"outDir": "./client/out",
"rootDir": "./client/src",
"sourceMap": true
},
"include": [
"src"
"./client"
],
"exclude": [
"node_modules",
".vscode-test"
],
"references": [
{ "path": "./client" },
{ "path": "./server" }
]
}