-
-
Notifications
You must be signed in to change notification settings - Fork 90
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Support analysis / types in Rust LSP #881
Labels
Comments
I've created two small reproducer scripts in Python and JavaScript. Python # %%
import json
from subprocess import Popen, PIPE
import re
from typing import Any
import uuid
from pathlib import Path
# Path to the Rust Analyzer executable and the file to analyze
rust_analyzer_path = "rust-analyzer"
file_path = Path("src/main.rs").absolute()
def extract_content_length(response: str) -> int:
# Split the response into lines
lines = response.split("\r\n")
# Find the line that starts with "Content-Length:"
content_length_line = next(
(line for line in lines if line.startswith("Content-Length:")), None
)
if content_length_line is not None:
# Extract the number from the line using a regular expression
match = re.search(r"Content-Length: (\d+)", content_length_line)
if match:
return int(match.group(1))
else:
raise ValueError("No number found in Content-Length line")
else:
raise ValueError("No Content-Length line found")
def send_request(server: Popen, request: dict[str, Any]) -> Any:
send_notification(server, request)
return receive_response(server)
def receive_response(server: Popen) -> Any:
response = ""
assert server.stdout is not None
while not response.endswith("\r\n\r\n"):
response += server.stdout.read(1).decode()
content_length = extract_content_length(response)
return json.loads(server.stdout.read(content_length).decode())
def send_notification(server: Popen, request: dict[str, Any]) -> None:
request_json = json.dumps(request)
header = f"Content-Length: {len(request_json.encode())}\r\n\r\n"
assert server.stdin is not None
server.stdin.write(header.encode())
server.stdin.write(request_json.encode())
server.stdin.flush()
# %%
# Start the Rust Analyzer server
server = Popen(
[rust_analyzer_path],
stdin=PIPE,
stdout=PIPE,
)
# %%
# Initialize the LSP client
initialize_params: dict[str, Any] = {
"processId": None,
"capabilities": {},
"initializationOptions": {"checkOnSave": {"enable": False}},
"rootUri": f"file://{file_path.parent}",
}
initalize_request_id = uuid.uuid4()
initialize_request = {
"jsonrpc": "2.0",
"id": str(initalize_request_id),
"method": "initialize",
"params": initialize_params,
}
result = send_request(server, initialize_request)
print(result)
# %%
send_notification(server, {"jsonrpc": "2.0", "method": "initialized"})
# # %%
# # Send textDocument/didOpen notification
did_open_params = {
"textDocument": {
"uri": f"file://{file_path}",
"languageId": "rust",
"version": 1,
"text": file_path.read_text(),
}
}
did_open_notification = {
"jsonrpc": "2.0",
"method": "textDocument/didOpen",
"params": did_open_params,
}
send_notification(server, did_open_notification)
# %%
result = receive_response(server)
print(result)
# %%
# Send textDocument/didChange notification
did_change_params = {
"textDocument": {
"uri": f"file://{file_path}",
"version": 2,
},
"contentChanges": [
{
"text": file_path.read_text(),
}
],
}
did_change_notification = {
"jsonrpc": "2.0",
"method": "textDocument/didChange",
"params": did_change_params,
}
send_notification(server, did_change_notification)
# %%
result = receive_response(server)
print(result)
# %%
exit_request = json.dumps(
{
"jsonrpc": "2.0",
"method": "exit",
}
)
send_notification(server, exit_request)
server.terminate() NodeJs const { spawn } = require('child_process');
const path = require('path');
// Path to the Rust Analyzer executable and the file to analyze
const rustAnalyzerPath = 'rust-analyzer';
const filePath = path.resolve('src/main.rs');
// Start the Rust Analyzer server
const server = spawn(rustAnalyzerPath, [], { stdio: ['pipe', 'pipe', process.stderr] });
// Function to send a JSON-RPC request to the server
function sendRequest(method, params, id) {
const request = JSON.stringify({ jsonrpc: '2.0', method, params, id });
const contentLength = Buffer.byteLength(request, 'utf8');
server.stdin.write(`Content-Length: ${contentLength}\r\n\r\n${request}`);
}
// Function to send a JSON-RPC notification to the server
function sendNotification(method, params) {
const notification = JSON.stringify({ jsonrpc: '2.0', method, params });
const contentLength = Buffer.byteLength(notification, 'utf8');
server.stdin.write(`Content-Length: ${contentLength}\r\n\r\n${notification}`);
}
// Initialize the LSP client
sendRequest('initialize', {
processId: process.pid,
rootPath: path.dirname(filePath),
rootUri: `file://${path.dirname(filePath)}`,
capabilities: {},
}, 1);
// Send the initialized notification
sendNotification('initialized', {});
// Open the file
sendNotification('textDocument/didOpen', {
textDocument: {
uri: `file://${filePath}`,
languageId: 'rust',
version: 1,
text: require('fs').readFileSync(filePath, 'utf8'),
},
});
// Read the server's responses
server.stdout.on('data', (data) => {
console.log('Server response:', data.toString());
});
// Keep the Node.js process running
setInterval(() => {}, 1000); |
This is the communication between vscode and r-a (see https://rust-analyzer.github.io/manual.html#troubleshooting) |
Hofer-Julian
added a commit
that referenced
this issue
Feb 14, 2024
Fixes #881 It still takes a bit until diagnostics arrive, but this way error messages from `cargo` are included as well.
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
In #868 we added rust-analyzer LSP support.
For some reason it only does syntax diagnostics, not types.
The text was updated successfully, but these errors were encountered: