Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

plugin: Support LogOutputChannel #12429

Merged
merged 4 commits into from
Apr 21, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 6 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,16 @@
## History

- [Previous Changelogs](https://github.com/eclipse-theia/theia/tree/master/doc/changelogs/)
## v1.37.0 0 -

## v1.37.0 -

- [plugin] implemented the VS Code `LogOutputChannel` API [#12017](https://github.com/eclipse-theia/theia/pull/12429) - Contributed on behalf of STMicroelectronics

<a name="breaking_changes_1.37.0">[Breaking Changes:](#breaking_changes_1.37.0)</a>
- [core] Inject core preference into `DockPanelRenderer` constructor [12360](https://github.com/eclipse-theia/theia/pull/12360)
- [core] Introduced `ScrollableTabBar.updateTabs()` to fully render tabs [12360](https://github.com/eclipse-theia/theia/pull/12360)
- [plugin] `plugin/src/theia-proposed.d.ts`: removed enum `LogLevel` and namespace `env` [#12017](https://github.com/eclipse-theia/theia/pull/12429)
- [plugin-ext] `output-channel-item.ts`: changed visibility from `private` to `protected` for member `proxy` and function `validate()` [#12017](https://github.com/eclipse-theia/theia/pull/12429)

## v1.36.0 0 - 03/30/2023

Expand Down
3 changes: 2 additions & 1 deletion packages/plugin-ext/src/common/plugin-api-rpc.ts
Original file line number Diff line number Diff line change
Expand Up @@ -287,7 +287,8 @@ export interface TerminalServiceExt {
getEnvironmentVariableCollection(extensionIdentifier: string): theia.EnvironmentVariableCollection;
}
export interface OutputChannelRegistryExt {
createOutputChannel(name: string, pluginInfo: PluginInfo): theia.OutputChannel
createOutputChannel(name: string, pluginInfo: PluginInfo): theia.OutputChannel,
createOutputChannel(name: string, pluginInfo: PluginInfo, options: { log: true }): theia.LogOutputChannel
}

export interface ConnectionMain {
Expand Down
27 changes: 20 additions & 7 deletions packages/plugin-ext/src/plugin/output-channel-registry.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,12 @@
//
// SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
// *****************************************************************************
import {
PLUGIN_RPC_CONTEXT as Ext, OutputChannelRegistryMain, PluginInfo, OutputChannelRegistryExt
} from '../common/plugin-api-rpc';
import { RPCProtocol } from '../common/rpc-protocol';

import * as theia from '@theia/plugin';
import { PLUGIN_RPC_CONTEXT as Ext, OutputChannelRegistryExt, OutputChannelRegistryMain, PluginInfo } from '../common/plugin-api-rpc';
import { RPCProtocol } from '../common/rpc-protocol';
import { isObject } from '../common/types';
import { LogOutputChannelImpl } from './output-channel/log-output-channel';
import { OutputChannelImpl } from './output-channel/output-channel-item';

export class OutputChannelRegistryExtImpl implements OutputChannelRegistryExt {
Expand All @@ -28,12 +29,24 @@ export class OutputChannelRegistryExtImpl implements OutputChannelRegistryExt {
this.proxy = rpc.getProxy(Ext.OUTPUT_CHANNEL_REGISTRY_MAIN);
}

createOutputChannel(name: string, pluginInfo: PluginInfo): theia.OutputChannel {
createOutputChannel(name: string, pluginInfo: PluginInfo): theia.OutputChannel;
createOutputChannel(name: string, pluginInfo: PluginInfo, options: { log: true; }): theia.LogOutputChannel;
createOutputChannel(name: string, pluginInfo: PluginInfo, options?: { log: true; }): theia.OutputChannel | theia.LogOutputChannel {
name = name.trim();
if (!name) {
throw new Error('illegal argument \'name\'. must not be falsy');
} else {
return new OutputChannelImpl(name, this.proxy, pluginInfo);
}
const isLogOutput = options && isObject(options);
return isLogOutput
? this.doCreateLogOutputChannel(name, pluginInfo)
: this.doCreateOutputChannel(name, pluginInfo);
}

private doCreateOutputChannel(name: string, pluginInfo: PluginInfo): OutputChannelImpl {
return new OutputChannelImpl(name, this.proxy, pluginInfo);
}

private doCreateLogOutputChannel(name: string, pluginInfo: PluginInfo): LogOutputChannelImpl {
return new LogOutputChannelImpl(name, this.proxy, pluginInfo);
}
}
108 changes: 108 additions & 0 deletions packages/plugin-ext/src/plugin/output-channel/log-output-channel.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
// *****************************************************************************
// Copyright (C) 2023 STMicroelectronics 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
// *****************************************************************************
/* eslint-disable @typescript-eslint/no-explicit-any */

import { Emitter } from '@theia/core/shared/vscode-languageserver-protocol';
import * as theia from '@theia/plugin';

import { OutputChannelRegistryMain, PluginInfo } from '../../common/plugin-api-rpc';
import { OutputChannelImpl } from './output-channel-item';
import { LogLevel } from '../types-impl';
import { isArray, isObject } from '@theia/core';

export class LogOutputChannelImpl extends OutputChannelImpl implements theia.LogOutputChannel {

readonly onDidChangeLogLevelEmitter: Emitter<theia.LogLevel> = new Emitter<theia.LogLevel>();
readonly onDidChangeLogLevel: theia.Event<theia.LogLevel> = this.onDidChangeLogLevelEmitter.event;
public logLevel: theia.LogLevel;

constructor(name: string, proxy: OutputChannelRegistryMain, pluginInfo: PluginInfo) {
super(name, proxy, pluginInfo);
this.setLogLevel(LogLevel.Info);
}

setLogLevel(level: theia.LogLevel): void {
if (this.logLevel !== level) {
this.logLevel = level;
this.onDidChangeLogLevelEmitter.fire(this.logLevel);
}
}

getLogLevel(): theia.LogLevel {
return this.logLevel;
}

override append(value: string): void {
super.validate();
this.info(value);
tsmaeder marked this conversation as resolved.
Show resolved Hide resolved
}

override appendLine(value: string): void {
super.validate();
this.append(value + '\n');
}

override dispose(): void {
super.dispose();
this.onDidChangeLogLevelEmitter.dispose();
}

protected log(level: theia.LogLevel, message: string): void {
super.validate();
if (this.checkLogLevel(level)) {
const now = new Date();
const eol = message.endsWith('\n') ? '' : '\n';
const logMessage = `${now.toISOString()} [${LogLevel[level]}] ${message}${eol}`;
this.proxy.$append(this.name, logMessage, this.pluginInfo);
}
}

private checkLogLevel(level: theia.LogLevel): boolean {
return this.logLevel <= level;
}

trace(message: string, ...args: any[]): void {
this.log(LogLevel.Trace, this.format(message, args));
}

debug(message: string, ...args: any[]): void {
this.log(LogLevel.Debug, this.format(message, args));
}

info(message: string, ...args: any[]): void {
this.log(LogLevel.Info, this.format(message, args));
}

warn(message: string, ...args: any[]): void {
this.log(LogLevel.Warning, this.format(message, args));
}

error(errorMsg: string | Error, ...args: any[]): void {
if (errorMsg instanceof Error) {
this.log(LogLevel.Error, this.format(errorMsg.stack || errorMsg.message, args));
} else {
this.log(LogLevel.Error, this.format(errorMsg, args));
}
}

private format(message: string, args: any[]): string {
if (args.length > 0) {
return `${message} ${args.map((arg: any) => isObject(arg) || isArray(arg) ? JSON.stringify(arg) : arg).join(' ')}`;
}
return message;
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ export class OutputChannelImpl implements theia.OutputChannel {

private disposed: boolean;

constructor(readonly name: string, private proxy: OutputChannelRegistryMain, private readonly pluginInfo: PluginInfo) {
constructor(readonly name: string, protected readonly proxy: OutputChannelRegistryMain, protected readonly pluginInfo: PluginInfo) {
tsmaeder marked this conversation as resolved.
Show resolved Hide resolved
}

dispose(): void {
Expand Down Expand Up @@ -65,7 +65,7 @@ export class OutputChannelImpl implements theia.OutputChannel {
this.proxy.$close(this.name);
}

private validate(): void {
protected validate(): void {
tsmaeder marked this conversation as resolved.
Show resolved Hide resolved
if (this.disposed) {
throw new Error('Channel has been closed');
}
Expand Down
6 changes: 4 additions & 2 deletions packages/plugin-ext/src/plugin/plugin-context.ts
Original file line number Diff line number Diff line change
Expand Up @@ -483,8 +483,10 @@ export function createAPIFactory(

return statusBarMessageRegistryExt.createStatusBarItem(alignment, priority, id);
},
createOutputChannel(name: string): theia.OutputChannel {
return outputChannelRegistryExt.createOutputChannel(name, pluginToPluginInfo(plugin));
createOutputChannel(name: string, options?: { log: true }): any {
return !options
? outputChannelRegistryExt.createOutputChannel(name, pluginToPluginInfo(plugin))
: outputChannelRegistryExt.createOutputChannel(name, pluginToPluginInfo(plugin), options);
},
createWebviewPanel(viewType: string,
title: string,
Expand Down
5 changes: 2 additions & 3 deletions packages/plugin-ext/src/plugin/types-impl.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2734,13 +2734,12 @@ export namespace DebugAdapterInlineImplementation {
export type DebugAdapterDescriptor = DebugAdapterExecutable | DebugAdapterServer | DebugAdapterNamedPipeServer | DebugAdapterInlineImplementation;

export enum LogLevel {
Off = 0,
Trace = 1,
Debug = 2,
Info = 3,
Warning = 4,
Error = 5,
Critical = 6,
Off = 7
Error = 5
}

/**
Expand Down
29 changes: 0 additions & 29 deletions packages/plugin/src/theia-proposed.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -168,35 +168,6 @@ export module '@theia/plugin' {
color?: ThemeColor;
}

// #region LogLevel: https://github.com/microsoft/vscode/issues/85992

/**
* The severity level of a log message
*/
export enum LogLevel {
Trace = 1,
ndoschek marked this conversation as resolved.
Show resolved Hide resolved
Debug = 2,
Info = 3,
Warning = 4,
Error = 5,
Critical = 6,
Off = 7
}

export namespace env {
/**
* Current logging level.
*/
export const logLevel: LogLevel;

/**
* An [event](#Event) that fires when the log level has changed.
*/
export const onDidChangeLogLevel: Event<LogLevel>;
}

// #endregion

// #region search in workspace
/**
* The parameters of a query for text search.
Expand Down
Loading