Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
50 commits
Select commit Hold shift + click to select a range
5707bb8
pickin up fast
juleswritescode Nov 7, 2025
8b96f00
so far
juleswritescode Nov 8, 2025
799f52d
changie
juleswritescode Nov 8, 2025
f8ca407
readied
juleswritescode Nov 8, 2025
6365f80
more removed
juleswritescode Nov 8, 2025
4324377
minor changes
juleswritescode Nov 8, 2025
9586d8c
Update crates/pgls_completions/src/relevance/filtering.rs
juleswritescode Nov 8, 2025
c3201e7
use indoc, add setup
juleswritescode Nov 9, 2025
cbbe1f2
Merge branch 'feat/completions-test-suite' of https://github.com/supa…
juleswritescode Nov 9, 2025
09664c1
ok
juleswritescode Nov 9, 2025
853929c
many fixings
juleswritescode Nov 22, 2025
ad45958
Merge branch 'main' of https://github.com/supabase-community/postgres…
juleswritescode Nov 22, 2025
0a9be8a
remove all commata?
juleswritescode Nov 22, 2025
6fabed2
use current version of bun
juleswritescode Nov 22, 2025
cdb4355
Merge branch 'feat/completions-test-suite' of https://github.com/supa…
juleswritescode Nov 22, 2025
c0e2d35
fixed aaaaaaaaaaaaaaat
juleswritescode Nov 22, 2025
324c4f5
commit
juleswritescode Nov 22, 2025
9c07d91
accept snaps
juleswritescode Nov 22, 2025
359a8ff
ok?
juleswritescode Nov 22, 2025
195c706
do not prefer public schema
juleswritescode Nov 22, 2025
9f8435f
more adjustments
juleswritescode Nov 22, 2025
61b02ff
snaps
juleswritescode Nov 22, 2025
0dc7f2b
ok
juleswritescode Nov 22, 2025
46c2596
slight improvement
juleswritescode Nov 22, 2025
faf3793
intermediary
juleswritescode Nov 29, 2025
f55386a
merged
juleswritescode Dec 12, 2025
4cf53b4
many changes
juleswritescode Dec 12, 2025
cf0c98d
this is gret
juleswritescode Dec 12, 2025
21217b5
commitered
juleswritescode Dec 13, 2025
0accdf2
many cheeeenges
juleswritescode Dec 13, 2025
f8daaf3
fix: rest of tests
juleswritescode Dec 13, 2025
7ce97c6
removed many stuffs
juleswritescode Dec 13, 2025
9e29117
squieliex
juleswritescode Dec 13, 2025
2f97f7f
readied
juleswritescode Dec 13, 2025
db53efd
Merge branch 'main' of https://github.com/supabase-community/postgres…
juleswritescode Dec 13, 2025
d4e8b48
only install if no cache
juleswritescode Dec 13, 2025
71969bb
rename test bin?
juleswritescode Dec 13, 2025
c484d0b
that one, too
juleswritescode Dec 13, 2025
a6cbde6
aha!
juleswritescode Dec 13, 2025
78cecce
remove depr tests
juleswritescode Dec 13, 2025
0068c2a
disable-db
juleswritescode Dec 13, 2025
87925f2
clean
juleswritescode Dec 13, 2025
c4e5747
ack
juleswritescode Dec 13, 2025
de5732d
remove error child node handling
juleswritescode Dec 14, 2025
d2a22bc
so far
juleswritescode Dec 14, 2025
4f5aa16
fixed eeeeitttt
juleswritescode Dec 14, 2025
7943dc4
ok
juleswritescode Dec 14, 2025
64e9158
cleanup
juleswritescode Dec 14, 2025
95edaf0
remove unused
juleswritescode Dec 14, 2025
a6e0efe
Merge branch 'main' into fix/remove-error-nodes
juleswritescode Dec 15, 2025
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
1 change: 1 addition & 0 deletions crates/pgls_completions/src/providers/columns.rs
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ fn get_completion_text(ctx: &TreesitterContext, col: &Column) -> CompletionText

#[cfg(test)]
mod tests {

use sqlx::PgPool;

use crate::test_helper::{TestCompletionsCase, TestCompletionsSuite};
Expand Down
210 changes: 4 additions & 206 deletions crates/pgls_treesitter/src/context/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -302,32 +302,11 @@ impl<'a> TreesitterContext<'a> {
return;
}

match parent_node_kind {
match current_node_kind {
"statement" | "subquery" => {
self.wrapping_clause_type =
self.get_wrapping_clause_from_current_node(current_node, &mut cursor);

self.wrapping_statement_range = Some(parent_node.range());
}
"invocation" => self.is_invocation = true,
_ => {}
}

// try to gather context from the siblings if we're within an error node.
if parent_node_kind == "ERROR" {
if let Some(clause_type) = self.get_wrapping_clause_from_error_node_child(current_node)
{
self.wrapping_clause_type = Some(clause_type);
}
if let Some(wrapping_node) = self.get_wrapping_node_from_error_node_child(current_node)
{
self.wrapping_node_kind = Some(wrapping_node)
self.wrapping_statement_range = Some(current_node.range());
}

self.get_info_from_error_node_child(current_node);
}

match current_node_kind {
"object_reference" | "column_reference" => {
if let Some((head, middle, _)) = parts_of_reference_query(current_node, self.text) {
self.identifier_qualifiers = (
Expand Down Expand Up @@ -361,6 +340,8 @@ impl<'a> TreesitterContext<'a> {
self.wrapping_node_kind = Some(WrappingNode::List);
}

"invocation" => self.is_invocation = true,

_ => {
if let Some(clause_type) =
self.get_wrapping_clause_from_current_node(current_node, &mut cursor)
Expand All @@ -382,189 +363,6 @@ impl<'a> TreesitterContext<'a> {
self.gather_context_from_node(cursor, current_node);
}

fn get_first_sibling(&self, node: tree_sitter::Node<'a>) -> tree_sitter::Node<'a> {
let mut first_sibling = node;
while let Some(n) = first_sibling.prev_sibling() {
first_sibling = n;
}
first_sibling
}

fn get_wrapping_node_from_error_node_child(
&self,
node: tree_sitter::Node<'a>,
) -> Option<WrappingNode> {
self.wrapping_clause_type
.as_ref()
.and_then(|clause| match clause {
WrappingClause::Insert => {
let mut first_sib = self.get_first_sibling(node);

let mut after_opening_bracket = false;
let mut before_closing_bracket = false;

while let Some(next_sib) = first_sib.next_sibling() {
if next_sib.kind() == "("
&& next_sib.end_position() <= node.start_position()
{
after_opening_bracket = true;
}

if next_sib.kind() == ")"
&& next_sib.start_position() >= node.end_position()
{
before_closing_bracket = true;
}

first_sib = next_sib;
}

if after_opening_bracket && before_closing_bracket {
Some(WrappingNode::List)
} else {
None
}
}
_ => None,
})
}

fn get_wrapping_clause_from_error_node_child(
&self,
node: tree_sitter::Node<'a>,
) -> Option<WrappingClause<'a>> {
let clause_combinations: Vec<(WrappingClause, &[&'static str])> = vec![
(WrappingClause::Where, &["where"]),
(WrappingClause::Update, &["update"]),
(WrappingClause::Select, &["select"]),
(WrappingClause::Delete, &["delete"]),
(WrappingClause::Insert, &["insert", "into"]),
(WrappingClause::From, &["from"]),
(WrappingClause::Join { on_node: None }, &["join"]),
(WrappingClause::AlterTable, &["alter", "table"]),
(WrappingClause::AlterColumn, &["alter", "table", "alter"]),
(WrappingClause::RenameColumn, &["alter", "table", "rename"]),
(
WrappingClause::AlterTable,
&["alter", "table", "if", "exists"],
),
(WrappingClause::DropTable, &["drop", "table"]),
(
WrappingClause::DropTable,
&["drop", "table", "if", "exists"],
),
];

let first_sibling = self.get_first_sibling(node);

/*
* For each clause, we'll iterate from first_sibling to the next ones,
* either until the end or until we land on the node under the cursor.
* We'll score the `WrappingClause` by how many tokens it matches in order.
*/
let mut clauses_with_score: Vec<(WrappingClause, usize)> = clause_combinations
.into_iter()
.map(|(clause, tokens)| {
let mut idx = 0;

let mut sibling = Some(first_sibling);
while let Some(sib) = sibling {
if sib.end_byte() >= node.end_byte() || idx >= tokens.len() {
break;
}

if let Some(sibling_content) = self.get_ts_node_content(&sib) {
if sibling_content == tokens[idx] {
idx += 1;
}
} else {
break;
}

sibling = sib.next_sibling();
}

(clause, idx)
})
.collect();

clauses_with_score.sort_by(|(_, score_a), (_, score_b)| score_b.cmp(score_a));
clauses_with_score
.iter()
.find(|(_, score)| *score > 0)
.map(|c| c.0.clone())
}

fn get_info_from_error_node_child(&mut self, node: tree_sitter::Node<'a>) {
let mut first_sibling = self.get_first_sibling(node);

if let Some(clause) = self.wrapping_clause_type.as_ref() {
match *clause {
WrappingClause::Insert => {
while let Some(sib) = first_sibling.next_sibling() {
match sib.kind() {
"object_reference" => {
if let Some(txt) = self.get_ts_node_content(&sib) {
let mut iter = txt.split('.').rev();
let table = iter.next().unwrap().to_string();
let schema = iter.next().map(|s| s.to_string());
self.mentioned_relations
.entry(schema)
.and_modify(|s| {
s.insert(table.clone());
})
.or_insert(HashSet::from([table]));
}
}

"column" => {
if let Some(txt) = self.get_ts_node_content(&sib) {
let entry = MentionedColumn {
column: txt,
alias: None,
};

self.mentioned_columns
.entry(Some(WrappingClause::Insert))
.and_modify(|s| {
s.insert(entry.clone());
})
.or_insert(HashSet::from([entry]));
}
}

_ => {}
}

first_sibling = sib;
}
}

WrappingClause::AlterColumn => {
while let Some(sib) = first_sibling.next_sibling() {
if sib.kind() == "object_reference" {
if let Some(txt) = self.get_ts_node_content(&sib) {
let mut iter = txt.split('.').rev();
let table = iter.next().unwrap().to_string();
let schema = iter.next().map(|s| s.to_string());
self.mentioned_relations
.entry(schema)
.and_modify(|s| {
s.insert(table.clone());
})
.or_insert(HashSet::from([table]));
}
}

first_sibling = sib;
}
}

_ => {}
}
}
}

fn get_wrapping_clause_from_current_node(
&self,
node: tree_sitter::Node<'a>,
Expand Down
Loading