add djls-django crate (#6)

* add djls-django crate

* rework

* oops

* add check for GDAL and GeoDjango

* lots of things

* remove unused scripts

* move scripts to dedicated mod and make static consts

* inline gdal check

* rename mod

* rename mod

* move server info to consts

* adjust pyproject

* hide rustfmt config

* simplify django setup

* adjust printing
This commit is contained in:
Josh Thomas 2024-12-07 16:02:48 -06:00 committed by GitHub
parent b7a1de98dd
commit fce343f44d
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
32 changed files with 1139 additions and 291 deletions

View file

@ -1,57 +1,56 @@
mod notifier;
mod server;
use crate::notifier::TowerLspNotifier;
use crate::server::{DjangoLanguageServer, LspNotification, LspRequest};
use anyhow::Result;
use djls_django::DjangoProject;
use tower_lsp::jsonrpc::Result as LspResult;
use tower_lsp::lsp_types::*;
use tower_lsp::{Client, LanguageServer, LspService, Server};
use tower_lsp::{LanguageServer, LspService, Server};
use djls_python::Python;
#[derive(Debug)]
struct Backend {
client: Client,
python: Python,
struct TowerLspBackend {
server: DjangoLanguageServer,
}
#[tower_lsp::async_trait]
impl LanguageServer for Backend {
async fn initialize(&self, _params: InitializeParams) -> LspResult<InitializeResult> {
Ok(InitializeResult {
capabilities: ServerCapabilities {
text_document_sync: Some(TextDocumentSyncCapability::Kind(
TextDocumentSyncKind::INCREMENTAL,
)),
..Default::default()
},
offset_encoding: None,
server_info: Some(ServerInfo {
name: String::from("Django Language Server"),
version: Some(String::from("0.1.0")),
}),
})
impl LanguageServer for TowerLspBackend {
async fn initialize(&self, params: InitializeParams) -> LspResult<InitializeResult> {
self.server
.handle_request(LspRequest::Initialize(params))
.map_err(|_| tower_lsp::jsonrpc::Error::internal_error())
}
async fn initialized(&self, _: InitializedParams) {
self.client
.log_message(MessageType::INFO, "server initialized!")
.await;
self.client
.log_message(MessageType::INFO, format!("\n{}", self.python))
.await;
async fn initialized(&self, params: InitializedParams) {
if self
.server
.handle_notification(LspNotification::Initialized(params))
.is_err()
{
// Handle error
}
}
async fn shutdown(&self) -> LspResult<()> {
Ok(())
self.server
.handle_notification(LspNotification::Shutdown)
.map_err(|_| tower_lsp::jsonrpc::Error::internal_error())
}
}
#[tokio::main]
async fn main() -> Result<()> {
let python = Python::initialize()?;
let django = DjangoProject::setup()?;
let stdin = tokio::io::stdin();
let stdout = tokio::io::stdout();
let (service, socket) = LspService::build(|client| Backend { client, python }).finish();
let (service, socket) = LspService::build(|client| {
let notifier = Box::new(TowerLspNotifier::new(client.clone()));
let server = DjangoLanguageServer::new(django, notifier);
TowerLspBackend { server }
})
.finish();
Server::new(stdin, stdout, socket).serve(service).await;

View file

@ -0,0 +1,59 @@
use anyhow::Result;
use tower_lsp::async_trait;
use tower_lsp::lsp_types::MessageActionItem;
use tower_lsp::lsp_types::MessageType;
use tower_lsp::Client;
#[async_trait]
pub trait Notifier: Send + Sync {
fn log_message(&self, typ: MessageType, msg: &str) -> Result<()>;
fn show_message(&self, typ: MessageType, msg: &str) -> Result<()>;
async fn show_message_request(
&self,
typ: MessageType,
msg: &str,
actions: Option<Vec<MessageActionItem>>,
) -> Result<Option<MessageActionItem>>;
}
pub struct TowerLspNotifier {
client: Client,
}
impl TowerLspNotifier {
pub fn new(client: Client) -> Self {
Self { client }
}
}
#[async_trait]
impl Notifier for TowerLspNotifier {
fn log_message(&self, typ: MessageType, msg: &str) -> Result<()> {
let client = self.client.clone();
let msg = msg.to_string();
tokio::spawn(async move {
client.log_message(typ, msg).await;
});
Ok(())
}
fn show_message(&self, typ: MessageType, msg: &str) -> Result<()> {
let client = self.client.clone();
let msg = msg.to_string();
tokio::spawn(async move {
client.show_message(typ, msg).await;
});
Ok(())
}
async fn show_message_request(
&self,
typ: MessageType,
msg: &str,
actions: Option<Vec<MessageActionItem>>,
) -> Result<Option<MessageActionItem>> {
let client = self.client.clone();
let msg = msg.to_string();
Ok(client.show_message_request(typ, msg, actions).await?)
}
}

60
crates/djls/src/server.rs Normal file
View file

@ -0,0 +1,60 @@
use crate::notifier::Notifier;
use anyhow::Result;
use djls_django::DjangoProject;
use tower_lsp::lsp_types::*;
const SERVER_NAME: &str = "Django Language Server";
const SERVER_VERSION: &str = "0.1.0";
pub enum LspRequest {
Initialize(InitializeParams),
}
pub enum LspNotification {
Initialized(InitializedParams),
Shutdown,
}
pub struct DjangoLanguageServer {
django: DjangoProject,
notifier: Box<dyn Notifier>,
}
impl DjangoLanguageServer {
pub fn new(django: DjangoProject, notifier: Box<dyn Notifier>) -> Self {
Self { django, notifier }
}
pub fn handle_request(&self, request: LspRequest) -> Result<InitializeResult> {
match request {
LspRequest::Initialize(_params) => Ok(InitializeResult {
capabilities: ServerCapabilities {
text_document_sync: Some(TextDocumentSyncCapability::Kind(
TextDocumentSyncKind::INCREMENTAL,
)),
..Default::default()
},
offset_encoding: None,
server_info: Some(ServerInfo {
name: SERVER_NAME.to_string(),
version: Some(SERVER_VERSION.to_string()),
}),
}),
}
}
pub fn handle_notification(&self, notification: LspNotification) -> Result<()> {
match notification {
LspNotification::Initialized(_) => {
self.notifier
.log_message(MessageType::INFO, "server initialized!")?;
self.notifier
.log_message(MessageType::INFO, &format!("\n{}", self.django.py()))?;
self.notifier
.log_message(MessageType::INFO, &format!("\n{}", self.django))?;
Ok(())
}
LspNotification::Shutdown => Ok(()),
}
}
}