@@ -8,12 +8,38 @@ pub fn hover(file: &ast::SourceFile, offset: TextSize) -> Option<String> {
88 let token = token_from_offset ( file, offset) ?;
99 let parent = token. parent ( ) ?;
1010
11- let name_ref = ast:: NameRef :: cast ( parent) ?;
11+ let binder = binder:: bind ( file) ;
12+
13+ if let Some ( name_ref) = ast:: NameRef :: cast ( parent. clone ( ) ) {
14+ if is_column_ref ( & name_ref) {
15+ return hover_column ( file, & name_ref, & binder) ;
16+ }
1217
13- if !is_column_ref ( & name_ref) {
14- return None ;
18+ if is_table_ref ( & name_ref) {
19+ return hover_table ( file, & name_ref, & binder) ;
20+ }
1521 }
1622
23+ if let Some ( name) = ast:: Name :: cast ( parent) {
24+ if let Some ( column) = name. syntax ( ) . parent ( ) . and_then ( ast:: Column :: cast)
25+ && let Some ( create_table) = column. syntax ( ) . ancestors ( ) . find_map ( ast:: CreateTable :: cast)
26+ {
27+ return hover_column_definition ( & create_table, & column, & binder) ;
28+ }
29+
30+ if let Some ( create_table) = name. syntax ( ) . ancestors ( ) . find_map ( ast:: CreateTable :: cast) {
31+ return format_create_table ( & create_table, & binder) ;
32+ }
33+ }
34+
35+ None
36+ }
37+
38+ fn hover_column (
39+ file : & ast:: SourceFile ,
40+ name_ref : & ast:: NameRef ,
41+ binder : & binder:: Binder ,
42+ ) -> Option < String > {
1743 let column_name = name_ref. syntax ( ) . text ( ) . to_string ( ) ;
1844
1945 let create_index = name_ref
@@ -24,11 +50,9 @@ pub fn hover(file: &ast::SourceFile, offset: TextSize) -> Option<String> {
2450 let relation_name = create_index. relation_name ( ) ?;
2551 let path = relation_name. path ( ) ?;
2652
27- let binder = binder:: bind ( file) ;
28-
29- let ( schema, table_name) = resolve:: resolve_table_info ( & binder, & path) ?;
53+ let ( schema, table_name) = resolve:: resolve_table_info ( binder, & path) ?;
3054
31- let column_ptr = resolve:: resolve_name_ref ( & binder, & name_ref) ?;
55+ let column_ptr = resolve:: resolve_name_ref ( binder, name_ref) ?;
3256
3357 let root = file. syntax ( ) ;
3458 let column_name_node = column_ptr. to_node ( root) ;
@@ -43,14 +67,128 @@ pub fn hover(file: &ast::SourceFile, offset: TextSize) -> Option<String> {
4367 ) )
4468}
4569
70+ fn hover_column_definition (
71+ create_table : & ast:: CreateTable ,
72+ column : & ast:: Column ,
73+ binder : & binder:: Binder ,
74+ ) -> Option < String > {
75+ let column_name = column. name ( ) ?. syntax ( ) . text ( ) . to_string ( ) ;
76+ let ty = column. ty ( ) ?;
77+ let path = create_table. path ( ) ?;
78+ let table_name = path. segment ( ) ?. name ( ) ?. syntax ( ) . text ( ) . to_string ( ) ;
79+
80+ let schema = if let Some ( qualifier) = path. qualifier ( ) {
81+ qualifier. syntax ( ) . text ( ) . to_string ( )
82+ } else if let Some ( schema) = table_schema ( create_table, binder) {
83+ schema
84+ } else {
85+ return Some ( format ! (
86+ "{}.{} {}" ,
87+ table_name,
88+ column_name,
89+ ty. syntax( ) . text( )
90+ ) ) ;
91+ } ;
92+
93+ Some ( format ! (
94+ "{}.{}.{} {}" ,
95+ schema,
96+ table_name,
97+ column_name,
98+ ty. syntax( ) . text( )
99+ ) )
100+ }
101+
102+ fn hover_table (
103+ file : & ast:: SourceFile ,
104+ name_ref : & ast:: NameRef ,
105+ binder : & binder:: Binder ,
106+ ) -> Option < String > {
107+ let table_ptr = resolve:: resolve_name_ref ( binder, name_ref) ?;
108+
109+ let root = file. syntax ( ) ;
110+ let table_name_node = table_ptr. to_node ( root) ;
111+
112+ let create_table = table_name_node
113+ . ancestors ( )
114+ . find_map ( ast:: CreateTable :: cast) ?;
115+
116+ format_create_table ( & create_table, binder)
117+ }
118+
119+ // Insert inferred schema into the create table hover info
120+ fn format_create_table ( create_table : & ast:: CreateTable , binder : & binder:: Binder ) -> Option < String > {
121+ let path = create_table. path ( ) ?;
122+ let mut text = create_table. syntax ( ) . text ( ) . to_string ( ) ;
123+
124+ if path. qualifier ( ) . is_some ( ) {
125+ return Some ( text) ;
126+ }
127+
128+ let Some ( schema) = table_schema ( create_table, binder) else {
129+ return Some ( text) ;
130+ } ;
131+
132+ let Some ( offset) = table_name_offset ( create_table, & path) else {
133+ return Some ( text) ;
134+ } ;
135+
136+ text. insert_str ( offset, & format ! ( "{}." , schema) ) ;
137+ Some ( text)
138+ }
139+
140+ fn table_schema ( create_table : & ast:: CreateTable , binder : & binder:: Binder ) -> Option < String > {
141+ let is_temp = create_table. temp_token ( ) . is_some ( ) || create_table. temporary_token ( ) . is_some ( ) ;
142+ if is_temp {
143+ return Some ( "pg_temp" . to_string ( ) ) ;
144+ }
145+
146+ let position = create_table. syntax ( ) . text_range ( ) . start ( ) ;
147+ let search_path = binder. search_path_at ( position) ;
148+ search_path. first ( ) . map ( |s| s. to_string ( ) )
149+ }
150+
151+ fn table_name_offset ( create_table : & ast:: CreateTable , path : & ast:: Path ) -> Option < usize > {
152+ let segment = path. segment ( ) ?;
153+ let name = segment. name ( ) ?;
154+ let name_start = name. syntax ( ) . text_range ( ) . start ( ) ;
155+ let create_table_start = create_table. syntax ( ) . text_range ( ) . start ( ) ;
156+ Some ( ( name_start - create_table_start) . into ( ) )
157+ }
158+
46159fn is_column_ref ( name_ref : & ast:: NameRef ) -> bool {
160+ let mut in_partition_item = false ;
161+
47162 for ancestor in name_ref. syntax ( ) . ancestors ( ) {
48163 if ast:: PartitionItem :: can_cast ( ancestor. kind ( ) ) {
49- return true ;
164+ in_partition_item = true ;
50165 }
51166 if ast:: CreateIndex :: can_cast ( ancestor. kind ( ) ) {
167+ return in_partition_item;
168+ }
169+ }
170+ false
171+ }
172+
173+ fn is_table_ref ( name_ref : & ast:: NameRef ) -> bool {
174+ let mut in_partition_item = false ;
175+
176+ for ancestor in name_ref. syntax ( ) . ancestors ( ) {
177+ if ast:: DropTable :: can_cast ( ancestor. kind ( ) ) {
178+ return true ;
179+ }
180+ if ast:: Table :: can_cast ( ancestor. kind ( ) ) {
52181 return true ;
53182 }
183+ if ast:: DropIndex :: can_cast ( ancestor. kind ( ) ) {
184+ return false ;
185+ }
186+ if ast:: PartitionItem :: can_cast ( ancestor. kind ( ) ) {
187+ in_partition_item = true ;
188+ }
189+ if ast:: CreateIndex :: can_cast ( ancestor. kind ( ) ) {
190+ return !in_partition_item;
191+ }
54192 }
55193 false
56194}
@@ -239,13 +377,16 @@ create index idx_email on public.users(email$0);
239377 }
240378
241379 #[ test]
242- fn hover_not_on_table_name ( ) {
243- hover_not_found (
244- "
245- create table users(id int);
246- create index idx on users$0(id);
247- " ,
248- ) ;
380+ fn hover_on_table_name ( ) {
381+ assert_snapshot ! ( check_hover( "
382+ create table t(id int);
383+ create index idx on t$0(id);
384+ " ) , @r"
385+ hover: create table public.t(id int)
386+ ╭▸
387+ 3 │ create index idx on t(id);
388+ ╰╴ ─ hover
389+ " ) ;
249390 }
250391
251392 #[ test]
@@ -257,4 +398,177 @@ create index idx$0 on users(id);
257398" ,
258399 ) ;
259400 }
401+
402+ #[ test]
403+ fn hover_table_in_create_index ( ) {
404+ assert_snapshot ! ( check_hover( "
405+ create table users(id int, email text);
406+ create index idx_email on users$0(email);
407+ " ) , @r"
408+ hover: create table public.users(id int, email text)
409+ ╭▸
410+ 3 │ create index idx_email on users(email);
411+ ╰╴ ─ hover
412+ " ) ;
413+ }
414+
415+ #[ test]
416+ fn hover_table_with_schema ( ) {
417+ assert_snapshot ! ( check_hover( "
418+ create table public.users(id int, email text);
419+ create index idx on public.users$0(id);
420+ " ) , @r"
421+ hover: create table public.users(id int, email text)
422+ ╭▸
423+ 3 │ create index idx on public.users(id);
424+ ╰╴ ─ hover
425+ " ) ;
426+ }
427+
428+ #[ test]
429+ fn hover_table_temp ( ) {
430+ assert_snapshot ! ( check_hover( "
431+ create temp table users(id int, email text);
432+ create index idx on users$0(id);
433+ " ) , @r"
434+ hover: create temp table pg_temp.users(id int, email text)
435+ ╭▸
436+ 3 │ create index idx on users(id);
437+ ╰╴ ─ hover
438+ " ) ;
439+ }
440+
441+ #[ test]
442+ fn hover_table_multiline ( ) {
443+ assert_snapshot ! ( check_hover( "
444+ create table users(
445+ id int,
446+ email text,
447+ name varchar(100)
448+ );
449+ create index idx on users$0(id);
450+ " ) , @r"
451+ hover: create table public.users(
452+ id int,
453+ email text,
454+ name varchar(100)
455+ )
456+ ╭▸
457+ 7 │ create index idx on users(id);
458+ ╰╴ ─ hover
459+ " ) ;
460+ }
461+
462+ #[ test]
463+ fn hover_table_with_search_path ( ) {
464+ assert_snapshot ! ( check_hover( r#"
465+ set search_path to myschema;
466+ create table users(id int, email text);
467+ create index idx on users$0(id);
468+ "# ) , @r"
469+ hover: create table myschema.users(id int, email text)
470+ ╭▸
471+ 4 │ create index idx on users(id);
472+ ╰╴ ─ hover
473+ " ) ;
474+ }
475+
476+ #[ test]
477+ fn hover_table_search_path_at_definition ( ) {
478+ assert_snapshot ! ( check_hover( r#"
479+ set search_path to myschema;
480+ create table users(id int, email text);
481+ set search_path to myschema, otherschema;
482+ create index idx on users$0(id);
483+ "# ) , @r"
484+ hover: create table myschema.users(id int, email text)
485+ ╭▸
486+ 5 │ create index idx on users(id);
487+ ╰╴ ─ hover
488+ " ) ;
489+ }
490+
491+ #[ test]
492+ fn hover_on_create_table_definition ( ) {
493+ assert_snapshot ! ( check_hover( "
494+ create table t$0(x bigint);
495+ " ) , @r"
496+ hover: create table public.t(x bigint)
497+ ╭▸
498+ 2 │ create table t(x bigint);
499+ ╰╴ ─ hover
500+ " ) ;
501+ }
502+
503+ #[ test]
504+ fn hover_on_create_table_definition_with_schema ( ) {
505+ assert_snapshot ! ( check_hover( "
506+ create table myschema.users$0(id int);
507+ " ) , @r"
508+ hover: create table myschema.users(id int)
509+ ╭▸
510+ 2 │ create table myschema.users(id int);
511+ ╰╴ ─ hover
512+ " ) ;
513+ }
514+
515+ #[ test]
516+ fn hover_on_create_temp_table_definition ( ) {
517+ assert_snapshot ! ( check_hover( "
518+ create temp table t$0(x bigint);
519+ " ) , @r"
520+ hover: create temp table pg_temp.t(x bigint)
521+ ╭▸
522+ 2 │ create temp table t(x bigint);
523+ ╰╴ ─ hover
524+ " ) ;
525+ }
526+
527+ #[ test]
528+ fn hover_on_column_in_create_table ( ) {
529+ assert_snapshot ! ( check_hover( "
530+ create table t(id$0 int);
531+ " ) , @r"
532+ hover: public.t.id int
533+ ╭▸
534+ 2 │ create table t(id int);
535+ ╰╴ ─ hover
536+ " ) ;
537+ }
538+
539+ #[ test]
540+ fn hover_on_column_in_create_table_with_schema ( ) {
541+ assert_snapshot ! ( check_hover( "
542+ create table myschema.users(id$0 int, name text);
543+ " ) , @r"
544+ hover: myschema.users.id int
545+ ╭▸
546+ 2 │ create table myschema.users(id int, name text);
547+ ╰╴ ─ hover
548+ " ) ;
549+ }
550+
551+ #[ test]
552+ fn hover_on_column_in_temp_table ( ) {
553+ assert_snapshot ! ( check_hover( "
554+ create temp table t(x$0 bigint);
555+ " ) , @r"
556+ hover: pg_temp.t.x bigint
557+ ╭▸
558+ 2 │ create temp table t(x bigint);
559+ ╰╴ ─ hover
560+ " ) ;
561+ }
562+
563+ #[ test]
564+ fn hover_on_multiple_columns ( ) {
565+ assert_snapshot ! ( check_hover( "
566+ create table t(id int, email$0 text, name varchar(100));
567+ " ) , @r"
568+ hover: public.t.email text
569+ ╭▸
570+ 2 │ create table t(id int, email text, name varchar(100));
571+ ╰╴ ─ hover
572+ " ) ;
573+ }
260574}
0 commit comments