Skip to content

Commit a941c62

Browse files
committed
Update LSP configuration
- Updated LSP configuration in `config.toml` to replace the existing LSP command with a new set of commands for Python and TypeScript. - Enhanced the LSP struct in `lsp.rs` to include an optional `lsp_name` field for better configuration management. - Implemented functionality to read VSCode settings based on the LSP name and notify configuration changes in the LSP manager.
1 parent 278abe9 commit a941c62

4 files changed

Lines changed: 150 additions & 9 deletions

File tree

anycode-backend/Cargo.lock

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

anycode-backend/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "anycode"
3-
version = "0.1.0"
3+
version = "0.0.1"
44
edition = "2024"
55

66
[profile.release]

anycode-backend/config.toml

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,9 @@ indent = { width = 4, unit = "\t" }
2424
name = "python"
2525
types = ["py"]
2626
comment = "#"
27-
lsp = ["pyright-langserver", "--stdio"]
27+
# lsp = ["pyright-langserver", "--stdio"]
28+
lsp = ["uvx", "ty", "server"]
29+
# lsp = ["/Users/max/.cursor/extensions/astral-sh.ty-2025.57.13300119-darwin-arm64/bundled/libs/bin/ty server"]
2830
indent = { width = 4, unit = " " }
2931
executable = true
3032
exec = "python -u {file}"
@@ -42,7 +44,27 @@ exectest = "tsx -m pytest -k {test} {file}"
4244

4345
[[language]]
4446
name = "typescript"
45-
types = ["ts", "tsx"]
47+
types = ["ts"]
48+
comment = "//"
49+
lsp = ["typescript-language-server", "--stdio"]
50+
indent = { width = 2, unit = " " }
51+
executable = true
52+
exec = "tsx {file}"
53+
exectest = "tsx -m pytest -k {test} {file}"
54+
55+
[[language]]
56+
name = "javascriptreact"
57+
types = ["jsx"]
58+
comment = "//"
59+
lsp = ["typescript-language-server", "--stdio"]
60+
indent = { width = 2, unit = " " }
61+
executable = true
62+
exec = "tsx {file}"
63+
exectest = "tsx -m pytest -k {test} {file}"
64+
65+
[[language]]
66+
name = "typescriptreact"
67+
types = ["tsx"]
4668
comment = "//"
4769
lsp = ["typescript-language-server", "--stdio"]
4870
indent = { width = 2, unit = " " }

anycode-backend/src/lsp.rs

Lines changed: 124 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ use crate::config::Config;
2020

2121
pub struct Lsp {
2222
lang: String,
23+
lsp_name: Option<String>,
2324
kill_send: Option<mpsc::Sender<()>>,
2425
stdin_send: Option<mpsc::Sender<String>>,
2526
next_id: AtomicUsize,
@@ -33,6 +34,7 @@ impl Lsp {
3334
pub fn new() -> Self {
3435
Self {
3536
lang: String::new(),
37+
lsp_name: None,
3638
kill_send: None,
3739
stdin_send: None,
3840
next_id: AtomicUsize::new(1),
@@ -44,7 +46,7 @@ impl Lsp {
4446
}
4547

4648
pub fn start(
47-
&mut self, lang: &str, cmd: &str,
49+
&mut self, lang: &str, cmd: &str, lsp_name: Option<String>,
4850
diagnostic_updates: Option<mpsc::Sender<PublishDiagnosticsParams>>
4951
) -> io::Result<()> {
5052

@@ -53,6 +55,7 @@ impl Lsp {
5355
let args = &s[1..];
5456

5557
self.lang = lang.to_string();
58+
self.lsp_name = lsp_name;
5659

5760
let (kill_send, mut kill_recv) = mpsc::channel::<()>(1);
5861
self.kill_send = Some(kill_send);
@@ -197,11 +200,18 @@ impl Lsp {
197200
let id = 0;
198201
let (tx, rx) = mpsc::channel::<String>(1);
199202
self.add_pending(id, tx).await;
200-
let message = lsp_messages::initialize(dir);
203+
let message = lsp_messages::initialize(dir, self.lsp_name.as_deref());
201204
self.send_async(message);
202205
self.wait(5, rx).await;
203206
self.remove_pending(id).await;
204207
self.initialized();
208+
209+
if let Some(lsp_name) = &self.lsp_name {
210+
let settings = lsp_messages::read_vscode_settings(lsp_name, dir)
211+
.unwrap_or_else(|| Value::Object(serde_json::Map::new()));
212+
self.did_change_configuration(settings);
213+
}
214+
205215
self.ready.store(true, Ordering::SeqCst)
206216
}
207217

@@ -266,11 +276,22 @@ impl Lsp {
266276
self.ready.load(Ordering::SeqCst)
267277
}
268278

279+
pub fn lsp_name(&self) -> Option<&str> {
280+
self.lsp_name.as_deref()
281+
}
282+
269283
pub fn initialized(&mut self) {
270284
let params = InitializedParams {};
271285
self.send_notification::<Initialized>(params);
272286
}
273287

288+
pub fn did_change_configuration(&self, settings: Value) {
289+
let params = DidChangeConfigurationParams {
290+
settings,
291+
};
292+
self.send_notification::<DidChangeConfiguration>(params);
293+
}
294+
274295
pub fn did_open(&mut self, lang: &str, path: &str, text: &str) {
275296
self.opened.insert(path.to_string());
276297

@@ -467,7 +488,7 @@ mod tests {
467488
let lang = "python";
468489

469490
let mut lsp = Lsp::new();
470-
lsp.start(lang, "pyright-langserver --stdio", None)?;
491+
lsp.start(lang, "pyright-langserver --stdio", Some("pyright-langserver".to_string()), None)?;
471492

472493
let dir = std::env::current_dir().unwrap()
473494
.to_string_lossy().into_owned();
@@ -515,6 +536,7 @@ mod tests {
515536
pub mod lsp_messages {
516537
use super::*;
517538
use serde_json::to_string;
539+
use std::path::PathBuf;
518540

519541
#[derive(Deserialize)]
520542
pub struct LspRawResponse {
@@ -524,7 +546,75 @@ pub mod lsp_messages {
524546
pub error: Option<Value>,
525547
}
526548

527-
pub fn initialize(dir: &str) -> String {
549+
pub fn read_vscode_settings(lsp_name: &str, dir: &str) -> Option<Value> {
550+
let settings_path = PathBuf::from(dir).join(".vscode").join("settings.json");
551+
552+
if !settings_path.exists() {
553+
debug!("Settings file not found: {:?}", settings_path);
554+
return None;
555+
}
556+
557+
let content = match std::fs::read_to_string(&settings_path) {
558+
Ok(c) => c,
559+
Err(e) => {
560+
debug!("Failed to read settings file: {:?}", e);
561+
return None;
562+
}
563+
};
564+
565+
let settings: Value = match serde_json::from_str(&content) {
566+
Ok(s) => s,
567+
Err(e) => {
568+
debug!("Failed to parse settings JSON: {:?}", e);
569+
return None;
570+
}
571+
};
572+
573+
let prefix = format!("{}.", lsp_name);
574+
let mut lsp_settings = serde_json::Map::new();
575+
576+
if let Some(obj) = settings.as_object() {
577+
for (key, value) in obj {
578+
if key.starts_with(&prefix) {
579+
let setting_key = key.strip_prefix(&prefix).unwrap();
580+
581+
let parts: Vec<&str> = setting_key.split('.').collect();
582+
if parts.is_empty() {
583+
continue;
584+
}
585+
586+
let mut current = &mut lsp_settings;
587+
for (i, part) in parts.iter().enumerate() {
588+
if i == parts.len() - 1 {
589+
current.insert(part.to_string(), value.clone());
590+
} else {
591+
if !current.contains_key(*part) {
592+
current.insert(part.to_string(), Value::Object(serde_json::Map::new()));
593+
}
594+
match current.get_mut(*part) {
595+
Some(Value::Object(obj)) => {
596+
current = obj;
597+
}
598+
_ => {
599+
break;
600+
}
601+
}
602+
}
603+
}
604+
}
605+
}
606+
}
607+
608+
if lsp_settings.is_empty() {
609+
None
610+
} else {
611+
let mut wrapper = serde_json::Map::new();
612+
wrapper.insert(lsp_name.to_string(), Value::Object(lsp_settings));
613+
Some(Value::Object(wrapper))
614+
}
615+
}
616+
617+
pub fn initialize(dir: &str, lsp_name: Option<&str>) -> String {
528618
let uri: Uri = format!("file://{}", dir).parse().unwrap();
529619

530620
let workspace_folders = Some(vec![
@@ -574,6 +664,12 @@ pub mod lsp_messages {
574664
..Default::default()
575665
};
576666

667+
let initialization_options = if let Some(name) = lsp_name {
668+
read_vscode_settings(name, dir)
669+
} else {
670+
None
671+
};
672+
577673
let params = InitializeParams {
578674
process_id: Some(std::process::id() as u32),
579675
root_path: Some(dir.to_string()),
@@ -584,6 +680,7 @@ pub mod lsp_messages {
584680
name: "anycode".to_string(),
585681
version: Some("1.0.0".to_string()),
586682
}),
683+
initialization_options,
587684
..Default::default()
588685
};
589686

@@ -632,7 +729,9 @@ impl LspManager {
632729
pub async fn init_new(&mut self, lang: String, lsp_cmd: &str) {
633730
let mut lsp = Lsp::new();
634731
let diagnostic_send = self.diagnostics_sender.as_mut().map(|s|s.clone());
635-
let result = lsp.start(&lang, &lsp_cmd, diagnostic_send);
732+
let lsp_name = lsp_cmd.split_whitespace().next().map(|s| s.to_string());
733+
734+
let result = lsp.start(&lang, &lsp_cmd, lsp_name, diagnostic_send);
636735

637736
match result {
638737
Ok(_) => {
@@ -652,4 +751,24 @@ impl LspManager {
652751

653752
self.lang2lsp.insert(lang, lsp);
654753
}
754+
755+
pub fn notify_configuration_changed(&mut self, lang: &str, dir: &str) {
756+
if let Some(lsp) = self.lang2lsp.get_mut(lang) {
757+
if let Some(lsp_name) = lsp.lsp_name() {
758+
if let Some(settings) = lsp_messages::read_vscode_settings(lsp_name, dir) {
759+
lsp.did_change_configuration(settings);
760+
}
761+
}
762+
}
763+
}
764+
765+
pub fn notify_all_configuration_changed(&mut self, dir: &str) {
766+
for lsp in self.lang2lsp.values_mut() {
767+
if let Some(lsp_name) = lsp.lsp_name() {
768+
if let Some(settings) = lsp_messages::read_vscode_settings(lsp_name, dir) {
769+
lsp.did_change_configuration(settings);
770+
}
771+
}
772+
}
773+
}
655774
}

0 commit comments

Comments
 (0)