use std::collections::HashMap;
use ambrosia::semantic_token::LEGEND_TYPE;
use dashmap::DashMap;
use tower_lsp::jsonrpc::Result;
use tower_lsp::lsp_types::*;
use tower_lsp::{Client, LanguageServer, LspService, Server};
#[derive(Debug)]
struct Backend {
client: Client,
vfs_map: DashMap<String, String>,
}
#[tower_lsp::async_trait]
impl LanguageServer for Backend {
async fn initialize(&self, _: InitializeParams) -> Result<InitializeResult> {
Ok(InitializeResult {
capabilities: ServerCapabilities {
text_document_sync: Some(TextDocumentSyncCapability::Kind(
TextDocumentSyncKind::FULL,
)),
workspace: None,
completion_provider: Some(CompletionOptions {
trigger_characters: Some(vec!["[".into(), "{".into(), "#".into(),"<".into()]),
resolve_provider: Some(false),
work_done_progress_options: Default::default(),
all_commit_characters: None,
completion_item: None,
}),
hover_provider: None,
semantic_tokens_provider: Some(
SemanticTokensServerCapabilities::SemanticTokensRegistrationOptions(
SemanticTokensRegistrationOptions {
text_document_registration_options: {
TextDocumentRegistrationOptions {
document_selector: Some(vec![DocumentFilter {
language: Some("wikitext".to_owned()),
scheme: Some("file".to_owned()),
pattern: None,
}]),
}
},
semantic_tokens_options: SemanticTokensOptions {
work_done_progress_options: Default::default(),
legend: SemanticTokensLegend {
token_types: LEGEND_TYPE.into(), token_modifiers: vec![],
},
range: Some(false),
full: Some(SemanticTokensFullOptions::Bool(true)),
},
static_registration_options: Default::default(),
},
),
),
..ServerCapabilities::default()
},
server_info: Some(ServerInfo {
name: env!("CARGO_PKG_NAME").to_owned(),
version: Some(env!("CARGO_PKG_VERSION").to_owned()),
}),
offset_encoding: None,
})
}
async fn did_open(&self, param: DidOpenTextDocumentParams) {
self.client
.log_message(MessageType::INFO, "file opened!")
.await;
self.vfs_map.insert(
param.text_document.uri.to_string(),
param.text_document.text,
);
}
async fn did_change(&self, param: DidChangeTextDocumentParams) {
self.client
.log_message(MessageType::INFO, "file changed!")
.await;
param
.content_changes
.into_iter()
.for_each(|change| match change.range {
Some(_) => todo!(),
None => {
self.vfs_map
.insert(param.text_document.uri.to_string(), change.text);
}
})
}
async fn initialized(&self, _: InitializedParams) {
self.client
.log_message(MessageType::INFO, "server initialized!")
.await;
}
async fn semantic_tokens_full(
&self,
params: SemanticTokensParams,
) -> Result<Option<SemanticTokensResult>> {
Ok(Some(SemanticTokensResult::Tokens(SemanticTokens {
result_id: None,
data: vec![SemanticToken {
delta_line: 0,
delta_start: 0,
length: self
.vfs_map
.get(params.text_document.uri.as_str())
.unwrap()
.len() as u32,
token_type: 0,
token_modifiers_bitset: 0,
}],
})))
}
async fn semantic_tokens_range(
&self,
params: SemanticTokensRangeParams,
) -> Result<Option<SemanticTokensRangeResult>> {
todo!()
}
async fn completion(&self, params: CompletionParams) -> Result<Option<CompletionResponse>> {
Ok(Some(CompletionResponse::Array(vec![
CompletionItem::new_simple("label".to_owned(), "detail".to_owned()),
CompletionItem::new_simple("label1".to_owned(), "detail1".to_owned()),
CompletionItem::new_simple("label2".to_owned(), "detail2".to_owned()),
])))
}
async fn shutdown(&self) -> Result<()> {
Ok(())
}
}
impl Backend {
fn new(client: Client) -> Self {
Backend {
client,
vfs_map: Default::default(),
}
}
}
#[tokio::main]
async fn main() {
let stdin = tokio::io::stdin();
let stdout = tokio::io::stdout();
let (service, socket) = LspService::new(Backend::new);
Server::new(stdin, stdout, socket).serve(service).await;
}