mirror of
https://github.com/microsoft/vscode.git
synced 2026-07-25 23:45:56 +01:00
#10271 Show diagnostics with children in problems panel
This commit is contained in:
@@ -7,26 +7,32 @@
|
||||
import * as paths from 'vs/base/common/paths';
|
||||
import URI from 'vs/base/common/uri';
|
||||
import { Range, IRange } from 'vs/editor/common/core/range';
|
||||
import { IMarker, MarkerSeverity } from 'vs/platform/markers/common/markers';
|
||||
import { IMarker, MarkerSeverity, IRelatedInformation } from 'vs/platform/markers/common/markers';
|
||||
import { IFilter, IMatch, or, matchesContiguousSubString, matchesPrefix, matchesFuzzy } from 'vs/base/common/filters';
|
||||
import Messages from 'vs/workbench/parts/markers/electron-browser/messages';
|
||||
import { Schemas } from 'vs/base/common/network';
|
||||
import { groupBy, isFalsyOrEmpty } from 'vs/base/common/arrays';
|
||||
import { values } from 'vs/base/common/map';
|
||||
|
||||
export class Resource {
|
||||
export abstract class NodeWithId {
|
||||
constructor(readonly id: string) { }
|
||||
}
|
||||
|
||||
export class ResourceData<T> extends NodeWithId {
|
||||
|
||||
private _name: string = null;
|
||||
private _path: string = null;
|
||||
|
||||
filteredMarkersCount: number = 0;
|
||||
count: number = 0;
|
||||
uriMatches: IMatch[] = [];
|
||||
|
||||
constructor(
|
||||
id: string,
|
||||
readonly uri: URI,
|
||||
readonly markers: Marker[],
|
||||
readonly data: T[]
|
||||
) {
|
||||
markers.sort(Marker.compare);
|
||||
super(id);
|
||||
this.count = this.data.length;
|
||||
}
|
||||
|
||||
public get path(): string {
|
||||
@@ -42,10 +48,21 @@ export class Resource {
|
||||
}
|
||||
return this._name;
|
||||
}
|
||||
}
|
||||
|
||||
static compare(a: Resource, b: Resource): number {
|
||||
let [firstMarkerOfA] = a.markers;
|
||||
let [firstMarkerOfB] = b.markers;
|
||||
export class ResourceMarkers extends ResourceData<Marker> {
|
||||
|
||||
constructor(
|
||||
uri: URI,
|
||||
markers: Marker[]
|
||||
) {
|
||||
const sorted = markers.sort(Marker.compare);
|
||||
super(uri.toString(), uri, sorted);
|
||||
}
|
||||
|
||||
static compare(a: ResourceMarkers, b: ResourceMarkers): number {
|
||||
let [firstMarkerOfA] = a.data;
|
||||
let [firstMarkerOfB] = b.data;
|
||||
let res = 0;
|
||||
if (firstMarkerOfA && firstMarkerOfB) {
|
||||
res = MarkerSeverity.compare(firstMarkerOfA.raw.severity, firstMarkerOfB.raw.severity);
|
||||
@@ -57,16 +74,19 @@ export class Resource {
|
||||
}
|
||||
}
|
||||
|
||||
export class Marker {
|
||||
export class Marker extends NodeWithId {
|
||||
|
||||
isSelected: boolean = false;
|
||||
messageMatches: IMatch[] = [];
|
||||
sourceMatches: IMatch[] = [];
|
||||
resourceRelatedInformation: ResourceData<RelatedInformation>[] = [];
|
||||
|
||||
constructor(
|
||||
readonly id: string,
|
||||
id: string,
|
||||
readonly raw: IMarker,
|
||||
) { }
|
||||
) {
|
||||
super(id);
|
||||
}
|
||||
|
||||
public get resource(): URI {
|
||||
return this.raw.resource;
|
||||
@@ -93,6 +113,15 @@ export class Marker {
|
||||
}
|
||||
}
|
||||
|
||||
export class RelatedInformation extends NodeWithId {
|
||||
constructor(
|
||||
id: string,
|
||||
readonly relatedInformation: IRelatedInformation,
|
||||
public matches: IMatch[]) {
|
||||
super(id);
|
||||
}
|
||||
}
|
||||
|
||||
export class FilterOptions {
|
||||
|
||||
static readonly _filter: IFilter = or(matchesPrefix, matchesContiguousSubString);
|
||||
@@ -126,12 +155,12 @@ export class FilterOptions {
|
||||
|
||||
export class MarkersModel {
|
||||
|
||||
private _cachedSortedResources: Resource[];
|
||||
private _markersByResource: Map<string, Resource>;
|
||||
private _cachedSortedResources: ResourceMarkers[];
|
||||
private _markersByResource: Map<string, ResourceMarkers>;
|
||||
private _filterOptions: FilterOptions;
|
||||
|
||||
constructor(markers: IMarker[] = []) {
|
||||
this._markersByResource = new Map<string, Resource>();
|
||||
this._markersByResource = new Map<string, ResourceMarkers>();
|
||||
this._filterOptions = new FilterOptions();
|
||||
|
||||
for (const group of groupBy(markers, MarkersModel._compareMarkersByUri)) {
|
||||
@@ -154,16 +183,16 @@ export class MarkersModel {
|
||||
return this._filterOptions;
|
||||
}
|
||||
|
||||
public get resources(): Resource[] {
|
||||
public get resources(): ResourceMarkers[] {
|
||||
if (!this._cachedSortedResources) {
|
||||
this._cachedSortedResources = values(this._markersByResource).sort(Resource.compare);
|
||||
this._cachedSortedResources = values(this._markersByResource).sort(ResourceMarkers.compare);
|
||||
}
|
||||
return this._cachedSortedResources;
|
||||
}
|
||||
|
||||
public forEachFilteredResource(callback: (resource: Resource) => any) {
|
||||
public forEachFilteredResource(callback: (resource: ResourceMarkers) => any) {
|
||||
this._markersByResource.forEach(resource => {
|
||||
if (resource.filteredMarkersCount > 0) {
|
||||
if (resource.count > 0) {
|
||||
callback(resource);
|
||||
}
|
||||
});
|
||||
@@ -172,7 +201,7 @@ export class MarkersModel {
|
||||
public hasFilteredResources(): boolean {
|
||||
let res = false;
|
||||
this._markersByResource.forEach(resource => {
|
||||
res = res || resource.filteredMarkersCount > 0;
|
||||
res = res || resource.count > 0;
|
||||
});
|
||||
return res;
|
||||
}
|
||||
@@ -189,8 +218,8 @@ export class MarkersModel {
|
||||
let total = 0;
|
||||
let filtered = 0;
|
||||
this._markersByResource.forEach(resource => {
|
||||
total += resource.markers.length;
|
||||
filtered += resource.filteredMarkersCount;
|
||||
total += resource.data.length;
|
||||
filtered += resource.count;
|
||||
});
|
||||
return { total, filtered };
|
||||
|
||||
@@ -212,13 +241,17 @@ export class MarkersModel {
|
||||
if (!this._filterOptions.hasFilters()) {
|
||||
// reset all filters/matches
|
||||
this._markersByResource.forEach(resource => {
|
||||
resource.filteredMarkersCount = resource.markers.length;
|
||||
resource.count = resource.data.length;
|
||||
resource.uriMatches = [];
|
||||
|
||||
for (const marker of resource.markers) {
|
||||
for (const marker of resource.data) {
|
||||
marker.isSelected = true;
|
||||
marker.messageMatches = [];
|
||||
marker.sourceMatches = [];
|
||||
marker.resourceRelatedInformation.forEach(r => {
|
||||
r.uriMatches = [];
|
||||
r.data.forEach(d => d.matches = []);
|
||||
});
|
||||
}
|
||||
});
|
||||
} else {
|
||||
@@ -226,21 +259,25 @@ export class MarkersModel {
|
||||
this._markersByResource.forEach(resource => {
|
||||
|
||||
resource.uriMatches = this._filterOptions.hasFilters() ? FilterOptions._filter(this._filterOptions.filter, paths.basename(resource.uri.fsPath)) : [];
|
||||
resource.filteredMarkersCount = 0;
|
||||
resource.count = 0;
|
||||
|
||||
for (const marker of resource.markers) {
|
||||
for (const marker of resource.data) {
|
||||
marker.messageMatches = this._filterOptions.hasFilters() ? FilterOptions._fuzzyFilter(this._filterOptions.filter, marker.raw.message) : [];
|
||||
marker.sourceMatches = marker.raw.source && this._filterOptions.hasFilters() ? FilterOptions._filter(this._filterOptions.filter, marker.raw.source) : [];
|
||||
marker.isSelected = this.filterMarker(marker.raw);
|
||||
if (marker.isSelected) {
|
||||
resource.filteredMarkersCount += 1;
|
||||
resource.count += 1;
|
||||
}
|
||||
marker.resourceRelatedInformation.forEach(r => {
|
||||
r.uriMatches = this._filterOptions.hasFilters() ? FilterOptions._filter(this._filterOptions.filter, paths.basename(r.uri.fsPath)) : [];
|
||||
r.data.forEach(d => d.matches = this._filterOptions.hasFilters() ? FilterOptions._fuzzyFilter(this._filterOptions.filter, d.relatedInformation.message) : []);
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private createResource(uri: URI, rawMarkers: IMarker[]): Resource {
|
||||
private createResource(uri: URI, rawMarkers: IMarker[]): ResourceMarkers {
|
||||
|
||||
let markers: Marker[] = [];
|
||||
let filteredCount = 0;
|
||||
@@ -252,19 +289,36 @@ export class MarkersModel {
|
||||
}
|
||||
}
|
||||
|
||||
const resource = new Resource(uri, markers);
|
||||
resource.filteredMarkersCount = filteredCount;
|
||||
const resource = new ResourceMarkers(uri, markers);
|
||||
resource.count = filteredCount;
|
||||
resource.uriMatches = this._filterOptions.hasFilters() ? FilterOptions._filter(this._filterOptions.filter, paths.basename(uri.fsPath)) : [];
|
||||
|
||||
return resource;
|
||||
}
|
||||
|
||||
private createMarker(marker: IMarker, index: number, uri: string): Marker {
|
||||
const res = new Marker(uri + index, marker);
|
||||
res.messageMatches = this._filterOptions.hasFilters() ? FilterOptions._fuzzyFilter(this._filterOptions.filter, marker.message) : [];
|
||||
res.sourceMatches = marker.source && this._filterOptions.hasFilters() ? FilterOptions._filter(this._filterOptions.filter, marker.source) : [];
|
||||
res.isSelected = this.filterMarker(marker);
|
||||
return res;
|
||||
private createMarker(rawMarker: IMarker, index: number, uri: string): Marker {
|
||||
const marker = new Marker(uri + index, rawMarker);
|
||||
marker.messageMatches = this._filterOptions.hasFilters() ? FilterOptions._fuzzyFilter(this._filterOptions.filter, rawMarker.message) : [];
|
||||
marker.sourceMatches = rawMarker.source && this._filterOptions.hasFilters() ? FilterOptions._filter(this._filterOptions.filter, rawMarker.source) : [];
|
||||
marker.isSelected = this.filterMarker(rawMarker);
|
||||
if (rawMarker.relatedInformation) {
|
||||
marker.resourceRelatedInformation = groupBy(rawMarker.relatedInformation, MarkersModel._compareMarkersByUri)
|
||||
.map(group => {
|
||||
const id = uri + index + uri + index.toString();
|
||||
const r = new ResourceData<RelatedInformation>(
|
||||
id,
|
||||
group[0].resource,
|
||||
group.map((relatedInformation, index) =>
|
||||
new RelatedInformation(
|
||||
id + index,
|
||||
relatedInformation,
|
||||
this._filterOptions.hasFilters() ? FilterOptions._fuzzyFilter(this._filterOptions.filter, relatedInformation.message) : []
|
||||
)));
|
||||
r.uriMatches = this._filterOptions.hasFilters() ? FilterOptions._filter(this._filterOptions.filter, paths.basename(r.uri.fsPath)) : [];
|
||||
return r;
|
||||
});
|
||||
}
|
||||
return marker;
|
||||
}
|
||||
|
||||
private filterMarker(marker: IMarker): boolean {
|
||||
@@ -292,6 +346,11 @@ export class MarkersModel {
|
||||
if (!!marker.source && !!FilterOptions._filter(this._filterOptions.filter, marker.source)) {
|
||||
return true;
|
||||
}
|
||||
if (!!marker.relatedInformation && marker.relatedInformation.some(r =>
|
||||
!!FilterOptions._filter(this._filterOptions.filter, paths.basename(r.resource.fsPath)) || !
|
||||
!FilterOptions._filter(this._filterOptions.filter, r.message))) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@@ -18,7 +18,7 @@ import { IEditorGroupService } from 'vs/workbench/services/group/common/groupSer
|
||||
import { Panel } from 'vs/workbench/browser/panel';
|
||||
import { IWorkbenchEditorService } from 'vs/workbench/services/editor/common/editorService';
|
||||
import Constants from 'vs/workbench/parts/markers/electron-browser/constants';
|
||||
import { Marker, Resource } from 'vs/workbench/parts/markers/electron-browser/markersModel';
|
||||
import { Marker, ResourceMarkers, RelatedInformation } from 'vs/workbench/parts/markers/electron-browser/markersModel';
|
||||
import { Controller } from 'vs/workbench/parts/markers/electron-browser/markersTreeController';
|
||||
import * as Viewer from 'vs/workbench/parts/markers/electron-browser/markersTreeViewer';
|
||||
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
||||
@@ -134,25 +134,20 @@ export class MarkersPanel extends Panel {
|
||||
}
|
||||
|
||||
public openFileAtElement(element: any, preserveFocus: boolean, sideByside: boolean, pinned: boolean): boolean {
|
||||
if (element instanceof Marker) {
|
||||
const marker: Marker = element;
|
||||
/* __GDPR__
|
||||
"problems.marker.opened" : {
|
||||
"source" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" }
|
||||
}
|
||||
*/
|
||||
this.telemetryService.publicLog('problems.marker.opened', { source: marker.raw.source });
|
||||
const { resource, selection } = element instanceof Marker ? { resource: element.resource, selection: element.range } :
|
||||
element instanceof RelatedInformation ? { resource: element.relatedInformation.resource, selection: element.relatedInformation } : { resource: null, selection: null };
|
||||
if (resource && selection) {
|
||||
this.editorService.openEditor({
|
||||
resource: marker.resource,
|
||||
resource,
|
||||
options: {
|
||||
selection: marker.range,
|
||||
selection,
|
||||
preserveFocus,
|
||||
pinned,
|
||||
revealIfVisible: true
|
||||
},
|
||||
}, sideByside).done(editor => {
|
||||
if (editor && preserveFocus) {
|
||||
this.rangeHighlightDecorations.highlightRange(marker, <ICodeEditor>editor.getControl());
|
||||
this.rangeHighlightDecorations.highlightRange({ resource, range: selection }, <ICodeEditor>editor.getControl());
|
||||
} else {
|
||||
this.rangeHighlightDecorations.removeHighlightRange();
|
||||
}
|
||||
@@ -195,7 +190,7 @@ export class MarkersPanel extends Panel {
|
||||
this.treeContainer = dom.append(parent, dom.$('.tree-container'));
|
||||
dom.addClass(this.treeContainer, 'show-file-icons');
|
||||
const renderer = this.instantiationService.createInstance(Viewer.Renderer);
|
||||
const dnd = this.instantiationService.createInstance(SimpleFileResourceDragAndDrop, obj => obj instanceof Resource ? obj.uri : void 0);
|
||||
const dnd = this.instantiationService.createInstance(SimpleFileResourceDragAndDrop, obj => obj instanceof ResourceMarkers ? obj.uri : void 0);
|
||||
const controller = this.instantiationService.createInstance(Controller);
|
||||
this.tree = this.instantiationService.createInstance(WorkbenchTree, this.treeContainer, {
|
||||
dataSource: new Viewer.DataSource(),
|
||||
@@ -205,7 +200,6 @@ export class MarkersPanel extends Panel {
|
||||
accessibilityProvider: new Viewer.MarkersTreeAccessibilityProvider(),
|
||||
dnd
|
||||
}, {
|
||||
indentPixels: 0,
|
||||
twistiePixels: 20,
|
||||
ariaLabel: Messages.MARKERS_PANEL_ARIA_LABEL_PROBLEMS_TREE
|
||||
});
|
||||
@@ -333,8 +327,8 @@ export class MarkersPanel extends Panel {
|
||||
}
|
||||
}
|
||||
|
||||
private getResourceForCurrentActiveResource(): Resource {
|
||||
let res: Resource = null;
|
||||
private getResourceForCurrentActiveResource(): ResourceMarkers {
|
||||
let res: ResourceMarkers = null;
|
||||
if (this.currentActiveResource) {
|
||||
this.markersWorkbenchService.markersModel.forEachFilteredResource(resource => {
|
||||
if (!res && resource.uri.toString() === this.currentActiveResource.toString()) {
|
||||
@@ -345,7 +339,7 @@ export class MarkersPanel extends Panel {
|
||||
return res;
|
||||
}
|
||||
|
||||
private hasSelectedMarkerFor(resource: Resource): boolean {
|
||||
private hasSelectedMarkerFor(resource: ResourceMarkers): boolean {
|
||||
let selectedElement = this.tree.getSelection();
|
||||
if (selectedElement && selectedElement.length > 0) {
|
||||
if (selectedElement[0] instanceof Marker) {
|
||||
@@ -379,7 +373,7 @@ export class MarkersPanel extends Panel {
|
||||
return super.getActionItem(action);
|
||||
}
|
||||
|
||||
public getFocusElement(): Resource | Marker {
|
||||
public getFocusElement(): ResourceMarkers | Marker {
|
||||
return this.tree.getFocus();
|
||||
}
|
||||
|
||||
|
||||
@@ -12,24 +12,20 @@ import { CountBadge } from 'vs/base/browser/ui/countBadge/countBadge';
|
||||
import { FileLabel, ResourceLabel } from 'vs/workbench/browser/labels';
|
||||
import { HighlightedLabel } from 'vs/base/browser/ui/highlightedlabel/highlightedLabel';
|
||||
import { IMarker, MarkerSeverity } from 'vs/platform/markers/common/markers';
|
||||
import { MarkersModel, Resource, Marker } from 'vs/workbench/parts/markers/electron-browser/markersModel';
|
||||
import { MarkersModel, ResourceMarkers, Marker, ResourceData, RelatedInformation, NodeWithId } from 'vs/workbench/parts/markers/electron-browser/markersModel';
|
||||
import Messages from 'vs/workbench/parts/markers/electron-browser/messages';
|
||||
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { attachBadgeStyler } from 'vs/platform/theme/common/styler';
|
||||
import { IThemeService } from 'vs/platform/theme/common/themeService';
|
||||
import { IDisposable } from 'vs/base/common/lifecycle';
|
||||
|
||||
interface IAnyResourceTemplateData {
|
||||
count: CountBadge;
|
||||
styler: IDisposable;
|
||||
}
|
||||
|
||||
interface IResourceTemplateData extends IAnyResourceTemplateData {
|
||||
interface IResourceTemplateData {
|
||||
resourceLabel: ResourceLabel;
|
||||
}
|
||||
|
||||
interface IFileResourceTemplateData extends IAnyResourceTemplateData {
|
||||
fileLabel: FileLabel;
|
||||
interface IProblemResourceTemplateData extends IResourceTemplateData {
|
||||
count: CountBadge;
|
||||
styler: IDisposable;
|
||||
}
|
||||
|
||||
interface IMarkerTemplateData {
|
||||
@@ -39,30 +35,35 @@ interface IMarkerTemplateData {
|
||||
lnCol: HTMLElement;
|
||||
}
|
||||
|
||||
interface IRelatedInformationTemplateData {
|
||||
description: HighlightedLabel;
|
||||
lnCol: HTMLElement;
|
||||
}
|
||||
|
||||
export class DataSource implements IDataSource {
|
||||
public getId(tree: ITree, element: MarkersModel | Resource | Marker): string {
|
||||
public getId(tree: ITree, element: any): string {
|
||||
if (element instanceof MarkersModel) {
|
||||
return 'root';
|
||||
}
|
||||
if (element instanceof Resource) {
|
||||
return element.uri.toString();
|
||||
}
|
||||
if (element instanceof Marker) {
|
||||
if (element instanceof NodeWithId) {
|
||||
return element.id;
|
||||
}
|
||||
return '';
|
||||
}
|
||||
|
||||
public hasChildren(tree: ITree, element: any): boolean {
|
||||
return element instanceof MarkersModel || element instanceof Resource;
|
||||
return element instanceof MarkersModel || element instanceof ResourceData || (element instanceof Marker && element.resourceRelatedInformation.length > 0);
|
||||
}
|
||||
|
||||
public getChildren(tree: ITree, element: MarkersModel | Resource): Promise {
|
||||
public getChildren(tree: ITree, element: any): Promise {
|
||||
if (element instanceof MarkersModel) {
|
||||
return Promise.as(element.resources);
|
||||
}
|
||||
if (element instanceof Resource) {
|
||||
return Promise.as(element.markers);
|
||||
if (element instanceof ResourceData) {
|
||||
return Promise.as(element.data);
|
||||
}
|
||||
if (element instanceof Marker && element.resourceRelatedInformation.length > 0) {
|
||||
return Promise.as(element.resourceRelatedInformation);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
@@ -73,9 +74,9 @@ export class DataSource implements IDataSource {
|
||||
}
|
||||
|
||||
export class DataFilter implements IFilter {
|
||||
public isVisible(tree: ITree, element: Resource | Marker | any): boolean {
|
||||
if (element instanceof Resource) {
|
||||
return element.filteredMarkersCount > 0;
|
||||
public isVisible(tree: ITree, element: any): boolean {
|
||||
if (element instanceof ResourceMarkers) {
|
||||
return element.count > 0;
|
||||
}
|
||||
if (element instanceof Marker) {
|
||||
return element.isSelected;
|
||||
@@ -86,9 +87,12 @@ export class DataFilter implements IFilter {
|
||||
|
||||
export class Renderer implements IRenderer {
|
||||
|
||||
private static readonly RESOURCE_TEMPLATE_ID = 'resource-template';
|
||||
private static readonly FILE_RESOURCE_TEMPLATE_ID = 'file-resource-template';
|
||||
private static readonly PROBLEM_RESOURCE_TEMPLATE_ID = 'problem-resource-template';
|
||||
private static readonly PROBLEM_FILE_RESOURCE_TEMPLATE_ID = 'problem-file-resource-template';
|
||||
private static readonly RELATED_RESOURCE_TEMPLATE_ID = 'related-resource-template';
|
||||
private static readonly RELATED_FILE_RESOURCE_TEMPLATE_ID = 'related-file-resource-template';
|
||||
private static readonly MARKER_TEMPLATE_ID = 'marker-template';
|
||||
private static readonly RELATED_INFORMATION_TEMPLATE_ID = 'related-info-template';
|
||||
|
||||
constructor(
|
||||
@IInstantiationService private instantiationService: IInstantiationService,
|
||||
@@ -101,35 +105,63 @@ export class Renderer implements IRenderer {
|
||||
}
|
||||
|
||||
public getTemplateId(tree: ITree, element: any): string {
|
||||
if (element instanceof Resource) {
|
||||
if ((<Resource>element).uri.scheme === network.Schemas.file || (<Resource>element).uri.scheme === network.Schemas.untitled) {
|
||||
return Renderer.FILE_RESOURCE_TEMPLATE_ID;
|
||||
if (element instanceof ResourceMarkers) {
|
||||
if ((element).uri.scheme === network.Schemas.file || (<ResourceMarkers>element).uri.scheme === network.Schemas.untitled) {
|
||||
return Renderer.PROBLEM_FILE_RESOURCE_TEMPLATE_ID;
|
||||
} else {
|
||||
return Renderer.RESOURCE_TEMPLATE_ID;
|
||||
return Renderer.PROBLEM_RESOURCE_TEMPLATE_ID;
|
||||
}
|
||||
}
|
||||
if (element instanceof ResourceData) {
|
||||
if ((element).uri.scheme === network.Schemas.file || (<ResourceMarkers>element).uri.scheme === network.Schemas.untitled) {
|
||||
return Renderer.RELATED_FILE_RESOURCE_TEMPLATE_ID;
|
||||
} else {
|
||||
return Renderer.RELATED_RESOURCE_TEMPLATE_ID;
|
||||
}
|
||||
}
|
||||
if (element instanceof Marker) {
|
||||
return Renderer.MARKER_TEMPLATE_ID;
|
||||
}
|
||||
if (element instanceof RelatedInformation) {
|
||||
return Renderer.RELATED_INFORMATION_TEMPLATE_ID;
|
||||
}
|
||||
return '';
|
||||
}
|
||||
|
||||
public renderTemplate(tree: ITree, templateId: string, container: HTMLElement): any {
|
||||
dom.addClass(container, 'markers-panel-tree-entry');
|
||||
switch (templateId) {
|
||||
case Renderer.FILE_RESOURCE_TEMPLATE_ID:
|
||||
case Renderer.PROBLEM_FILE_RESOURCE_TEMPLATE_ID:
|
||||
return this.renderProblemFileResourceTemplate(container);
|
||||
case Renderer.PROBLEM_RESOURCE_TEMPLATE_ID:
|
||||
return this.renderProblemResourceTemplate(container);
|
||||
case Renderer.RELATED_FILE_RESOURCE_TEMPLATE_ID:
|
||||
return this.renderFileResourceTemplate(container);
|
||||
case Renderer.RESOURCE_TEMPLATE_ID:
|
||||
case Renderer.RELATED_RESOURCE_TEMPLATE_ID:
|
||||
return this.renderResourceTemplate(container);
|
||||
case Renderer.MARKER_TEMPLATE_ID:
|
||||
return this.renderMarkerTemplate(container);
|
||||
case Renderer.RELATED_INFORMATION_TEMPLATE_ID:
|
||||
return this.renderRelatedInformationTemplate(container);
|
||||
}
|
||||
}
|
||||
|
||||
private renderFileResourceTemplate(container: HTMLElement): IFileResourceTemplateData {
|
||||
const data: IFileResourceTemplateData = Object.create(null);
|
||||
private renderFileResourceTemplate(container: HTMLElement): IResourceTemplateData {
|
||||
const data: IProblemResourceTemplateData = Object.create(null);
|
||||
const resourceLabelContainer = dom.append(container, dom.$('.resource-label-container'));
|
||||
data.fileLabel = this.instantiationService.createInstance(FileLabel, resourceLabelContainer, { supportHighlights: true });
|
||||
data.resourceLabel = this.instantiationService.createInstance(FileLabel, resourceLabelContainer, { supportHighlights: true });
|
||||
return data;
|
||||
}
|
||||
|
||||
private renderResourceTemplate(container: HTMLElement): IResourceTemplateData {
|
||||
const data: IProblemResourceTemplateData = Object.create(null);
|
||||
const resourceLabelContainer = dom.append(container, dom.$('.resource-label-container'));
|
||||
data.resourceLabel = this.instantiationService.createInstance(ResourceLabel, resourceLabelContainer, { supportHighlights: true });
|
||||
return data;
|
||||
}
|
||||
|
||||
private renderProblemFileResourceTemplate(container: HTMLElement): IProblemResourceTemplateData {
|
||||
const data = <IProblemResourceTemplateData>this.renderFileResourceTemplate(container);
|
||||
|
||||
const badgeWrapper = dom.append(container, dom.$('.count-badge-wrapper'));
|
||||
data.count = new CountBadge(badgeWrapper);
|
||||
@@ -138,10 +170,8 @@ export class Renderer implements IRenderer {
|
||||
return data;
|
||||
}
|
||||
|
||||
private renderResourceTemplate(container: HTMLElement): IResourceTemplateData {
|
||||
const data: IResourceTemplateData = Object.create(null);
|
||||
const resourceLabelContainer = dom.append(container, dom.$('.resource-label-container'));
|
||||
data.resourceLabel = this.instantiationService.createInstance(ResourceLabel, resourceLabelContainer, { supportHighlights: true });
|
||||
private renderProblemResourceTemplate(container: HTMLElement): IProblemResourceTemplateData {
|
||||
const data = <IProblemResourceTemplateData>this.renderResourceTemplate(container);
|
||||
|
||||
const badgeWrapper = dom.append(container, dom.$('.count-badge-wrapper'));
|
||||
data.count = new CountBadge(badgeWrapper);
|
||||
@@ -159,23 +189,36 @@ export class Renderer implements IRenderer {
|
||||
return data;
|
||||
}
|
||||
|
||||
private renderRelatedInformationTemplate(container: HTMLElement): IRelatedInformationTemplateData {
|
||||
const data: IRelatedInformationTemplateData = Object.create(null);
|
||||
data.description = new HighlightedLabel(dom.append(container, dom.$('.marker-description')));
|
||||
data.lnCol = dom.append(container, dom.$('span.marker-line'));
|
||||
return data;
|
||||
}
|
||||
|
||||
public renderElement(tree: ITree, element: any, templateId: string, templateData: any): void {
|
||||
switch (templateId) {
|
||||
case Renderer.FILE_RESOURCE_TEMPLATE_ID:
|
||||
case Renderer.RESOURCE_TEMPLATE_ID:
|
||||
return this.renderResourceElement(tree, <Resource>element, templateData);
|
||||
case Renderer.PROBLEM_FILE_RESOURCE_TEMPLATE_ID:
|
||||
case Renderer.PROBLEM_RESOURCE_TEMPLATE_ID:
|
||||
case Renderer.RELATED_FILE_RESOURCE_TEMPLATE_ID:
|
||||
case Renderer.RELATED_RESOURCE_TEMPLATE_ID:
|
||||
return this.renderResourceElement(tree, <ResourceData<any>>element, templateData);
|
||||
case Renderer.MARKER_TEMPLATE_ID:
|
||||
return this.renderMarkerElement(tree, (<Marker>element), templateData);
|
||||
case Renderer.RELATED_INFORMATION_TEMPLATE_ID:
|
||||
return this.renderRelatedInformationElement(tree, (<RelatedInformation>element), templateData);
|
||||
}
|
||||
}
|
||||
|
||||
private renderResourceElement(tree: ITree, element: Resource, templateData: IAnyResourceTemplateData) {
|
||||
if ((<IFileResourceTemplateData>templateData).fileLabel) {
|
||||
(<IFileResourceTemplateData>templateData).fileLabel.setFile(element.uri, { matches: element.uriMatches });
|
||||
} else if ((<IResourceTemplateData>templateData).resourceLabel) {
|
||||
(<IResourceTemplateData>templateData).resourceLabel.setLabel({ name: element.name, description: element.uri.toString(), resource: element.uri }, { matches: element.uriMatches });
|
||||
private renderResourceElement(tree: ITree, element: ResourceData<any>, templateData: IResourceTemplateData | IProblemResourceTemplateData) {
|
||||
if (templateData.resourceLabel instanceof FileLabel) {
|
||||
templateData.resourceLabel.setFile(element.uri, { matches: element.uriMatches });
|
||||
} else {
|
||||
templateData.resourceLabel.setLabel({ name: element.name, description: element.uri.toString(), resource: element.uri }, { matches: element.uriMatches });
|
||||
}
|
||||
if ((<IProblemResourceTemplateData>templateData).count) {
|
||||
(<IProblemResourceTemplateData>templateData).count.setCount(element.count);
|
||||
}
|
||||
templateData.count.setCount(element.filteredMarkersCount);
|
||||
}
|
||||
|
||||
private renderMarkerElement(tree: ITree, element: Marker, templateData: IMarkerTemplateData) {
|
||||
@@ -190,6 +233,12 @@ export class Renderer implements IRenderer {
|
||||
templateData.lnCol.textContent = Messages.MARKERS_PANEL_AT_LINE_COL_NUMBER(marker.startLineNumber, marker.startColumn);
|
||||
}
|
||||
|
||||
private renderRelatedInformationElement(tree: ITree, element: RelatedInformation, templateData: IRelatedInformationTemplateData) {
|
||||
templateData.description.set(element.relatedInformation.message, element.matches);
|
||||
templateData.description.element.title = element.relatedInformation.message;
|
||||
templateData.lnCol.textContent = Messages.MARKERS_PANEL_AT_LINE_COL_NUMBER(element.relatedInformation.startLineNumber, element.relatedInformation.startColumn);
|
||||
}
|
||||
|
||||
private static iconClassNameFor(element: IMarker): string {
|
||||
switch (element.severity) {
|
||||
case MarkerSeverity.Hint:
|
||||
@@ -205,15 +254,16 @@ export class Renderer implements IRenderer {
|
||||
}
|
||||
|
||||
public disposeTemplate(tree: ITree, templateId: string, templateData: any): void {
|
||||
if (templateId === Renderer.FILE_RESOURCE_TEMPLATE_ID) {
|
||||
(<IFileResourceTemplateData>templateData).fileLabel.dispose();
|
||||
(<IFileResourceTemplateData>templateData).styler.dispose();
|
||||
} else if (templateId === Renderer.RESOURCE_TEMPLATE_ID) {
|
||||
(<IResourceTemplateData>templateData).resourceLabel.dispose();
|
||||
(<IResourceTemplateData>templateData).styler.dispose();
|
||||
if (templateId === Renderer.PROBLEM_RESOURCE_TEMPLATE_ID || templateId === Renderer.PROBLEM_FILE_RESOURCE_TEMPLATE_ID) {
|
||||
(<IProblemResourceTemplateData>templateData).resourceLabel.dispose();
|
||||
(<IProblemResourceTemplateData>templateData).styler.dispose();
|
||||
} else if (templateId === Renderer.RELATED_RESOURCE_TEMPLATE_ID || templateId === Renderer.RELATED_FILE_RESOURCE_TEMPLATE_ID) {
|
||||
(<IProblemResourceTemplateData>templateData).resourceLabel.dispose();
|
||||
} else if (templateId === Renderer.MARKER_TEMPLATE_ID) {
|
||||
(<IMarkerTemplateData>templateData).description.dispose();
|
||||
(<IMarkerTemplateData>templateData).source.dispose();
|
||||
} else if (templateId === Renderer.RELATED_INFORMATION_TEMPLATE_ID) {
|
||||
(<IRelatedInformationTemplateData>templateData).description.dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -221,11 +271,17 @@ export class Renderer implements IRenderer {
|
||||
export class MarkersTreeAccessibilityProvider implements IAccessibilityProvider {
|
||||
|
||||
public getAriaLabel(tree: ITree, element: any): string {
|
||||
if (element instanceof Resource) {
|
||||
return Messages.MARKERS_TREE_ARIA_LABEL_RESOURCE(element.name, element.filteredMarkersCount);
|
||||
if (element instanceof ResourceMarkers) {
|
||||
return Messages.MARKERS_TREE_ARIA_LABEL_RESOURCE(element.name, element.count);
|
||||
}
|
||||
if (element instanceof Marker) {
|
||||
return Messages.MARKERS_TREE_ARIA_LABEL_MARKER(element.raw);
|
||||
return Messages.MARKERS_TREE_ARIA_LABEL_MARKER(element);
|
||||
}
|
||||
if (element instanceof ResourceData) {
|
||||
return element.name;
|
||||
}
|
||||
if (element instanceof RelatedInformation) {
|
||||
return Messages.MARKERS_TREE_ARIA_LABEL_RELATED_INFORMATION(element.relatedInformation);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -5,7 +5,8 @@
|
||||
'use strict';
|
||||
|
||||
import * as nls from 'vs/nls';
|
||||
import { IMarker, MarkerSeverity } from 'vs/platform/markers/common/markers';
|
||||
import { MarkerSeverity, IRelatedInformation } from 'vs/platform/markers/common/markers';
|
||||
import { Marker } from './markersModel';
|
||||
|
||||
export default class Messages {
|
||||
|
||||
@@ -40,23 +41,24 @@ export default class Messages {
|
||||
public static readonly MARKERS_PANEL_AT_LINE_COL_NUMBER = (ln: number, col: number): string => { return nls.localize('markers.panel.at.ln.col.number', "({0}, {1})", '' + ln, '' + col); };
|
||||
|
||||
public static readonly MARKERS_TREE_ARIA_LABEL_RESOURCE = (fileName: string, noOfProblems: number): string => { return nls.localize('problems.tree.aria.label.resource', "{0} with {1} problems", fileName, noOfProblems); };
|
||||
public static readonly MARKERS_TREE_ARIA_LABEL_MARKER = (marker: IMarker): string => {
|
||||
switch (marker.severity) {
|
||||
public static readonly MARKERS_TREE_ARIA_LABEL_MARKER = (marker: Marker): string => {
|
||||
const relatedInformationMessage = marker.resourceRelatedInformation.length ? nls.localize('problems.tree.aria.label.marker.relatedInformation', " This problem has references to {0} locations.", marker.resourceRelatedInformation.reduce((count, r) => count + r.count, 0)) : '';
|
||||
switch (marker.raw.severity) {
|
||||
case MarkerSeverity.Error:
|
||||
return marker.source ? nls.localize('problems.tree.aria.label.error.marker', "Error generated by {0}: {1} at line {2} and character {3}", marker.source, marker.message, marker.startLineNumber, marker.startColumn)
|
||||
: nls.localize('problems.tree.aria.label.error.marker.nosource', "Error: {0} at line {1} and character {2}", marker.message, marker.startLineNumber, marker.startColumn);
|
||||
return marker.raw.source ? nls.localize('problems.tree.aria.label.error.marker', "Error generated by {0}: {1} at line {2} and character {3}.{4}", marker.raw.source, marker.raw.message, marker.raw.startLineNumber, marker.raw.startColumn, relatedInformationMessage)
|
||||
: nls.localize('problems.tree.aria.label.error.marker.nosource', "Error: {0} at line {1} and character {2}.{3}", marker.raw.message, marker.raw.startLineNumber, marker.raw.startColumn, relatedInformationMessage);
|
||||
case MarkerSeverity.Warning:
|
||||
return marker.source ? nls.localize('problems.tree.aria.label.warning.marker', "Warning generated by {0}: {1} at line {2} and character {3}", marker.source, marker.message, marker.startLineNumber, marker.startColumn)
|
||||
: nls.localize('problems.tree.aria.label.warning.marker.nosource', "Warning: {0} at line {1} and character {2}", marker.message, marker.startLineNumber, marker.startColumn);
|
||||
return marker.raw.source ? nls.localize('problems.tree.aria.label.warning.marker', "Warning generated by {0}: {1} at line {2} and character {3}.{4}", marker.raw.source, marker.raw.message, marker.raw.startLineNumber, marker.raw.startColumn, relatedInformationMessage)
|
||||
: nls.localize('problems.tree.aria.label.warning.marker.nosource', "Warning: {0} at line {1} and character {2}.{3}", marker.raw.message, marker.raw.startLineNumber, marker.raw.startColumn, relatedInformationMessage, relatedInformationMessage);
|
||||
|
||||
case MarkerSeverity.Info:
|
||||
return marker.source ? nls.localize('problems.tree.aria.label.info.marker', "Info generated by {0}: {1} at line {2} and character {3}", marker.source, marker.message, marker.startLineNumber, marker.startColumn)
|
||||
: nls.localize('problems.tree.aria.label.info.marker.nosource', "Info: {0} at line {1} and character {2}", marker.message, marker.startLineNumber, marker.startColumn);
|
||||
return marker.raw.source ? nls.localize('problems.tree.aria.label.info.marker', "Info generated by {0}: {1} at line {2} and character {3}.{4}", marker.raw.source, marker.raw.message, marker.raw.startLineNumber, marker.raw.startColumn, relatedInformationMessage)
|
||||
: nls.localize('problems.tree.aria.label.info.marker.nosource', "Info: {0} at line {1} and character {2}.{3}", marker.raw.message, marker.raw.startLineNumber, marker.raw.startColumn, relatedInformationMessage);
|
||||
default:
|
||||
return marker.source ? nls.localize('problems.tree.aria.label.marker', "Problem generated by {0}: {1} at line {2} and character {3}", marker.source, marker.message, marker.startLineNumber, marker.startColumn)
|
||||
: nls.localize('problems.tree.aria.label.marker.nosource', "Problem: {0} at line {1} and character {2}", marker.message, marker.startLineNumber, marker.startColumn);
|
||||
return marker.raw.source ? nls.localize('problems.tree.aria.label.marker', "Problem generated by {0}: {1} at line {2} and character {3}.{4}", marker.raw.source, marker.raw.message, marker.raw.startLineNumber, marker.raw.startColumn, relatedInformationMessage)
|
||||
: nls.localize('problems.tree.aria.label.marker.nosource', "Problem: {0} at line {1} and character {2}.{3}", marker.raw.message, marker.raw.startLineNumber, marker.raw.startColumn, relatedInformationMessage);
|
||||
}
|
||||
}
|
||||
|
||||
public static readonly MARKERS_TREE_ARIA_LABEL_RELATED_INFORMATION = (relatedInformation: IRelatedInformation): string => nls.localize('problems.tree.aria.label.relatedinfo.message', "{0} at line {1} and character {2}", relatedInformation.message, relatedInformation.startLineNumber, relatedInformation.startColumn);
|
||||
public static SHOW_ERRORS_WARNINGS_ACTION_LABEL: string = nls.localize('errors.warnings.show.label', "Show Errors and Warnings");
|
||||
}
|
||||
|
||||
@@ -8,19 +8,19 @@
|
||||
import * as assert from 'assert';
|
||||
import URI from 'vs/base/common/uri';
|
||||
import { IMarker, MarkerSeverity } from 'vs/platform/markers/common/markers';
|
||||
import { MarkersModel, Marker, Resource } from 'vs/workbench/parts/markers/electron-browser/markersModel';
|
||||
import { MarkersModel, Marker, ResourceMarkers } from 'vs/workbench/parts/markers/electron-browser/markersModel';
|
||||
|
||||
class TestMarkersModel extends MarkersModel {
|
||||
|
||||
get filteredResources(): Resource[] {
|
||||
let res: Resource[] = [];
|
||||
get filteredResources(): ResourceMarkers[] {
|
||||
let res: ResourceMarkers[] = [];
|
||||
this.forEachFilteredResource(resource => res.push(resource));
|
||||
return res;
|
||||
}
|
||||
|
||||
static compare(a: any, b: any): number {
|
||||
if (a instanceof Resource && b instanceof Resource) {
|
||||
return Resource.compare(a, b);
|
||||
if (a instanceof ResourceMarkers && b instanceof ResourceMarkers) {
|
||||
return ResourceMarkers.compare(a, b);
|
||||
}
|
||||
if (a instanceof Marker && b instanceof Marker) {
|
||||
return Marker.compare(a, b);
|
||||
@@ -45,22 +45,22 @@ suite('MarkersModel Test', () => {
|
||||
assert.equal(4, actuals.length);
|
||||
|
||||
assert.ok(compareResource(actuals[0], 'res1'));
|
||||
assert.equal(2, actuals[0].markers.length);
|
||||
assert.ok(hasMarker(actuals[0].markers, marker1));
|
||||
assert.ok(hasMarker(actuals[0].markers, marker3));
|
||||
assert.equal(2, actuals[0].data.length);
|
||||
assert.ok(hasMarker(actuals[0].data, marker1));
|
||||
assert.ok(hasMarker(actuals[0].data, marker3));
|
||||
|
||||
assert.ok(compareResource(actuals[1], 'res2'));
|
||||
assert.equal(2, actuals[1].markers.length);
|
||||
assert.ok(hasMarker(actuals[1].markers, marker2));
|
||||
assert.ok(hasMarker(actuals[1].markers, marker6));
|
||||
assert.equal(2, actuals[1].data.length);
|
||||
assert.ok(hasMarker(actuals[1].data, marker2));
|
||||
assert.ok(hasMarker(actuals[1].data, marker6));
|
||||
|
||||
assert.ok(compareResource(actuals[2], 'res3'));
|
||||
assert.equal(1, actuals[2].markers.length);
|
||||
assert.ok(hasMarker(actuals[2].markers, marker4));
|
||||
assert.equal(1, actuals[2].data.length);
|
||||
assert.ok(hasMarker(actuals[2].data, marker4));
|
||||
|
||||
assert.ok(compareResource(actuals[3], 'res4'));
|
||||
assert.equal(1, actuals[3].markers.length);
|
||||
assert.ok(hasMarker(actuals[3].markers, marker5));
|
||||
assert.equal(1, actuals[3].data.length);
|
||||
assert.ok(hasMarker(actuals[3].data, marker5));
|
||||
});
|
||||
|
||||
test('sort palces resources with no errors at the end', function () {
|
||||
@@ -119,7 +119,7 @@ suite('MarkersModel Test', () => {
|
||||
let marker15 = anErrorWithRange(8, 2, 8, 4);
|
||||
let testObject = new TestMarkersModel([marker1, marker2, marker3, marker4, marker5, marker6, marker7, marker8, marker9, marker10, marker11, marker12, marker13, marker14, marker15]);
|
||||
|
||||
let actuals = testObject.filteredResources[0].markers.sort(TestMarkersModel.compare);
|
||||
let actuals = testObject.filteredResources[0].data.sort(TestMarkersModel.compare);
|
||||
|
||||
assert.equal(actuals[0].raw, marker6);
|
||||
assert.equal(actuals[1].raw, marker14);
|
||||
@@ -153,7 +153,7 @@ suite('MarkersModel Test', () => {
|
||||
}).length === 1;
|
||||
}
|
||||
|
||||
function compareResource(a: Resource, b: string): boolean {
|
||||
function compareResource(a: ResourceMarkers, b: string): boolean {
|
||||
return a.uri.toString() === URI.file(b).toString();
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user