add initial autocomplete for installed templatetags (#46)

This commit is contained in:
Josh Thomas 2024-12-23 19:36:54 -06:00 committed by GitHub
parent 5eb8a775e4
commit c16635b1c0
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
8 changed files with 359 additions and 58 deletions

View file

@ -2,7 +2,10 @@ use crate::documents::Store;
use crate::notifier::Notifier;
use crate::tasks::DebugTask;
use anyhow::Result;
use djls_project::DjangoProject;
use djls_worker::Worker;
use pyo3::prelude::*;
use std::collections::BTreeMap;
use std::sync::Arc;
use std::time::Duration;
use tower_lsp::lsp_types::*;
@ -12,6 +15,12 @@ const SERVER_VERSION: &str = "0.1.0";
pub enum LspRequest {
Initialize(InitializeParams),
Completion(CompletionParams),
}
pub enum LspResponse {
Initialize(InitializeResult),
Completion(Option<CompletionResponse>),
}
pub enum LspNotification {
@ -23,6 +32,7 @@ pub enum LspNotification {
}
pub struct DjangoLanguageServer {
project: Option<DjangoProject>,
notifier: Arc<Box<dyn Notifier>>,
documents: Store,
worker: Worker,
@ -33,33 +43,77 @@ impl DjangoLanguageServer {
let notifier = Arc::new(notifier);
Self {
project: None,
notifier,
documents: Store::new(),
worker: Worker::new(),
}
}
pub fn handle_request(&self, request: LspRequest) -> Result<InitializeResult> {
pub fn handle_request(&mut self, request: LspRequest) -> Result<LspResponse> {
match request {
LspRequest::Initialize(_params) => Ok(InitializeResult {
capabilities: ServerCapabilities {
text_document_sync: Some(TextDocumentSyncCapability::Options(
TextDocumentSyncOptions {
open_close: Some(true),
change: Some(TextDocumentSyncKind::INCREMENTAL),
will_save: Some(false),
will_save_wait_until: Some(false),
save: Some(SaveOptions::default().into()),
},
)),
..Default::default()
},
offset_encoding: None,
server_info: Some(ServerInfo {
name: SERVER_NAME.to_string(),
version: Some(SERVER_VERSION.to_string()),
}),
}),
LspRequest::Initialize(params) => {
if let Some(mut project) = DjangoProject::from_initialize_params(&params) {
if let Err(e) = project.initialize() {
self.notifier.log_message(
MessageType::ERROR,
&format!("Failed to initialize Django project: {}", e),
)?;
} else {
self.notifier.log_message(
MessageType::INFO,
&format!("Using project path: {}", project.path().display()),
)?;
self.project = Some(project);
}
}
Ok(LspResponse::Initialize(InitializeResult {
capabilities: ServerCapabilities {
completion_provider: Some(CompletionOptions {
resolve_provider: Some(false),
trigger_characters: Some(vec![
"{".to_string(),
"%".to_string(),
" ".to_string(),
]),
..Default::default()
}),
text_document_sync: Some(TextDocumentSyncCapability::Options(
TextDocumentSyncOptions {
open_close: Some(true),
change: Some(TextDocumentSyncKind::INCREMENTAL),
will_save: Some(false),
will_save_wait_until: Some(false),
save: Some(SaveOptions::default().into()),
},
)),
..Default::default()
},
offset_encoding: None,
server_info: Some(ServerInfo {
name: SERVER_NAME.to_string(),
version: Some(SERVER_VERSION.to_string()),
}),
}))
}
LspRequest::Completion(params) => {
let completions = if let Some(project) = &self.project {
if let Some(tags) = project.template_tags() {
self.documents.get_completions(
params.text_document_position.text_document.uri.as_str(),
params.text_document_position.position,
tags,
)
} else {
None
}
} else {
None
};
Ok(LspResponse::Completion(completions))
}
}
}
@ -71,36 +125,6 @@ impl DjangoLanguageServer {
MessageType::INFO,
&format!("Opened document: {}", params.text_document.uri),
)?;
// Execute - still sync
self.worker.execute(DebugTask::new(
"Quick task".to_string(),
Duration::from_millis(100),
self.notifier.clone(),
))?;
// Submit - spawn async task
let worker = self.worker.clone();
let task = DebugTask::new(
"Important task".to_string(),
Duration::from_secs(1),
self.notifier.clone(),
);
tokio::spawn(async move {
let _ = worker.submit(task).await;
});
// Wait for result - spawn async task
let worker = self.worker.clone();
let task = DebugTask::new(
"Task with result".to_string(),
Duration::from_secs(2),
self.notifier.clone(),
);
tokio::spawn(async move {
let _ = worker.wait_for(task).await;
});
Ok(())
}
LspNotification::DidChangeTextDocument(params) => {