Skip to content

Commit 1b436c1

Browse files
authored
Implement Downloadable and LanguageServer traits (#271)
- Prepare the extension to offer multiple LSPs - Standardize retrieval and download of components - Simplify debugger interaction with jdtls
1 parent 905fbd5 commit 1b436c1

10 files changed

Lines changed: 1170 additions & 1059 deletions

File tree

src/debugger.rs

Lines changed: 73 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,8 @@ use zed_extension_api::{
1111

1212
use crate::{
1313
config::get_java_debug_jar,
14-
lsp::LspWrapper,
14+
downloadable::Downloadable,
15+
lsp,
1516
util::{
1617
ArgsStringOrList, create_path_if_not_exists, get_curr_dir, mark_checked_once,
1718
path_to_string, should_use_local_or_download,
@@ -66,15 +67,13 @@ const JAVA_DEBUG_PLUGIN_FORK_URL: &str = "https://github.com/zed-industries/java
6667

6768
const MAVEN_METADATA_URL: &str = "https://repo1.maven.org/maven2/com/microsoft/java/com.microsoft.java.debug.plugin/maven-metadata.xml";
6869

69-
pub fn find_latest_local_debugger() -> Option<PathBuf> {
70+
fn find_latest_local_debugger() -> Option<PathBuf> {
7071
let prefix = PathBuf::from(DEBUGGER_INSTALL_PATH);
71-
// walk the dir where we install debugger
7272
fs::read_dir(&prefix)
7373
.map(|entries| {
7474
entries
7575
.filter_map(Result::ok)
7676
.map(|entry| entry.path())
77-
// get the most recently created jar file
7877
.filter(|path| {
7978
path.is_file() && path.extension().and_then(|ext| ext.to_str()) == Some("jar")
8079
})
@@ -90,52 +89,12 @@ pub fn find_latest_local_debugger() -> Option<PathBuf> {
9089
}
9190

9291
pub struct Debugger {
93-
lsp: LspWrapper,
9492
plugin_path: Option<PathBuf>,
9593
}
9694

9795
impl Debugger {
98-
pub fn new(lsp: LspWrapper) -> Debugger {
99-
Debugger {
100-
plugin_path: None,
101-
lsp,
102-
}
103-
}
104-
105-
pub fn loaded(&self) -> bool {
106-
self.plugin_path.is_some()
107-
}
108-
109-
pub fn get_or_download(
110-
&mut self,
111-
language_server_id: &LanguageServerId,
112-
configuration: &Option<Value>,
113-
worktree: &Worktree,
114-
) -> zed::Result<PathBuf> {
115-
// when the fix to https://github.com/microsoft/java-debug/issues/605 becomes part of an official release
116-
// switch back to this:
117-
// return self.get_or_download_latest_official(language_server_id);
118-
119-
// Use user-configured path if provided
120-
if let Some(jar_path) = get_java_debug_jar(configuration, worktree) {
121-
let path = PathBuf::from(&jar_path);
122-
self.plugin_path = Some(path.clone());
123-
return Ok(path);
124-
}
125-
126-
// Use local installation if update mode requires it
127-
if let Some(path) = should_use_local_or_download(
128-
configuration,
129-
find_latest_local_debugger(),
130-
DEBUGGER_INSTALL_PATH,
131-
)
132-
.map_err(|err| format!("Failed to resolve debugger installation: {err}"))?
133-
{
134-
self.plugin_path = Some(path.clone());
135-
return Ok(path);
136-
}
137-
138-
self.get_or_download_fork(language_server_id)
96+
pub fn new() -> Debugger {
97+
Debugger { plugin_path: None }
13998
}
14099

141100
fn get_or_download_fork(
@@ -283,16 +242,13 @@ impl Debugger {
283242
Ok(jar_path)
284243
}
285244

286-
pub fn start_session(&self) -> zed::Result<TcpArgumentsTemplate> {
287-
let port = self
288-
.lsp
289-
.get()
290-
.map_err(|err| format!("Failed to acquire LSP client lock: {err}"))?
291-
.request::<u16>(
292-
"workspace/executeCommand",
293-
json!({ "command": "vscode.java.startDebugSession" }),
294-
)
295-
.map_err(|err| format!("Failed to start debug session via LSP: {err}"))?;
245+
pub fn start_session(&self, workspace: &str) -> zed::Result<TcpArgumentsTemplate> {
246+
let port = lsp::request::<u16>(
247+
workspace,
248+
"workspace/executeCommand",
249+
json!({ "command": "vscode.java.startDebugSession" }),
250+
)
251+
.map_err(|err| format!("Failed to start debug session via LSP: {err}"))?;
296252

297253
Ok(TcpArgumentsTemplate {
298254
host: None,
@@ -325,11 +281,7 @@ impl Debugger {
325281
.cloned()
326282
.collect::<Vec<String>>();
327283

328-
let entries = self
329-
.lsp
330-
.get()
331-
.map_err(|err| format!("Failed to acquire LSP client lock: {err}"))?
332-
.resolve_main_class(arguments)
284+
let entries = lsp::resolve_main_class(&workspace_folder, arguments)
333285
.map_err(|err| format!("Failed to resolve main class: {err}"))?
334286
.into_iter()
335287
.filter(|entry| {
@@ -382,11 +334,7 @@ impl Debugger {
382334

383335
let arguments = vec![main_class.clone(), project_name.clone(), scope.clone()];
384336

385-
let result = self
386-
.lsp
387-
.get()
388-
.map_err(|err| format!("Failed to acquire LSP client lock: {err}"))?
389-
.resolve_class_path(arguments)
337+
let result = lsp::resolve_class_path(&workspace_folder, arguments)
390338
.map_err(|err| format!("Failed to resolve classpath: {err}"))?;
391339

392340
for resolved in result {
@@ -411,6 +359,10 @@ impl Debugger {
411359
Ok(config)
412360
}
413361

362+
pub fn plugin_path(&self) -> Option<&PathBuf> {
363+
self.plugin_path.as_ref()
364+
}
365+
414366
pub fn inject_plugin_into_options(
415367
&self,
416368
initialization_options: Option<Value>,
@@ -456,3 +408,58 @@ impl Debugger {
456408
}
457409
}
458410
}
411+
412+
impl Downloadable for Debugger {
413+
const INSTALL_PATH: &'static str = DEBUGGER_INSTALL_PATH;
414+
415+
fn find_local(&self) -> Option<PathBuf> {
416+
find_latest_local_debugger()
417+
}
418+
419+
fn loaded(&self) -> bool {
420+
self.plugin_path.is_some()
421+
}
422+
423+
fn fetch_latest_version(&self) -> zed::Result<String> {
424+
Ok("0.53.2".to_string())
425+
}
426+
427+
fn download(
428+
&mut self,
429+
_version: &str,
430+
language_server_id: &LanguageServerId,
431+
) -> zed::Result<PathBuf> {
432+
self.get_or_download_fork(language_server_id)
433+
}
434+
435+
fn get_or_download(
436+
&mut self,
437+
language_server_id: &LanguageServerId,
438+
configuration: &Option<Value>,
439+
worktree: &Worktree,
440+
) -> zed::Result<PathBuf> {
441+
if let Some(jar_path) = self.user_configured_path(configuration, worktree) {
442+
let path = PathBuf::from(&jar_path);
443+
self.plugin_path = Some(path.clone());
444+
return Ok(path);
445+
}
446+
447+
if let Some(path) =
448+
should_use_local_or_download(configuration, self.find_local(), Self::INSTALL_PATH)
449+
.map_err(|err| format!("Failed to resolve debugger installation: {err}"))?
450+
{
451+
self.plugin_path = Some(path.clone());
452+
return Ok(path);
453+
}
454+
455+
self.get_or_download_fork(language_server_id)
456+
}
457+
458+
fn user_configured_path(
459+
&self,
460+
configuration: &Option<Value>,
461+
worktree: &Worktree,
462+
) -> Option<String> {
463+
get_java_debug_jar(configuration, worktree)
464+
}
465+
}

src/downloadable.rs

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
use std::path::PathBuf;
2+
3+
use zed_extension_api::{self as zed, LanguageServerId, Worktree, serde_json::Value};
4+
5+
use crate::util::should_use_local_or_download;
6+
7+
pub trait Downloadable {
8+
const INSTALL_PATH: &'static str;
9+
10+
fn find_local(&self) -> Option<PathBuf>;
11+
12+
fn loaded(&self) -> bool;
13+
14+
fn fetch_latest_version(&self) -> zed::Result<String>;
15+
16+
fn download(
17+
&mut self,
18+
version: &str,
19+
language_server_id: &LanguageServerId,
20+
) -> zed::Result<PathBuf>;
21+
22+
fn get_or_download(
23+
&mut self,
24+
language_server_id: &LanguageServerId,
25+
configuration: &Option<Value>,
26+
worktree: &Worktree,
27+
) -> zed::Result<PathBuf> {
28+
if let Some(path) = self.user_configured_path(configuration, worktree) {
29+
return Ok(PathBuf::from(path));
30+
}
31+
32+
if let Some(path) =
33+
should_use_local_or_download(configuration, self.find_local(), Self::INSTALL_PATH)?
34+
{
35+
return Ok(path);
36+
}
37+
38+
let version = self.fetch_latest_version()?;
39+
self.download(&version, language_server_id)
40+
}
41+
42+
fn user_configured_path(
43+
&self,
44+
_configuration: &Option<Value>,
45+
_worktree: &Worktree,
46+
) -> Option<String> {
47+
None
48+
}
49+
}

0 commit comments

Comments
 (0)