From c3a565ad92b5476faf45f712893151ad764422e6 Mon Sep 17 00:00:00 2001 From: Neeraj Singh Date: Mon, 10 Aug 2026 01:28:34 +0530 Subject: [PATCH] Fix: Auto-scroll to matching items when expanding tree nodes during search - Added search term tracking to ObjectBrowser class - Implemented onDidExpandElement handler to detect node expansion - Added reveal() call for first matching child with 50ms delay for DOM rendering - Added 'Set Object Browser Search Term' command as workaround for VS Code API limitation Fixes the issue where tree search highlights matches but doesn't scroll to them when expanding collapsed nodes (libraries/source files). --- src/ui/views/objectBrowser.ts | 84 +++++++++++++++++++++++++++++++++++ 1 file changed, 84 insertions(+) diff --git a/src/ui/views/objectBrowser.ts b/src/ui/views/objectBrowser.ts index 108707a88..d52b8f8f2 100644 --- a/src/ui/views/objectBrowser.ts +++ b/src/ui/views/objectBrowser.ts @@ -73,6 +73,9 @@ abstract class ObjectBrowserItem extends BrowserItem { class ObjectBrowser implements vscode.TreeDataProvider { private readonly emitter = new vscode.EventEmitter(); readonly onDidChangeTreeData = this.emitter.event; + + // Track active tree search term for auto-scroll on expansion + private currentSearchTerm: string = ''; async moveFilterInList(node: ObjectBrowserItem, filterMovement: `TOP` | `UP` | `DOWN` | `BOTTOM`) { const config = getConfig(); @@ -156,6 +159,22 @@ class ObjectBrowser implements vscode.TreeDataProvider { return element; } + + /** + * Update the current search term for auto-scroll on expansion + * @param term The active search term (empty string if no search is active) + */ + updateSearchTerm(term: string) { + this.currentSearchTerm = term; + } + + /** + * Get the current search term + * @returns The active search term or empty string + */ + getCurrentSearchTerm(): string { + return this.currentSearchTerm; + } } class CreateFilterItem extends BrowserItem { @@ -567,6 +586,51 @@ export function initializeObjectBrowser(context: vscode.ExtensionContext) { dragAndDropController: new ObjectBrowserMemberItemDragAndDrop() }); + // Handle tree expansion during active search - auto-scroll to first matching child + objectTreeViewer.onDidExpandElement(async (event) => { + const searchTerm = objectBrowser.getCurrentSearchTerm(); + + // Only proceed if there's an active search term + if (!searchTerm || searchTerm.trim() === '') { + return; + } + + // Check if the expanded element is a source physical file or library + if (event.element instanceof ObjectBrowserSourcePhysicalFileItem || + event.element instanceof ObjectBrowserObjectItem) { + + try { + // Get children of the expanded node + const children = await event.element.getChildren(); + + if (!children || children.length === 0) { + return; + } + + // Find the first child that matches the search term (case-insensitive substring match) + const searchLower = searchTerm.toLowerCase(); + const firstMatch = children.find(child => { + const label = child.label?.toString() || ''; + return label.toLowerCase().includes(searchLower); + }); + + // If a match is found, reveal it to bring it into view + if (firstMatch) { + // Defer reveal() to allow DOM rendering to complete + setTimeout(() => { + objectTreeViewer.reveal(firstMatch, { + select: false, // Don't change selection + focus: false // Don't steal focus + }); + }, 50); + } + } catch (error) { + // Silently handle errors to avoid disrupting tree expansion + console.error('Error in tree expansion search handler:', error); + } + } + }); + const getSelectedItems = (node?: T | T[]) => node ? Array.isArray(node) ? node : [node] : objectTreeViewer.selection as T[]; context.subscriptions.push( @@ -1532,6 +1596,26 @@ Do you want to replace it?`, item.name), { modal: true }, skipAllLabel, overwrit vscode.commands.executeCommand('objectBrowser.focus'); vscode.commands.executeCommand('list.find'); }), + + // Command to manually set search term for auto-scroll (workaround for VS Code API limitation) + vscode.commands.registerCommand(`code-for-ibmi.setObjectBrowserSearchTerm`, async () => { + const searchTerm = await vscode.window.showInputBox({ + prompt: vscode.l10n.t(`Enter the search term you're using in the Object Browser (for auto-scroll on expansion)`), + placeHolder: vscode.l10n.t(`Search term...`), + value: objectBrowser.getCurrentSearchTerm() + }); + + if (searchTerm !== undefined) { + objectBrowser.updateSearchTerm(searchTerm); + if (searchTerm) { + vscode.window.showInformationMessage( + vscode.l10n.t(`Search term set to "{0}". Tree will auto-scroll to matches when expanding nodes.`, searchTerm) + ); + } else { + vscode.window.showInformationMessage(vscode.l10n.t(`Search term cleared.`)); + } + } + }), vscode.commands.registerCommand(`code-for-ibmi.renameQSYS`, async (node?: (ObjectBrowserMemberItem | ObjectBrowserObjectItem)) => { node = getSelectedItems(node).at(0); if (node instanceof ObjectBrowserObjectItem || node instanceof ObjectBrowserSourcePhysicalFileItem) {