Skip to content

Commit 48f2753

Browse files
committed
Add Windows path support for LSP URI handling (#1)
- Add path_to_uri function to handle Windows paths (C:/...) correctly - Replace manual file:// URI construction with path_to_uri throughout LSP - Update postinstall script to use cpy for cross-platform compatibility
1 parent dac4471 commit 48f2753

3 files changed

Lines changed: 44 additions & 17 deletions

File tree

anycode-backend/src/lsp.rs

Lines changed: 21 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ use lsp_types::*;
1717
use lsp_types::notification::*;
1818

1919
use crate::config::Config;
20+
use crate::utils::path_to_uri;
2021

2122
pub struct Lsp {
2223
lang: String,
@@ -300,7 +301,7 @@ impl Lsp {
300301

301302
let params = DidOpenTextDocumentParams {
302303
text_document: TextDocumentItem {
303-
uri: format!("file://{}", path).parse().unwrap(),
304+
uri: path_to_uri(path).unwrap(),
304305
language_id: lang.to_string(),
305306
version: 0,
306307
text: text.to_string(),
@@ -315,7 +316,7 @@ impl Lsp {
315316
}
316317
let params = DidCloseTextDocumentParams {
317318
text_document: TextDocumentIdentifier {
318-
uri: format!("file://{}", path).parse().unwrap()
319+
uri: path_to_uri(path).unwrap()
319320
},
320321
};
321322
self.send_notification::<DidCloseTextDocument>(params);
@@ -324,7 +325,7 @@ impl Lsp {
324325
pub fn did_save(&mut self, path: &str, text: Option<&str>) {
325326
let params = DidSaveTextDocumentParams {
326327
text_document: TextDocumentIdentifier {
327-
uri: format!("file://{}", path).parse().unwrap()
328+
uri: path_to_uri(path).unwrap()
328329
},
329330
text: text.map(|s| s.to_string()),
330331
};
@@ -367,7 +368,7 @@ impl Lsp {
367368
) {
368369
let params = DidChangeTextDocumentParams {
369370
text_document: VersionedTextDocumentIdentifier {
370-
uri: format!("file://{}", path).parse().unwrap(),
371+
uri: path_to_uri(path).unwrap(),
371372
version: self.get_next_version(path) as i32,
372373
},
373374
content_changes,
@@ -383,7 +384,7 @@ impl Lsp {
383384
let params = CompletionParams {
384385
text_document_position: TextDocumentPositionParams {
385386
text_document: TextDocumentIdentifier {
386-
uri: format!("file://{}", path).parse().unwrap(),
387+
uri: path_to_uri(path)?,
387388
},
388389
position: Position::new(line as u32, character as u32),
389390
},
@@ -414,7 +415,7 @@ impl Lsp {
414415
let params = lsp_types::GotoDefinitionParams {
415416
text_document_position_params: TextDocumentPositionParams {
416417
text_document: TextDocumentIdentifier {
417-
uri: format!("file://{}", path).parse()?,
418+
uri: path_to_uri(path)?,
418419
},
419420
position: Position::new(line as u32, character as u32),
420421
},
@@ -446,7 +447,7 @@ impl Lsp {
446447
let params = ReferenceParams {
447448
text_document_position: TextDocumentPositionParams {
448449
text_document: TextDocumentIdentifier {
449-
uri: format!("file://{}", path).parse()?,
450+
uri: path_to_uri(path)?,
450451
},
451452
position: Position::new(line as u32, character as u32),
452453
},
@@ -472,7 +473,7 @@ impl Lsp {
472473
let params = HoverParams {
473474
text_document_position_params: TextDocumentPositionParams {
474475
text_document: TextDocumentIdentifier {
475-
uri: format!("file://{}", path).parse()?,
476+
uri: path_to_uri(path)?,
476477
},
477478
position: Position::new(line as u32, character as u32),
478479
},
@@ -548,6 +549,7 @@ pub mod lsp_messages {
548549
use super::*;
549550
use serde_json::to_string;
550551
use std::path::PathBuf;
552+
use crate::utils::path_to_uri;
551553

552554
#[derive(Deserialize)]
553555
pub struct LspRawResponse {
@@ -626,16 +628,19 @@ pub mod lsp_messages {
626628
}
627629

628630
pub fn initialize(dir: &str, lsp_name: Option<&str>) -> String {
629-
let uri: Uri = format!("file://{}", dir).parse().unwrap();
631+
let uri: Uri = path_to_uri(dir).unwrap();
632+
633+
let path = std::path::Path::new(dir);
634+
let folder_name = path
635+
.file_name()
636+
.or_else(|| path.file_stem())
637+
.and_then(|n| n.to_str())
638+
.unwrap_or("workspace")
639+
.to_string();
630640

631641
let workspace_folders = Some(vec![
632642
WorkspaceFolder {
633-
name: std::path::Path::new(dir)
634-
.file_name()
635-
.unwrap()
636-
.to_str()
637-
.unwrap()
638-
.to_string(),
643+
name: folder_name,
639644
uri: uri.clone(),
640645
}
641646
]);
@@ -786,7 +791,7 @@ impl LspManager {
786791
pub async fn stop_by_lang(&mut self, lang: &str) {
787792
if let Some(mut lsp) = self.lang2lsp.remove(lang) {
788793
lsp.stop().await;
789-
info!("Stopped LSP server for language: {}", lang);
794+
info!("stopped lsp: {}", lang);
790795
}
791796
}
792797
}

anycode-backend/src/utils.rs

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
use pathdiff::diff_paths;
22
use std::path::{Path, PathBuf};
3+
use lsp_types::Uri;
34

45
pub const DEFAULT_IGNORE_DIRS: &[&str] = &[
56
// Version control and IDEs
@@ -209,4 +210,25 @@ pub fn offset_to_byte(o: usize, s: &str) -> usize {
209210
}
210211

211212
byte_index
213+
}
214+
215+
pub fn path_to_uri(path: &str) -> anyhow::Result<Uri> {
216+
let path_obj = std::path::Path::new(path);
217+
let canonical_path = path_obj.canonicalize()
218+
.unwrap_or_else(|_| path_obj.to_path_buf());
219+
220+
let path_str = canonical_path.to_string_lossy().replace('\\', "/");
221+
222+
let uri_str = if path_str.len() > 2 && &path_str[1..2] == ":" {
223+
// Windows path like C:/... -> file:///C:/...
224+
format!("file:///{}", path_str)
225+
} else if path_str.starts_with('/') {
226+
// Unix absolute path /path -> file:///path
227+
format!("file://{}", path_str)
228+
} else {
229+
// Relative path -> file:///path
230+
format!("file:///{}", path_str)
231+
};
232+
233+
uri_str.parse().map_err(|e| anyhow::anyhow!("Failed to parse URI: {}", e))
212234
}

anycode/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
"type": "module",
66
"main": "dist/index.js",
77
"scripts": {
8-
"postinstall": "mkdir -p public && cp node_modules/anycode-base/wasm/*.wasm public/ 2>/dev/null || true",
8+
"postinstall": "cpy \"node_modules/anycode-base/wasm/*.wasm\" public",
99
"dev": "vite --host 0.0.0.0",
1010
"build:dev": "vite build --mode development && cpy dist ../anycode-backend --parents",
1111
"build": "vite build && cpy dist ../anycode-backend --parents",

0 commit comments

Comments
 (0)