Skip to content

Commit fc12e12

Browse files
committed
language server: clarify async shared state design
1 parent 5cd6834 commit fc12e12

File tree

4 files changed

+103
-95
lines changed

4 files changed

+103
-95
lines changed

crates/language-server/src/backend.rs

Lines changed: 12 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
use std::sync::Arc;
2-
use tokio::sync::Mutex;
2+
use std::sync::{Mutex, MutexGuard};
3+
// use tokio::sync::{Mutex, MutexGuard};
34

45
use crate::db::LanguageServerDatabase;
56

@@ -11,28 +12,24 @@ use lsp_types::{
1112
use tower_lsp::Client;
1213

1314
pub struct Backend {
14-
client: Arc<Mutex<Client>>,
15-
db: Arc<Mutex<LanguageServerDatabase>>,
16-
workspace: Arc<Mutex<Workspace>>,
15+
pub(crate) client: Arc<tokio::sync::Mutex<Client>>,
16+
pub(crate) db: Arc<Mutex<LanguageServerDatabase>>,
17+
pub(crate) workspace: Arc<Mutex<Workspace>>,
1718
}
1819

1920
impl Backend {
20-
pub(crate) fn db(&self) -> Arc<Mutex<LanguageServerDatabase>> {
21-
self.db.clone()
22-
}
23-
24-
pub(crate) fn workspace(&self) -> Arc<Mutex<Workspace>> {
25-
self.workspace.clone()
26-
}
21+
// pub(crate) fn db(&self) -> MutexGuard<LanguageServerDatabase> {
22+
// self.db.lock().unwrap()
23+
// }
2724

28-
pub(crate) fn client(&self) -> Arc<Mutex<Client>> {
29-
self.client.clone()
30-
}
25+
// pub(crate) fn workspace(&self) -> MutexGuard<Workspace> {
26+
// self.workspace.lock().unwrap()
27+
// }
3128

3229
pub fn new(client: Client) -> Self {
3330
let db = Arc::new(Mutex::new(LanguageServerDatabase::default()));
3431
let workspace = Arc::new(Mutex::new(Workspace::default()));
35-
let client = Arc::new(Mutex::new(client));
32+
let client = Arc::new(tokio::sync::Mutex::new(client));
3633
Self {
3734
client,
3835
db,

crates/language-server/src/handlers/notifications.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ pub fn handle_watched_file_changes(
2929
lsp_types::FileChangeType::CREATED => {
3030
// TODO: handle this more carefully!
3131
// this is inefficient, a hack for now
32-
// let db = state.db();
32+
// let db = state.db.lock().unwrap();
3333
// let db = &mut state.db.lock().unwrap();
3434
let _ = workspace.sync(db);
3535
let input = workspace

crates/language-server/src/language_server.rs

Lines changed: 71 additions & 76 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,8 @@ use lsp_types::{
44
TextDocumentItem,
55
};
66

7-
use tower_lsp::{jsonrpc::Result, LanguageServer};
7+
use tokio::sync::MutexGuard;
8+
use tower_lsp::{jsonrpc::Result, Client, LanguageServer};
89

910
use crate::{
1011
backend::Backend,
@@ -27,23 +28,24 @@ impl LanguageServer for Backend {
2728
}),
2829
};
2930
// setup logging
30-
let _ = self.init_logger(log::Level::Info);
31+
{
32+
let _ = self.init_logger(log::Level::Info);
33+
}
3134

3235
// setup workspace
33-
let workspace = self.workspace();
34-
let workspace = &mut workspace.lock().await;
35-
let db = self.db();
36-
let db = &mut db.lock().await;
37-
38-
let _ = workspace.set_workspace_root(
39-
db,
40-
initialize_params
41-
.root_uri
42-
.unwrap()
43-
.to_file_path()
44-
.ok()
45-
.unwrap(),
46-
);
36+
{
37+
let workspace = &mut self.workspace.lock().unwrap();
38+
let db = &mut self.db.lock().unwrap();
39+
let _ = workspace.set_workspace_root(
40+
db,
41+
initialize_params
42+
.root_uri
43+
.unwrap()
44+
.to_file_path()
45+
.ok()
46+
.unwrap(),
47+
);
48+
}
4749

4850
// register watchers
4951
let _ = self.register_watchers().await;
@@ -56,29 +58,35 @@ impl LanguageServer for Backend {
5658

5759
async fn did_open(&self, params: lsp_types::DidOpenTextDocumentParams) {
5860
info!("did open: {:?}", params);
59-
let workspace = self.workspace();
60-
let workspace = &mut workspace.lock().await;
61-
let db = self.db();
62-
let db = &mut db.lock().await;
63-
let _ = workspace.sync(db);
61+
{
62+
let workspace = &mut self.workspace.lock().unwrap();
63+
let db = &mut self.db.lock().unwrap();
64+
let _ = workspace.sync(db);
65+
}
6466

65-
self.on_change(TextDocumentItem {
66-
uri: params.text_document.uri,
67-
language_id: LANGUAGE_ID.to_string(),
68-
version: params.text_document.version,
69-
text: params.text_document.text,
70-
})
67+
on_change(
68+
self,
69+
TextDocumentItem {
70+
uri: params.text_document.uri,
71+
language_id: LANGUAGE_ID.to_string(),
72+
version: params.text_document.version,
73+
text: params.text_document.text,
74+
},
75+
)
7176
.await;
7277
}
7378

7479
async fn did_change(&self, params: lsp_types::DidChangeTextDocumentParams) {
7580
info!("did change: {:?}", params);
76-
self.on_change(TextDocumentItem {
77-
uri: params.text_document.uri,
78-
language_id: LANGUAGE_ID.to_string(),
79-
version: params.text_document.version,
80-
text: params.content_changes[0].text.clone(),
81-
})
81+
on_change(
82+
self,
83+
TextDocumentItem {
84+
uri: params.text_document.uri,
85+
language_id: LANGUAGE_ID.to_string(),
86+
version: params.text_document.version,
87+
text: params.content_changes[0].text.clone(),
88+
},
89+
)
8290
.await;
8391
}
8492

@@ -88,10 +96,10 @@ impl LanguageServer for Backend {
8896
// The fix: handle document renaming more explicitly in the "will rename" flow, along with the document
8997
// rename refactor.
9098
async fn did_close(&self, params: DidCloseTextDocumentParams) {
91-
let workspace = self.workspace();
92-
let workspace = &mut workspace.lock().await;
93-
let db = self.db();
94-
let db = &mut db.lock().await;
99+
let workspace = &mut self.workspace.lock().unwrap();
100+
// let workspace = &mut workspace.lock().await;
101+
let db = &mut self.db.lock().unwrap();
102+
// let db = &mut db.lock().await;
95103

96104
let input = workspace
97105
.input_from_file_path(
@@ -108,11 +116,6 @@ impl LanguageServer for Backend {
108116
let _ = input.sync(db, None);
109117
}
110118
async fn did_change_watched_files(&self, params: DidChangeWatchedFilesParams) {
111-
let workspace = self.workspace();
112-
let workspace = &mut workspace.lock().await;
113-
let db = self.db();
114-
let db = &mut db.lock().await;
115-
116119
let changes = params.changes;
117120
for change in changes {
118121
let uri = change.uri;
@@ -122,13 +125,17 @@ impl LanguageServer for Backend {
122125
lsp_types::FileChangeType::CREATED => {
123126
// TODO: handle this more carefully!
124127
// this is inefficient, a hack for now
128+
let workspace = &mut self.workspace.lock().unwrap();
129+
let db = &mut self.db.lock().unwrap();
125130
let _ = workspace.sync(db);
126131
let input = workspace
127132
.input_from_file_path(db, path.to_str().unwrap())
128133
.unwrap();
129134
let _ = input.sync(db, None);
130135
}
131136
lsp_types::FileChangeType::CHANGED => {
137+
let workspace = &mut self.workspace.lock().unwrap();
138+
let db = &mut self.db.lock().unwrap();
132139
let input = workspace
133140
.input_from_file_path(db, path.to_str().unwrap())
134141
.unwrap();
@@ -137,50 +144,34 @@ impl LanguageServer for Backend {
137144
lsp_types::FileChangeType::DELETED => {
138145
// TODO: handle this more carefully!
139146
// this is inefficient, a hack for now
147+
let workspace = &mut self.workspace.lock().unwrap();
148+
let db = &mut self.db.lock().unwrap();
140149
let _ = workspace.sync(db);
141150
}
142151
_ => {}
143152
}
144153
// collect diagnostics for the file
145154
if change.typ != lsp_types::FileChangeType::DELETED {
146-
// let diags = get_diagnostics(db, workspace, uri.clone());
147-
// for (uri, more_diags) in diags.ok().unwrap() {
148-
// let diags = diagnostics.entry(uri).or_insert_with(Vec::new);
149-
// diags.extend(more_diags);
150-
// }
151155
let text = std::fs::read_to_string(path).unwrap();
152-
self.on_change(TextDocumentItem {
153-
uri: uri.clone(),
154-
language_id: LANGUAGE_ID.to_string(),
155-
version: 0,
156-
text,
157-
})
156+
on_change(
157+
self,
158+
TextDocumentItem {
159+
uri: uri.clone(),
160+
language_id: LANGUAGE_ID.to_string(),
161+
version: 0,
162+
text,
163+
},
164+
)
158165
.await;
159166
}
160167
}
161168
}
162-
163-
// async fn will_rename_files(&self, params: RenameFilesParams) -> Result<Option<WorkspaceEdit>> {
164-
// let workspace = &mut *self.workspace.lock().await;
165-
// let db = &mut *self.db.lock().await;
166-
167-
// for file in params.files {
168-
// let _ = workspace.rename_file(db, &*file.old_uri, &*file.new_uri);
169-
// }
170-
171-
// // TODO: implement file rename auto-refactoring
172-
// Ok(None)
173-
// }
174169
}
175170

176-
impl Backend {
177-
async fn on_change(&self, params: TextDocumentItem) {
178-
let workspace = self.workspace();
179-
let workspace = &mut workspace.lock().await;
180-
let db = self.db();
181-
let db = &mut db.lock().await;
182-
let client = self.client();
183-
let client = &mut *client.lock().await;
171+
async fn on_change(backend: &Backend, params: TextDocumentItem) {
172+
let diagnostics = {
173+
let workspace = &mut backend.workspace.lock().unwrap();
174+
let db = &mut backend.db.lock().unwrap();
184175
let input = workspace
185176
.input_from_file_path(
186177
db,
@@ -193,12 +184,16 @@ impl Backend {
193184
)
194185
.unwrap();
195186
let _ = input.sync(db, Some(params.text));
196-
let diagnostics = get_diagnostics(db, workspace, params.uri.clone())
187+
get_diagnostics(db, workspace, params.uri.clone())
188+
};
189+
190+
let client = backend.client.lock().await;
191+
let diagnostics =
192+
diagnostics
197193
.unwrap()
198194
.into_iter()
199195
.map(|(uri, diags)| client.publish_diagnostics(uri, diags, None))
200196
.collect::<Vec<_>>();
201197

202-
futures::future::join_all(diagnostics).await;
203-
}
198+
futures::future::join_all(diagnostics).await;
204199
}

crates/language-server/src/logger.rs

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,8 @@ impl log::Log for Logger {
2222
let message = format!("{} - {}", record.level(), record.args());
2323
let level = record.level();
2424
let client = self.client.clone();
25-
tokio::task::spawn(async move {
26-
let client = client.lock().await;
25+
tokio::spawn(async move {
26+
let mut client = client.lock().await;
2727
client
2828
.log_message(
2929
match level {
@@ -37,6 +37,22 @@ impl log::Log for Logger {
3737
)
3838
.await;
3939
});
40+
// let client = self.client.clone();
41+
// tokio::task::spawn_blocking(async move {
42+
// let client = client.lock().await;
43+
// client
44+
// .log_message(
45+
// match level {
46+
// log::Level::Error => lsp_types::MessageType::ERROR,
47+
// log::Level::Warn => lsp_types::MessageType::WARNING,
48+
// log::Level::Info => lsp_types::MessageType::INFO,
49+
// log::Level::Debug => lsp_types::MessageType::LOG,
50+
// log::Level::Trace => lsp_types::MessageType::LOG,
51+
// },
52+
// message,
53+
// )
54+
// .await;
55+
// });
4056
}
4157
}
4258

@@ -47,7 +63,7 @@ impl Backend {
4763
pub fn init_logger(&self, level: Level) -> Result<(), SetLoggerError> {
4864
let logger = Logger {
4965
level,
50-
client: self.client(),
66+
client: self.client.clone(),
5167
};
5268
let static_logger = Box::leak(Box::new(logger));
5369
log::set_logger(static_logger)?;

0 commit comments

Comments
 (0)