From c56e49670ed87ab5fcfb5895f84a8564b865f645 Mon Sep 17 00:00:00 2001 From: Matt Bierner Date: Wed, 12 Oct 2022 10:19:43 -0700 Subject: [PATCH] Reduce event listeners created when rendering explorer items (#163394) Reduce event listeners created when rendering explorer Every time an explorer item is rendered, we currently hook up a `themeService.onDidFileIconThemeChange` listener for it. This ends up creating a lot of extra event listeners even though this even it pretty rarely fired Instead, this PR switches us to have a single listener the re-renders the entire tree. Since this should not be a common event, I believe this is reasonable. Profiling also shows that this cuts both the rendering time and amount of garbage generated --- .../files/browser/views/explorerView.ts | 1 + .../files/browser/views/explorerViewer.ts | 45 +++++++------------ 2 files changed, 18 insertions(+), 28 deletions(-) diff --git a/src/vs/workbench/contrib/files/browser/views/explorerView.ts b/src/vs/workbench/contrib/files/browser/views/explorerView.ts index a36bc07ee12..eb3cb2b6df9 100644 --- a/src/vs/workbench/contrib/files/browser/views/explorerView.ts +++ b/src/vs/workbench/contrib/files/browser/views/explorerView.ts @@ -452,6 +452,7 @@ export class ExplorerView extends ViewPane implements IExplorerView { } }); this._register(this.tree); + this._register(this.themeService.onDidColorThemeChange(() => this.tree.rerender())); // Bind configuration const onDidChangeCompressionConfiguration = Event.filter(this.configurationService.onDidChangeConfiguration, e => e.affectsConfiguration('explorer.compactFolders')); diff --git a/src/vs/workbench/contrib/files/browser/views/explorerViewer.ts b/src/vs/workbench/contrib/files/browser/views/explorerViewer.ts index 1d7d4cf70bd..b652e4e4948 100644 --- a/src/vs/workbench/contrib/files/browser/views/explorerViewer.ts +++ b/src/vs/workbench/contrib/files/browser/views/explorerViewer.ts @@ -384,37 +384,26 @@ export class FilesRenderer implements ICompressibleTreeRenderer { - // Offset nested children unless folders have both chevrons and icons, otherwise alignment breaks - const theme = this.themeService.getFileIconTheme(); + // Offset nested children unless folders have both chevrons and icons, otherwise alignment breaks + const theme = this.themeService.getFileIconTheme(); - // Hack to always render chevrons for file nests, or else may not be able to identify them. - const twistieContainer = (templateData.container.parentElement?.parentElement?.querySelector('.monaco-tl-twistie') as HTMLElement); - if (twistieContainer) { - if (stat.hasNests && theme.hidesExplorerArrows) { - twistieContainer.classList.add('force-twistie'); - } else { - twistieContainer.classList.remove('force-twistie'); - } - } + // Hack to always render chevrons for file nests, or else may not be able to identify them. + const twistieContainer = templateData.container.parentElement?.parentElement?.querySelector('.monaco-tl-twistie'); + twistieContainer?.classList.toggle('force-twistie', stat.hasNests && theme.hidesExplorerArrows); - // when explorer arrows are hidden or there are no folder icons, nests get misaligned as they are forced to have arrows and files typically have icons - // Apply some CSS magic to get things looking as reasonable as possible. - const themeIsUnhappyWithNesting = theme.hasFileIcons && (theme.hidesExplorerArrows || !theme.hasFolderIcons); - const realignNestedChildren = stat.nestedParent && themeIsUnhappyWithNesting; + // when explorer arrows are hidden or there are no folder icons, nests get misaligned as they are forced to have arrows and files typically have icons + // Apply some CSS magic to get things looking as reasonable as possible. + const themeIsUnhappyWithNesting = theme.hasFileIcons && (theme.hidesExplorerArrows || !theme.hasFolderIcons); + const realignNestedChildren = stat.nestedParent && themeIsUnhappyWithNesting; - templateData.label.setResource({ resource: stat.resource, name: label }, { - fileKind: stat.isRoot ? FileKind.ROOT_FOLDER : stat.isDirectory ? FileKind.FOLDER : FileKind.FILE, - extraClasses: realignNestedChildren ? [...extraClasses, 'align-nest-icon-with-parent-icon'] : extraClasses, - fileDecorations: this.config.explorer.decorations, - matches: createMatches(filterData), - separator: this.labelService.getSeparator(stat.resource.scheme, stat.resource.authority), - domId - }); - }; - - templateData.elementDisposables.add(this.themeService.onDidFileIconThemeChange(() => setResourceData())); - setResourceData(); + templateData.label.setResource({ resource: stat.resource, name: label }, { + fileKind: stat.isRoot ? FileKind.ROOT_FOLDER : stat.isDirectory ? FileKind.FOLDER : FileKind.FILE, + extraClasses: realignNestedChildren ? [...extraClasses, 'align-nest-icon-with-parent-icon'] : extraClasses, + fileDecorations: this.config.explorer.decorations, + matches: createMatches(filterData), + separator: this.labelService.getSeparator(stat.resource.scheme, stat.resource.authority), + domId + }); templateData.elementDisposables.add(templateData.label.onDidRender(() => { try {