Skip to content

Commit e098272

Browse files
swap in tower-lsp-server dependency (#100)
1 parent 33fb726 commit e098272

File tree

11 files changed

+72
-51
lines changed

11 files changed

+72
-51
lines changed

Cargo.toml

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,7 @@ serde = { version = "1.0", features = ["derive"] }
1717
serde_json = "1.0"
1818
thiserror = "2.0"
1919
tokio = { version = "1.42", features = ["full"] }
20-
tower-lsp = { version = "0.20", features = ["proposed"] }
21-
lsp-types = "0.97"
20+
tower-lsp-server = { version = "0.21", features = ["proposed"] }
2221

2322
[profile.dev.package]
2423
insta.opt-level = 3

crates/djls-project/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,6 @@ edition = "2021"
55

66
[dependencies]
77
pyo3 = { workspace = true }
8-
tower-lsp = { workspace = true }
8+
tower-lsp-server = { workspace = true, features = ["proposed"] }
99

1010
which = "7.0.1"

crates/djls-project/src/lib.rs

Lines changed: 1 addition & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ pub use templatetags::TemplateTags;
55
use pyo3::prelude::*;
66
use std::fmt;
77
use std::path::{Path, PathBuf};
8-
use tower_lsp::lsp_types::*;
8+
use tower_lsp_server::lsp_types::*;
99
use which::which;
1010

1111
#[derive(Debug)]
@@ -24,21 +24,6 @@ impl DjangoProject {
2424
}
2525
}
2626

27-
pub fn from_initialize_params(params: &InitializeParams) -> Option<Self> {
28-
// Try current directory first
29-
let path = std::env::current_dir()
30-
.ok()
31-
// Fall back to workspace root if provided
32-
.or_else(|| {
33-
params
34-
.root_uri
35-
.as_ref()
36-
.and_then(|uri| uri.to_file_path().ok())
37-
});
38-
39-
path.map(Self::new)
40-
}
41-
4227
pub fn initialize(&mut self) -> PyResult<()> {
4328
let python_env = PythonEnvironment::new().ok_or_else(|| {
4429
PyErr::new::<pyo3::exceptions::PyRuntimeError, _>("Could not find Python in PATH")

crates/djls-server/Cargo.toml

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,4 +13,6 @@ pyo3 = { workspace = true }
1313
serde = { workspace = true }
1414
serde_json = { workspace = true }
1515
tokio = { workspace = true }
16-
tower-lsp = { workspace = true }
16+
tower-lsp-server = { workspace = true }
17+
18+
percent-encoding = "2.3"

crates/djls-server/src/documents.rs

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,7 @@
11
use anyhow::{anyhow, Result};
22
use djls_project::TemplateTags;
33
use std::collections::HashMap;
4-
use tower_lsp::lsp_types::{
5-
CompletionItem, CompletionItemKind, CompletionResponse, DidChangeTextDocumentParams,
6-
DidCloseTextDocumentParams, DidOpenTextDocumentParams, Documentation, InsertTextFormat,
7-
MarkupContent, MarkupKind, Position, Range,
8-
};
4+
use tower_lsp_server::lsp_types::*;
95

106
#[derive(Debug)]
117
pub struct Store {
@@ -23,7 +19,7 @@ impl Store {
2319

2420
pub fn handle_did_open(&mut self, params: DidOpenTextDocumentParams) -> Result<()> {
2521
let document = TextDocument::new(
26-
String::from(params.text_document.uri),
22+
params.text_document.uri.to_string(),
2723
params.text_document.text,
2824
params.text_document.version,
2925
params.text_document.language_id,
@@ -58,7 +54,7 @@ impl Store {
5854
}
5955

6056
pub fn handle_did_close(&mut self, params: DidCloseTextDocumentParams) -> Result<()> {
61-
self.remove_document(&String::from(params.text_document.uri));
57+
self.remove_document(params.text_document.uri.as_str());
6258

6359
Ok(())
6460
}

crates/djls-server/src/lib.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,19 @@
11
mod documents;
22
mod server;
33
mod tasks;
4+
mod workspace;
45

56
use crate::server::DjangoLanguageServer;
67
use anyhow::Result;
8+
use tower_lsp_server::{LspService, Server};
79

810
pub async fn serve() -> Result<()> {
911
let stdin = tokio::io::stdin();
1012
let stdout = tokio::io::stdout();
1113

12-
let (service, socket) = tower_lsp::LspService::build(DjangoLanguageServer::new).finish();
14+
let (service, socket) = LspService::build(DjangoLanguageServer::new).finish();
1315

14-
tower_lsp::Server::new(stdin, stdout, socket)
15-
.serve(service)
16-
.await;
16+
Server::new(stdin, stdout, socket).serve(service).await;
1717

1818
Ok(())
1919
}

crates/djls-server/src/server.rs

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,13 @@
11
use crate::documents::Store;
2+
use crate::workspace::get_project_path;
23
use anyhow::Result;
34
use djls_project::DjangoProject;
45
use djls_worker::Worker;
56
use std::sync::Arc;
67
use tokio::sync::RwLock;
7-
use tower_lsp::jsonrpc::Result as LspResult;
8-
use tower_lsp::lsp_types::*;
9-
use tower_lsp::{Client, LanguageServer};
8+
use tower_lsp_server::jsonrpc::Result as LspResult;
9+
use tower_lsp_server::lsp_types::*;
10+
use tower_lsp_server::{Client, LanguageServer};
1011

1112
const SERVER_NAME: &str = "Django Language Server";
1213
const SERVER_VERSION: &str = "0.1.0";
@@ -34,12 +35,12 @@ impl DjangoLanguageServer {
3435
}
3536
}
3637

37-
#[tower_lsp::async_trait]
3838
impl LanguageServer for DjangoLanguageServer {
3939
async fn initialize(&self, params: InitializeParams) -> LspResult<InitializeResult> {
40-
let project = DjangoProject::from_initialize_params(&params);
40+
let project_path = get_project_path(&params);
4141

42-
if let Some(mut project) = project {
42+
if let Some(path) = project_path {
43+
let mut project = DjangoProject::new(path);
4344
match project.initialize() {
4445
Ok(()) => {
4546
self.log_message(
@@ -109,7 +110,7 @@ impl LanguageServer for DjangoLanguageServer {
109110

110111
self.log_message(
111112
MessageType::INFO,
112-
&format!("Opened document: {}", params.text_document.uri),
113+
&format!("Opened document: {:?}", params.text_document.uri),
113114
)
114115
.await
115116
.ok();
@@ -128,7 +129,7 @@ impl LanguageServer for DjangoLanguageServer {
128129

129130
self.log_message(
130131
MessageType::INFO,
131-
&format!("Changed document: {}", params.text_document.uri),
132+
&format!("Changed document: {:?}", params.text_document.uri),
132133
)
133134
.await
134135
.ok();
@@ -147,7 +148,7 @@ impl LanguageServer for DjangoLanguageServer {
147148

148149
self.log_message(
149150
MessageType::INFO,
150-
&format!("Closed document: {}", params.text_document.uri),
151+
&format!("Closed document: {:?}", params.text_document.uri),
151152
)
152153
.await
153154
.ok();

crates/djls-server/src/workspace.rs

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
use percent_encoding::percent_decode_str;
2+
use std::path::PathBuf;
3+
use tower_lsp_server::lsp_types::{InitializeParams, Uri};
4+
5+
/// Determines the project root path from initialization parameters.
6+
///
7+
/// Tries the current directory first, then falls back to the first workspace folder.
8+
pub fn get_project_path(params: &InitializeParams) -> Option<PathBuf> {
9+
// Try current directory first
10+
std::env::current_dir().ok().or_else(|| {
11+
// Fall back to the first workspace folder URI
12+
params
13+
.workspace_folders
14+
.as_ref()
15+
.and_then(|folders| folders.first())
16+
.and_then(|folder| uri_to_pathbuf(&folder.uri))
17+
})
18+
}
19+
20+
/// Converts a `file:` URI into an absolute `PathBuf`.
21+
fn uri_to_pathbuf(uri: &Uri) -> Option<PathBuf> {
22+
// Check if the scheme is "file"
23+
if uri.scheme().map_or(true, |s| s.as_str() != "file") {
24+
return None;
25+
}
26+
27+
// Get the path part as a string
28+
let encoded_path_str = uri.path().as_str();
29+
30+
// Decode the percent-encoded path string
31+
let decoded_path_cow = percent_decode_str(encoded_path_str).decode_utf8_lossy();
32+
let path_str = decoded_path_cow.as_ref();
33+
34+
#[cfg(windows)]
35+
let path_str = {
36+
// Remove leading '/' for paths like /C:/...
37+
path_str.strip_prefix('/').unwrap_or(path_str)
38+
};
39+
40+
Some(PathBuf::from(path_str))
41+
}

crates/djls-templates/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ edition = "2021"
55

66
[dependencies]
77
anyhow = { workspace = true }
8-
lsp-types = { workspace = true }
8+
tower-lsp-server = { workspace = true }
99
serde = { workspace = true }
1010
thiserror = { workspace = true }
1111
toml = "0.8"

crates/djls-templates/src/error.rs

Lines changed: 6 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
use crate::ast::{AstError, Span};
22
use crate::lexer::LexerError;
33
use crate::parser::ParserError;
4-
use lsp_types;
54
use serde::Serialize;
65
use thiserror::Error;
6+
use tower_lsp_server::lsp_types;
77

88
#[derive(Debug, Error, Serialize)]
99
pub enum TemplateError {
@@ -71,14 +71,11 @@ impl TemplateError {
7171
}
7272

7373
pub fn to_lsp_diagnostic(error: &TemplateError, _source: &str) -> lsp_types::Diagnostic {
74-
let range = error.span().map_or_else(
75-
|| lsp_types::Range::default(),
76-
|span| {
77-
let start = lsp_types::Position::new(0, *span.start());
78-
let end = lsp_types::Position::new(0, span.start() + span.length());
79-
lsp_types::Range::new(start, end)
80-
},
81-
);
74+
let range = error.span().map_or_else(lsp_types::Range::default, |span| {
75+
let start = lsp_types::Position::new(0, *span.start());
76+
let end = lsp_types::Position::new(0, span.start() + span.length());
77+
lsp_types::Range::new(start, end)
78+
});
8279

8380
lsp_types::Diagnostic {
8481
range,

crates/djls/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,6 @@ pyo3 = { workspace = true, features = ["extension-module"] }
1515
pyo3-async-runtimes = { workspace = true, features = ["tokio-runtime"] }
1616
serde_json = { workspace = true }
1717
tokio = { workspace = true }
18+
tower-lsp-server = { workspace = true }
1819

1920
clap = { version = "4.5", features = ["derive"] }
20-
tower-lsp = { version = "0.20", features = ["proposed"] }

0 commit comments

Comments
 (0)