Skip to content

Commit e3a32fe

Browse files
committed
feat(lsp): patch root fields in initialize request
- Add ensure_root to patch rootUri, rootPath, and workspaceFolders in LSP initialize - Remove wine pre-build and runner from Cross.toml for Windows target - Refactor PID patching logic to run after ensure_root in proxy/io.rs - Update tests to cover ensure_root behavior
1 parent 4592b1a commit e3a32fe

File tree

4 files changed

+96
-26
lines changed

4 files changed

+96
-26
lines changed

Cross.toml

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,3 @@ image = "ghcr.io/cross-rs/x86_64-unknown-linux-gnu:latest"
33

44
[target.x86_64-pc-windows-gnu]
55
image = "ghcr.io/cross-rs/x86_64-pc-windows-gnu:latest"
6-
pre-build = [
7-
"dpkg --add-architecture i386",
8-
"apt-get update",
9-
"apt-get install -y wine wine64"
10-
]
11-
runner = "wine64"

src/lsp/binding.rs

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -301,6 +301,63 @@ pub fn encode_path(msg: &Bytes, config: &mut ProxyConfig) {
301301
}
302302
}
303303

304+
pub fn ensure_root(msg: &mut Bytes, config: &ProxyConfig) {
305+
let docker_uri = format!("file://{}", config.docker_internal_path);
306+
307+
// Patch rootUri
308+
let key = b"\"rootUri\":\"";
309+
if let Some(mut beg) = find(msg, key) {
310+
beg += key.len();
311+
if let Some(mut end) = find(&msg[beg..], b"\"") {
312+
end += beg; // Make it absolute position
313+
let before = &msg[..beg];
314+
let after = &msg[end..];
315+
*msg = Bytes::from([before, docker_uri.as_bytes(), after].concat());
316+
}
317+
}
318+
319+
// Patch rootPath if present
320+
let key = b"\"rootPath\":\"";
321+
if let Some(mut beg) = find(msg, key) {
322+
beg += key.len();
323+
if let Some(mut end) = find(&msg[beg..], b"\"") {
324+
end += beg;
325+
let before = &msg[..beg];
326+
let after = &msg[end..];
327+
*msg = Bytes::from([before, docker_uri.as_bytes(), after].concat());
328+
}
329+
}
330+
331+
let key = b"\"workspaceFolders\":[";
332+
if let Some(mut beg) = find(msg, key) {
333+
beg += key.len();
334+
if let Some(mut end) = find(&msg[beg..], b"]") {
335+
end += beg;
336+
let before = &msg[..beg];
337+
let after = &msg[end..];
338+
if let Some(ws) = patch_workspace_folders(&msg[beg..end], &docker_uri) {
339+
*msg = Bytes::from([before, &ws, after].concat());
340+
}
341+
}
342+
}
343+
}
344+
345+
fn patch_workspace_folders(msg: &[u8], docker_uri: &str) -> Option<Bytes> {
346+
let key = b"\"uri\":\"";
347+
let mut result = None;
348+
for uri_beg in find_iter(msg, key) {
349+
let beg = uri_beg + key.len();
350+
if let Some(mut end) = find(&msg[beg..], b"\"") {
351+
end += beg;
352+
let before = &msg[..beg];
353+
let after = &msg[end..];
354+
result = Some(Bytes::from([before, docker_uri.as_bytes(), after].concat()));
355+
}
356+
}
357+
358+
result
359+
}
360+
304361
#[cfg(test)]
305362
mod tests {
306363
use super::*;
@@ -365,6 +422,25 @@ mod tests {
365422
lspbody!(&expected => "bytes")
366423
);
367424
}
425+
426+
#[test]
427+
fn ensure_root_patches_correctly() {
428+
let mut config = construct_config();
429+
config.local_path = "/test/path/app".to_string();
430+
431+
let msg = lspmsg!(
432+
"method": "initialize",
433+
"rootUri": "file:///test/path",
434+
"rootPath": "/test/path"
435+
);
436+
437+
let mut request = Bytes::from(msg);
438+
ensure_root(&mut request, &config);
439+
440+
let body = lspbody!(&request => "string");
441+
assert!(find(body, b"\"rootUri\":\"file:///usr/home/app\"").is_some());
442+
assert!(find(body, b"\"rootPath\":\"file:///usr/home/app\"").is_some());
443+
}
368444
}
369445

370446
#[cfg(test)]

src/lsp/pid.rs

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
use memchr::memmem::find;
21
use serde_json::{Value, json};
32
use tokio_util::bytes::Bytes;
43
use tracing::{debug, trace};
@@ -21,12 +20,7 @@ impl PidHandler {
2120
pub fn try_take_initialize_process_id(
2221
&mut self,
2322
raw_bytes: &mut Bytes,
24-
) -> serde_json::error::Result<bool> {
25-
if find(raw_bytes, br#""method":"initialize""#).is_none() {
26-
trace!("Initialize method not found, skipping patch");
27-
return Ok(false);
28-
}
29-
23+
) -> serde_json::error::Result<()> {
3024
debug!("Initialize method found, patching");
3125
trace!(?raw_bytes, "before patch");
3226

@@ -42,6 +36,6 @@ impl PidHandler {
4236
trace!(?raw_bytes, "patched");
4337
}
4438

45-
Ok(true)
39+
Ok(())
4640
}
4741
}

src/proxy/io.rs

Lines changed: 18 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
1+
use memchr::memmem::find;
12
use std::time::Duration;
23
use tokio_util::sync::CancellationToken;
34

45
use crate::lsp::{
5-
binding::{RequestTracker, redirect_uri},
6+
binding::{RequestTracker, ensure_root, redirect_uri},
67
parser::{LspFramedReader, send_message},
78
pid::PidHandler,
89
};
@@ -109,7 +110,7 @@ where
109110
async move {
110111
let mut reader = LspFramedReader::new(reader);
111112
let mut empty_counter = 0;
112-
let mut pid_patched = false;
113+
let mut lsp_initialized = false;
113114
// The PID patch is required only on the client side for the `initialize` method.
114115
let mut pid_handler: Option<PidHandler> = match pair {
115116
Pair::Server => None,
@@ -137,15 +138,14 @@ where
137138
}
138139

139140
for mut msg in msgs {
140-
if config_clone.requires_patch_pid() &&
141-
!pid_patched &&
142-
let Some(ref mut pid_handler_ref) = pid_handler {
143-
trace!("Trying to take the PID from the initialize method");
141+
if config_clone.use_docker {
142+
if !lsp_initialized && find(&msg, br#""method":"initialize""#).is_some() {
143+
lsp_initialized = true;
144+
145+
ensure_root(&mut msg, &config_clone);
144146

145-
// The function returns true if the take succeeds
146-
pid_patched = pid_handler_ref.try_take_initialize_process_id(&mut msg)?;
147+
trace!("Initialize method found");
147148

148-
if pid_patched {
149149
// If it is in initialize method, capture the
150150
// colon encoding in Windows
151151
#[cfg(windows)]
@@ -154,14 +154,20 @@ where
154154
use crate::lsp::binding::encode_path;
155155
encode_path(&msg, &mut config_clone);
156156
}
157-
}
158-
}
159157

160-
if config_clone.use_docker {
158+
if config_clone.requires_patch_pid() &&
159+
let Some(ref mut pid_handler_ref) = pid_handler {
160+
trace!("Trying to take the PID from the initialize method");
161+
162+
// The function returns true if the take succeeds
163+
pid_handler_ref.try_take_initialize_process_id(&mut msg)?;
164+
}
165+
}
161166

162167
redirect_uri(&mut msg, &pair, &config_clone)?;
163168
tracker_inner.check_for_methods(GOTO_METHODS, &mut msg, &pair).await?;
164169
}
170+
165171
send_message(&mut writer, &msg).await.map_err(|e| {
166172
error!("Failed to forward the request: {}", e);
167173
e

0 commit comments

Comments
 (0)