I'm currently writing a language server in rust and have the following problem: I want to add code completion sensitive to the code already been written. I followed the the example for the crate lsp-server I'm using. How can I get the text of the file currently in edit?
Sadly there is not much documentation. I've already tried to look my way through the GitHub repository of rust-analyzer but it is to overwhelming and I can't find a solution. I know how to get the file path but when I open the file I only get the saved version not the edited one.
Currently my code does not much differ from the example, but I add it anyway:
mod completion_data;
use std::error::Error;
use lsp_server::{Connection, ExtractError, Message, RequestId, Response};
use lsp_types::notification::{Initialized, Notification};
use lsp_types::request::{
CodeLensRequest, Completion, DocumentColor, DocumentHighlightRequest, HoverRequest, Initialize,
Request, ShowDocument,
};
use lsp_types::{
CompletionItem, CompletionList, CompletionOptions, TextDocumentChangeRegistrationOptions,
TextDocumentIdentifier, TextDocumentSyncCapability, TextDocumentSyncOptions, WorkspaceEdit,
};
use lsp_types::{InitializeParams, ServerCapabilities};
use serde::de::DeserializeOwned;
use crate::completion_data::get_completion_items;
fn main() -> Result<(), Box<dyn Error + Sync + Send>> {
// Note that we must have our logging only write out to stderr.
eprintln!("starting generic LSP server");
// Create the transport. Includes the stdio (stdin and stdout) versions but this could
// also be implemented to use sockets or HTTP.
let (connection, io_threads) = Connection::stdio();
// Run the server and wait for the two threads to end (typically by trigger LSP Exit event).
let server_capabilities = serde_json::to_value(&ServerCapabilities {
completion_provider: Some(CompletionOptions {
trigger_characters: Some(vec!["&".to_string()]),
..Default::default()
}),
..Default::default()
})
.unwrap();
let initialization_params = connection.initialize(server_capabilities)?;
main_loop(connection, initialization_params)?;
io_threads.join()?;
// Shut down gracefully.
eprintln!("shutting down server");
Ok(())
}
fn main_loop(
connection: Connection,
params: serde_json::Value,
) -> Result<(), Box<dyn Error + Sync + Send>> {
let _params: InitializeParams = serde_json::from_value(params).unwrap();
for msg in &connection.receiver {
match msg {
Message::Request(request) => {
if connection.handle_shutdown(&request)? {
return Ok(());
}
match request.method.as_str() {
Completion::METHOD => {
let (id, compilation) = cast::<Completion>(request)?;
//TODO Get the current text and based on it suggest completion
}
_ => {}
}
}
Message::Response(resp) => {
eprintln!("got response: {:?}", resp);
}
Message::Notification(not) => {
eprintln!("got notification: {:?}", not);
}
}
}
Ok(())
}
fn cast<R>(
req: lsp_server::Request,
) -> Result<(RequestId, R::Params), ExtractError<lsp_server::Request>>
where
R: lsp_types::request::Request,
R::Params: serde::de::DeserializeOwned,
{
req.extract(R::METHOD)
}