perl_workspace_folder/
lib.rs1#![deny(unsafe_code)]
8#![warn(rust_2018_idioms)]
9#![warn(missing_docs)]
10#![warn(clippy::all)]
11
12use std::path::PathBuf;
13
14#[cfg(not(target_arch = "wasm32"))]
15use perl_uri::uri_to_fs_path;
16use serde_json::Value;
17
18#[derive(Debug, Clone, Default, PartialEq, Eq)]
20pub struct WorkspaceFolderChange {
21 pub added: Vec<String>,
23 pub removed: Vec<String>,
25}
26
27#[must_use]
34pub fn workspace_folder_to_path(workspace_folder: &str) -> PathBuf {
35 if workspace_folder.starts_with("file://") {
36 #[cfg(not(target_arch = "wasm32"))]
37 if let Some(path) = uri_to_fs_path(workspace_folder) {
38 return path;
39 }
40
41 return PathBuf::from(workspace_folder.trim_start_matches("file://"));
42 }
43
44 PathBuf::from(workspace_folder)
45}
46
47#[must_use]
51pub fn extract_workspace_folder_uris(workspace_folders: &[Value]) -> Vec<String> {
52 workspace_folders
53 .iter()
54 .filter_map(|folder| {
55 folder.get("uri").and_then(Value::as_str).map(std::string::ToString::to_string)
56 })
57 .collect()
58}
59
60#[must_use]
64pub fn extract_workspace_folder_change(event: &Value) -> WorkspaceFolderChange {
65 let added = event
66 .get("added")
67 .and_then(Value::as_array)
68 .map_or_else(Vec::new, |entries| extract_workspace_folder_uris(entries));
69
70 let removed = event
71 .get("removed")
72 .and_then(Value::as_array)
73 .map_or_else(Vec::new, |entries| extract_workspace_folder_uris(entries));
74
75 WorkspaceFolderChange { added, removed }
76}
77
78#[must_use]
82pub fn root_path_to_file_uri(root_path: &str) -> String {
83 let path = std::path::Path::new(root_path);
84 url::Url::from_file_path(path).map_or_else(
85 |_| {
86 if root_path.starts_with('/') {
87 format!("file://{}", root_path)
88 } else {
89 format!("file:///{}", root_path.replace('\\', "/"))
90 }
91 },
92 |uri| uri.to_string(),
93 )
94}
95
96#[cfg(test)]
97mod tests {
98 use super::{
99 extract_workspace_folder_change, extract_workspace_folder_uris, root_path_to_file_uri,
100 workspace_folder_to_path,
101 };
102 use serde_json::json;
103 use std::path::PathBuf;
104
105 #[test]
106 fn parses_plain_folder_path() {
107 assert_eq!(workspace_folder_to_path("/tmp/project"), PathBuf::from("/tmp/project"));
108 }
109
110 #[cfg(not(target_arch = "wasm32"))]
111 #[test]
112 fn parses_file_uri_when_possible() {
113 let parsed = workspace_folder_to_path("file:///tmp/project");
114 assert!(parsed.to_string_lossy().contains("tmp"));
115 assert!(parsed.to_string_lossy().contains("project"));
116 }
117
118 #[test]
119 fn extracts_workspace_uris() {
120 let entries = vec![
121 json!({"uri": "file:///one"}),
122 json!({"uri": "file:///two"}),
123 json!({"name": "invalid"}),
124 ];
125 let uris = extract_workspace_folder_uris(&entries);
126 assert_eq!(uris, vec!["file:///one", "file:///two"]);
127 }
128
129 #[test]
130 fn extracts_workspace_change_entries() {
131 let change = extract_workspace_folder_change(&json!({
132 "added": [{"uri": "file:///add"}],
133 "removed": [{"uri": "file:///remove"}],
134 }));
135
136 assert_eq!(change.added, vec!["file:///add"]);
137 assert_eq!(change.removed, vec!["file:///remove"]);
138 }
139
140 #[test]
141 fn converts_legacy_root_path_to_file_uri() {
142 let uri = root_path_to_file_uri("/legacy/workspace");
143 assert_eq!(uri, "file:///legacy/workspace");
144 }
145}