feat: Enhance symbol search with co-location boosting and receiver type support

Improves search accuracy by boosting results when multiple query symbols appear in the same file, addressing cases where common names like "run" return too many results. Adds Go method receiver type extraction to qualified names for better searchability (e.g., "scrapeLoop.run"). Optimizes database queries with two-pass approach to handle distinctive vs common symbol names efficiently.
This commit is contained in:
Colby McHenry
2026-04-06 11:16:56 -05:00
parent d256af3a23
commit 7a3afc9124
16 changed files with 466 additions and 877 deletions
+12
View File
@@ -27,4 +27,16 @@ export const goExtractor: LanguageExtractor = {
}
return sig;
},
getReceiverType: (node, source) => {
// Go method_declaration has a "receiver" field: func (sl *scrapeLoop) run(...)
// The receiver is a parameter_list containing a parameter_declaration
// with a type that may be a pointer_type (*scrapeLoop) or plain type (scrapeLoop)
const receiver = getChildByField(node, 'receiver');
if (!receiver) return undefined;
// Find the type identifier inside the receiver
const text = getNodeText(receiver, source);
// Extract type name from patterns like "(sl *Type)", "(sl Type)", "(*Type)", "(Type)"
const match = text.match(/\*?\s*([A-Za-z_][A-Za-z0-9_]*)\s*\)/);
return match?.[1];
},
};
+7
View File
@@ -163,4 +163,11 @@ export interface LanguageExtractor {
* Returns info about each declared variable, allowing the core to create nodes.
*/
extractVariables?: (node: SyntaxNode, source: string) => VariableInfo[];
/**
* Extract receiver/owner type name from a method declaration.
* Used by Go to get the struct receiver (e.g., "scrapeLoop" from "func (sl *scrapeLoop) run()").
* When present, the receiver type is included in the qualified name for better searchability.
*/
getReceiverType?: (node: SyntaxNode, source: string) => string | undefined;
}
+10 -2
View File
@@ -505,13 +505,21 @@ export class TreeSitterExtractor {
const isAsync = this.extractor.isAsync?.(node);
const isStatic = this.extractor.isStatic?.(node);
const methodNode = this.createNode('method', name, node, {
// For languages with receiver types (Go), include receiver in qualified name
// so FTS can match "scrapeLoop.run" → qualified_name "...::scrapeLoop::run"
const receiverType = this.extractor.getReceiverType?.(node, this.source);
const extraProps: Partial<Node> = {
docstring,
signature,
visibility,
isAsync,
isStatic,
});
};
if (receiverType) {
extraProps.qualifiedName = `${this.filePath}::${receiverType}::${name}`;
}
const methodNode = this.createNode('method', name, node, extraProps);
if (!methodNode) return;
// Extract type annotations (parameter types and return type)