Skip to content

Commit 5e4e89e

Browse files
get_diagnostics
1 parent abb8893 commit 5e4e89e

File tree

3 files changed

+135
-65
lines changed

3 files changed

+135
-65
lines changed

crates/pg_lsp/src/b_server.rs

Lines changed: 44 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -1,31 +1,27 @@
1-
use std::sync::Arc;
2-
31
use notification::ShowMessage;
42
use pg_commands::CommandType;
5-
use pg_workspace::Workspace;
63
use tokio::sync::RwLock;
74
use tower_lsp::jsonrpc;
85
use tower_lsp::lsp_types::*;
96
use tower_lsp::{Client, LanguageServer};
107

118
use crate::client::client_flags::ClientFlags;
12-
use crate::db_connection::DbConnection;
139
use crate::server::options::ClientConfigurationOptions;
10+
use crate::utils::file_path;
11+
use crate::utils::normalize_uri;
12+
use crate::workspace_handler::WorkspaceHandler;
1413

1514
struct Server {
1615
client: Client,
17-
db: RwLock<Option<DbConnection>>,
18-
ide: Arc<RwLock<Workspace>>,
16+
workspace_handler: WorkspaceHandler,
1917
client_capabilities: RwLock<Option<ClientFlags>>,
2018
}
2119

2220
impl Server {
2321
pub async fn new(client: Client) -> Self {
24-
let ide = Arc::new(RwLock::new(Workspace::new()));
2522
Self {
2623
client,
27-
db: RwLock::new(None),
28-
ide,
24+
workspace_handler: WorkspaceHandler::new(),
2925
client_capabilities: RwLock::new(None),
3026
}
3127
}
@@ -54,46 +50,6 @@ impl Server {
5450
}
5551
}
5652

57-
/// `update_db_connection` will update `Self`'s database connection.
58-
/// If the passed-in connection string is the same that we're already connected to, it's a noop.
59-
/// Otherwise, it'll first open a new connection, replace `Self`'s connection, and then close
60-
/// the old one.
61-
async fn update_db_connection(
62-
&self,
63-
options: ClientConfigurationOptions,
64-
) -> anyhow::Result<()> {
65-
if options.db_connection_string.is_none()
66-
|| self
67-
.db
68-
.read()
69-
.await
70-
.as_ref()
71-
// if the connection is already connected to the same database, do nothing
72-
.is_some_and(|c| c.connected_to(options.db_connection_string.as_ref().unwrap()))
73-
{
74-
return Ok(());
75-
}
76-
77-
let connection_string = options.db_connection_string.unwrap();
78-
79-
let mut db = DbConnection::new(connection_string).await?;
80-
81-
let ide = self.ide.clone();
82-
db.listen_for_schema_updates(move |schema| {
83-
let _guard = ide.blocking_write().set_schema_cache(schema);
84-
});
85-
86-
let mut current_db = self.db.blocking_write();
87-
let old_db = current_db.replace(db);
88-
89-
if old_db.is_some() {
90-
let old_db = old_db.unwrap();
91-
old_db.close().await;
92-
}
93-
94-
Ok(())
95-
}
96-
9753
async fn request_opts_from_client(&self) -> Option<ClientConfigurationOptions> {
9854
let params = ConfigurationParams {
9955
items: vec![ConfigurationItem {
@@ -130,6 +86,30 @@ impl Server {
13086
}
13187
}
13288
}
89+
90+
async fn publish_diagnostics(&self, mut uri: Url) -> anyhow::Result<()> {
91+
normalize_uri(&mut uri);
92+
93+
let diagnostics = self
94+
.workspace_handler
95+
.get_diagnostics(file_path(&uri))
96+
.await;
97+
98+
self.client
99+
.send_notification::<ShowMessage>(ShowMessageParams {
100+
typ: MessageType::INFO,
101+
message: format!("diagnostics {}", diagnostics.len()),
102+
})
103+
.await;
104+
105+
let params = PublishDiagnosticsParams {
106+
uri,
107+
diagnostics,
108+
version: None,
109+
};
110+
111+
Ok(())
112+
}
133113
}
134114

135115
#[tower_lsp::async_trait]
@@ -186,16 +166,24 @@ impl LanguageServer for Server {
186166

187167
if capabilities.as_ref().unwrap().supports_pull_opts {
188168
let opts = self.request_opts_from_client().await;
189-
if opts.is_some() {
190-
self.update_db_connection(opts.unwrap()).await;
169+
if opts
170+
.as_ref()
171+
.is_some_and(|o| o.db_connection_string.is_some())
172+
{
173+
let conn_str = opts.unwrap().db_connection_string.unwrap();
174+
self.workspace_handler.change_db(conn_str).await;
191175
return;
192176
}
193177
}
194178

195179
let opts = self.parse_options_from_client(params.settings);
196180

197-
if opts.is_some() {
198-
self.update_db_connection(opts.unwrap()).await;
181+
if opts
182+
.as_ref()
183+
.is_some_and(|o| o.db_connection_string.is_some())
184+
{
185+
let conn_str = opts.unwrap().db_connection_string.unwrap();
186+
self.workspace_handler.change_db(conn_str).await;
199187
}
200188
}
201189

@@ -213,21 +201,12 @@ impl LanguageServer for Server {
213201
let stmt = serde_json::from_value(params)
214202
.map_err(|_| jsonrpc::Error::invalid_request())?;
215203

216-
let conn = self.db.read().await;
217-
match conn
218-
.as_ref()
219-
.expect("No connection to the database.")
220-
.run_stmt(stmt)
221-
.await
222-
{
223-
Ok(pg_result) => {
204+
match self.workspace_handler.run_stmt(stmt).await {
205+
Ok(rows_affected) => {
224206
self.client
225207
.send_notification::<ShowMessage>(ShowMessageParams {
226208
typ: MessageType::INFO,
227-
message: format!(
228-
"Success! Affected rows: {}",
229-
pg_result.rows_affected()
230-
),
209+
message: format!("Success! Affected rows: {}", rows_affected),
231210
})
232211
.await;
233212
}

crates/pg_lsp/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,3 +4,4 @@ pub mod server;
44
mod utils;
55

66
mod b_server;
7+
mod workspace_handler;
Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
use std::sync::Arc;
2+
3+
use lsp_types::Range;
4+
use pg_base_db::PgLspPath;
5+
use pg_diagnostics::Diagnostic;
6+
use pg_workspace::Workspace;
7+
use text_size::TextRange;
8+
use tokio::sync::RwLock;
9+
10+
use crate::{db_connection::DbConnection, utils::line_index_ext::LineIndexExt};
11+
12+
pub struct WorkspaceHandler {
13+
db: RwLock<Option<DbConnection>>,
14+
ide: Arc<RwLock<Workspace>>,
15+
}
16+
17+
impl WorkspaceHandler {
18+
pub fn new() -> Self {
19+
let ide = Arc::new(RwLock::new(Workspace::new()));
20+
Self {
21+
db: RwLock::new(None),
22+
ide,
23+
}
24+
}
25+
26+
/// `update_db_connection` will update `Self`'s database connection.
27+
/// If the passed-in connection string is the same that we're already connected to, it's a noop.
28+
/// Otherwise, it'll first open a new connection, replace `Self`'s connection, and then close
29+
/// the old one.
30+
pub async fn change_db(&self, connection_string: String) -> anyhow::Result<()> {
31+
if self
32+
.db
33+
.read()
34+
.await
35+
.as_ref()
36+
// if the connection is already connected to the same database, do nothing
37+
.is_some_and(|c| c.connected_to(&connection_string))
38+
{
39+
return Ok(());
40+
}
41+
42+
let mut db = DbConnection::new(connection_string).await?;
43+
44+
let ide = self.ide.clone();
45+
db.listen_for_schema_updates(move |schema| {
46+
let _guard = ide.blocking_write().set_schema_cache(schema);
47+
});
48+
49+
let mut current_db = self.db.blocking_write();
50+
let old_db = current_db.replace(db);
51+
52+
if old_db.is_some() {
53+
let old_db = old_db.unwrap();
54+
old_db.close().await;
55+
}
56+
57+
Ok(())
58+
}
59+
60+
pub async fn run_stmt(&self, stmt: String) -> anyhow::Result<u64> {
61+
let db = self.db.read().await;
62+
db.as_ref()
63+
.expect("No Db Connection")
64+
.run_stmt(stmt)
65+
.await
66+
.map(|pg_query_result| pg_query_result.rows_affected())
67+
}
68+
69+
pub async fn get_diagnostics(&self, path: PgLspPath) -> Vec<(Diagnostic, Range)> {
70+
let ide = self.ide.read().await;
71+
72+
// make sure there are documents at the provided path before
73+
// trying to collect diagnostics.
74+
let doc = ide.documents.get(&path);
75+
if doc.is_none() {
76+
return vec![];
77+
}
78+
79+
self.ide
80+
.read()
81+
.await
82+
.diagnostics(&path)
83+
.into_iter()
84+
.map(|d| {
85+
let range = doc.as_ref().unwrap().line_index.line_col_lsp_range(d.range).unwrap();
86+
(d, range)
87+
})
88+
.collect()
89+
}
90+
}

0 commit comments

Comments
 (0)