Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Re-use disposable store while rendering scm lists #163479

Merged
merged 2 commits into from Oct 23, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
22 changes: 8 additions & 14 deletions src/vs/workbench/contrib/scm/browser/scmRepositoryRenderer.ts
Expand Up @@ -4,7 +4,7 @@
*--------------------------------------------------------------------------------------------*/

import 'vs/css!./media/scm';
import { IDisposable, Disposable, DisposableStore, combinedDisposable, toDisposable } from 'vs/base/common/lifecycle';
import { IDisposable, DisposableStore, combinedDisposable, toDisposable } from 'vs/base/common/lifecycle';
import { append, $ } from 'vs/base/browser/dom';
import { ISCMRepository, ISCMViewService } from 'vs/workbench/contrib/scm/common/scm';
import { CountBadge } from 'vs/base/browser/ui/countBadge/countBadge';
Expand All @@ -30,7 +30,7 @@ interface RepositoryTemplate {
readonly countContainer: HTMLElement;
readonly count: CountBadge;
readonly toolBar: ToolBar;
disposable: IDisposable;
readonly elementDisposables: DisposableStore;
readonly templateDisposable: IDisposable;
}

Expand Down Expand Up @@ -65,16 +65,12 @@ export class RepositoryRenderer implements ICompressibleTreeRenderer<ISCMReposit
const badgeStyler = attachBadgeStyler(count, this.themeService);
const visibilityDisposable = toolBar.onDidChangeDropdownVisibility(e => provider.classList.toggle('active', e));

const disposable = Disposable.None;
const templateDisposable = combinedDisposable(visibilityDisposable, toolBar, badgeStyler);

return { label, name, description, countContainer, count, toolBar, disposable, templateDisposable };
return { label, name, description, countContainer, count, toolBar, elementDisposables: new DisposableStore(), templateDisposable };
}

renderElement(arg: ISCMRepository | ITreeNode<ISCMRepository, FuzzyScore>, index: number, templateData: RepositoryTemplate, height: number | undefined): void {
templateData.disposable.dispose();

const disposables = new DisposableStore();
const repository = isSCMRepository(arg) ? arg : arg.element;

if (repository.provider.rootUri) {
Expand Down Expand Up @@ -113,8 +109,8 @@ export class RepositoryRenderer implements ICompressibleTreeRenderer<ISCMReposit

// TODO@joao TODO@lszomoru
let disposed = false;
disposables.add(toDisposable(() => disposed = true));
disposables.add(repository.provider.onDidChange(() => {
templateData.elementDisposables.add(toDisposable(() => disposed = true));
templateData.elementDisposables.add(repository.provider.onDidChange(() => {
if (disposed) {
return;
}
Expand All @@ -125,26 +121,24 @@ export class RepositoryRenderer implements ICompressibleTreeRenderer<ISCMReposit
onDidChangeProvider();

const menus = this.scmViewService.menus.getRepositoryMenus(repository.provider);
disposables.add(connectPrimaryMenu(menus.titleMenu.menu, (primary, secondary) => {
templateData.elementDisposables.add(connectPrimaryMenu(menus.titleMenu.menu, (primary, secondary) => {
menuPrimaryActions = primary;
menuSecondaryActions = secondary;
updateToolbar();
}));
templateData.toolBar.context = repository.provider;

templateData.disposable = disposables;
}

renderCompressedElements(): void {
throw new Error('Should never happen since node is incompressible');
}

disposeElement(group: ISCMRepository | ITreeNode<ISCMRepository, FuzzyScore>, index: number, template: RepositoryTemplate): void {
template.disposable.dispose();
template.elementDisposables.clear();
}

disposeTemplate(templateData: RepositoryTemplate): void {
templateData.disposable.dispose();
templateData.elementDisposables.dispose();
templateData.templateDisposable.dispose();
}
}
68 changes: 24 additions & 44 deletions src/vs/workbench/contrib/scm/browser/scmViewPane.ts
Expand Up @@ -165,7 +165,7 @@ class ActionButtonRenderer implements ICompressibleTreeRenderer<ISCMActionButton

interface InputTemplate {
readonly inputWidget: SCMInputWidget;
disposable: IDisposable;
readonly elementDisposables: DisposableStore;
readonly templateDisposable: IDisposable;
}

Expand Down Expand Up @@ -194,24 +194,21 @@ class InputRenderer implements ICompressibleTreeRenderer<ISCMInput, FuzzyScore,
// Disable hover for list item
container.parentElement!.parentElement!.classList.add('force-no-hover');

const disposables = new DisposableStore();
const templateDisposable = new DisposableStore();
const inputElement = append(container, $('.scm-input'));
const inputWidget = this.instantiationService.createInstance(SCMInputWidget, inputElement, this.overflowWidgetsDomNode);
disposables.add(inputWidget);
templateDisposable.add(inputWidget);

return { inputWidget, disposable: Disposable.None, templateDisposable: disposables };
return { inputWidget, elementDisposables: templateDisposable.add(new DisposableStore()), templateDisposable };
}

renderElement(node: ITreeNode<ISCMInput, FuzzyScore>, index: number, templateData: InputTemplate): void {
templateData.disposable.dispose();

const disposables = new DisposableStore();
const input = node.element;
templateData.inputWidget.input = input;

// Remember widget
this.inputWidgets.set(input, templateData.inputWidget);
disposables.add({ dispose: () => this.inputWidgets.delete(input) });
templateData.elementDisposables.add({ dispose: () => this.inputWidgets.delete(input) });

// Widget cursor selections
const selections = this.editorSelections.get(input);
Expand All @@ -220,7 +217,7 @@ class InputRenderer implements ICompressibleTreeRenderer<ISCMInput, FuzzyScore,
templateData.inputWidget.selections = selections;
}

disposables.add(toDisposable(() => {
templateData.elementDisposables.add(toDisposable(() => {
const selections = templateData.inputWidget.selections;

if (selections) {
Expand All @@ -241,32 +238,29 @@ class InputRenderer implements ICompressibleTreeRenderer<ISCMInput, FuzzyScore,
};

const startListeningContentHeightChange = () => {
disposables.add(templateData.inputWidget.onDidChangeContentHeight(onDidChangeContentHeight));
templateData.elementDisposables.add(templateData.inputWidget.onDidChangeContentHeight(onDidChangeContentHeight));
onDidChangeContentHeight();
};

// Setup height change listener on next tick
const timeout = disposableTimeout(startListeningContentHeightChange, 0);
disposables.add(timeout);
templateData.elementDisposables.add(timeout);

// Layout the editor whenever the outer layout happens
const layoutEditor = () => templateData.inputWidget.layout();
disposables.add(this.outerLayout.onDidChange(layoutEditor));
templateData.elementDisposables.add(this.outerLayout.onDidChange(layoutEditor));
layoutEditor();

templateData.disposable = disposables;
}

renderCompressedElements(): void {
throw new Error('Should never happen since node is incompressible');
}

disposeElement(group: ITreeNode<ISCMInput, FuzzyScore>, index: number, template: InputTemplate): void {
template.disposable.dispose();
template.elementDisposables.clear();
}

disposeTemplate(templateData: InputTemplate): void {
templateData.disposable.dispose();
templateData.templateDisposable.dispose();
}

Expand Down Expand Up @@ -299,7 +293,7 @@ interface ResourceGroupTemplate {
readonly name: HTMLElement;
readonly count: CountBadge;
readonly actionBar: ActionBar;
elementDisposables: IDisposable;
readonly elementDisposables: DisposableStore;
readonly disposables: IDisposable;
}

Expand All @@ -325,34 +319,28 @@ class ResourceGroupRenderer implements ICompressibleTreeRenderer<ISCMResourceGro
const countContainer = append(element, $('.count'));
const count = new CountBadge(countContainer);
const styler = attachBadgeStyler(count, this.themeService);
const elementDisposables = Disposable.None;
const disposables = combinedDisposable(actionBar, styler);

return { name, count, actionBar, elementDisposables, disposables };
return { name, count, actionBar, elementDisposables: new DisposableStore(), disposables };
}

renderElement(node: ITreeNode<ISCMResourceGroup, FuzzyScore>, index: number, template: ResourceGroupTemplate): void {
template.elementDisposables.dispose();

const group = node.element;
template.name.textContent = group.label;
template.actionBar.clear();
template.actionBar.context = group;
template.count.setCount(group.elements.length);

const disposables = new DisposableStore();
const menus = this.scmViewService.menus.getRepositoryMenus(group.provider);
disposables.add(connectPrimaryMenuToInlineActionBar(menus.getResourceGroupMenu(group), template.actionBar));

template.elementDisposables = disposables;
template.elementDisposables.add(connectPrimaryMenuToInlineActionBar(menus.getResourceGroupMenu(group), template.actionBar));
}

renderCompressedElements(node: ITreeNode<ICompressedTreeNode<ISCMResourceGroup>, FuzzyScore>, index: number, templateData: ResourceGroupTemplate, height: number | undefined): void {
throw new Error('Should never happen since node is incompressible');
}

disposeElement(group: ITreeNode<ISCMResourceGroup, FuzzyScore>, index: number, template: ResourceGroupTemplate): void {
template.elementDisposables.dispose();
template.elementDisposables.clear();
}

disposeTemplate(template: ResourceGroupTemplate): void {
Expand All @@ -367,8 +355,8 @@ interface ResourceTemplate {
fileLabel: IResourceLabel;
decorationIcon: HTMLElement;
actionBar: ActionBar;
elementDisposables: IDisposable;
disposables: IDisposable;
readonly elementDisposables: DisposableStore;
readonly disposables: IDisposable;
}

interface RenderedResourceData {
Expand Down Expand Up @@ -430,13 +418,10 @@ class ResourceRenderer implements ICompressibleTreeRenderer<ISCMResource | IReso
const decorationIcon = append(element, $('.decoration-icon'));
const disposables = combinedDisposable(actionBar, fileLabel);

return { element, name, fileLabel, decorationIcon, actionBar, elementDisposables: Disposable.None, disposables };
return { element, name, fileLabel, decorationIcon, actionBar, elementDisposables: new DisposableStore(), disposables };
}

renderElement(node: ITreeNode<ISCMResource, FuzzyScore | LabelFuzzyScore> | ITreeNode<ISCMResource | IResourceNode<ISCMResource, ISCMResourceGroup>, FuzzyScore | LabelFuzzyScore>, index: number, template: ResourceTemplate): void {
template.elementDisposables.dispose();

const elementDisposables = new DisposableStore();
const resourceOrFolder = node.element;
const iconResource = ResourceTree.isResourceNode(resourceOrFolder) ? resourceOrFolder.element : resourceOrFolder;
const uri = ResourceTree.isResourceNode(resourceOrFolder) ? resourceOrFolder.uri : resourceOrFolder.sourceUri;
Expand All @@ -454,19 +439,19 @@ class ResourceRenderer implements ICompressibleTreeRenderer<ISCMResource | IReso
if (ResourceTree.isResourceNode(resourceOrFolder)) {
if (resourceOrFolder.element) {
const menus = this.scmViewService.menus.getRepositoryMenus(resourceOrFolder.element.resourceGroup.provider);
elementDisposables.add(connectPrimaryMenuToInlineActionBar(menus.getResourceMenu(resourceOrFolder.element), template.actionBar));
template.elementDisposables.add(connectPrimaryMenuToInlineActionBar(menus.getResourceMenu(resourceOrFolder.element), template.actionBar));
template.element.classList.toggle('faded', resourceOrFolder.element.decorations.faded);
strikethrough = resourceOrFolder.element.decorations.strikeThrough;
} else {
matches = createMatches(node.filterData as FuzzyScore | undefined);
const menus = this.scmViewService.menus.getRepositoryMenus(resourceOrFolder.context.provider);
elementDisposables.add(connectPrimaryMenuToInlineActionBar(menus.getResourceFolderMenu(resourceOrFolder.context), template.actionBar));
template.elementDisposables.add(connectPrimaryMenuToInlineActionBar(menus.getResourceFolderMenu(resourceOrFolder.context), template.actionBar));
template.element.classList.remove('faded');
}
} else {
[matches, descriptionMatches] = this._processFilterData(uri, node.filterData);
const menus = this.scmViewService.menus.getRepositoryMenus(resourceOrFolder.resourceGroup.provider);
elementDisposables.add(connectPrimaryMenuToInlineActionBar(menus.getResourceMenu(resourceOrFolder), template.actionBar));
template.elementDisposables.add(connectPrimaryMenuToInlineActionBar(menus.getResourceMenu(resourceOrFolder), template.actionBar));
template.element.classList.toggle('faded', resourceOrFolder.decorations.faded);
strikethrough = resourceOrFolder.decorations.strikeThrough;
}
Expand All @@ -487,20 +472,16 @@ class ResourceRenderer implements ICompressibleTreeRenderer<ISCMResource | IReso
this.renderIcon(template, renderedData);

this.renderedResources.set(template, renderedData);
elementDisposables.add(toDisposable(() => this.renderedResources.delete(template)));
template.elementDisposables.add(toDisposable(() => this.renderedResources.delete(template)));

template.element.setAttribute('data-tooltip', tooltip);
template.elementDisposables = elementDisposables;
}

disposeElement(resource: ITreeNode<ISCMResource, FuzzyScore | LabelFuzzyScore> | ITreeNode<IResourceNode<ISCMResource, ISCMResourceGroup>, FuzzyScore | LabelFuzzyScore>, index: number, template: ResourceTemplate): void {
template.elementDisposables.dispose();
template.elementDisposables.clear();
}

renderCompressedElements(node: ITreeNode<ICompressedTreeNode<ISCMResource> | ICompressedTreeNode<IResourceNode<ISCMResource, ISCMResourceGroup>>, FuzzyScore | LabelFuzzyScore>, index: number, template: ResourceTemplate, height: number | undefined): void {
template.elementDisposables.dispose();

const elementDisposables = new DisposableStore();
const compressed = node.element as ICompressedTreeNode<IResourceNode<ISCMResource, ISCMResourceGroup>>;
const folder = compressed.elements[compressed.elements.length - 1];

Expand All @@ -519,19 +500,18 @@ class ResourceRenderer implements ICompressibleTreeRenderer<ISCMResource | IReso
template.actionBar.context = folder;

const menus = this.scmViewService.menus.getRepositoryMenus(folder.context.provider);
elementDisposables.add(connectPrimaryMenuToInlineActionBar(menus.getResourceFolderMenu(folder.context), template.actionBar));
template.elementDisposables.add(connectPrimaryMenuToInlineActionBar(menus.getResourceFolderMenu(folder.context), template.actionBar));

template.name.classList.remove('strike-through');
template.element.classList.remove('faded');
template.decorationIcon.style.display = 'none';
template.decorationIcon.style.backgroundImage = '';

template.element.setAttribute('data-tooltip', '');
template.elementDisposables = elementDisposables;
}

disposeCompressedElements(node: ITreeNode<ICompressedTreeNode<ISCMResource> | ICompressedTreeNode<IResourceNode<ISCMResource, ISCMResourceGroup>>, FuzzyScore | LabelFuzzyScore>, index: number, template: ResourceTemplate, height: number | undefined): void {
template.elementDisposables.dispose();
template.elementDisposables.clear();
}

disposeTemplate(template: ResourceTemplate): void {
Expand Down