Skip to content

Commit 8e68b89

Browse files
maybe
1 parent e3bc0c2 commit 8e68b89

File tree

15 files changed

+182
-7
lines changed

15 files changed

+182
-7
lines changed

crates/pg_completions/Cargo.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@ async-std = "1.12.0"
1616

1717
text-size.workspace = true
1818

19+
serde = { workspace = true, features = ["derive"] }
20+
serde_json = { workspace = true }
1921
pg_schema_cache.workspace = true
2022
tree-sitter.workspace = true
2123
tree_sitter_sql.workspace = true

crates/pg_completions/src/complete.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
use serde::{Deserialize, Serialize};
12
use text_size::TextSize;
23

34
use crate::{
@@ -17,9 +18,9 @@ pub struct CompletionParams<'a> {
1718
pub tree: Option<&'a tree_sitter::Tree>,
1819
}
1920

20-
#[derive(Debug, Default)]
21+
#[derive(Debug, Default, Serialize, Deserialize)]
2122
pub struct CompletionResult {
22-
pub items: Vec<CompletionItem>,
23+
pub(crate) items: Vec<CompletionItem>,
2324
}
2425

2526
impl IntoIterator for CompletionResult {

crates/pg_completions/src/item.rs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,12 @@
1-
#[derive(Debug, PartialEq, Eq)]
1+
use serde::{Deserialize, Serialize};
2+
3+
#[derive(Debug, PartialEq, Eq, Serialize, Deserialize)]
24
pub enum CompletionItemKind {
35
Table,
46
Function,
57
}
68

7-
#[derive(Debug)]
9+
#[derive(Debug, Serialize, Deserialize)]
810
pub struct CompletionItem {
911
pub label: String,
1012
pub(crate) score: i32,

crates/pg_lsp_new/Cargo.toml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,10 @@ name = "pg_lsp_new"
1010
repository.workspace = true
1111
version = "0.0.0"
1212

13+
[[bin]]
14+
name = "pglsp_new"
15+
path = "src/main.rs"
16+
test = false
1317

1418
[dependencies]
1519
anyhow = { workspace = true }
@@ -18,6 +22,7 @@ futures = "0.3.31"
1822
pg_configuration = { workspace = true }
1923
pg_console = { workspace = true }
2024
pg_diagnostics = { workspace = true }
25+
pg_completions = { workspace = true }
2126
pg_fs = { workspace = true }
2227
pg_lsp_converters = { workspace = true }
2328
pg_text_edit = { workspace = true }
@@ -29,6 +34,7 @@ text-size.workspace = true
2934
tokio = { workspace = true, features = ["rt", "io-std"] }
3035
tower-lsp = { version = "0.20.0" }
3136
tracing = { workspace = true, features = ["attributes"] }
37+
tracing-subscriber = { workspace = true }
3238

3339
[dev-dependencies]
3440

crates/pg_lsp_new/src/handlers.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,2 @@
1+
pub(crate) mod completions;
12
pub(crate) mod text_document;
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
use crate::session::Session;
2+
use anyhow::Result;
3+
use pg_workspace_new::workspace::CompletionParams;
4+
use text_size::TextSize;
5+
use tower_lsp::lsp_types::{self, CompletionItem, CompletionItemLabelDetails};
6+
7+
pub fn get_completions(
8+
session: &Session,
9+
params: lsp_types::CompletionParams,
10+
) -> Result<lsp_types::CompletionResponse> {
11+
let pos = params.text_document_position.position;
12+
let url = params.text_document_position.text_document.uri;
13+
14+
let path = session.file_path(&url)?;
15+
16+
let completion_result = session.workspace.get_completions(CompletionParams {
17+
path,
18+
position: TextSize::from(pos.character),
19+
})?;
20+
21+
let items: Vec<CompletionItem> = completion_result
22+
.into_iter()
23+
.map(|i| CompletionItem {
24+
label: i.label,
25+
label_details: Some(CompletionItemLabelDetails {
26+
description: Some(i.description),
27+
detail: None,
28+
}),
29+
preselect: Some(i.preselected),
30+
kind: Some(to_lsp_types_completion_item_kind(i.kind)),
31+
..CompletionItem::default()
32+
})
33+
.collect();
34+
35+
Ok(lsp_types::CompletionResponse::Array(items))
36+
}
37+
38+
fn to_lsp_types_completion_item_kind(
39+
pg_comp_kind: pg_completions::CompletionItemKind,
40+
) -> lsp_types::CompletionItemKind {
41+
match pg_comp_kind {
42+
pg_completions::CompletionItemKind::Function
43+
| pg_completions::CompletionItemKind::Table => lsp_types::CompletionItemKind::CLASS,
44+
}
45+
}

crates/pg_lsp_new/src/handlers/text_document.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,11 +24,11 @@ pub(crate) async fn did_open(
2424
let version = params.text_document.version;
2525
let content = params.text_document.text;
2626

27-
let biome_path = session.file_path(&url)?;
27+
let path = session.file_path(&url)?;
2828
let doc = Document::new(version, &content);
2929

3030
session.workspace.open_file(OpenFileParams {
31-
path: biome_path,
31+
path,
3232
version,
3333
content,
3434
})?;

crates/pg_lsp_new/src/main.rs

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
use std::{fs::File, path::PathBuf, str::FromStr};
2+
3+
use pg_lsp_new::ServerFactory;
4+
use tracing_subscriber::fmt::format::FmtSpan;
5+
6+
#[tokio::main]
7+
async fn main() -> anyhow::Result<()> {
8+
// This is currently only used for local debugging.
9+
// The `pglsp.toml` and `pglsp.log` filepaths should be dynamic.
10+
11+
let log_path = PathBuf::from_str("pglsp.log").expect("Opened the log file.");
12+
let log_file = File::create(log_path).expect("Could not open the file.");
13+
14+
let subscriber = tracing_subscriber::FmtSubscriber::builder()
15+
.with_span_events(FmtSpan::ENTER)
16+
.with_span_events(FmtSpan::CLOSE)
17+
.with_ansi(false)
18+
.with_writer(log_file)
19+
.finish();
20+
21+
tracing::subscriber::set_global_default(subscriber)?;
22+
23+
let stdin = tokio::io::stdin();
24+
let stdout = tokio::io::stdout();
25+
26+
let config_path = PathBuf::from_str("pglsp.toml").expect("Could not find the pglsp.toml file.");
27+
28+
tracing::info!("Starting server.");
29+
30+
ServerFactory::new(true)
31+
.create(Some(config_path))
32+
.accept(stdin, stdout)
33+
.await;
34+
35+
Ok(())
36+
}

crates/pg_lsp_new/src/server.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -232,6 +232,14 @@ impl LanguageServer for LSPServer {
232232
.await
233233
.ok();
234234
}
235+
236+
#[tracing::instrument(level = "trace", skip(self))]
237+
async fn completion(&self, params: CompletionParams) -> LspResult<Option<CompletionResponse>> {
238+
match handlers::completions::get_completions(&self.session, params) {
239+
Ok(result) => LspResult::Ok(Some(result)),
240+
Err(e) => LspResult::Err(into_lsp_error(e)),
241+
}
242+
}
235243
}
236244

237245
impl Drop for LSPServer {
@@ -379,6 +387,7 @@ impl ServerFactory {
379387
workspace_method!(builder, change_file);
380388
workspace_method!(builder, close_file);
381389
workspace_method!(builder, pull_diagnostics);
390+
workspace_method!(builder, get_completions);
382391

383392
let (service, socket) = builder.finish();
384393
ServerConnection { socket, service }

crates/pg_workspace_new/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ ignore = { workspace = true }
1919
pg_configuration = { workspace = true }
2020
pg_console = { workspace = true }
2121
pg_diagnostics = { workspace = true }
22+
pg_completions = { workspace = true }
2223
pg_fs = { workspace = true, features = ["serde"] }
2324
pg_query_ext = { workspace = true }
2425
pg_schema_cache = { workspace = true }

crates/pg_workspace_new/src/diagnostics.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,12 @@ impl WorkspaceError {
6060
pub fn vcs_disabled() -> Self {
6161
Self::Vcs(VcsDiagnostic::DisabledVcs(DisabledVcs {}))
6262
}
63+
64+
pub fn runtime(msg: &str) -> Self {
65+
Self::RuntimeError(RuntimeError {
66+
message: msg.into(),
67+
})
68+
}
6369
}
6470

6571
impl Error for WorkspaceError {}

crates/pg_workspace_new/src/workspace.rs

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ pub use self::client::{TransportRequest, WorkspaceClient, WorkspaceTransport};
44
use pg_configuration::PartialConfiguration;
55
use pg_fs::PgLspPath;
66
use serde::{Deserialize, Serialize};
7-
use text_size::TextRange;
7+
use text_size::{TextRange, TextSize};
88

99
use crate::WorkspaceError;
1010

@@ -39,6 +39,14 @@ pub struct PullDiagnosticsParams {
3939
// pub skip: Vec<RuleSelector>,
4040
}
4141

42+
#[derive(Debug, serde::Serialize, serde::Deserialize)]
43+
pub struct CompletionParams {
44+
/// The File for which a completion is requested.
45+
pub path: PgLspPath,
46+
/// The Cursor position in the file for which a completion is requested.
47+
pub position: TextSize,
48+
}
49+
4250
#[derive(Debug, serde::Serialize, serde::Deserialize)]
4351
pub struct PullDiagnosticsResult {
4452
pub diagnostics: Vec<pg_diagnostics::serde::Diagnostic>,
@@ -105,6 +113,11 @@ pub trait Workspace: Send + Sync + RefUnwindSafe {
105113
params: PullDiagnosticsParams,
106114
) -> Result<PullDiagnosticsResult, WorkspaceError>;
107115

116+
fn get_completions(
117+
&self,
118+
params: CompletionParams,
119+
) -> Result<pg_completions::CompletionResult, WorkspaceError>;
120+
108121
/// Refresh the schema cache for this workspace
109122
fn refresh_schema_cache(&self) -> Result<(), WorkspaceError>;
110123

crates/pg_workspace_new/src/workspace/client.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -127,4 +127,11 @@ where
127127
) -> Result<super::PullDiagnosticsResult, WorkspaceError> {
128128
self.request("pglsp/pull_diagnostics", params)
129129
}
130+
131+
fn get_completions(
132+
&self,
133+
params: super::CompletionParams,
134+
) -> Result<pg_completions::CompletionResult, WorkspaceError> {
135+
self.request("pglsp/get_completions", params)
136+
}
130137
}

crates/pg_workspace_new/src/workspace/server.rs

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -342,6 +342,45 @@ impl Workspace for WorkspaceServer {
342342
skipped_diagnostics: 0,
343343
})
344344
}
345+
346+
#[tracing::instrument(level = "info", skip(self))]
347+
fn get_completions(
348+
&self,
349+
params: super::CompletionParams,
350+
) -> Result<pg_completions::CompletionResult, WorkspaceError> {
351+
let doc = self
352+
.documents
353+
.get(&params.path)
354+
.ok_or(WorkspaceError::not_found())?;
355+
356+
tracing::info!("Found the document.");
357+
tracing::info!("Looking for statement at position: {:?}", &params.position);
358+
359+
let statement_ref = match doc.statement_ref_at_offset(&params.position) {
360+
Some(s) => s,
361+
None => return Ok(pg_completions::CompletionResult::default()),
362+
};
363+
364+
let tree = self.tree_sitter.fetch(&statement_ref);
365+
let text = doc
366+
.statement_by_id(statement_ref.id)
367+
.expect("Found statement_ref but no matching statement")
368+
.text;
369+
370+
let schema_cache = self
371+
.schema_cache
372+
.read()
373+
.map_err(|_| WorkspaceError::runtime("Unable to load SchemaCache"))?;
374+
375+
let result = pg_completions::complete(pg_completions::CompletionParams {
376+
position: params.position,
377+
schema: &schema_cache,
378+
tree: tree.as_deref(),
379+
text,
380+
});
381+
382+
Ok(result)
383+
}
345384
}
346385

347386
/// Returns `true` if `path` is a directory or

crates/pg_workspace_new/src/workspace/server/document.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,13 @@ impl Document {
129129
.collect()
130130
}
131131

132+
pub(super) fn statement_by_id(&self, id: StatementId) -> Option<Statement> {
133+
self.statements
134+
.iter()
135+
.find(|s| s.0 == id)
136+
.map(|pos| self.statement(pos))
137+
}
138+
132139
pub(super) fn statement_ref(&self, inner_ref: &StatementPosition) -> StatementRef {
133140
StatementRef {
134141
id: inner_ref.0,

0 commit comments

Comments
 (0)