mirror of
https://github.com/joshuadavidthomas/django-language-server.git
synced 2025-09-10 20:36:21 +00:00
swap in tower-lsp-server dependency (#100)
This commit is contained in:
parent
33fb726bdc
commit
e098272ea6
11 changed files with 72 additions and 51 deletions
|
@ -17,8 +17,7 @@ serde = { version = "1.0", features = ["derive"] }
|
||||||
serde_json = "1.0"
|
serde_json = "1.0"
|
||||||
thiserror = "2.0"
|
thiserror = "2.0"
|
||||||
tokio = { version = "1.42", features = ["full"] }
|
tokio = { version = "1.42", features = ["full"] }
|
||||||
tower-lsp = { version = "0.20", features = ["proposed"] }
|
tower-lsp-server = { version = "0.21", features = ["proposed"] }
|
||||||
lsp-types = "0.97"
|
|
||||||
|
|
||||||
[profile.dev.package]
|
[profile.dev.package]
|
||||||
insta.opt-level = 3
|
insta.opt-level = 3
|
||||||
|
|
|
@ -5,6 +5,6 @@ edition = "2021"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
pyo3 = { workspace = true }
|
pyo3 = { workspace = true }
|
||||||
tower-lsp = { workspace = true }
|
tower-lsp-server = { workspace = true, features = ["proposed"] }
|
||||||
|
|
||||||
which = "7.0.1"
|
which = "7.0.1"
|
||||||
|
|
|
@ -5,7 +5,7 @@ pub use templatetags::TemplateTags;
|
||||||
use pyo3::prelude::*;
|
use pyo3::prelude::*;
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use std::path::{Path, PathBuf};
|
use std::path::{Path, PathBuf};
|
||||||
use tower_lsp::lsp_types::*;
|
use tower_lsp_server::lsp_types::*;
|
||||||
use which::which;
|
use which::which;
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
|
@ -24,21 +24,6 @@ impl DjangoProject {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn from_initialize_params(params: &InitializeParams) -> Option<Self> {
|
|
||||||
// Try current directory first
|
|
||||||
let path = std::env::current_dir()
|
|
||||||
.ok()
|
|
||||||
// Fall back to workspace root if provided
|
|
||||||
.or_else(|| {
|
|
||||||
params
|
|
||||||
.root_uri
|
|
||||||
.as_ref()
|
|
||||||
.and_then(|uri| uri.to_file_path().ok())
|
|
||||||
});
|
|
||||||
|
|
||||||
path.map(Self::new)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn initialize(&mut self) -> PyResult<()> {
|
pub fn initialize(&mut self) -> PyResult<()> {
|
||||||
let python_env = PythonEnvironment::new().ok_or_else(|| {
|
let python_env = PythonEnvironment::new().ok_or_else(|| {
|
||||||
PyErr::new::<pyo3::exceptions::PyRuntimeError, _>("Could not find Python in PATH")
|
PyErr::new::<pyo3::exceptions::PyRuntimeError, _>("Could not find Python in PATH")
|
||||||
|
|
|
@ -13,4 +13,6 @@ pyo3 = { workspace = true }
|
||||||
serde = { workspace = true }
|
serde = { workspace = true }
|
||||||
serde_json = { workspace = true }
|
serde_json = { workspace = true }
|
||||||
tokio = { workspace = true }
|
tokio = { workspace = true }
|
||||||
tower-lsp = { workspace = true }
|
tower-lsp-server = { workspace = true }
|
||||||
|
|
||||||
|
percent-encoding = "2.3"
|
||||||
|
|
|
@ -1,11 +1,7 @@
|
||||||
use anyhow::{anyhow, Result};
|
use anyhow::{anyhow, Result};
|
||||||
use djls_project::TemplateTags;
|
use djls_project::TemplateTags;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use tower_lsp::lsp_types::{
|
use tower_lsp_server::lsp_types::*;
|
||||||
CompletionItem, CompletionItemKind, CompletionResponse, DidChangeTextDocumentParams,
|
|
||||||
DidCloseTextDocumentParams, DidOpenTextDocumentParams, Documentation, InsertTextFormat,
|
|
||||||
MarkupContent, MarkupKind, Position, Range,
|
|
||||||
};
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct Store {
|
pub struct Store {
|
||||||
|
@ -23,7 +19,7 @@ impl Store {
|
||||||
|
|
||||||
pub fn handle_did_open(&mut self, params: DidOpenTextDocumentParams) -> Result<()> {
|
pub fn handle_did_open(&mut self, params: DidOpenTextDocumentParams) -> Result<()> {
|
||||||
let document = TextDocument::new(
|
let document = TextDocument::new(
|
||||||
String::from(params.text_document.uri),
|
params.text_document.uri.to_string(),
|
||||||
params.text_document.text,
|
params.text_document.text,
|
||||||
params.text_document.version,
|
params.text_document.version,
|
||||||
params.text_document.language_id,
|
params.text_document.language_id,
|
||||||
|
@ -58,7 +54,7 @@ impl Store {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn handle_did_close(&mut self, params: DidCloseTextDocumentParams) -> Result<()> {
|
pub fn handle_did_close(&mut self, params: DidCloseTextDocumentParams) -> Result<()> {
|
||||||
self.remove_document(&String::from(params.text_document.uri));
|
self.remove_document(params.text_document.uri.as_str());
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,19 +1,19 @@
|
||||||
mod documents;
|
mod documents;
|
||||||
mod server;
|
mod server;
|
||||||
mod tasks;
|
mod tasks;
|
||||||
|
mod workspace;
|
||||||
|
|
||||||
use crate::server::DjangoLanguageServer;
|
use crate::server::DjangoLanguageServer;
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
|
use tower_lsp_server::{LspService, Server};
|
||||||
|
|
||||||
pub async fn serve() -> Result<()> {
|
pub async fn serve() -> Result<()> {
|
||||||
let stdin = tokio::io::stdin();
|
let stdin = tokio::io::stdin();
|
||||||
let stdout = tokio::io::stdout();
|
let stdout = tokio::io::stdout();
|
||||||
|
|
||||||
let (service, socket) = tower_lsp::LspService::build(DjangoLanguageServer::new).finish();
|
let (service, socket) = LspService::build(DjangoLanguageServer::new).finish();
|
||||||
|
|
||||||
tower_lsp::Server::new(stdin, stdout, socket)
|
Server::new(stdin, stdout, socket).serve(service).await;
|
||||||
.serve(service)
|
|
||||||
.await;
|
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,12 +1,13 @@
|
||||||
use crate::documents::Store;
|
use crate::documents::Store;
|
||||||
|
use crate::workspace::get_project_path;
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
use djls_project::DjangoProject;
|
use djls_project::DjangoProject;
|
||||||
use djls_worker::Worker;
|
use djls_worker::Worker;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use tokio::sync::RwLock;
|
use tokio::sync::RwLock;
|
||||||
use tower_lsp::jsonrpc::Result as LspResult;
|
use tower_lsp_server::jsonrpc::Result as LspResult;
|
||||||
use tower_lsp::lsp_types::*;
|
use tower_lsp_server::lsp_types::*;
|
||||||
use tower_lsp::{Client, LanguageServer};
|
use tower_lsp_server::{Client, LanguageServer};
|
||||||
|
|
||||||
const SERVER_NAME: &str = "Django Language Server";
|
const SERVER_NAME: &str = "Django Language Server";
|
||||||
const SERVER_VERSION: &str = "0.1.0";
|
const SERVER_VERSION: &str = "0.1.0";
|
||||||
|
@ -34,12 +35,12 @@ impl DjangoLanguageServer {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tower_lsp::async_trait]
|
|
||||||
impl LanguageServer for DjangoLanguageServer {
|
impl LanguageServer for DjangoLanguageServer {
|
||||||
async fn initialize(&self, params: InitializeParams) -> LspResult<InitializeResult> {
|
async fn initialize(&self, params: InitializeParams) -> LspResult<InitializeResult> {
|
||||||
let project = DjangoProject::from_initialize_params(¶ms);
|
let project_path = get_project_path(¶ms);
|
||||||
|
|
||||||
if let Some(mut project) = project {
|
if let Some(path) = project_path {
|
||||||
|
let mut project = DjangoProject::new(path);
|
||||||
match project.initialize() {
|
match project.initialize() {
|
||||||
Ok(()) => {
|
Ok(()) => {
|
||||||
self.log_message(
|
self.log_message(
|
||||||
|
@ -109,7 +110,7 @@ impl LanguageServer for DjangoLanguageServer {
|
||||||
|
|
||||||
self.log_message(
|
self.log_message(
|
||||||
MessageType::INFO,
|
MessageType::INFO,
|
||||||
&format!("Opened document: {}", params.text_document.uri),
|
&format!("Opened document: {:?}", params.text_document.uri),
|
||||||
)
|
)
|
||||||
.await
|
.await
|
||||||
.ok();
|
.ok();
|
||||||
|
@ -128,7 +129,7 @@ impl LanguageServer for DjangoLanguageServer {
|
||||||
|
|
||||||
self.log_message(
|
self.log_message(
|
||||||
MessageType::INFO,
|
MessageType::INFO,
|
||||||
&format!("Changed document: {}", params.text_document.uri),
|
&format!("Changed document: {:?}", params.text_document.uri),
|
||||||
)
|
)
|
||||||
.await
|
.await
|
||||||
.ok();
|
.ok();
|
||||||
|
@ -147,7 +148,7 @@ impl LanguageServer for DjangoLanguageServer {
|
||||||
|
|
||||||
self.log_message(
|
self.log_message(
|
||||||
MessageType::INFO,
|
MessageType::INFO,
|
||||||
&format!("Closed document: {}", params.text_document.uri),
|
&format!("Closed document: {:?}", params.text_document.uri),
|
||||||
)
|
)
|
||||||
.await
|
.await
|
||||||
.ok();
|
.ok();
|
||||||
|
|
41
crates/djls-server/src/workspace.rs
Normal file
41
crates/djls-server/src/workspace.rs
Normal file
|
@ -0,0 +1,41 @@
|
||||||
|
use percent_encoding::percent_decode_str;
|
||||||
|
use std::path::PathBuf;
|
||||||
|
use tower_lsp_server::lsp_types::{InitializeParams, Uri};
|
||||||
|
|
||||||
|
/// Determines the project root path from initialization parameters.
|
||||||
|
///
|
||||||
|
/// Tries the current directory first, then falls back to the first workspace folder.
|
||||||
|
pub fn get_project_path(params: &InitializeParams) -> Option<PathBuf> {
|
||||||
|
// Try current directory first
|
||||||
|
std::env::current_dir().ok().or_else(|| {
|
||||||
|
// Fall back to the first workspace folder URI
|
||||||
|
params
|
||||||
|
.workspace_folders
|
||||||
|
.as_ref()
|
||||||
|
.and_then(|folders| folders.first())
|
||||||
|
.and_then(|folder| uri_to_pathbuf(&folder.uri))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Converts a `file:` URI into an absolute `PathBuf`.
|
||||||
|
fn uri_to_pathbuf(uri: &Uri) -> Option<PathBuf> {
|
||||||
|
// Check if the scheme is "file"
|
||||||
|
if uri.scheme().map_or(true, |s| s.as_str() != "file") {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the path part as a string
|
||||||
|
let encoded_path_str = uri.path().as_str();
|
||||||
|
|
||||||
|
// Decode the percent-encoded path string
|
||||||
|
let decoded_path_cow = percent_decode_str(encoded_path_str).decode_utf8_lossy();
|
||||||
|
let path_str = decoded_path_cow.as_ref();
|
||||||
|
|
||||||
|
#[cfg(windows)]
|
||||||
|
let path_str = {
|
||||||
|
// Remove leading '/' for paths like /C:/...
|
||||||
|
path_str.strip_prefix('/').unwrap_or(path_str)
|
||||||
|
};
|
||||||
|
|
||||||
|
Some(PathBuf::from(path_str))
|
||||||
|
}
|
|
@ -5,7 +5,7 @@ edition = "2021"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
anyhow = { workspace = true }
|
anyhow = { workspace = true }
|
||||||
lsp-types = { workspace = true }
|
tower-lsp-server = { workspace = true }
|
||||||
serde = { workspace = true }
|
serde = { workspace = true }
|
||||||
thiserror = { workspace = true }
|
thiserror = { workspace = true }
|
||||||
toml = "0.8"
|
toml = "0.8"
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
use crate::ast::{AstError, Span};
|
use crate::ast::{AstError, Span};
|
||||||
use crate::lexer::LexerError;
|
use crate::lexer::LexerError;
|
||||||
use crate::parser::ParserError;
|
use crate::parser::ParserError;
|
||||||
use lsp_types;
|
|
||||||
use serde::Serialize;
|
use serde::Serialize;
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
|
use tower_lsp_server::lsp_types;
|
||||||
|
|
||||||
#[derive(Debug, Error, Serialize)]
|
#[derive(Debug, Error, Serialize)]
|
||||||
pub enum TemplateError {
|
pub enum TemplateError {
|
||||||
|
@ -71,14 +71,11 @@ impl TemplateError {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn to_lsp_diagnostic(error: &TemplateError, _source: &str) -> lsp_types::Diagnostic {
|
pub fn to_lsp_diagnostic(error: &TemplateError, _source: &str) -> lsp_types::Diagnostic {
|
||||||
let range = error.span().map_or_else(
|
let range = error.span().map_or_else(lsp_types::Range::default, |span| {
|
||||||
|| lsp_types::Range::default(),
|
|
||||||
|span| {
|
|
||||||
let start = lsp_types::Position::new(0, *span.start());
|
let start = lsp_types::Position::new(0, *span.start());
|
||||||
let end = lsp_types::Position::new(0, span.start() + span.length());
|
let end = lsp_types::Position::new(0, span.start() + span.length());
|
||||||
lsp_types::Range::new(start, end)
|
lsp_types::Range::new(start, end)
|
||||||
},
|
});
|
||||||
);
|
|
||||||
|
|
||||||
lsp_types::Diagnostic {
|
lsp_types::Diagnostic {
|
||||||
range,
|
range,
|
||||||
|
|
|
@ -15,6 +15,6 @@ pyo3 = { workspace = true, features = ["extension-module"] }
|
||||||
pyo3-async-runtimes = { workspace = true, features = ["tokio-runtime"] }
|
pyo3-async-runtimes = { workspace = true, features = ["tokio-runtime"] }
|
||||||
serde_json = { workspace = true }
|
serde_json = { workspace = true }
|
||||||
tokio = { workspace = true }
|
tokio = { workspace = true }
|
||||||
|
tower-lsp-server = { workspace = true }
|
||||||
|
|
||||||
clap = { version = "4.5", features = ["derive"] }
|
clap = { version = "4.5", features = ["derive"] }
|
||||||
tower-lsp = { version = "0.20", features = ["proposed"] }
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue