diff --git a/src/vs/workbench/buildfile.js b/src/vs/workbench/buildfile.js index f6b793139f30a7a02737a7ccd10b8aaa400b5a65..e578ac9be9a0dbe8546f5b445a9eebe37f16f38b 100644 --- a/src/vs/workbench/buildfile.js +++ b/src/vs/workbench/buildfile.js @@ -37,6 +37,8 @@ exports.collectModules= function(excludes) { createModuleDescription('vs/workbench/parts/debug/browser/debugViewlet', excludes), createModuleDescription('vs/workbench/parts/debug/browser/repl', excludes), + createModuleDescription('vs/workbench/parts/errorList/browser/errorList', excludes), + createModuleDescription('vs/workbench/services/search/node/searchApp', []), createModuleDescription('vs/workbench/services/files/node/watcher/unix/watcherApp', []), diff --git a/src/vs/workbench/parts/errorList/browser/errorList.contribution.ts b/src/vs/workbench/parts/errorList/browser/errorList.contribution.ts new file mode 100644 index 0000000000000000000000000000000000000000..89986d9499c4b83bde205ff2bbacd3159c44fb0d --- /dev/null +++ b/src/vs/workbench/parts/errorList/browser/errorList.contribution.ts @@ -0,0 +1,60 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import nls = require('vs/nls'); +import platform = require('vs/platform/platform'); +import panel = require('vs/workbench/browser/panel'); +import {ERROR_LIST_PANEL_ID} from 'vs/workbench/parts/errorList/browser/errorListConstants'; +import {IAction, Action} from 'vs/base/common/actions'; +import {IPartService} from 'vs/workbench/services/part/common/partService'; +import {IPanelService} from 'vs/workbench/services/panel/common/panelService'; +import {TPromise} from 'vs/base/common/winjs.base'; +import {IWorkbenchActionRegistry, Extensions as ActionExtensions} from 'vs/workbench/common/actionRegistry'; +import {SyncActionDescriptor} from 'vs/platform/actions/common/actions'; +import {KeyMod, KeyCode} from 'vs/base/common/keyCodes'; + +class ToggleErrorListAction extends Action { + + public static ID = 'workbench.action.errorList.toggle'; + public static LABEL = nls.localize('toggleErrorList', "Toggle Error List"); + + constructor(id: string, label: string, + @IPartService private partService: IPartService, + @IPanelService private panelService: IPanelService + ) { + super(id, label); + } + + public run(event?: any): TPromise { + const panel = this.panelService.getActivePanel(); + if (panel && panel.getId() === ERROR_LIST_PANEL_ID) { + this.partService.setPanelHidden(true); + + return TPromise.as(null); + } + + return this.panelService.openPanel(ERROR_LIST_PANEL_ID, true); + } + +} + +// register panel +(platform.Registry.as(panel.Extensions.Panels)).registerPanel(new panel.PanelDescriptor( + 'vs/workbench/parts/errorList/browser/errorList', + 'ErrorList', + ERROR_LIST_PANEL_ID, + nls.localize('errorListPanel', "Error List"), + 'errorList' +)); + + +// register toggle output action globally +let actionRegistry = platform.Registry.as(ActionExtensions.WorkbenchActions); +actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(ToggleErrorListAction, ToggleErrorListAction.ID, ToggleErrorListAction.LABEL, { + primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.KEY_A, + linux: { + primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.KEY_A + } +}), nls.localize('viewCategory', "View")); diff --git a/src/vs/workbench/parts/errorList/browser/errorList.ts b/src/vs/workbench/parts/errorList/browser/errorList.ts new file mode 100644 index 0000000000000000000000000000000000000000..3fa1daf10dd41253574b99e89b2f1297000cef3e --- /dev/null +++ b/src/vs/workbench/parts/errorList/browser/errorList.ts @@ -0,0 +1,187 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import 'vs/css!./media/errorList'; +import { TPromise } from 'vs/base/common/winjs.base'; +import lifecycle = require('vs/base/common/lifecycle'); +import { Panel } from 'vs/workbench/browser/panel'; +import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; +import builder = require('vs/base/browser/builder'); +import {ERROR_LIST_PANEL_ID} from 'vs/workbench/parts/errorList/browser/errorListConstants'; +import {IMarkerService, IMarker} from 'vs/platform/markers/common/markers'; +import { List } from 'vs/base/browser/ui/list/listWidget'; +import { IRenderer, IDelegate, IFocusChangeEvent, ISelectionChangeEvent } from 'vs/base/browser/ui/list/list'; +import { append, addClass, removeClass, toggleClass, emmet as $, hide, show } from 'vs/base/browser/dom'; +import Severity from 'vs/base/common/severity'; +import {IWorkbenchEditorService} from 'vs/workbench/services/editor/common/editorService'; +import * as errors from 'vs/base/common/errors'; +import * as paths from 'vs/base/common/paths'; + +interface IMarkerTemplateData { + icon: HTMLElement; + label: HTMLElement; + + file: HTMLElement; + line: HTMLElement; + column: HTMLElement; +} + +class Renderer implements IRenderer { + + constructor() { + + } + + get templateId(): string { + return 'errorListItem'; + } + + renderTemplate(container: HTMLElement): IMarkerTemplateData { + const data = Object.create(null); + + data.icon = append(container, $('.icon')); + data.label = append(container, $('span.label')); + + data.column = append(container, $('.column')); + data.line = append(container, $('.line')); + data.file = append(container, $('.file')); + + return data; + } + + disposeTemplate(templateData: IMarkerTemplateData): void { + // Nothing to do here + } + + renderElement(element: IMarker, index: number, templateData: IMarkerTemplateData): void { + templateData.icon.className = 'icon ' + Renderer.iconClassNameFor(element); + templateData.label.textContent = element.message; + + templateData.file.textContent = paths.basename(element.resource.fsPath); + templateData.line.textContent = String(element.startLineNumber); + templateData.column.textContent = String(element.startColumn); + } + + private static iconClassNameFor(element: IMarker): string { + switch (element.severity) { + case Severity.Ignore: + return 'info'; + case Severity.Info: + return 'info'; + case Severity.Warning: + return 'warning'; + case Severity.Error: + return 'error'; + } + return ''; + } +} + +const HEIGHT = 22; + +class Delegate implements IDelegate { + + constructor(private listProvider: () => List) { } + + getHeight(element: IMarker): number { + return HEIGHT; + } + + getTemplateId(element: IMarker): string { + return 'errorListItem'; + } +} + +export class ErrorList extends Panel { + + private toDispose: lifecycle.IDisposable[]; + private list: List; + private delegate: IDelegate; + private markerService: IMarkerService; + private _editorService: IWorkbenchEditorService; + + constructor( + @IMarkerService markerService: IMarkerService, + @ITelemetryService telemetryService: ITelemetryService, + @IWorkbenchEditorService editorService: IWorkbenchEditorService + ) { + super(ERROR_LIST_PANEL_ID, telemetryService); + this.markerService = markerService; + this._editorService = editorService; + + this.toDispose = []; + } + + public create(parent: builder.Builder): TPromise { + super.create(parent); + + addClass(parent.getHTMLElement(), 'new-error-list'); + + let renderer: IRenderer = new Renderer(); + + this.delegate = new Delegate(() => this.list); + this.list = new List(parent.getHTMLElement(), this.delegate, [renderer]); + + this.toDispose.push(this.markerService.onMarkerChanged((changedResources) => { + this._onMarkersChanged(); + })); + this.toDispose.push(this.list.onSelectionChange((e) => { + if (!e.elements.length) { + return; + } + let el = e.elements[0]; + this._editorService.openEditor({ + resource: el.resource, + options: { + selection: { + startLineNumber: el.startLineNumber, + startColumn: el.startColumn, + endLineNumber: el.endLineNumber, + endColumn: el.endColumn + } + } + }).done(null, errors.onUnexpectedError); + })); + this._onMarkersChanged(); + + return TPromise.as(null); + } + + private _onMarkersChanged(): void { + let allMarkers = this.markerService.read().slice(0); + + allMarkers.sort((a, b) => { + if (a.severity === b.severity) { + let aRes = a.resource.toString(); + let bRes = b.resource.toString(); + if (aRes === bRes) { + if (a.startLineNumber === b.startLineNumber) { + return a.startColumn - b.startColumn; + } + return a.startLineNumber - b.startLineNumber; + } + if (aRes < bRes) { + return -1; + } + if (aRes > bRes) { + return 1; + } + } + return b.severity - a.severity; + }); + + this.list.splice(0, this.list.length, ...allMarkers); + } + + public dispose(): void { + this.toDispose = lifecycle.disposeAll(this.toDispose); + this.list.dispose(); + super.dispose(); + } + + public layout(dimension: builder.Dimension): void { + this.list.layout(dimension.height); + } +} diff --git a/src/vs/workbench/parts/errorList/browser/errorListConstants.ts b/src/vs/workbench/parts/errorList/browser/errorListConstants.ts new file mode 100644 index 0000000000000000000000000000000000000000..c1f117eda03585f71bb785ab6e65093a14adb1e7 --- /dev/null +++ b/src/vs/workbench/parts/errorList/browser/errorListConstants.ts @@ -0,0 +1,6 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +export const ERROR_LIST_PANEL_ID = 'workbench.panel.errorList'; diff --git a/src/vs/workbench/parts/errorList/browser/media/errorList.css b/src/vs/workbench/parts/errorList/browser/media/errorList.css new file mode 100644 index 0000000000000000000000000000000000000000..e52c89ed1ac75d5c715cf3add5076bceb2785b6b --- /dev/null +++ b/src/vs/workbench/parts/errorList/browser/media/errorList.css @@ -0,0 +1,75 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +.new-error-list .monaco-list-row { + line-height: 22px; +} + +.new-error-list .icon { + float: left; + display: block; + width: 16px; + height: 22px; + margin-right: 4px; + margin-left: 4px; +} + + +.new-error-list .icon.warning { + background: url('status-warning.svg') center center no-repeat; +} + +.new-error-list .icon.error { + background: url('status-error.svg') center center no-repeat; +} + +.new-error-list .icon.info:before { + background: url('status-info.svg') center center no-repeat; +} + +.vs-dark .new-error-list .icon.warning { + background: url('status-warning-inverse.svg') center center no-repeat; +} + +.vs-dark .new-error-list .icon.error { + background: url('status-error-inverse.svg') center center no-repeat; +} + +.vs-dark .new-error-list .icon.info:before { + background: url('status-info-inverse.svg') center center no-repeat; +} + +.new-error-list .label { + display: block; + float: left; + text-overflow: ellipsis; + overflow: hidden; + /* icon: 16 + 4 + 4 */ + /* line: 20 + 4 + 4 */ + /* col: 20 + 4 + 4 */ + /* file: 100 + 4 + 4 */ + max-width: calc(100% - 24px - 28px - 28px - 108px - 20px) +} + +.new-error-list .file { + float: right; + margin: 0 4px; + width: 100px; +} + +.new-error-list .line { + float: right; + margin: 0 4px; + width: 20px; + text-align: center; +} + +.new-error-list .column { + float: right; + margin: 0 4px; + margin-right: 20px; + width: 20px; + text-align: center; +} diff --git a/src/vs/workbench/parts/errorList/browser/media/status-error-inverse.svg b/src/vs/workbench/parts/errorList/browser/media/status-error-inverse.svg new file mode 100644 index 0000000000000000000000000000000000000000..3c852a7ffde95dab5e0031517b5692aca17aac14 --- /dev/null +++ b/src/vs/workbench/parts/errorList/browser/media/status-error-inverse.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/vs/workbench/parts/errorList/browser/media/status-error.svg b/src/vs/workbench/parts/errorList/browser/media/status-error.svg new file mode 100644 index 0000000000000000000000000000000000000000..a1ddb39fed6a755eb9291cf128002c1a2269e703 --- /dev/null +++ b/src/vs/workbench/parts/errorList/browser/media/status-error.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/vs/workbench/parts/errorList/browser/media/status-info-inverse.svg b/src/vs/workbench/parts/errorList/browser/media/status-info-inverse.svg new file mode 100644 index 0000000000000000000000000000000000000000..d38c363e0e4cd4e72f0ef664e6f2e725360342d7 --- /dev/null +++ b/src/vs/workbench/parts/errorList/browser/media/status-info-inverse.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/vs/workbench/parts/errorList/browser/media/status-info.svg b/src/vs/workbench/parts/errorList/browser/media/status-info.svg new file mode 100644 index 0000000000000000000000000000000000000000..f1245e7bcfe98ec3e9b63ad314275653e2d4ac8c --- /dev/null +++ b/src/vs/workbench/parts/errorList/browser/media/status-info.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/vs/workbench/parts/errorList/browser/media/status-warning-inverse.svg b/src/vs/workbench/parts/errorList/browser/media/status-warning-inverse.svg new file mode 100644 index 0000000000000000000000000000000000000000..df44e61b3265c38e04f054eb6aebfa17901ad839 --- /dev/null +++ b/src/vs/workbench/parts/errorList/browser/media/status-warning-inverse.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/vs/workbench/parts/errorList/browser/media/status-warning.svg b/src/vs/workbench/parts/errorList/browser/media/status-warning.svg new file mode 100644 index 0000000000000000000000000000000000000000..f4e2a84b0af409036b5c141957e6f8fe3830279c --- /dev/null +++ b/src/vs/workbench/parts/errorList/browser/media/status-warning.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/vs/workbench/workbench.main.js b/src/vs/workbench/workbench.main.js index 701b06156a2614513be0d25ba4b2d545d24317c1..217f1dcd3e078836cf073e900955b40d868f9bad 100644 --- a/src/vs/workbench/workbench.main.js +++ b/src/vs/workbench/workbench.main.js @@ -48,6 +48,8 @@ define([ 'vs/workbench/parts/debug/electron-browser/debug.contribution', + 'vs/workbench/parts/errorList/browser/errorList.contribution', + 'vs/workbench/parts/html/browser/html.contribution', 'vs/workbench/parts/extensions/electron-browser/extensions.contribution',