提交 99f78e83 编写于 作者: J Joao Moreno

markers: filter stats

上级 87e290d0
...@@ -247,6 +247,10 @@ export abstract class AbstractTree<T, TFilterData, TRef> implements IDisposable ...@@ -247,6 +247,10 @@ export abstract class AbstractTree<T, TFilterData, TRef> implements IDisposable
// Tree // Tree
getNode(location?: TRef): ITreeNode<T, TFilterData> {
return this.model.getNode(location);
}
collapse(location: TRef): boolean { collapse(location: TRef): boolean {
return this.model.setCollapsed(location, true); return this.model.setCollapsed(location, true);
} }
......
...@@ -116,16 +116,16 @@ export class IndexTreeModel<T, TFilterData = void> implements ITreeModel<T, TFil ...@@ -116,16 +116,16 @@ export class IndexTreeModel<T, TFilterData = void> implements ITreeModel<T, TFil
} }
getListIndex(location: number[]): number { getListIndex(location: number[]): number {
return this.getNodeWithListIndex(location).listIndex; return this.getTreeNodeWithListIndex(location).listIndex;
} }
setCollapsed(location: number[], collapsed: boolean): boolean { setCollapsed(location: number[], collapsed: boolean): boolean {
const { node, listIndex, revealed } = this.getNodeWithListIndex(location); const { node, listIndex, revealed } = this.getTreeNodeWithListIndex(location);
return this.eventBufferer.bufferEvents(() => this._setCollapsed(node, listIndex, revealed, collapsed)); return this.eventBufferer.bufferEvents(() => this._setCollapsed(node, listIndex, revealed, collapsed));
} }
toggleCollapsed(location: number[]): void { toggleCollapsed(location: number[]): void {
const { node, listIndex, revealed } = this.getNodeWithListIndex(location); const { node, listIndex, revealed } = this.getTreeNodeWithListIndex(location);
this.eventBufferer.bufferEvents(() => this._setCollapsed(node, listIndex, revealed)); this.eventBufferer.bufferEvents(() => this._setCollapsed(node, listIndex, revealed));
} }
...@@ -146,7 +146,7 @@ export class IndexTreeModel<T, TFilterData = void> implements ITreeModel<T, TFil ...@@ -146,7 +146,7 @@ export class IndexTreeModel<T, TFilterData = void> implements ITreeModel<T, TFil
} }
isCollapsed(location: number[]): boolean { isCollapsed(location: number[]): boolean {
return this.getNode(location).collapsed; return this.getTreeNode(location).collapsed;
} }
refilter(): void { refilter(): void {
...@@ -348,10 +348,8 @@ export class IndexTreeModel<T, TFilterData = void> implements ITreeModel<T, TFil ...@@ -348,10 +348,8 @@ export class IndexTreeModel<T, TFilterData = void> implements ITreeModel<T, TFil
} }
} }
/** // cheap
* Cheaper version of findNode, which doesn't require list indices. private getTreeNode(location: number[], node: IMutableTreeNode<T, TFilterData> = this.root): IMutableTreeNode<T, TFilterData> {
*/
private getNode(location: number[], node: IMutableTreeNode<T, TFilterData> = this.root): IMutableTreeNode<T, TFilterData> {
if (location.length === 0) { if (location.length === 0) {
return node; return node;
} }
...@@ -362,10 +360,11 @@ export class IndexTreeModel<T, TFilterData = void> implements ITreeModel<T, TFil ...@@ -362,10 +360,11 @@ export class IndexTreeModel<T, TFilterData = void> implements ITreeModel<T, TFil
throw new Error('Invalid tree location'); throw new Error('Invalid tree location');
} }
return this.getNode(rest, node.children[index]); return this.getTreeNode(rest, node.children[index]);
} }
private getNodeWithListIndex(location: number[]): { node: IMutableTreeNode<T, TFilterData>, listIndex: number, revealed: boolean } { // expensive
private getTreeNodeWithListIndex(location: number[]): { node: IMutableTreeNode<T, TFilterData>, listIndex: number, revealed: boolean } {
const { parentNode, listIndex, revealed } = this.getParentNodeWithListIndex(location); const { parentNode, listIndex, revealed } = this.getParentNodeWithListIndex(location);
const index = location[location.length - 1]; const index = location[location.length - 1];
...@@ -399,6 +398,10 @@ export class IndexTreeModel<T, TFilterData = void> implements ITreeModel<T, TFil ...@@ -399,6 +398,10 @@ export class IndexTreeModel<T, TFilterData = void> implements ITreeModel<T, TFil
return this.getParentNodeWithListIndex(rest, node.children[index], listIndex + 1, revealed); return this.getParentNodeWithListIndex(rest, node.children[index], listIndex + 1, revealed);
} }
getNode(location: number[] = []): ITreeNode<T, TFilterData> {
return this.getTreeNode(location);
}
// TODO@joao perf! // TODO@joao perf!
getNodeLocation(node: ITreeNode<T, TFilterData>): number[] { getNodeLocation(node: ITreeNode<T, TFilterData>): number[] {
const location = []; const location = [];
...@@ -421,12 +424,12 @@ export class IndexTreeModel<T, TFilterData = void> implements ITreeModel<T, TFil ...@@ -421,12 +424,12 @@ export class IndexTreeModel<T, TFilterData = void> implements ITreeModel<T, TFil
getParentElement(location: number[]): T | null { getParentElement(location: number[]): T | null {
const parentLocation = this.getParentNodeLocation(location); const parentLocation = this.getParentNodeLocation(location);
const node = this.getNode(parentLocation); const node = this.getTreeNode(parentLocation);
return node === this.root ? null : node.element; return node === this.root ? null : node.element;
} }
getFirstElementChild(location: number[]): T | null { getFirstElementChild(location: number[]): T | null {
const node = this.getNode(location); const node = this.getTreeNode(location);
if (node.children.length === 0) { if (node.children.length === 0) {
return null; return null;
...@@ -436,7 +439,7 @@ export class IndexTreeModel<T, TFilterData = void> implements ITreeModel<T, TFil ...@@ -436,7 +439,7 @@ export class IndexTreeModel<T, TFilterData = void> implements ITreeModel<T, TFil
} }
getLastElementAncestor(location: number[]): T | null { getLastElementAncestor(location: number[]): T | null {
const node = this.getNode(location); const node = this.getTreeNode(location);
if (node.children.length === 0) { if (node.children.length === 0) {
return null; return null;
......
...@@ -90,6 +90,11 @@ export class ObjectTreeModel<T extends NonNullable<any>, TFilterData = void> imp ...@@ -90,6 +90,11 @@ export class ObjectTreeModel<T extends NonNullable<any>, TFilterData = void> imp
this.model.refilter(); this.model.refilter();
} }
getNode(element: T = null): ITreeNode<T, TFilterData> {
const location = this.getElementLocation(element);
return this.model.getNode(location);
}
getNodeLocation(node: ITreeNode<T, TFilterData>): T { getNodeLocation(node: ITreeNode<T, TFilterData>): T {
return node.element; return node.element;
} }
......
...@@ -58,6 +58,7 @@ export interface ITreeModel<T, TFilterData, TRef> { ...@@ -58,6 +58,7 @@ export interface ITreeModel<T, TFilterData, TRef> {
isCollapsed(ref: TRef): boolean; isCollapsed(ref: TRef): boolean;
refilter(): void; refilter(): void;
getNode(location?: TRef): ITreeNode<T, any>;
getNodeLocation(node: ITreeNode<T, any>): TRef; getNodeLocation(node: ITreeNode<T, any>): TRef;
getParentNodeLocation(location: TRef): TRef | null; getParentNodeLocation(location: TRef): TRef | null;
......
...@@ -59,7 +59,7 @@ export class MarkersWorkbenchService extends Disposable implements IMarkersWorkb ...@@ -59,7 +59,7 @@ export class MarkersWorkbenchService extends Disposable implements IMarkersWorkb
} }
private refreshBadge(): void { private refreshBadge(): void {
const { total } = this.markersModel.stats(); const total = this.markersModel.resourceMarkers.reduce((r, rm) => r + rm.markers.length, 0);
const message = localize('totalProblems', 'Total {0} Problems', total); const message = localize('totalProblems', 'Total {0} Problems', total);
this.activityService.showActivity(Constants.MARKERS_PANEL_ID, new NumberBadge(total, () => message)); this.activityService.showActivity(Constants.MARKERS_PANEL_ID, new NumberBadge(total, () => message));
} }
......
...@@ -125,16 +125,6 @@ export class MarkersModel { ...@@ -125,16 +125,6 @@ export class MarkersModel {
this._onDidChange.fire(resource); this._onDidChange.fire(resource);
} }
stats(): { total: number, filtered: number } {
let total = 0;
// let filtered = 0;
this.resourcesByUri.forEach(resource => {
total += resource.markers.length;
// filtered += resource.filteredCount; // TODO@joao
});
return { total, filtered: total };
}
dispose(): void { dispose(): void {
this._onDidChange.dispose(); this._onDidChange.dispose();
this.resourcesByUri.clear(); this.resourcesByUri.clear();
......
...@@ -15,7 +15,7 @@ import { IEditorService, SIDE_GROUP, ACTIVE_GROUP } from 'vs/workbench/services/ ...@@ -15,7 +15,7 @@ import { IEditorService, SIDE_GROUP, ACTIVE_GROUP } from 'vs/workbench/services/
import Constants from 'vs/workbench/parts/markers/electron-browser/constants'; import Constants from 'vs/workbench/parts/markers/electron-browser/constants';
import { Marker, ResourceMarkers, RelatedInformation, MarkersModel } from 'vs/workbench/parts/markers/electron-browser/markersModel'; import { Marker, ResourceMarkers, RelatedInformation, MarkersModel } from 'vs/workbench/parts/markers/electron-browser/markersModel';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
import { MarkersFilterActionItem, MarkersFilterAction, QuickFixAction, QuickFixActionItem, IMarkersFilterActionChangeEvent } from 'vs/workbench/parts/markers/electron-browser/markersPanelActions'; import { MarkersFilterActionItem, MarkersFilterAction, QuickFixAction, QuickFixActionItem, IMarkersFilterActionChangeEvent, IMarkerFilterController } from 'vs/workbench/parts/markers/electron-browser/markersPanelActions';
import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
import Messages from 'vs/workbench/parts/markers/electron-browser/messages'; import Messages from 'vs/workbench/parts/markers/electron-browser/messages';
import { RangeHighlightDecorations } from 'vs/workbench/browser/parts/editor/rangeDecorations'; import { RangeHighlightDecorations } from 'vs/workbench/browser/parts/editor/rangeDecorations';
...@@ -28,7 +28,7 @@ import { localize } from 'vs/nls'; ...@@ -28,7 +28,7 @@ import { localize } from 'vs/nls';
import { IContextKey, IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; import { IContextKey, IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
import { Iterator } from 'vs/base/common/iterator'; import { Iterator } from 'vs/base/common/iterator';
import { ITreeElement, ITreeNode } from 'vs/base/browser/ui/tree/tree'; import { ITreeElement, ITreeNode } from 'vs/base/browser/ui/tree/tree';
import { debounceEvent, Relay } from 'vs/base/common/event'; import { debounceEvent, Relay, Event, Emitter } from 'vs/base/common/event';
import { WorkbenchObjectTree, ObjectTreeResourceNavigator } from 'vs/platform/list/browser/listService'; import { WorkbenchObjectTree, ObjectTreeResourceNavigator } from 'vs/platform/list/browser/listService';
import { FilterOptions } from 'vs/workbench/parts/markers/electron-browser/markersFilterOptions'; import { FilterOptions } from 'vs/workbench/parts/markers/electron-browser/markersFilterOptions';
import { IExpression, getEmptyExpression } from 'vs/base/common/glob'; import { IExpression, getEmptyExpression } from 'vs/base/common/glob';
...@@ -61,7 +61,7 @@ function createModelIterator(model: MarkersModel): Iterator<ITreeElement<TreeEle ...@@ -61,7 +61,7 @@ function createModelIterator(model: MarkersModel): Iterator<ITreeElement<TreeEle
}); });
} }
export class MarkersPanel extends Panel { export class MarkersPanel extends Panel implements IMarkerFilterController {
private lastSelectedRelativeTop: number = 0; private lastSelectedRelativeTop: number = 0;
private currentActiveResource: URI = null; private currentActiveResource: URI = null;
...@@ -82,6 +82,10 @@ export class MarkersPanel extends Panel { ...@@ -82,6 +82,10 @@ export class MarkersPanel extends Panel {
private filter: Filter; private filter: Filter;
private _onDidFilter = new Emitter<void>();
readonly onDidFilter: Event<void> = this._onDidFilter.event;
private cachedFilterStats: { total: number; filtered: number; } | undefined = undefined;
private currentResourceGotAddedToMarkersData: boolean = false; private currentResourceGotAddedToMarkersData: boolean = false;
constructor( constructor(
...@@ -217,20 +221,22 @@ export class MarkersPanel extends Panel { ...@@ -217,20 +221,22 @@ export class MarkersPanel extends Panel {
// TODO@joao // TODO@joao
private refreshPanel(): TPromise<any> { private refreshPanel(): TPromise<any> {
if (this.isVisible()) { if (this.isVisible()) {
this.cachedFilterStats = undefined;
this.collapseAllAction.enabled = true /* this.markersWorkbenchService.markersModel.hasFilteredResources() */; this.collapseAllAction.enabled = true /* this.markersWorkbenchService.markersModel.hasFilteredResources() */;
dom.toggleClass(this.treeContainer, 'hidden', false/* !this.markersWorkbenchService.markersModel.hasFilteredResources() */); dom.toggleClass(this.treeContainer, 'hidden', false/* !this.markersWorkbenchService.markersModel.hasFilteredResources() */);
this.renderMessage(); this.renderMessage();
// if (this.markersWorkbenchService.markersModel.hasFilteredResources()) {
this.tree.setChildren(null, createModelIterator(this.markersWorkbenchService.markersModel)); this.tree.setChildren(null, createModelIterator(this.markersWorkbenchService.markersModel));
// } this._onDidFilter.fire();
} }
return TPromise.as(null); return TPromise.as(null);
} }
private updateFilter() { private updateFilter() {
this.cachedFilterStats = undefined;
const excludeExpression = this.getExcludeExpression(this.filterAction.useFilesExclude); const excludeExpression = this.getExcludeExpression(this.filterAction.useFilesExclude);
this.filter.options = new FilterOptions(this.filterAction.filterText, excludeExpression); this.filter.options = new FilterOptions(this.filterAction.filterText, excludeExpression);
this.tree.refilter(); this.tree.refilter();
this._onDidFilter.fire();
} }
private getExcludeExpression(useFilesExclude: boolean): IExpression { private getExcludeExpression(useFilesExclude: boolean): IExpression {
...@@ -408,10 +414,9 @@ export class MarkersPanel extends Panel { ...@@ -408,10 +414,9 @@ export class MarkersPanel extends Panel {
// TODO@joao // TODO@joao
private renderMessage(): void { private renderMessage(): void {
dom.clearNode(this.messageBoxContainer); dom.clearNode(this.messageBoxContainer);
const markersModel = this.markersWorkbenchService.markersModel;
// if (markersModel.hasFilteredResources()) { // if (markersModel.hasFilteredResources()) {
this.messageBoxContainer.style.display = 'none'; this.messageBoxContainer.style.display = 'none';
const { total, filtered } = markersModel.stats(); const { total, filtered } = this.getFilterStats();
if (filtered === total) { if (filtered === total) {
this.ariaLabelElement.setAttribute('aria-label', localize('No problems filtered', "Showing {0} problems", total)); this.ariaLabelElement.setAttribute('aria-label', localize('No problems filtered', "Showing {0} problems", total));
} else { } else {
...@@ -598,7 +603,7 @@ export class MarkersPanel extends Panel { ...@@ -598,7 +603,7 @@ export class MarkersPanel extends Panel {
public getActionItem(action: IAction): IActionItem { public getActionItem(action: IAction): IActionItem {
if (action.id === MarkersFilterAction.ID) { if (action.id === MarkersFilterAction.ID) {
this.filterInputActionItem = this.instantiationService.createInstance(MarkersFilterActionItem, this.filterAction); this.filterInputActionItem = this.instantiationService.createInstance(MarkersFilterActionItem, this.filterAction, this);
return this.filterInputActionItem; return this.filterInputActionItem;
} }
if (action.id === QuickFixAction.ID) { if (action.id === QuickFixAction.ID) {
...@@ -607,6 +612,36 @@ export class MarkersPanel extends Panel { ...@@ -607,6 +612,36 @@ export class MarkersPanel extends Panel {
return super.getActionItem(action); return super.getActionItem(action);
} }
getFilterOptions(): FilterOptions {
return this.filter.options;
}
getFilterStats(): { total: number; filtered: number; } {
if (!this.cachedFilterStats) {
this.cachedFilterStats = this.computeFilterStats();
}
return this.cachedFilterStats;
}
private computeFilterStats(): { total: number; filtered: number; } {
const root = this.tree.getNode();
let total = 0;
let filtered = 0;
for (const resourceMarkerNode of root.children) {
for (const markerNode of resourceMarkerNode.children) {
total++;
if (resourceMarkerNode.visible && markerNode.visible) {
filtered++;
}
}
}
return { total, filtered };
}
public shutdown(): void { public shutdown(): void {
// store memento // store memento
this.panelSettings['filter'] = this.filterAction.filterText; this.panelSettings['filter'] = this.filterAction.filterText;
......
...@@ -40,6 +40,9 @@ import { IMarkerData } from 'vs/platform/markers/common/markers'; ...@@ -40,6 +40,9 @@ import { IMarkerData } from 'vs/platform/markers/common/markers';
import { getCodeActions } from 'vs/editor/contrib/codeAction/codeAction'; import { getCodeActions } from 'vs/editor/contrib/codeAction/codeAction';
import { URI } from 'vs/base/common/uri'; import { URI } from 'vs/base/common/uri';
import { CodeActionKind } from 'vs/editor/contrib/codeAction/codeActionTrigger'; import { CodeActionKind } from 'vs/editor/contrib/codeAction/codeActionTrigger';
import { Event } from 'vs/base/common/event';
import { FilterOptions } from 'vs/workbench/parts/markers/electron-browser/markersFilterOptions';
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
export class ToggleMarkersPanelAction extends TogglePanelAction { export class ToggleMarkersPanelAction extends TogglePanelAction {
...@@ -118,6 +121,12 @@ export class MarkersFilterAction extends Action { ...@@ -118,6 +121,12 @@ export class MarkersFilterAction extends Action {
} }
} }
export interface IMarkerFilterController {
onDidFilter: Event<void>;
getFilterOptions(): FilterOptions;
getFilterStats(): { total: number, filtered: number };
}
export class MarkersFilterActionItem extends BaseActionItem { export class MarkersFilterActionItem extends BaseActionItem {
private delayedFilterUpdate: Delayer<void>; private delayedFilterUpdate: Delayer<void>;
...@@ -129,11 +138,11 @@ export class MarkersFilterActionItem extends BaseActionItem { ...@@ -129,11 +138,11 @@ export class MarkersFilterActionItem extends BaseActionItem {
constructor( constructor(
readonly action: MarkersFilterAction, readonly action: MarkersFilterAction,
private filterController: IMarkerFilterController,
@IInstantiationService private instantiationService: IInstantiationService, @IInstantiationService private instantiationService: IInstantiationService,
@IContextViewService private contextViewService: IContextViewService, @IContextViewService private contextViewService: IContextViewService,
@IThemeService private themeService: IThemeService, @IThemeService private themeService: IThemeService,
@IMarkersWorkbenchService private markersWorkbenchService: IMarkersWorkbenchService, @ITelemetryService private telemetryService: ITelemetryService,
// @ITelemetryService private telemetryService: ITelemetryService,
@IContextKeyService contextKeyService: IContextKeyService @IContextKeyService contextKeyService: IContextKeyService
) { ) {
super(null, action); super(null, action);
...@@ -209,7 +218,7 @@ export class MarkersFilterActionItem extends BaseActionItem { ...@@ -209,7 +218,7 @@ export class MarkersFilterActionItem extends BaseActionItem {
this.filterBadge.style.borderColor = border; this.filterBadge.style.borderColor = border;
})); }));
this.updateBadge(); this.updateBadge();
this._register(this.markersWorkbenchService.markersModel.onDidChange(() => this.updateBadge())); this._register(this.filterController.onDidFilter(() => this.updateBadge()));
} }
private createFilesExcludeCheckbox(container: HTMLElement): void { private createFilesExcludeCheckbox(container: HTMLElement): void {
...@@ -240,7 +249,7 @@ export class MarkersFilterActionItem extends BaseActionItem { ...@@ -240,7 +249,7 @@ export class MarkersFilterActionItem extends BaseActionItem {
} }
private updateBadge(): void { private updateBadge(): void {
const { total, filtered } = this.markersWorkbenchService.markersModel.stats(); const { total, filtered } = this.filterController.getFilterStats();
DOM.toggleClass(this.filterBadge, 'hidden', total === filtered || filtered === 0); DOM.toggleClass(this.filterBadge, 'hidden', total === filtered || filtered === 0);
this.filterBadge.textContent = localize('showing filtered problems', "Showing {0} of {1}", filtered, total); this.filterBadge.textContent = localize('showing filtered problems', "Showing {0} of {1}", filtered, total);
this.adjustInputBox(); this.adjustInputBox();
...@@ -276,12 +285,12 @@ export class MarkersFilterActionItem extends BaseActionItem { ...@@ -276,12 +285,12 @@ export class MarkersFilterActionItem extends BaseActionItem {
} }
} }
// TODO@joao
private reportFilteringUsed(): void { private reportFilteringUsed(): void {
// let data = {}; const filterOptions = this.filterController.getFilterOptions();
// data['errors'] = this.filterOptions.filterErrors; const data = {};
// data['warnings'] = this.filterOptions.filterWarnings; data['errors'] = filterOptions.filterErrors;
// data['infos'] = this.filterOptions.filterInfos; data['warnings'] = filterOptions.filterWarnings;
data['infos'] = filterOptions.filterInfos;
/* __GDPR__ /* __GDPR__
"problems.filter" : { "problems.filter" : {
"errors" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, "errors" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true },
...@@ -289,7 +298,7 @@ export class MarkersFilterActionItem extends BaseActionItem { ...@@ -289,7 +298,7 @@ export class MarkersFilterActionItem extends BaseActionItem {
"infos": { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true } "infos": { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }
} }
*/ */
// this.telemetryService.publicLog('problems.filter', data); this.telemetryService.publicLog('problems.filter', data);
} }
} }
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册