Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ crate-type = ["cdylib"]

[dependencies]
hex = "0.4.3"
percent-encoding = "2.3.2"
regex = "1.12.2"
serde = { version = "1.0.228", features = ["derive"] }
serde_json = "1.0.145"
Expand Down
8 changes: 4 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ This extension adds support for the Java language to [Zed](https://zed.dev). It

Install the extension via Zeds extension manager. It should work out of the box for most people. However, there are some things to know:

- It is generally recommended to open projects with the Zed-project root at the Java project root folder (where you would commonly have your `pom.xml` or `build.gradle` file).
- It is generally recommended to open projects with the Zed-project root at the Java project root folder (where you would commonly have your `pom.xml` or `build.gradle` file). The extension will automatically detect Maven and Gradle projects in subdirectories, but opening at the project root provides the best experience.

- By default the extension will download and run the latest official version of JDTLS for you, but this requires Java version 21 to be available on your system via either the `$JAVA_HOME` environment variable or as a `java(.exe)` executable on your `$PATH`. If your project requires a lower Java version in the environment, you can specify a different JDK to use for running JDTLS via the `java_home` configuration option.

Expand Down Expand Up @@ -115,9 +115,9 @@ JDTLS provides many configuration options that can be passed via the `initialize
"jdtls": {
"initialization_options": {
"bundles": [],
"workspaceFolders": [
"file:///home/snjeza/Project"
],
// The extension automatically sets this to the worktree root.
// Override only if your Java project root differs from the opened folder:
// "workspaceFolders": ["file:///path/to/your/java/project"],
"settings": {
"java": {
"configuration": {
Expand Down
7 changes: 1 addition & 6 deletions src/java.rs
Original file line number Diff line number Diff line change
Expand Up @@ -388,12 +388,7 @@ impl Extension for Java {
// Inject workspaceFolders default if not already set by the user
let options_obj = options.as_object_mut().unwrap();
if !options_obj.contains_key("workspaceFolders") {
let root = worktree.root_path();
let uri = if root.starts_with('/') {
format!("file://{root}")
} else {
format!("file:///{}", root.replace('\\', "/"))
};
let uri = util::path_to_file_uri(&worktree.root_path());
options_obj.insert("workspaceFolders".to_string(), json!([uri]));
}

Expand Down
69 changes: 69 additions & 0 deletions src/util.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
use percent_encoding::utf8_percent_encode;
use regex::Regex;
use serde::{Deserialize, Serialize, Serializer};
use std::{
Expand Down Expand Up @@ -316,6 +317,42 @@ pub fn path_to_string<P: AsRef<Path>>(path: P) -> zed::Result<String> {
.map_err(|_| PATH_TO_STR_ERROR.to_string())
}

/// Characters to percent-encode in the path component of a file:// URI.
/// Encodes everything except characters that are valid unencoded in URI paths per RFC 3986.
const PATH_ENCODE_SET: percent_encoding::AsciiSet = percent_encoding::NON_ALPHANUMERIC
.remove(b'/')
.remove(b':')
.remove(b'-')
.remove(b'.')
.remove(b'_')
.remove(b'~')
.remove(b'@');

/// Converts a filesystem path to a `file://` URI with proper percent-encoding.
///
/// Handles both Unix (`/home/user/project`) and Windows (`C:\Users\user\project`) paths.
///
/// # Arguments
///
/// * `path` - The filesystem path to convert.
///
/// # Returns
///
/// A properly encoded `file://` URI string.
pub fn path_to_file_uri(path: &str) -> String {
Comment thread
tartarughina marked this conversation as resolved.
let mut uri = String::with_capacity(path.len() + 8);
uri.push_str("file://");
if path.starts_with('/') {
uri.extend(utf8_percent_encode(path, &PATH_ENCODE_SET));
} else {
for chunk in path.split('\\') {
uri.push('/');
uri.extend(utf8_percent_encode(chunk, &PATH_ENCODE_SET));
}
}
uri
}

/// Remove all files or directories that aren't equal to [`filename`].
///
/// This function scans the directory given by [`prefix`] and removes any
Expand Down Expand Up @@ -498,4 +535,36 @@ mod tests {
let serialized = serde_json::to_value(&wrapper).unwrap();
assert_eq!(serialized["args"], "");
}

#[test]
fn test_file_uri_unix_path() {
assert_eq!(
path_to_file_uri("/home/user/project"),
"file:///home/user/project"
);
}

#[test]
fn test_file_uri_unix_path_with_spaces() {
assert_eq!(
path_to_file_uri("/my/path with/spaces"),
"file:///my/path%20with/spaces"
);
}

#[test]
fn test_file_uri_windows_path() {
assert_eq!(
path_to_file_uri(r"C:\Users\user\project"),
"file:///C:/Users/user/project"
);
}

#[test]
fn test_file_uri_windows_path_with_spaces() {
assert_eq!(
path_to_file_uri(r"C:\Users\My User\project"),
"file:///C:/Users/My%20User/project"
);
}
}
Loading