Skip to content

Commit 8e02824

Browse files
committedMay 29, 2024
feat: add hover to ide
1 parent ec41f63 commit 8e02824

File tree

11 files changed

+134
-32
lines changed

11 files changed

+134
-32
lines changed
 

‎Cargo.lock

+1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

‎crates/hover/src/lib.rs

+5-5
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,11 @@ use resolve::Hoverable;
44
use schema_cache::SchemaCache;
55
use text_size::{TextRange, TextSize};
66

7-
pub struct HoverParams {
7+
pub struct HoverParams<'a> {
88
pub position: text_size::TextSize,
99
pub source: String,
10-
pub ast: Option<sql_parser::EnrichedAst>,
11-
pub tree: tree_sitter::Tree,
10+
pub enriched_ast: Option<&'a sql_parser::EnrichedAst>,
11+
pub tree: &'a tree_sitter::Tree,
1212
pub schema_cache: SchemaCache,
1313
}
1414

@@ -19,8 +19,8 @@ pub struct HoverResult {
1919
}
2020

2121
pub fn hover(params: HoverParams) -> Option<HoverResult> {
22-
let elem = if params.ast.is_some() {
23-
resolve::resolve_from_enriched_ast(params.position, params.ast.unwrap())
22+
let elem = if params.enriched_ast.is_some() {
23+
resolve::resolve_from_enriched_ast(params.position, params.enriched_ast.unwrap())
2424
} else {
2525
resolve::resolve_from_tree_sitter(params.position, params.tree, &params.source)
2626
};

‎crates/hover/src/resolve.rs

+4-4
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ pub enum Hoverable {
2323
Column(HoverableColumn),
2424
}
2525

26-
pub fn resolve_from_enriched_ast(pos: TextSize, ast: EnrichedAst) -> Option<Hoverable> {
26+
pub fn resolve_from_enriched_ast(pos: TextSize, ast: &EnrichedAst) -> Option<Hoverable> {
2727
let node = ast.covering_node(TextRange::empty(pos));
2828

2929
if node.is_none() {
@@ -46,7 +46,7 @@ pub fn resolve_from_enriched_ast(pos: TextSize, ast: EnrichedAst) -> Option<Hove
4646
}
4747
}
4848

49-
pub fn resolve_from_tree_sitter(pos: TextSize, tree: Tree, source: &str) -> Option<Hoverable> {
49+
pub fn resolve_from_tree_sitter(pos: TextSize, tree: &Tree, source: &str) -> Option<Hoverable> {
5050
let r = tree
5151
.root_node()
5252
.named_descendant_for_byte_range(usize::from(pos), usize::from(pos));
@@ -90,7 +90,7 @@ mod tests {
9090
let root = sql_parser::parse_sql_statement(input).unwrap();
9191
let ast = parse_ast(input, &root).ast;
9292

93-
let hover = super::resolve_from_enriched_ast(position, ast);
93+
let hover = super::resolve_from_enriched_ast(position, &ast);
9494

9595
assert!(hover.is_some());
9696

@@ -116,7 +116,7 @@ mod tests {
116116

117117
let tree = parser.parse(input, None).unwrap();
118118

119-
let hover = super::resolve_from_tree_sitter(position, tree, input);
119+
let hover = super::resolve_from_tree_sitter(position, &tree, input);
120120

121121
assert!(hover.is_some());
122122

‎crates/ide/Cargo.toml

+1
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ edition = "2021"
77
text-size = "1.1.1"
88
dashmap = "5.5.3"
99
base_db.workspace = true
10+
hover.workspace = true
1011
sql_parser.workspace = true
1112
diagnostics.workspace = true
1213
tree-sitter.workspace = true

‎crates/ide/src/features.rs

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
pub mod hover;

‎crates/ide/src/features/hover.rs

+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
use base_db::PgLspPath;
2+
use text_size::TextSize;
3+
4+
pub struct HoverParams {
5+
pub position: TextSize,
6+
pub url: PgLspPath,
7+
}

‎crates/ide/src/lib.rs

+37-4
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,13 @@
1+
mod features;
12
mod pg_query;
23
mod tree_sitter;
34

45
use std::sync::{RwLock, RwLockWriteGuard};
56

67
use base_db::{Document, DocumentChange, PgLspPath, StatementRef};
78
use dashmap::{DashMap, DashSet};
8-
use diagnostics::Diagnostic;
99
use pg_query::PgQueryParser;
1010
use schema_cache::SchemaCache;
11-
use text_size::TextRange;
1211
use tracing::{event, span, Level};
1312
use tree_sitter::TreeSitterParser;
1413

@@ -101,8 +100,42 @@ impl IDE {
101100
diagnostics
102101
}
103102

104-
/// Analyse all statements that were changed since the last analysis
105-
pub fn analyse(&self) {}
103+
pub fn hover(&self, params: features::hover::HoverParams) -> Option<hover::HoverResult> {
104+
let doc = self.documents.get(&params.url)?;
105+
let stmt = doc.statement_at_offset(&params.position)?;
106+
107+
let tree = self.tree_sitter.tree(&stmt);
108+
109+
if tree.is_none() {
110+
return None;
111+
}
112+
113+
hover::hover(hover::HoverParams {
114+
tree: tree.unwrap().as_ref(),
115+
enriched_ast: self
116+
.pg_query
117+
.enriched_ast(&stmt)
118+
.as_ref()
119+
.map(|x| x.as_ref()),
120+
// TODO translate position to statement position range
121+
position: params.position,
122+
source: stmt.text,
123+
schema_cache: self.schema_cache.read().unwrap().clone(),
124+
})
125+
}
126+
127+
/// Drain changed statements to kick off analysis
128+
pub fn drain_changed_stmt(&self) -> Vec<StatementRef> {
129+
let changed: Vec<StatementRef> = self
130+
.changed_stmts
131+
.iter()
132+
.map(|arc| (*arc).clone())
133+
.collect();
134+
135+
self.changed_stmts.clear();
136+
137+
changed
138+
}
106139

107140
pub fn set_schema_cache(&self, cache: SchemaCache) {
108141
let mut schema_cache: RwLockWriteGuard<SchemaCache> = self.schema_cache.write().unwrap();

‎crates/ide/src/pg_query.rs

+33-6
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,15 @@
1+
use std::sync::Arc;
2+
13
use base_db::{ChangedStatement, StatementRef};
24
use dashmap::DashMap;
35
use diagnostics::{Diagnostic, Severity};
46
use text_size::TextRange;
57

68
pub struct PgQueryParser {
7-
ast_db: DashMap<StatementRef, sql_parser::AstNode>,
8-
native_diagnostics: DashMap<StatementRef, sql_parser::NativeError>,
9-
enriched_ast_db: DashMap<StatementRef, sql_parser::EnrichedAst>,
10-
cst_db: DashMap<StatementRef, sql_parser::Cst>,
9+
ast_db: DashMap<StatementRef, Arc<sql_parser::AstNode>>,
10+
native_diagnostics: DashMap<StatementRef, Arc<sql_parser::NativeError>>,
11+
enriched_ast_db: DashMap<StatementRef, Arc<sql_parser::EnrichedAst>>,
12+
cst_db: DashMap<StatementRef, Arc<sql_parser::Cst>>,
1113
}
1214

1315
impl PgQueryParser {
@@ -20,6 +22,31 @@ impl PgQueryParser {
2022
}
2123
}
2224

25+
pub fn ast(&self, statement: &StatementRef) -> Option<Arc<sql_parser::AstNode>> {
26+
self.ast_db.get(statement).map(|x| x.clone())
27+
}
28+
29+
pub fn enriched_ast(&self, statement: &StatementRef) -> Option<Arc<sql_parser::EnrichedAst>> {
30+
self.enriched_ast_db.get(statement).map(|x| x.clone())
31+
}
32+
33+
pub fn cst(&self, statement: &StatementRef) -> Option<Arc<sql_parser::Cst>> {
34+
self.cst_db.get(statement).map(|x| x.clone())
35+
}
36+
37+
pub fn compute_cst(&self, statement: &StatementRef) {
38+
if self.cst_db.contains_key(statement) {
39+
return;
40+
}
41+
42+
if let Some(ast) = self.ast_db.get(statement) {
43+
let r = sql_parser::parse_ast(&statement.text, &ast);
44+
self.cst_db.insert(statement.clone(), Arc::new(r.cst));
45+
self.enriched_ast_db
46+
.insert(statement.clone(), Arc::new(r.ast));
47+
}
48+
}
49+
2350
pub fn diagnostics(&self, statement: &StatementRef, at_range: TextRange) -> Vec<Diagnostic> {
2451
let mut diagnostics = Vec::new();
2552
if let Some(err) = self.native_diagnostics.get(statement) {
@@ -37,10 +64,10 @@ impl PgQueryParser {
3764
pub fn add_statement(&self, statement: &StatementRef) {
3865
let r = sql_parser::parse_sql_statement(statement.text.as_str());
3966
if r.is_ok() {
40-
self.ast_db.insert(statement.clone(), r.unwrap());
67+
self.ast_db.insert(statement.clone(), Arc::new(r.unwrap()));
4168
} else {
4269
self.native_diagnostics
43-
.insert(statement.clone(), r.unwrap_err());
70+
.insert(statement.clone(), Arc::new(r.unwrap_err()));
4471
}
4572
}
4673

‎crates/ide/src/tree_sitter.rs

+12-6
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
1-
use std::sync::RwLock;
1+
use std::sync::{Arc, RwLock};
22

33
use base_db::{ChangedStatement, StatementRef};
44
use dashmap::DashMap;
55
use text_size::TextRange;
6-
use tree_sitter::{InputEdit, Tree};
6+
use tree_sitter::InputEdit;
77

88
pub struct TreeSitterParser {
9-
db: DashMap<StatementRef, Tree>,
9+
db: DashMap<StatementRef, Arc<tree_sitter::Tree>>,
1010

1111
parser: RwLock<tree_sitter::Parser>,
1212
}
@@ -24,12 +24,16 @@ impl TreeSitterParser {
2424
}
2525
}
2626

27+
pub fn tree(&self, statement: &StatementRef) -> Option<Arc<tree_sitter::Tree>> {
28+
self.db.get(statement).map(|x| x.clone())
29+
}
30+
2731
pub fn add_statement(&self, statement: &StatementRef) {
2832
let mut guard = self.parser.write().expect("Error reading parser");
2933
// todo handle error
3034
let tree = guard.parse(&statement.text, None).unwrap();
3135
drop(guard);
32-
self.db.insert(statement.clone(), tree);
36+
self.db.insert(statement.clone(), Arc::new(tree));
3337
}
3438

3539
pub fn remove_statement(&self, statement: &StatementRef) {
@@ -60,8 +64,10 @@ impl TreeSitterParser {
6064

6165
let mut guard = self.parser.write().expect("Error reading parser");
6266
// todo handle error
63-
self.db
64-
.insert(new_stmt, guard.parse(new_text, Some(&tree)).unwrap());
67+
self.db.insert(
68+
new_stmt,
69+
Arc::new(guard.parse(new_text, Some(&tree)).unwrap()),
70+
);
6571
drop(guard);
6672
}
6773
}

‎crates/lsp/src/server.rs

+32-7
Original file line numberDiff line numberDiff line change
@@ -5,21 +5,22 @@ use async_std::task::{self};
55
use base_db::{Change, Document, DocumentChange, PgLspPath, StatementRef};
66
use crossbeam_channel::{unbounded, Receiver, Sender};
77
use ide::IDE;
8-
use lsp_server::{Connection, Message, Notification};
8+
use lsp_server::{Connection, Message, Notification, RequestId};
99
use lsp_types::{
1010
notification::{
1111
DidChangeConfiguration, DidChangeTextDocument, DidCloseTextDocument, DidOpenTextDocument,
1212
DidSaveTextDocument, LogMessage, Notification as _, PublishDiagnostics, ShowMessage,
1313
},
14-
request::{RegisterCapability, WorkspaceConfiguration},
14+
request::{HoverRequest, RegisterCapability, WorkspaceConfiguration},
1515
ConfigurationItem, ConfigurationParams, DidChangeConfigurationParams,
1616
DidChangeTextDocumentParams, DidCloseTextDocumentParams, DidOpenTextDocumentParams,
17-
DidSaveTextDocumentParams, InitializeParams, InitializeResult, LogMessageParams,
18-
PublishDiagnosticsParams, Registration, RegistrationParams, SaveOptions, ServerCapabilities,
19-
ServerInfo, ShowMessageParams, TextDocumentSyncCapability, TextDocumentSyncKind,
20-
TextDocumentSyncOptions, TextDocumentSyncSaveOptions,
17+
DidSaveTextDocumentParams, HoverParams, HoverProviderCapability, InitializeParams,
18+
InitializeResult, LogMessageParams, PublishDiagnosticsParams, Registration, RegistrationParams,
19+
SaveOptions, ServerCapabilities, ServerInfo, ShowMessageParams, TextDocumentSyncCapability,
20+
TextDocumentSyncKind, TextDocumentSyncOptions, TextDocumentSyncSaveOptions,
2121
};
2222
use schema_cache::SchemaCache;
23+
use serde::Serialize;
2324
use std::sync::Arc;
2425
use threadpool::ThreadPool;
2526
use tracing::{event, instrument, Level};
@@ -65,7 +66,7 @@ pub struct Server {
6566
internal_rx: Receiver<InternalMessage>,
6667
pool: ThreadPool,
6768
client_flags: Arc<ClientFlags>,
68-
ide: IDE,
69+
ide: Arc<IDE>,
6970
db_conn: Option<DbConnection>,
7071
}
7172

@@ -192,6 +193,7 @@ impl Server {
192193
})),
193194
},
194195
)),
196+
hover_provider: Some(HoverProviderCapability::Simple(true)),
195197
..ServerCapabilities::default()
196198
}
197199
}
@@ -302,6 +304,28 @@ impl Server {
302304
Ok(())
303305
}
304306

307+
fn hover(&mut self, id: RequestId, mut params: HoverParams) -> anyhow::Result<()> {
308+
normalize_uri(&mut params.text_document_position_params.text_document.uri);
309+
310+
self.run_query(id, move |ide| ide.hover(params));
311+
312+
Ok(())
313+
}
314+
315+
fn run_query<R, Q>(&self, id: RequestId, query: Q)
316+
where
317+
R: Serialize,
318+
Q: FnOnce(&IDE) -> R + Send + 'static,
319+
{
320+
let client = self.client.clone();
321+
let ide = Arc::clone(&self.ide);
322+
323+
self.pool.execute(move || {
324+
let response = lsp_server::Response::new_ok(id, query(&ide));
325+
client.send_response(response).unwrap();
326+
});
327+
}
328+
305329
#[instrument(skip(self), name = "pglsp/refresh_schema_cache")]
306330
fn refresh_schema_cache(&self) {
307331
if self.db_conn.is_none() {
@@ -350,6 +374,7 @@ impl Server {
350374
}
351375

352376
if let Some(response) = dispatch::RequestDispatcher::new(request)
377+
.on::<HoverRequest, _>(|id, params| self.hover(id, params))?
353378
.default()
354379
{
355380
self.client.send_response(response)?;

‎crates/sql_parser/src/parser/parse_ast/ast_builder.rs

+1
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ impl RangedNode {
2020
}
2121
}
2222

23+
#[derive(Debug, Clone)]
2324
pub struct EnrichedAst {
2425
inner: StableGraph<RangedNode, ()>,
2526
}

0 commit comments

Comments
 (0)
Please sign in to comment.