Skip to content
Open
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
28 changes: 23 additions & 5 deletions crates/pgls_inlay_hints/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -47,22 +47,39 @@ pub fn inlay_hints(params: InlayHintsParams<'_>) -> Vec<InlayHint> {
collect_references: true,
})
.references;
inlay_hints_of_references(&references, params.sql)
}

/// The inlay hints of the `references` of the statement `sql`, which
/// [`pgls_catalog::resolve::resolve`] collected. Ordered by offset.
pub fn inlay_hints_of_references(references: &[Reference], sql: &str) -> Vec<InlayHint> {
let calls: Vec<_> = references
.into_iter()
.iter()
.filter_map(|reference| match reference {
Reference::Function {
location,
function,
arguments,
..
} => Some((location, function, arguments)),
} => Some((*location, function, arguments)),
_ => None,
})
// Only functions with named parameters get hints, which most built-in functions don't.
.filter(|(_, function, _)| {
function.signature.as_ref().is_some_and(|signature| {
signature.arguments.iter().any(|argument| {
argument
.name
.as_deref()
.is_some_and(|name| !name.is_empty())
})
})
})
.collect();
if calls.is_empty() {
return Vec::new();
}
let Ok(scan) = pgls_query::scan(params.sql) else {
let Ok(scan) = pgls_query::scan(sql) else {
return Vec::new();
};
let tokens: Vec<ScanToken> = scan
Expand Down Expand Up @@ -98,7 +115,7 @@ pub fn inlay_hints(params: InlayHintsParams<'_>) -> Vec<InlayHint> {
else {
continue;
};
if is_reference_to(params.sql, tokens, name) {
if is_reference_to(sql, tokens, name) {
continue;
}
let Ok(offset) = u32::try_from(tokens[0].start) else {
Expand All @@ -118,7 +135,8 @@ pub fn inlay_hints(params: InlayHintsParams<'_>) -> Vec<InlayHint> {
/// The tokens of each argument of the call whose name starts at `location`, without a leading
/// `DISTINCT` or `ALL` of an aggregate.
fn argument_tokens(tokens: &[ScanToken], location: i32) -> Option<Vec<&[ScanToken]>> {
let name = tokens.iter().position(|token| token.start == location)?;
let name = tokens.partition_point(|token| token.start < location);
tokens.get(name).filter(|token| token.start == location)?;
// The name is at most `schema.name`.
let open = name
+ tokens[name..]
Expand Down
12 changes: 8 additions & 4 deletions crates/pgls_semantic_tokens/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -61,13 +61,18 @@ pub fn semantic_tokens(params: SemanticTokensParams<'_>) -> Vec<SemanticToken> {
collect_references: true,
})
.references;
semantic_tokens_of_references(&references, params.sql)
}

/// The semantic tokens of the `references` of the statement `sql`, which
/// [`pgls_catalog::resolve::resolve`] collected. Ordered by their start, and they don't overlap.
pub fn semantic_tokens_of_references(references: &[Reference], sql: &str) -> Vec<SemanticToken> {
let mut tokens = Vec::new();
for reference in &references {
for reference in references {
let Some(span) = reference.span() else {
continue;
};
let Some(text) = params.sql.get(std::ops::Range::<usize>::from(span)) else {
let Some(text) = sql.get(std::ops::Range::<usize>::from(span)) else {
continue;
};
let parts: Vec<TextRange> = name_parts(text)
Expand Down Expand Up @@ -127,8 +132,7 @@ pub fn semantic_tokens(params: SemanticTokensParams<'_>) -> Vec<SemanticToken> {
}
// `table.column`, but not `alias.column`.
[table, _]
if relation
.is_some_and(|(_, name)| identifier(&params.sql[*table]) == *name) =>
if relation.is_some_and(|(_, name)| identifier(&sql[*table]) == *name) =>
{
push(Some(table), SemanticTokenKind::Class, schema);
}
Expand Down
Loading
Loading