From 368d10973c035af06bd4bc4b7174052dbf4dffbd Mon Sep 17 00:00:00 2001 From: Amiram Wingarten Date: Sat, 11 Apr 2020 23:39:42 +0300 Subject: [PATCH] [output] add severity/color to appendLine method Signed-off-by: Amiram Wingarten --- CHANGELOG.md | 1 + examples/api-samples/compile.tsconfig.json | 3 ++ examples/api-samples/package.json | 3 +- .../browser/api-samples-frontend-module.ts | 2 + .../sample-output-channel-with-severity.ts | 37 +++++++++++++++++++ packages/output/src/browser/output-widget.tsx | 14 +++++-- packages/output/src/browser/style/output.css | 8 ++++ packages/output/src/common/output-channel.ts | 27 ++++++++++---- 8 files changed, 82 insertions(+), 13 deletions(-) create mode 100644 examples/api-samples/src/browser/output/sample-output-channel-with-severity.ts diff --git a/CHANGELOG.md b/CHANGELOG.md index b245ea8501a47..7557361cc9b08 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,7 @@ ## v1.1.0 - [task] fixed presentation.reveal & focus for detected tasks [#7548](https://github.com/eclipse-theia/theia/pull/7548) +- [output] added optional argument `severity` to `OutputChannel.appendLine` method for coloring. Breaking changes: diff --git a/examples/api-samples/compile.tsconfig.json b/examples/api-samples/compile.tsconfig.json index 4e5540e26056b..3fa08280f9188 100644 --- a/examples/api-samples/compile.tsconfig.json +++ b/examples/api-samples/compile.tsconfig.json @@ -11,6 +11,9 @@ "references": [ { "path": "../../packages/core/compile.tsconfig.json" + }, + { + "path": "../../packages/output/compile.tsconfig.json" } ] } diff --git a/examples/api-samples/package.json b/examples/api-samples/package.json index b147fde9f3ffe..58e3ab0d9a7c2 100644 --- a/examples/api-samples/package.json +++ b/examples/api-samples/package.json @@ -4,7 +4,8 @@ "version": "1.0.0", "description": "Theia - Example code to demonstrate Theia API", "dependencies": { - "@theia/core": "^1.0.0" + "@theia/core": "^1.0.0", + "@theia/output": "^1.0.0" }, "theiaExtensions": [ { diff --git a/examples/api-samples/src/browser/api-samples-frontend-module.ts b/examples/api-samples/src/browser/api-samples-frontend-module.ts index afacf29ff68b5..2fac6d83ffaeb 100644 --- a/examples/api-samples/src/browser/api-samples-frontend-module.ts +++ b/examples/api-samples/src/browser/api-samples-frontend-module.ts @@ -17,8 +17,10 @@ import { ContainerModule } from 'inversify'; import { bindDynamicLabelProvider } from './label/sample-dynamic-label-provider-command-contribution'; import { bindSampleUnclosableView } from './view/sample-unclosable-view-contribution'; +import { bindSampleOutputChannelWithSeverity } from './output/sample-output-channel-with-severity'; export default new ContainerModule(bind => { bindDynamicLabelProvider(bind); bindSampleUnclosableView(bind); + bindSampleOutputChannelWithSeverity(bind); }); diff --git a/examples/api-samples/src/browser/output/sample-output-channel-with-severity.ts b/examples/api-samples/src/browser/output/sample-output-channel-with-severity.ts new file mode 100644 index 0000000000000..e8e72101199d9 --- /dev/null +++ b/examples/api-samples/src/browser/output/sample-output-channel-with-severity.ts @@ -0,0 +1,37 @@ +/******************************************************************************** + * Copyright (c) 2020 SAP SE or an SAP affiliate company and others. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + * + * This Source Code may also be made available under the following Secondary + * Licenses when the conditions for such availability set forth in the Eclipse + * Public License v. 2.0 are satisfied: GNU General Public License, version 2 + * with the GNU Classpath Exception which is available at + * https://www.gnu.org/software/classpath/license.html. + * + * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 + ********************************************************************************/ +import { FrontendApplicationContribution } from '@theia/core/lib/browser'; +import { inject, injectable, interfaces } from 'inversify'; +import { OutputChannelManager, OutputChannelSeverity } from '@theia/output/lib/common/output-channel'; + +@injectable() +export class SampleOutputChannelWithSeverity + implements FrontendApplicationContribution { + @inject(OutputChannelManager) + protected readonly outputChannelManager: OutputChannelManager; + public onStart(): void { + const channel = this.outputChannelManager.getChannel('my test channel'); + channel.appendLine('hello info1'); // showed without color + channel.appendLine('hello info2', OutputChannelSeverity.Info); + channel.appendLine('hello error', OutputChannelSeverity.Error); + channel.appendLine('hello warning', OutputChannelSeverity.Warning); + } +} +export const bindSampleOutputChannelWithSeverity = (bind: interfaces.Bind) => { + bind(FrontendApplicationContribution) + .to(SampleOutputChannelWithSeverity) + .inSingletonScope(); +}; diff --git a/packages/output/src/browser/output-widget.tsx b/packages/output/src/browser/output-widget.tsx index 3e0d60d9a1c2a..72fcf8000f4e0 100644 --- a/packages/output/src/browser/output-widget.tsx +++ b/packages/output/src/browser/output-widget.tsx @@ -16,7 +16,7 @@ import { inject, injectable, postConstruct } from 'inversify'; import { Message } from '@theia/core/lib/browser'; -import { OutputChannelManager, OutputChannel } from '../common/output-channel'; +import { OutputChannel, OutputChannelManager, OutputChannelSeverity } from '../common/output-channel'; import { ReactWidget } from '@theia/core/lib/browser/widgets/react-widget'; import * as React from 'react'; @@ -117,10 +117,16 @@ export class OutputWidget extends ReactWidget { }; if (this.outputChannelManager.selectedChannel) { - for (const text of this.outputChannelManager.selectedChannel.getLines()) { - const lines = text.split(/[\n\r]+/); + for (const outputChannelLine of this.outputChannelManager.selectedChannel.getLines()) { + const lines = outputChannelLine.text.split(/[\n\r]+/); + let className; + if (outputChannelLine.severity === OutputChannelSeverity.Error) { + className = 'theia-output-error'; + } else if (outputChannelLine.severity === OutputChannelSeverity.Warning) { + className = 'theia-output-warning'; + } for (const line of lines) { - result.push(
{line}
); + result.push(
{line}
); } } } diff --git a/packages/output/src/browser/style/output.css b/packages/output/src/browser/style/output.css index 2b277750b3d6b..0561490972001 100644 --- a/packages/output/src/browser/style/output.css +++ b/packages/output/src/browser/style/output.css @@ -63,3 +63,11 @@ .output-tab-icon::before { content: "\f024" } + +.theia-output-error { + color: var(--theia-errorForeground); +} + +.theia-output-warning { + color: var(--theia-editorWarning-foreground); +} diff --git a/packages/output/src/common/output-channel.ts b/packages/output/src/common/output-channel.ts index c1213f4bab76b..9d27021aef143 100644 --- a/packages/output/src/common/output-channel.ts +++ b/packages/output/src/common/output-channel.ts @@ -105,12 +105,22 @@ export class OutputChannelManager implements Disposable { } } +export enum OutputChannelSeverity { + Error = 1, + Warning = 2, + Info = 3 +} +export interface OutputChannelLine { + text: string; + severity?: OutputChannelSeverity; +} + export class OutputChannel { private readonly visibilityChangeEmitter = new Emitter<{ visible: boolean }>(); private readonly contentChangeEmitter = new Emitter(); - private lines: string[] = []; - private currentLine: string | undefined; + private lines: OutputChannelLine[] = []; + private currentLine: OutputChannelLine | undefined; private visible: boolean = true; readonly onVisibilityChange: Event<{ visible: boolean }> = this.visibilityChangeEmitter.event; @@ -120,19 +130,20 @@ export class OutputChannel { append(value: string): void { if (this.currentLine === undefined) { - this.currentLine = value; + this.currentLine = { text: value, severity: OutputChannelSeverity.Info }; } else { - this.currentLine += value; + this.currentLine.text += value; } this.contentChangeEmitter.fire(this); } - appendLine(line: string): void { + appendLine(line: string, severity = OutputChannelSeverity.Info): void { if (this.currentLine !== undefined) { - this.lines.push(this.currentLine + line); + this.currentLine.text = this.currentLine.text + line; + this.lines.push(this.currentLine); this.currentLine = undefined; } else { - this.lines.push(line); + this.lines.push({ text: line, severity }); } const maxChannelHistory = this.preferences['output.maxChannelHistory']; if (this.lines.length > maxChannelHistory) { @@ -152,7 +163,7 @@ export class OutputChannel { this.visibilityChangeEmitter.fire({ visible }); } - getLines(): string[] { + getLines(): OutputChannelLine[] { if (this.currentLine !== undefined) { return [...this.lines, this.currentLine]; } else {