use std::future::Future;
use lsp_types::{
DidChangeTextDocumentParams, DidCloseTextDocumentParams, DidOpenTextDocumentParams,
DidSaveTextDocumentParams, InitializeParams, InitializeResult, InitializedParams,
ServerCapabilities, TextDocumentSyncCapability, TextDocumentSyncKind,
};
use tokio_util::sync::CancellationToken;
use crate::context::Context;
use crate::documents::{Documents, PositionEncoding};
use crate::error::LspError;
fn negotiate_position_encoding(
documents: &Documents,
params: &InitializeParams,
) -> lsp_types::PositionEncodingKind {
let offered = params
.capabilities
.general
.as_ref()
.and_then(|g| g.position_encodings.as_deref());
let preferred = [
lsp_types::PositionEncodingKind::UTF8,
lsp_types::PositionEncodingKind::UTF16,
];
let chosen = offered
.and_then(|encodings| {
preferred
.iter()
.find(|kind| encodings.contains(kind))
.cloned()
})
.unwrap_or(lsp_types::PositionEncodingKind::UTF16);
documents.set_position_encoding(if chosen == lsp_types::PositionEncodingKind::UTF8 {
PositionEncoding::Utf8
} else {
PositionEncoding::Utf16
});
chosen
}
pub trait LanguageServer: Send + Sync + 'static {
const TEXT_DOCUMENT_SYNC: TextDocumentSyncKind = TextDocumentSyncKind::INCREMENTAL;
fn documents(&self) -> &Documents;
fn server_capabilities(&self, params: &InitializeParams) -> ServerCapabilities {
let position_encoding = negotiate_position_encoding(self.documents(), params);
ServerCapabilities {
text_document_sync: Some(TextDocumentSyncCapability::Kind(Self::TEXT_DOCUMENT_SYNC)),
position_encoding: Some(position_encoding),
..ServerCapabilities::default()
}
}
fn initialize(
&self,
_ctx: &Context,
params: InitializeParams,
_ct: CancellationToken,
) -> impl Future<Output = Result<InitializeResult, LspError>> + Send {
async move {
Ok(InitializeResult {
capabilities: self.server_capabilities(¶ms),
server_info: None,
})
}
}
fn initialized(
&self,
_ctx: &Context,
_params: InitializedParams,
) -> impl Future<Output = ()> + Send {
async {}
}
fn shutdown(
&self,
_ctx: &Context,
_ct: CancellationToken,
) -> impl Future<Output = Result<(), LspError>> + Send {
async { Ok(()) }
}
fn exit(&self, _ctx: &Context) -> impl Future<Output = ()> + Send {
async {}
}
fn text_document_did_open(
&self,
_ctx: &Context,
_params: DidOpenTextDocumentParams,
) -> impl Future<Output = ()> + Send {
async {}
}
fn text_document_did_change(
&self,
_ctx: &Context,
_params: DidChangeTextDocumentParams,
) -> impl Future<Output = ()> + Send {
async {}
}
fn text_document_did_close(
&self,
_ctx: &Context,
_params: DidCloseTextDocumentParams,
) -> impl Future<Output = ()> + Send {
async {}
}
fn text_document_did_save(
&self,
_ctx: &Context,
_params: DidSaveTextDocumentParams,
) -> impl Future<Output = ()> + Send {
async {}
}
}