Skip to content

Commit 05e039b

Browse files
Moved this tool into it's own file
1 parent 39f4b11 commit 05e039b

File tree

3 files changed

+783
-459
lines changed

3 files changed

+783
-459
lines changed

src/core/Cline.ts

Lines changed: 5 additions & 246 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ import { parseSourceCodeForDefinitionsTopLevel } from "../services/tree-sitter"
3737
import { CheckpointStorage } from "../shared/checkpoints"
3838
import { ApiConfiguration } from "../shared/api"
3939
import { findLastIndex } from "../shared/array"
40+
import { getSymbolDocumentation as getSymbolDocumentationUtil } from "./tools/getSymbolDocumentation"
4041
import { combineApiRequests } from "../shared/combineApiRequests"
4142
import { combineCommandSequences } from "../shared/combineCommandSequences"
4243
import {
@@ -3553,254 +3554,12 @@ export class Cline extends EventEmitter<ClineEvents> {
35533554
/**
35543555
* Gets documentation for a symbol by name, optionally scoped to a specific file.
35553556
* Uses VS Code's language services to find symbol definitions and hover information.
3557+
*
3558+
* Implementation is delegated to the standalone utility function for better testability
3559+
* and separation of concerns.
35563560
*/
35573561
async getSymbolDocumentation(symbolName: string, filePath?: string): Promise<string> {
3558-
// Show output channel
3559-
try {
3560-
console.log(`[DEBUG] getSymbolDocumentation: ${symbolName}, ${filePath}`)
3561-
// STEP 1: If file path is provided, try to find the symbol in that file first
3562-
if (filePath) {
3563-
const uri = vscode.Uri.file(path.resolve(cwd, filePath))
3564-
3565-
try {
3566-
// Try to open the document
3567-
const document = await vscode.workspace.openTextDocument(uri)
3568-
3569-
// STEP 1a: Check if symbol is defined in the document
3570-
const documentSymbols = await vscode.commands.executeCommand<vscode.DocumentSymbol[]>(
3571-
"vscode.executeDocumentSymbolProvider",
3572-
uri,
3573-
)
3574-
3575-
// Helper function to search recursively through DocumentSymbol hierarchy
3576-
const findSymbolInHierarchy = (
3577-
symbols?: vscode.DocumentSymbol[],
3578-
): vscode.DocumentSymbol | undefined => {
3579-
if (!symbols) return undefined
3580-
3581-
for (const symbol of symbols) {
3582-
if (symbol.name === symbolName) {
3583-
return symbol
3584-
}
3585-
3586-
const found = findSymbolInHierarchy(symbol.children)
3587-
if (found) return found
3588-
}
3589-
3590-
return undefined
3591-
}
3592-
3593-
// Look for the symbol in document symbols
3594-
const foundSymbol = findSymbolInHierarchy(documentSymbols)
3595-
3596-
if (foundSymbol) {
3597-
// Found the symbol definition in document
3598-
const hoverResults = await vscode.commands.executeCommand<vscode.Hover[]>(
3599-
"vscode.executeHoverProvider",
3600-
uri,
3601-
foundSymbol.selectionRange.start,
3602-
)
3603-
3604-
let hoverText = ""
3605-
if (hoverResults && hoverResults.length > 0) {
3606-
// Extract the text from hover results
3607-
for (const content of hoverResults[0].contents) {
3608-
if (typeof content === "string") {
3609-
hoverText += content + "\n"
3610-
} else {
3611-
// MarkdownString
3612-
hoverText += content.value + "\n"
3613-
}
3614-
}
3615-
}
3616-
3617-
return `Symbol: ${symbolName}
3618-
Location: ${uri.fsPath}:${foundSymbol.selectionRange.start.line + 1}:${foundSymbol.selectionRange.start.character + 1}
3619-
Kind: ${vscode.SymbolKind[foundSymbol.kind]}
3620-
Status: Defined in file
3621-
3622-
Documentation:
3623-
${hoverText || "No documentation available for this symbol."}`
3624-
}
3625-
3626-
// STEP 1b: If not defined in document, search for references to the symbol
3627-
// Find all occurrences of the symbol in text
3628-
const text = document.getText()
3629-
const occurrences: vscode.Position[] = []
3630-
const regex = new RegExp(`\\b${symbolName}\\b`, "g")
3631-
3632-
console.log(`[DEBUG] Searching for symbol: ${symbolName}`)
3633-
3634-
let match
3635-
while ((match = regex.exec(text)) !== null) {
3636-
const pos = document.positionAt(match.index)
3637-
occurrences.push(pos)
3638-
}
3639-
3640-
console.log(`[DEBUG] Found ${occurrences.length} occurrences in ${filePath}`)
3641-
3642-
// Try each occurrence to see if we can get hover or definition info
3643-
for (const position of occurrences) {
3644-
// Skip occurrences in import statements
3645-
const line = document.lineAt(position.line).text
3646-
const lineText = document.lineAt(position.line).text
3647-
console.log(`[DEBUG] Checking occurrence at line ${position.line + 1}: ${lineText}`)
3648-
3649-
// if (/^\s*(import|from|require|use|include|using)/.test(line)) {
3650-
// continue
3651-
// }
3652-
3653-
// Try hover first
3654-
const hoverResults = await vscode.commands.executeCommand<vscode.Hover[]>(
3655-
"vscode.executeHoverProvider",
3656-
uri,
3657-
position,
3658-
)
3659-
3660-
console.log(`[DEBUG] hover results: ${hoverResults?.length}`)
3661-
3662-
if (hoverResults && hoverResults.length > 0) {
3663-
// Extract the text from hover results
3664-
let hoverText = ""
3665-
for (const content of hoverResults[0].contents) {
3666-
if (typeof content === "string") {
3667-
hoverText += content + "\n"
3668-
} else {
3669-
// MarkdownString
3670-
hoverText += content.value + "\n"
3671-
}
3672-
}
3673-
3674-
if (hoverText.trim()) {
3675-
// Try to get definition as well
3676-
const definitions = await vscode.commands.executeCommand<vscode.Location[]>(
3677-
"vscode.executeDefinitionProvider",
3678-
uri,
3679-
position,
3680-
)
3681-
3682-
console.log(`[DEBUG] definition results length: ${definitions?.length}`)
3683-
3684-
let defLocationStr = `${uri.fsPath}:${position.line + 1}:${position.character + 1}`
3685-
let definedInFile = "Referenced in file"
3686-
3687-
if (definitions && definitions.length > 0) {
3688-
const def = definitions[0]
3689-
defLocationStr = `${def.uri.fsPath}:${def.range.start.line + 1}:${def.range.start.character + 1}`
3690-
definedInFile = "Imported/Referenced"
3691-
}
3692-
3693-
return `Symbol: ${symbolName}
3694-
Location: ${defLocationStr}
3695-
Status: ${definedInFile}
3696-
Referenced in: ${filePath}
3697-
3698-
Documentation:
3699-
${hoverText.trim()}`
3700-
}
3701-
}
3702-
3703-
// If hover didn't work, try getting the definition directly
3704-
const definitions = await vscode.commands.executeCommand<vscode.Location[]>(
3705-
"vscode.executeDefinitionProvider",
3706-
uri,
3707-
position,
3708-
)
3709-
3710-
if (definitions && definitions.length > 0) {
3711-
const def = definitions[0]
3712-
const defHoverResults = await vscode.commands.executeCommand<vscode.Hover[]>(
3713-
"vscode.executeHoverProvider",
3714-
def.uri,
3715-
def.range.start,
3716-
)
3717-
3718-
if (defHoverResults && defHoverResults.length > 0) {
3719-
// Extract the text from hover results
3720-
let hoverText = ""
3721-
for (const content of defHoverResults[0].contents) {
3722-
if (typeof content === "string") {
3723-
hoverText += content + "\n"
3724-
} else {
3725-
// MarkdownString
3726-
hoverText += content.value + "\n"
3727-
}
3728-
}
3729-
3730-
if (hoverText.trim()) {
3731-
return `Symbol: ${symbolName}
3732-
Location: ${def.uri.fsPath}:${def.range.start.line + 1}:${def.range.start.character + 1}
3733-
Status: Imported/Referenced
3734-
Referenced in: ${filePath}
3735-
3736-
Documentation:
3737-
${hoverText.trim()}`
3738-
}
3739-
}
3740-
3741-
// We found a definition but no hover info
3742-
return `Symbol: ${symbolName}
3743-
Location: ${def.uri.fsPath}:${def.range.start.line + 1}:${def.range.start.character + 1}
3744-
Status: Imported/Referenced
3745-
Referenced in: ${filePath}
3746-
3747-
No documentation is available for this symbol.`
3748-
}
3749-
}
3750-
3751-
// Couldn't find the symbol in the file
3752-
return `No symbol '${symbolName}' found in file '${filePath}'.`
3753-
} catch (error) {
3754-
return `Error: Could not analyze file '${filePath}': ${error.message}`
3755-
}
3756-
}
3757-
3758-
// STEP 2: If no file path or symbol not found in specified file, try workspace symbols
3759-
const workspaceSymbols = await vscode.commands.executeCommand<vscode.SymbolInformation[]>(
3760-
"vscode.executeWorkspaceSymbolProvider",
3761-
symbolName,
3762-
)
3763-
3764-
if (workspaceSymbols && workspaceSymbols.length > 0) {
3765-
// Found at least one matching symbol in workspace
3766-
const symbol = workspaceSymbols[0]
3767-
const uri = symbol.location.uri
3768-
const position = symbol.location.range.start
3769-
3770-
const hoverResults = await vscode.commands.executeCommand<vscode.Hover[]>(
3771-
"vscode.executeHoverProvider",
3772-
uri,
3773-
position,
3774-
)
3775-
3776-
let hoverText = ""
3777-
if (hoverResults && hoverResults.length > 0) {
3778-
// Extract the text from hover results
3779-
for (const content of hoverResults[0].contents) {
3780-
if (typeof content === "string") {
3781-
hoverText += content + "\n"
3782-
} else {
3783-
// MarkdownString
3784-
hoverText += content.value + "\n"
3785-
}
3786-
}
3787-
}
3788-
3789-
return `Symbol: ${symbolName}
3790-
Location: ${uri.fsPath}:${position.line + 1}:${position.character + 1}
3791-
Kind: ${vscode.SymbolKind[symbol.kind]}
3792-
Container: ${symbol.containerName || "Global Scope"}
3793-
${filePath ? `Not directly referenced in: ${filePath}` : ""}
3794-
3795-
Documentation:
3796-
${hoverText.trim() || "No documentation available for this symbol."}`
3797-
}
3798-
3799-
// STEP 3: No results found
3800-
return `No symbol found for '${symbolName}'${filePath ? ` in or referenced by file '${filePath}'` : ""}.`
3801-
} catch (error) {
3802-
return `Error retrieving documentation for symbol '${symbolName}': ${error.message}`
3803-
}
3562+
return getSymbolDocumentationUtil(symbolName, filePath, cwd)
38043563
}
38053564

38063565
async getEnvironmentDetails(includeFileDetails: boolean = false) {

0 commit comments

Comments
 (0)