use crate::config::CqllsConfig;
use log::info;
use std::collections::HashMap;
use tokio::sync::RwLock;
use tower_lsp::lsp_types::*;
use tower_lsp::{Client, LanguageServer};
#[derive(Debug)]
pub struct Backend {
pub client: Client,
pub documents: RwLock<HashMap<Url, String>>,
pub current_document: RwLock<Option<RwLock<Document>>>,
pub config: CqllsConfig,
}
#[derive(Debug, Clone)]
pub struct Document {
pub uri: Url,
pub text: String,
}
impl Document {
pub fn new(uri: Url, text: String) -> Self {
Self { uri, text }
}
pub fn change(&mut self, uri: Url, text: String) {
self.uri = uri;
self.text = text;
}
}
impl Backend {
}
#[tower_lsp::async_trait]
impl LanguageServer for Backend {
async fn initialize(
&self,
_: InitializeParams,
) -> tower_lsp::jsonrpc::Result<InitializeResult> {
Ok(InitializeResult {
capabilities: ServerCapabilities {
text_document_sync: Some(TextDocumentSyncCapability::Kind(
TextDocumentSyncKind::FULL,
)),
completion_provider: Some(CompletionOptions {
resolve_provider: Some(false),
trigger_characters: Some(vec![
".".to_string(),
"\"".to_string(),
"'".to_string(),
" ".to_string(),
]),
..Default::default()
}),
document_formatting_provider: Some(OneOf::Left(true)),
..Default::default()
},
..Default::default()
})
}
async fn formatting(
&self,
params: DocumentFormattingParams,
) -> tower_lsp::jsonrpc::Result<Option<Vec<TextEdit>>> {
let document = params.text_document.uri;
if let Some(current_doc) = self.documents.read().await.get(&document) {
let lines: Vec<&str> = current_doc.split('\n').collect();
return Ok(Some(self.format_file(&lines, &document).await));
} else {
return Ok(Some(vec![]));
}
}
async fn initialized(&self, _: InitializedParams) {
self.client
.log_message(MessageType::INFO, "LSP initialized!")
.await;
}
async fn shutdown(&self) -> tower_lsp::jsonrpc::Result<()> {
Ok(())
}
async fn did_change(&self, params: DidChangeTextDocumentParams) {
let uri = params.text_document.uri;
let changes = ¶ms.content_changes;
if let Some(change) = changes.first() {
self.documents
.write()
.await
.insert(uri.clone(), change.text.clone());
let mut current = self.current_document.write().await;
if let Some(ref mut document_lock) = *current {
let mut document = document_lock.write().await;
if document.uri == uri {
document.change(uri.clone(), change.text.clone());
}
}
let diags = self.compute_diagnostics(&change.text).await;
self.client
.publish_diagnostics(uri.clone(), diags, Some(params.text_document.version))
.await;
}
}
async fn did_open(&self, params: DidOpenTextDocumentParams) {
let uri = params.text_document.uri;
let text = params.text_document.text;
let mut current = self.current_document.write().await;
if current.is_none() {
*current = Some(RwLock::new(Document::new(uri.clone(), text.clone())));
}
if let Some(ref mut document_lock) = *current {
let mut document = document_lock.write().await;
document.change(uri.clone(), text.clone());
}
self.documents
.write()
.await
.insert(uri.clone(), text.clone());
self.client
.log_message(MessageType::INFO, format!("Opened: {}", uri))
.await;
let diags = self.compute_diagnostics(&text).await;
self.client
.publish_diagnostics(uri.clone(), diags, Some(params.text_document.version))
.await;
self.client
.log_message(MessageType::INFO, format!("Opened: {}", uri))
.await;
}
async fn completion(
&self,
params: CompletionParams,
) -> tower_lsp::jsonrpc::Result<Option<CompletionResponse>> {
let uri = params.text_document_position.text_document.uri;
let position = params.text_document_position.position;
let documents = self.documents.read().await;
let text = match documents.get(&uri) {
Some(text) => text,
None => return Ok(None),
};
let line = match text.lines().nth(position.line as usize) {
Some(line) => line,
None => return Ok(None),
};
let in_string = Self::is_in_string_literal(line, position.character);
let ssh_keyspaces = self.should_suggest_keyspaces(line, &position);
let ssh_graph_types = self.should_suggest_graph_engine_types(line, &position);
let ssh_keywords = self.should_suggest_keywords(line, &position).await;
let ssh_fields = self.should_suggest_fields(line, &position);
let ssh_from = self.should_suggest_from(line, &position);
let ssh_table_completions = self.should_suggest_table_completions(line, &position);
let ssh_if_not_exists = self.should_suggest_if_not_exists(line, &position);
let ssh_create_keywords = self.should_suggest_create_keywords(line, &position);
let ssh_alter_keywords = self.should_suggest_alter_keywords(line, &position);
let ssh_drop_keywords = self.should_suggest_drop_keywords(line, &position);
let ssh_drop_keyspaces = self.should_suggest_drop_keyspaces(line, &position);
let ssh_drop_tables = self.should_suggest_drop_tables(line, &position);
let ssh_drop_aggregate = self.should_suggest_drop_aggregate(line, &position);
let ssh_drop_function = self.should_suggest_drop_function(line, &position);
let ssh_drop_index = self.should_suggest_drop_indexes(line, &position);
let ssh_drop_type = self.should_suggest_drop_types(line, &position);
let ssh_drop_view = self.should_suggest_drop_views(line, &position);
let ssh_types = self
.should_suggest_types_completions(line, &position, &uri)
.await;
let ssh_type_modifiers = self
.should_suggest_type_modifiers(line, &position, &uri)
.await;
if ssh_keyspaces {
return if in_string {
self.handle_in_string_keyspace_completion(line, &position)
.await
} else {
self.handle_out_of_string_keyspace_completion(line, &position)
.await
};
}
if ssh_create_keywords {
return self.handle_create_keywords();
}
if ssh_alter_keywords {
return self.handle_alter_keywords();
}
if ssh_drop_keywords {
return self.handle_drop_keywords();
}
if ssh_drop_keyspaces {
return self.handle_drop_keyspace_completions(line, &position).await;
}
if ssh_drop_tables {
return self.handle_table_completion(&position).await;
}
if ssh_drop_aggregate {
return self.handle_drop_aggregate_completions().await;
}
if ssh_drop_function {
return self.handle_drop_function_completions().await;
}
if ssh_drop_index {
return self.handle_drop_index_completions().await;
}
if ssh_drop_type {
return self.handle_drop_type_completions().await;
}
if ssh_drop_view {
return self.handle_drop_view_completions().await;
}
if ssh_fields {
return self.handle_fields_completion(line, &position).await;
}
if ssh_from {
return self.handle_from_completion();
}
if ssh_table_completions {
return self.handle_table_completion(&position).await;
}
if ssh_types {
return self.handle_types_completion();
}
if ssh_type_modifiers {
return self.handle_type_modifiers_completion(line);
}
if ssh_if_not_exists {
return self.handle_if_not_exists();
}
if ssh_graph_types {
return if in_string {
self.handle_in_string_graph_engine_completion(line, &position)
.await
} else {
self.handle_out_of_string_graph_engine_completion().await
};
}
if ssh_keywords && !in_string {
return self.handle_keywords_completion();
}
Ok(Some(CompletionResponse::Array(vec![])))
}
}