Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion crates/squawk_ide/src/binder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -375,7 +375,7 @@ fn bind_set(b: &mut Binder, set: ast::Set) {
}
}

fn extract_string_literal(literal: &ast::Literal) -> Option<String> {
pub(crate) fn extract_string_literal(literal: &ast::Literal) -> Option<String> {
let text = literal.syntax().text().to_string();

if text.starts_with('\'') && text.ends_with('\'') && text.len() >= 2 {
Expand Down
137 changes: 129 additions & 8 deletions crates/squawk_ide/src/document_symbols.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use rowan::TextRange;
use squawk_syntax::ast::{self, AstNode};

use crate::binder;
use crate::binder::{self, extract_string_literal};
use crate::resolve::{resolve_function_info, resolve_table_info, resolve_type_info};

#[derive(Debug)]
Expand All @@ -10,6 +10,7 @@ pub enum DocumentSymbolKind {
Function,
Type,
Column,
Variant,
}

#[derive(Debug)]
Expand Down Expand Up @@ -126,13 +127,28 @@ fn create_type_symbol(
let full_range = create_type.syntax().text_range();
let focus_range = name_node.syntax().text_range();

let mut children = vec![];
if let Some(variant_list) = create_type.variant_list() {
for variant in variant_list.variants() {
if let Some(variant_symbol) = create_variant_symbol(variant) {
children.push(variant_symbol);
}
}
} else if let Some(column_list) = create_type.column_list() {
for column in column_list.columns() {
if let Some(column_symbol) = create_column_symbol(column) {
children.push(column_symbol);
}
}
}

Some(DocumentSymbol {
name,
detail: None,
kind: DocumentSymbolKind::Type,
full_range,
focus_range,
children: vec![],
children,
})
}

Expand All @@ -155,6 +171,23 @@ fn create_column_symbol(column: ast::Column) -> Option<DocumentSymbol> {
})
}

fn create_variant_symbol(variant: ast::Variant) -> Option<DocumentSymbol> {
let literal = variant.literal()?;
let name = extract_string_literal(&literal)?;

let full_range = variant.syntax().text_range();
let focus_range = literal.syntax().text_range();

Some(DocumentSymbol {
name,
detail: None,
kind: DocumentSymbolKind::Variant,
full_range,
focus_range,
children: vec![],
})
}

#[cfg(test)]
mod tests {
use super::*;
Expand Down Expand Up @@ -197,6 +230,7 @@ mod tests {
DocumentSymbolKind::Function => "function",
DocumentSymbolKind::Type => "type",
DocumentSymbolKind::Column => "column",
DocumentSymbolKind::Variant => "variant",
};

let title = if let Some(detail) = &symbol.detail {
Expand Down Expand Up @@ -227,10 +261,14 @@ mod tests {
.map(|child| {
let kind = match child.kind {
DocumentSymbolKind::Column => "column",
_ => unreachable!("only columns can be children"),
DocumentSymbolKind::Variant => "variant",
_ => unreachable!("only columns and variants can be children"),
};
let detail = &child.detail.as_ref().unwrap();
format!("{}: {} {}", kind, child.name, detail)
if let Some(detail) = &child.detail {
format!("{}: {} {}", kind, child.name, detail)
} else {
format!("{}: {}", kind, child.name)
}
})
.collect();

Expand Down Expand Up @@ -392,7 +430,16 @@ create function my_schema.hello() returns void as $$ select 1; $$ language sql;
│ ┬───────────┯━━━━━───────────────────────────────
│ │ │
│ │ focus range
╰╴full range
│ full range
1 │ create type status as enum ('active', 'inactive');
│ ┯━━━━━━━ ┯━━━━━━━━━
│ │ │
│ │ full range for `variant: inactive`
│ │ focus range
│ full range for `variant: active`
╰╴ focus range
"
);
}
Expand All @@ -408,7 +455,43 @@ create function my_schema.hello() returns void as $$ select 1; $$ language sql;
│ ┬───────────┯━━━━━────────────────────────
│ │ │
│ │ focus range
╰╴full range
│ full range
1 │ create type person as (name text, age int);
│ ┯━━━───── ┯━━────
│ │ │
│ │ full range for `column: age int`
│ │ focus range
│ full range for `column: name text`
╰╴ focus range
"
);
}

#[test]
fn create_type_composite_multiple_columns() {
assert_snapshot!(
symbols("create type address as (street text, city text, zip varchar(10));"),
@r"
info: type: public.address
╭▸
1 │ create type address as (street text, city text, zip varchar(10));
│ ┬───────────┯━━━━━━─────────────────────────────────────────────
│ │ │
│ │ focus range
│ full range
1 │ create type address as (street text, city text, zip varchar(10));
│ ┯━━━━━───── ┯━━━───── ┯━━────────────
│ │ │ │
│ │ │ full range for `column: zip varchar(10)`
│ │ │ focus range
│ │ full range for `column: city text`
│ │ focus range
│ full range for `column: street text`
╰╴ focus range
"
);
}
Expand All @@ -424,7 +507,45 @@ create function my_schema.hello() returns void as $$ select 1; $$ language sql;
│ ┬────────────────────┯━━━━━───────────────────────────────
│ │ │
│ │ focus range
╰╴full range
│ full range
1 │ create type myschema.status as enum ('active', 'inactive');
│ ┯━━━━━━━ ┯━━━━━━━━━
│ │ │
│ │ full range for `variant: inactive`
│ │ focus range
│ full range for `variant: active`
╰╴ focus range
"
);
}

#[test]
fn create_type_enum_multiple_variants() {
assert_snapshot!(
symbols("create type priority as enum ('low', 'medium', 'high', 'urgent');"),
@r"
info: type: public.priority
╭▸
1 │ create type priority as enum ('low', 'medium', 'high', 'urgent');
│ ┬───────────┯━━━━━━━────────────────────────────────────────────
│ │ │
│ │ focus range
│ full range
1 │ create type priority as enum ('low', 'medium', 'high', 'urgent');
│ ┯━━━━ ┯━━━━━━━ ┯━━━━━ ┯━━━━━━━
│ │ │ │ │
│ │ │ │ full range for `variant: urgent`
│ │ │ │ focus range
│ │ │ full range for `variant: high`
│ │ │ focus range
│ │ full range for `variant: medium`
│ │ focus range
│ full range for `variant: low`
╰╴ focus range
"
);
}
Expand Down
42 changes: 42 additions & 0 deletions crates/squawk_ide/src/goto_definition.rs
Original file line number Diff line number Diff line change
Expand Up @@ -457,6 +457,48 @@ drop type int4_range$0;
");
}

#[test]
fn goto_cast_operator() {
assert_snapshot!(goto("
create type foo as enum ('a', 'b');
select x::foo$0;
"), @r"
╭▸
2 │ create type foo as enum ('a', 'b');
│ ─── 2. destination
3 │ select x::foo;
╰╴ ─ 1. source
");
}

#[test]
fn goto_cast_function() {
assert_snapshot!(goto("
create type bar as enum ('x', 'y');
select cast(x as bar$0);
"), @r"
╭▸
2 │ create type bar as enum ('x', 'y');
│ ─── 2. destination
3 │ select cast(x as bar);
╰╴ ─ 1. source
");
}

#[test]
fn goto_cast_with_schema() {
assert_snapshot!(goto("
create type public.baz as enum ('m', 'n');
select x::public.baz$0;
"), @r"
╭▸
2 │ create type public.baz as enum ('m', 'n');
│ ─── 2. destination
3 │ select x::public.baz;
╰╴ ─ 1. source
");
}

#[test]
fn begin_to_rollback() {
assert_snapshot!(goto(
Expand Down
54 changes: 50 additions & 4 deletions crates/squawk_ide/src/hover.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,10 @@ pub fn hover(file: &ast::SourceFile, offset: TextSize) -> Option<String> {
return hover_column(file, &name_ref, &binder);
}

if is_type_ref(&name_ref) {
return hover_type(file, &name_ref, &binder);
}

if is_select_column(&name_ref) {
// Try hover as column first
if let Some(result) = hover_column(file, &name_ref, &binder) {
Expand Down Expand Up @@ -45,10 +49,6 @@ pub fn hover(file: &ast::SourceFile, offset: TextSize) -> Option<String> {
return hover_index(file, &name_ref, &binder);
}

if is_type_ref(&name_ref) {
return hover_type(file, &name_ref, &binder);
}

if is_function_ref(&name_ref) {
return hover_function(file, &name_ref, &binder);
}
Expand Down Expand Up @@ -461,10 +461,17 @@ fn is_index_ref(name_ref: &ast::NameRef) -> bool {
}

fn is_type_ref(name_ref: &ast::NameRef) -> bool {
let mut in_type = false;
for ancestor in name_ref.syntax().ancestors() {
if ast::PathType::can_cast(ancestor.kind()) || ast::ExprType::can_cast(ancestor.kind()) {
in_type = true;
}
if ast::DropType::can_cast(ancestor.kind()) {
return true;
}
if ast::CastExpr::can_cast(ancestor.kind()) && in_type {
return true;
}
}
false
}
Expand Down Expand Up @@ -1342,6 +1349,45 @@ drop type int4_range$0;
");
}

#[test]
fn hover_on_cast_operator() {
assert_snapshot!(check_hover("
create type foo as enum ('a', 'b');
select x::foo$0;
"), @r"
hover: type public.foo as enum ('a', 'b')
╭▸
3 │ select x::foo;
╰╴ ─ hover
");
}

#[test]
fn hover_on_cast_function() {
assert_snapshot!(check_hover("
create type bar as enum ('x', 'y');
select cast(x as bar$0);
"), @r"
hover: type public.bar as enum ('x', 'y')
╭▸
3 │ select cast(x as bar);
╰╴ ─ hover
");
}

#[test]
fn hover_on_cast_with_schema() {
assert_snapshot!(check_hover("
create type myschema.baz as enum ('m', 'n');
select x::myschema.baz$0;
"), @r"
hover: type myschema.baz as enum ('m', 'n')
╭▸
3 │ select x::myschema.baz;
╰╴ ─ hover
");
}

#[test]
fn hover_on_drop_function() {
assert_snapshot!(check_hover("
Expand Down
Loading
Loading