Skip to content

Commit 0af11c4

Browse files
so far
1 parent 0c17133 commit 0af11c4

File tree

7 files changed

+191
-88
lines changed

7 files changed

+191
-88
lines changed

crates/pg_lsp/src/b_server.rs

Lines changed: 159 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,159 @@
1+
use std::sync::Arc;
2+
3+
use notification::ShowMessage;
4+
use pg_commands::CommandType;
5+
use pg_workspace::Workspace;
6+
use tokio::sync::{Mutex, RwLock};
7+
use tower_lsp::jsonrpc::Result;
8+
use tower_lsp::lsp_types::*;
9+
use tower_lsp::{Client, LanguageServer};
10+
11+
use crate::client::client_flags::ClientFlags;
12+
use crate::db_connection::DbConnection;
13+
use crate::server::options::ClientConfigurationOptions;
14+
15+
struct Server {
16+
client: Client,
17+
db: Mutex<Option<DbConnection>>,
18+
ide: Arc<RwLock<Workspace>>,
19+
client_capabilities: RwLock<Option<ClientFlags>>,
20+
}
21+
22+
impl Server {
23+
pub async fn new(client: Client) -> Self {
24+
let ide = Arc::new(RwLock::new(Workspace::new()));
25+
Self {
26+
client,
27+
db: Mutex::new(None),
28+
ide,
29+
client_capabilities: RwLock::new(None),
30+
}
31+
}
32+
33+
/// When the client sends a didChangeConfiguration notification, we need to parse the received JSON.
34+
fn parse_options_from_client(
35+
&self,
36+
mut value: serde_json::Value,
37+
) -> Result<ClientConfigurationOptions> {
38+
let options = match value.get_mut("pglsp") {
39+
Some(section) => section.take(),
40+
None => value,
41+
};
42+
43+
let options = match serde_json::from_value::<ClientConfigurationOptions>(options) {
44+
Ok(new_options) => Some(new_options),
45+
Err(why) => {
46+
let message = format!(
47+
"The texlab configuration is invalid; using the default settings instead.\nDetails: {why}"
48+
);
49+
let typ = MessageType::WARNING;
50+
self.client
51+
.send_notification::<ShowMessage>(ShowMessageParams { message, typ });
52+
None
53+
}
54+
};
55+
56+
Ok(options.unwrap_or_default())
57+
}
58+
59+
async fn update_db_connection(
60+
&self,
61+
options: ClientConfigurationOptions,
62+
) -> anyhow::Result<()> {
63+
if options.db_connection_string.is_none()
64+
|| self
65+
.db
66+
.lock()
67+
.await
68+
.as_ref()
69+
// if the connection is already connected to the same database, do nothing
70+
.is_some_and(|c| c.connected_to(options.db_connection_string.as_ref().unwrap()))
71+
{
72+
return Ok(());
73+
}
74+
75+
let connection_string = options.db_connection_string.unwrap();
76+
77+
let mut db = DbConnection::new(connection_string).await?;
78+
79+
let ide = self.ide.clone();
80+
db.listen_for_schema_updates(move |schema| {
81+
let _guard = ide.blocking_write().set_schema_cache(schema);
82+
});
83+
84+
let mut current_db = self.db.lock().await;
85+
let old_db = current_db.replace(db);
86+
87+
if old_db.is_some() {
88+
let old_db = old_db.unwrap();
89+
old_db.close().await;
90+
}
91+
92+
Ok(())
93+
}
94+
}
95+
96+
#[tower_lsp::async_trait]
97+
impl LanguageServer for Server {
98+
async fn initialize(&self, params: InitializeParams) -> Result<InitializeResult> {
99+
let flags = ClientFlags::from_initialize_request_params(&params);
100+
self.client_capabilities.blocking_write().replace(flags);
101+
102+
Ok(InitializeResult {
103+
server_info: None,
104+
capabilities: ServerCapabilities {
105+
text_document_sync: Some(TextDocumentSyncCapability::Options(
106+
TextDocumentSyncOptions {
107+
open_close: Some(true),
108+
change: Some(TextDocumentSyncKind::INCREMENTAL),
109+
will_save: None,
110+
will_save_wait_until: None,
111+
save: Some(TextDocumentSyncSaveOptions::SaveOptions(SaveOptions {
112+
include_text: Some(false),
113+
})),
114+
},
115+
)),
116+
hover_provider: Some(HoverProviderCapability::Simple(true)),
117+
execute_command_provider: Some(ExecuteCommandOptions {
118+
commands: CommandType::ALL
119+
.iter()
120+
.map(|c| c.id().to_string())
121+
.collect(),
122+
..Default::default()
123+
}),
124+
inlay_hint_provider: Some(OneOf::Left(true)),
125+
code_action_provider: Some(CodeActionProviderCapability::Simple(true)),
126+
completion_provider: Some(CompletionOptions::default()),
127+
..ServerCapabilities::default()
128+
},
129+
})
130+
}
131+
132+
async fn initialized(&self, _params: InitializedParams) {
133+
self.client
134+
.log_message(MessageType::INFO, "Postgres LSP Connected!")
135+
.await;
136+
}
137+
138+
async fn shutdown(&self) -> Result<()> {
139+
self.client
140+
.log_message(MessageType::INFO, "Postgres LSP terminated.")
141+
.await;
142+
Ok(())
143+
}
144+
145+
146+
async fn did_change_configuration(&self, params: DidChangeConfigurationParams) {
147+
match self.parse_options_from_client(params.settings) {
148+
Ok(opts) => {
149+
self.update_db_connection(opts).await;
150+
}
151+
Err(e) => {
152+
self.client
153+
.log_message(MessageType::ERROR, format!("Error parsing configuration: {}", e))
154+
.await;
155+
}
156+
};
157+
158+
}
159+
}

crates/pg_lsp/src/client.rs

Lines changed: 18 additions & 77 deletions
Original file line numberDiff line numberDiff line change
@@ -1,52 +1,28 @@
11
pub mod client_flags;
22

3-
use std::{
4-
collections::HashMap,
5-
sync::{
6-
atomic::{AtomicI32, Ordering},
7-
Arc, Mutex,
8-
},
9-
};
3+
use anyhow::Result;
4+
use serde::Serialize;
5+
use tower_lsp::lsp_types::{notification::ShowMessage, MessageType, ShowMessageParams};
6+
use tower_lsp::Client;
107

11-
use anyhow::{bail, Result};
12-
use crossbeam_channel::Sender;
13-
use lsp_server::{ErrorCode, Message, Request, RequestId, Response};
14-
use lsp_types::{notification::ShowMessage, MessageType, ShowMessageParams};
15-
use serde::{de::DeserializeOwned, Serialize};
16-
17-
use crate::server::options::Options;
18-
19-
#[derive(Debug)]
20-
struct RawClient {
21-
sender: Sender<Message>,
22-
next_id: AtomicI32,
23-
pending: Mutex<HashMap<RequestId, Sender<Response>>>,
24-
}
8+
use crate::server::options::ClientConfigurationOptions;
259

2610
#[derive(Debug, Clone)]
2711
pub struct LspClient {
28-
raw: Arc<RawClient>,
12+
client: Client,
2913
}
3014

3115
impl LspClient {
32-
pub fn new(sender: Sender<Message>) -> Self {
33-
let raw = Arc::new(RawClient {
34-
sender,
35-
next_id: AtomicI32::new(1),
36-
pending: Default::default(),
37-
});
38-
39-
Self { raw }
16+
pub fn new(client: Client) -> Self {
17+
Self { client }
4018
}
4119

4220
pub fn send_notification<N>(&self, params: N::Params) -> Result<()>
4321
where
44-
N: lsp_types::notification::Notification,
22+
N: tower_lsp::lsp_types::notification::Notification,
4523
N::Params: Serialize,
4624
{
47-
self.raw
48-
.sender
49-
.send(lsp_server::Notification::new(N::METHOD.to_string(), params).into())?;
25+
self.client.send_notification::<N>(params);
5026
Ok(())
5127
}
5228

@@ -58,54 +34,19 @@ impl LspClient {
5834
});
5935
}
6036

61-
pub fn send_request<R>(&self, params: R::Params) -> Result<R::Result>
37+
pub async fn send_request<R>(&self, params: R::Params) -> Result<R::Result>
6238
where
63-
R: lsp_types::request::Request,
64-
R::Params: Serialize,
65-
R::Result: DeserializeOwned,
39+
R: tower_lsp::lsp_types::request::Request,
6640
{
67-
let id = RequestId::from(self.raw.next_id.fetch_add(1, Ordering::SeqCst));
41+
let response = self.client.send_request::<R>(params).await?;
6842

69-
let (tx, rx) = crossbeam_channel::bounded(1);
70-
self.raw.pending.lock().unwrap().insert(id.clone(), tx);
71-
72-
self.raw
73-
.sender
74-
.send(Request::new(id, R::METHOD.to_string(), params).into())?;
75-
76-
let response = rx.recv()?;
77-
let result = match response.error {
78-
Some(error) => bail!(error.message),
79-
None => response.result.unwrap_or_default(),
80-
};
81-
82-
Ok(serde_json::from_value(result)?)
83-
}
84-
85-
pub fn send_response(&self, response: lsp_server::Response) -> Result<()> {
86-
self.raw.sender.send(response.into())?;
87-
Ok(())
88-
}
89-
90-
pub fn send_error(&self, id: RequestId, code: ErrorCode, message: String) -> Result<()> {
91-
self.send_response(lsp_server::Response::new_err(id, code as i32, message))?;
92-
Ok(())
93-
}
94-
95-
pub fn recv_response(&self, response: lsp_server::Response) -> Result<()> {
96-
let tx = self
97-
.raw
98-
.pending
99-
.lock()
100-
.unwrap()
101-
.remove(&response.id)
102-
.expect("response with known request id received");
103-
104-
tx.send(response)?;
105-
Ok(())
43+
Ok(response)
10644
}
10745

108-
pub fn parse_options(&self, mut value: serde_json::Value) -> Result<Options> {
46+
pub fn parse_options(
47+
&self,
48+
mut value: serde_json::Value,
49+
) -> Result<ClientConfigurationOptions> {
10950
// if there are multiple servers, we need to extract the options for pglsp first
11051
let options = match value.get_mut("pglsp") {
11152
Some(section) => section.take(),

crates/pg_lsp/src/client/client_flags.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use lsp_types::InitializeParams;
1+
use tower_lsp::lsp_types::InitializeParams;
22

33
/// Contains information about the client's capabilities.
44
/// This is used to determine which features the server can use.

crates/pg_lsp/src/lib.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,3 +2,5 @@ mod client;
22
mod db_connection;
33
pub mod server;
44
mod utils;
5+
6+
mod b_server;

crates/pg_lsp/src/server.rs

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ use pg_workspace::Workspace;
2929
use serde::{de::DeserializeOwned, Serialize};
3030
use std::{collections::HashSet, future::Future, sync::Arc, time::Duration};
3131
use text_size::TextSize;
32+
use tower_lsp::Client;
3233

3334
use tokio::sync::mpsc;
3435
use tokio_util::sync::CancellationToken;
@@ -39,13 +40,13 @@ use crate::{
3940
utils::{file_path, from_proto, line_index_ext::LineIndexExt, normalize_uri, to_proto},
4041
};
4142

42-
use self::{debouncer::EventDebouncer, options::Options};
43+
use self::{debouncer::EventDebouncer, options::ClientConfigurationOptions};
4344
use sqlx::{postgres::PgPool, Executor};
4445

4546
#[derive(Debug)]
4647
enum InternalMessage {
4748
PublishDiagnostics(lsp_types::Url),
48-
SetOptions(Options),
49+
SetOptions(ClientConfigurationOptions),
4950
SetSchemaCache(SchemaCache),
5051
SetDatabaseConnection(DbConnection),
5152
}
@@ -61,7 +62,7 @@ fn get_client_receiver(
6162
tokio::task::spawn(async move {
6263
loop {
6364
let msg = match connection.receiver.recv() {
64-
Ok(msg) => msg,
65+
Ok(msg) => msg,
6566
Err(e) => {
6667
eprint!("Connection was closed by LSP client: {}", e);
6768
cancel_token.cancel();
@@ -97,12 +98,12 @@ pub struct Server {
9798
}
9899

99100
impl Server {
100-
pub fn init(connection: Connection) -> anyhow::Result<Self> {
101-
let client = LspClient::new(connection.sender.clone());
101+
pub fn init(client: Client) -> anyhow::Result<Self> {
102+
let client = LspClient::new(client);
102103
let cancel_token = Arc::new(CancellationToken::new());
103104

104-
let (client_flags, client_rx) = Self::establish_client_connection(connection, &cancel_token)?;
105-
105+
let (client_flags, client_rx) =
106+
Self::establish_client_connection(connection, &cancel_token)?;
106107

107108
let ide = Arc::new(Workspace::new());
108109

@@ -211,7 +212,7 @@ impl Server {
211212
});
212213
}
213214

214-
fn update_db_connection(&self, options: Options) -> anyhow::Result<()> {
215+
fn update_db_connection(&self, options: ClientConfigurationOptions) -> anyhow::Result<()> {
215216
if options.db_connection_string.is_none()
216217
|| self
217218
.db_conn

crates/pg_lsp/src/server/options.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,6 @@ use serde::{Deserialize, Serialize};
33
#[derive(Debug, Clone, Default, Serialize, Deserialize)]
44
#[serde(rename_all = "camelCase")]
55
#[serde(default)]
6-
pub struct Options {
6+
pub struct ClientConfigurationOptions {
77
pub db_connection_string: Option<String>,
88
}

crates/pg_schema_cache/src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,11 @@
44
#![feature(future_join)]
55

66
mod functions;
7-
mod versions;
87
mod schema_cache;
98
mod schemas;
109
mod tables;
1110
mod types;
11+
mod versions;
1212

1313
use sqlx::postgres::PgPool;
1414

0 commit comments

Comments
 (0)