diff --git a/src/vs/workbench/parts/markers/browser/MarkersPanel.ts b/src/vs/workbench/parts/markers/browser/MarkersPanel.ts index 302545a08db8f4c75b2dd132f4437f8f8c2d42e0..a097d2545fe7f2fe7cc275ec193375519c483547 100644 --- a/src/vs/workbench/parts/markers/browser/MarkersPanel.ts +++ b/src/vs/workbench/parts/markers/browser/MarkersPanel.ts @@ -3,8 +3,9 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import nls = require('vs/nls'); import 'vs/css!./media/markers'; +import * as errors from 'vs/base/common/errors'; +import * as Set from 'vs/base/common/set'; import URI from 'vs/base/common/uri'; import { TPromise } from 'vs/base/common/winjs.base'; import dom = require('vs/base/browser/dom'); @@ -13,11 +14,13 @@ import builder = require('vs/base/browser/builder'); import { IMarkerService } from 'vs/platform/markers/common/markers'; import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; import { Panel } from 'vs/workbench/browser/panel'; +import {IAction} from 'vs/base/common/actions'; import { IWorkbenchEditorService } from 'vs/workbench/services/editor/common/editorService'; import Constants from 'vs/workbench/parts/markers/common/Constants'; import { MarkersModel } from 'vs/workbench/parts/markers/common/MarkersModel'; import {Controller} from 'vs/workbench/parts/markers/browser/MarkersTreeController'; import Tree = require('vs/base/parts/tree/browser/tree'); +import {CollapseAction} from 'vs/base/parts/tree/browser/treeDefaults'; import TreeImpl = require('vs/base/parts/tree/browser/treeImpl'); import * as Viewer from 'vs/workbench/parts/markers/browser/MarkersTreeViewer'; import {IInstantiationService} from 'vs/platform/instantiation/common/instantiation'; @@ -28,7 +31,9 @@ export class MarkersPanel extends Panel { private markersModel: MarkersModel; private tree: Tree.ITree; - private _toDispose: lifecycle.IDisposable[]; + private toDispose: lifecycle.IDisposable[]; + private actions: IAction[]; + private handled: Set.ArraySet; constructor( @IInstantiationService private instantiationService: IInstantiationService, @@ -38,7 +43,8 @@ export class MarkersPanel extends Panel { ) { super(Constants.MARKERS_PANEL_ID, telemetryService); this.markersModel= new MarkersModel(); - this._toDispose = []; + this.toDispose = []; + this.handled= new Set.ArraySet(); } public create(parent: builder.Builder): TPromise { @@ -57,53 +63,72 @@ export class MarkersPanel extends Panel { twistiePixels: 20, }); - this._toDispose.push(this.markerService.onMarkerChanged((changedResources) => { + this.toDispose.push(this.markerService.onMarkerChanged((changedResources) => { this.updateTitleArea(); this.updateResources(changedResources); - this.tree.refresh(); + this.tree.refresh().then(this.autoExpand.bind(this)); })); this.render(); return TPromise.as(null); } public getTitle():string { - let title= ''; - let marketStatistics= this.markerService.getStatistics(); - title= this.appendToTitle(title, marketStatistics.errors, 'markers.panel.single.error.label', 'markers.panel.multiple.errors.label') - title= this.appendToTitle(title, marketStatistics.warnings, 'markers.panel.single.warning.label', 'markers.panel.multiple.warnings.label') - title= this.appendToTitle(title, marketStatistics.infos, 'markers.panel.single.info.label', 'markers.panel.multiple.infos.label') - title= this.appendToTitle(title, marketStatistics.unknwons, 'markers.panel.single.unknown.label', 'markers.panel.multiple.unknowns.label') + let markerStatistics= this.markerService.getStatistics(); + let title= MarkersModel.getStatisticsLabel(markerStatistics); return title ? title : Messages.getString('markers.panel.no.problems'); } - private appendToTitle(title: string, markersCount: number, singleMarkerKey: string, multipleMarkerKey: string): string { - if (markersCount <= 0) { - return title; - } - title= title ? title + ', ' : ''; - title += Messages.getString(markersCount === 1 ? singleMarkerKey : multipleMarkerKey, ''+markersCount); - return title; - } - public layout(dimension: builder.Dimension): void { this.tree.layout(dimension.height); } + public focus(): void { + this.tree.DOMFocus(); + this.tree.focusFirst(); + } + + public getActions(): IAction[] { + if (!this.actions) { + this.actions = [ + this.instantiationService.createInstance(CollapseAction, this.tree, true) + ]; + + this.actions.forEach(a => { + this.toDispose.push(a); + }); + } + return this.actions; + } + private updateResources(resources: URI[]) { resources.forEach((resource) => { - let markers= this.markerService.read({resource: resource}).slice(0) + let markers= this.markerService.read({resource: resource}).slice(0); this.markersModel.updateResource(resource, markers); - }) + }); } private render(): void { let allMarkers = this.markerService.read().slice(0); this.markersModel.updateMarkers(allMarkers); - this.tree.setInput(this.markersModel); + this.tree.setInput(this.markersModel).then(this.autoExpand.bind(this)); + } + + private autoExpand(): void { + this.markersModel.getResources().forEach((resource) => { + if (this.handled.contains(resource.uri.toString())) { + return; + } + if (resource.statistics.errors > 0 && resource.statistics.errors < 10) { + this.tree.expand(resource).done(null, errors.onUnexpectedError); + } else { + this.tree.collapse(resource).done(null, errors.onUnexpectedError); + } + this.handled.set(resource.uri.toString()); + }); } public dispose(): void { - this._toDispose = lifecycle.dispose(this._toDispose); + this.toDispose = lifecycle.dispose(this.toDispose); super.dispose(); } } \ No newline at end of file diff --git a/src/vs/workbench/parts/markers/browser/MarkersTreeController.ts b/src/vs/workbench/parts/markers/browser/MarkersTreeController.ts index 6aa58f0f3290c8be8b3ac815677d7f902802f24d..c181fd3cff5ef51c3ac258f8f3941696d4ef00e2 100644 --- a/src/vs/workbench/parts/markers/browser/MarkersTreeController.ts +++ b/src/vs/workbench/parts/markers/browser/MarkersTreeController.ts @@ -7,21 +7,19 @@ import * as errors from 'vs/base/common/errors'; import mouse = require('vs/base/browser/mouseEvent'); import keyboard = require('vs/base/browser/keyboardEvent'); -import actionsrenderer = require('vs/base/parts/tree/browser/actionsRenderer'); import tree = require('vs/base/parts/tree/browser/tree'); import treedefaults = require('vs/base/parts/tree/browser/treeDefaults'); -import { IContextMenuService } from 'vs/platform/contextview/browser/contextView'; import { CommonKeybindings } from 'vs/base/common/keyCodes'; import { Marker } from 'vs/workbench/parts/markers/common/MarkersModel'; import { IWorkbenchEditorService } from 'vs/workbench/services/editor/common/editorService'; +import {ICodeEditorService} from 'vs/editor/common/services/codeEditorService'; +import {ICommonCodeEditor} from 'vs/editor/common/editorCommon'; import { IMarker } from 'vs/platform/markers/common/markers'; export class Controller extends treedefaults.DefaultController { - private contextMenuService:IContextMenuService; - private actionProvider:actionsrenderer.IActionProvider; - - constructor(@IWorkbenchEditorService private editorService: IWorkbenchEditorService) { + constructor(@IWorkbenchEditorService private editorService: IWorkbenchEditorService, + @ICodeEditorService private codeEditorService: ICodeEditorService) { super({ clickBehavior: treedefaults.ClickBehavior.ON_MOUSE_UP }); this.downKeyBindingDispatcher.set(CommonKeybindings.SHIFT_UP_ARROW, this.onUp.bind(this)); this.downKeyBindingDispatcher.set(CommonKeybindings.SHIFT_DOWN_ARROW, this.onDown.bind(this)); @@ -36,7 +34,7 @@ export class Controller extends treedefaults.DefaultController { return super.onLeftClick(tree, element, event); } - protected onEnter(tree:tree.ITree, event:keyboard.IKeyboardEvent):boolean { + protected onEnter(tree: tree.ITree, event: keyboard.IKeyboardEvent): boolean { super.onEnter(tree, event); this.openFileAtElement(tree.getFocus()); return true; @@ -44,7 +42,7 @@ export class Controller extends treedefaults.DefaultController { private openFileAtElement(element: any) { if (element instanceof Marker) { - let marker= element.marker; + let marker = element.marker; this.editorService.openEditor({ resource: marker.resource, options: { @@ -60,4 +58,29 @@ export class Controller extends treedefaults.DefaultController { } return false; } + + public _preview(element: any): void { + if (element instanceof Marker) { + let marker = element.marker; + const editors = this.codeEditorService.listCodeEditors(); + let editor: ICommonCodeEditor; + for (let candidate of editors) { + if (!candidate.getModel() + || candidate.getModel().getAssociatedResource().toString() !== marker.resource.toString()) { + + continue; + } + + if (!editor || this.editorService.getActiveEditor() + && candidate === this.editorService.getActiveEditor().getControl()) { + + editor = candidate; + } + } + + if (editor) { + editor.revealRangeInCenter(marker); + } + } + } } diff --git a/src/vs/workbench/parts/markers/browser/MarkersTreeViewer.ts b/src/vs/workbench/parts/markers/browser/MarkersTreeViewer.ts index 2e143e82046ac54428082e6091c54957ada54736..9e0f20a63652fb25bc05a94bcf1da61ae5e05c52 100644 --- a/src/vs/workbench/parts/markers/browser/MarkersTreeViewer.ts +++ b/src/vs/workbench/parts/markers/browser/MarkersTreeViewer.ts @@ -15,9 +15,11 @@ import { CountBadge } from 'vs/base/browser/ui/countBadge/countBadge'; import { FileLabel } from 'vs/base/browser/ui/fileLabel/fileLabel'; import { IMarker } from 'vs/platform/markers/common/markers'; import { MarkersModel, Resource, Marker } from 'vs/workbench/parts/markers/common/MarkersModel'; +import MarkersStatisticsWidget from 'vs/workbench/parts/markers/browser/MarkersStatisticsWidget'; interface IResourceTemplateData { file: FileLabel; + statistics: MarkersStatisticsWidget; count: CountBadge; } @@ -97,6 +99,8 @@ export class Renderer implements IRenderer { var data: IResourceTemplateData = Object.create(null); data.file = new FileLabel(container, null, this.contextService); + // data.statistics= new MarkersStatisticsWidget(dom.append(container, dom.emmet('.marker-stats'))); + const badgeWrapper = dom.append(container, dom.emmet('.count-badge-wrapper')); data.count = new CountBadge(badgeWrapper); @@ -121,6 +125,7 @@ export class Renderer implements IRenderer { private renderResourceElement(tree: ITree, element: Resource, templateData: IResourceTemplateData) { templateData.file.setValue(element.uri); + // templateData.statistics.setStatistics(element.statistics); templateData.count.setCount(element.markers.length); } diff --git a/src/vs/workbench/parts/markers/browser/media/markers.css b/src/vs/workbench/parts/markers/browser/media/markers.css index 0bdfc8845d7bb26263ad5efec734d6f7d886b8e2..611f1362abcf6a6a1a98e42325bbf89400df08f2 100644 --- a/src/vs/workbench/parts/markers/browser/media/markers.css +++ b/src/vs/workbench/parts/markers/browser/media/markers.css @@ -12,14 +12,18 @@ margin-left: 4px; } -.markers-panel > .monaco-tree .monaco-tree-row .content .monaco-file-label { +.markers-panel > .monaco-tree .monaco-tree-row .content > * { vertical-align: middle; } +.markers-panel > .monaco-tree .monaco-tree-row .content .marker-stats { + display: inline-block; + margin-left: 10px; +} + .markers-panel > .monaco-tree .monaco-tree-row .content .count-badge-wrapper { - display: block; - float: right; - margin-right: 10px; + display: inline-block; + margin-left: 10px; line-height: 22px; } diff --git a/src/vs/workbench/parts/markers/common/MarkersModel.ts b/src/vs/workbench/parts/markers/common/MarkersModel.ts index c08e8646f413eff150411e84fbbee5b52a15599f..b48d3eba9c3b17c1a6e88f024cb3dd8e8d80701f 100644 --- a/src/vs/workbench/parts/markers/common/MarkersModel.ts +++ b/src/vs/workbench/parts/markers/common/MarkersModel.ts @@ -8,6 +8,7 @@ import * as Map from 'vs/base/common/map'; import Severity from 'vs/base/common/severity'; import URI from 'vs/base/common/uri'; import { IMarker, MarkerStatistics } from 'vs/platform/markers/common/markers'; +import Messages from 'vs/workbench/parts/markers/common/Messages'; export class Resource { constructor(public uri: URI, public markers: Marker[], public statistics: MarkerStatistics){}; @@ -29,10 +30,6 @@ export class MarkersModel { public getResources():Resource[] { var resources= this.markersByResource.entries().map(this.toResource.bind(this)); resources.sort((a: Resource, b: Resource) => { - let compare= this.compare(a.statistics, b.statistics); - if (compare !== 0) { - return compare; - } return a.uri.toString().localeCompare(b.uri.toString()); }); return resources; @@ -59,6 +56,23 @@ export class MarkersModel { }); } + public static getStatisticsLabel(marketStatistics: MarkerStatistics):string { + let label= this.getLabel('', marketStatistics.errors, 'markers.panel.single.error.label', 'markers.panel.multiple.errors.label'); + label= this.getLabel(label, marketStatistics.warnings, 'markers.panel.single.warning.label', 'markers.panel.multiple.warnings.label'); + label= this.getLabel(label, marketStatistics.infos, 'markers.panel.single.info.label', 'markers.panel.multiple.infos.label'); + label= this.getLabel(label, marketStatistics.unknwons, 'markers.panel.single.unknown.label', 'markers.panel.multiple.unknowns.label'); + return label; + } + + private static getLabel(title: string, markersCount: number, singleMarkerKey: string, multipleMarkerKey: string): string { + if (markersCount <= 0) { + return title; + } + title= title ? title + ', ' : ''; + title += Messages.getString(markersCount === 1 ? singleMarkerKey : multipleMarkerKey, ''+markersCount); + return title; + } + private toResource(entry: Map.Entry) { let markers= entry.value.map(this.toMarker); let resource= new Resource(entry.key, markers, this.getStatistics(entry.value)); @@ -69,34 +83,6 @@ export class MarkersModel { return new Marker(marker.resource.toString() + index, marker); } - private compare(stat1: MarkerStatistics, stat2: MarkerStatistics): number { - if (stat1.errors > stat2.errors) { - return -1; - } - if (stat2.errors > stat1.errors) { - return 1; - } - if (stat1.warnings > stat2.warnings) { - return -1; - } - if (stat2.warnings > stat1.warnings) { - return 1; - } - if (stat1.infos > stat2.infos) { - return -1; - } - if (stat2.infos > stat1.infos) { - return 1; - } - if (stat1.unknwons > stat2.unknwons) { - return -1; - } - if (stat2.unknwons > stat1.unknwons) { - return 1; - } - return 0; - } - private getStatistics(markers: IMarker[]): MarkerStatistics { let errors= 0, warnings= 0, infos= 0, unknowns = 0; markers.forEach((marker) => {