Skip to content
This repository has been archived by the owner on Jun 20, 2018. It is now read-only.

Commit

Permalink
CHE-9836 add output channel API (#32)
Browse files Browse the repository at this point in the history
Signed-off-by: Oleksii Orel <oorel@redhat.com>
  • Loading branch information
olexii4 authored and benoitf committed Jun 19, 2018
1 parent ad0f594 commit b9a2ee8
Show file tree
Hide file tree
Showing 9 changed files with 256 additions and 5 deletions.
11 changes: 10 additions & 1 deletion packages/plugin-ext/src/api/plugin-api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -398,6 +398,14 @@ export interface PreferenceRegistryExt {
$acceptConfigurationChanged(data: { [key: string]: any }, eventData: PreferenceChange): void;
}

export interface OutputChannelRegistryMain {
$append(channelName: string, value: string): PromiseLike<void>;
$clear(channelName: string): PromiseLike<void>;
$dispose(channelName: string): PromiseLike<void>;
$reveal(channelName: string, preserveFocus: boolean): PromiseLike<void>;
$close(channelName: string): PromiseLike<void>;
}

export const PLUGIN_RPC_CONTEXT = {
COMMAND_REGISTRY_MAIN: <ProxyIdentifier<CommandRegistryMain>>createProxyIdentifier<CommandRegistryMain>('CommandRegistryMain'),
QUICK_OPEN_MAIN: createProxyIdentifier<QuickOpenMain>('QuickOpenMain'),
Expand All @@ -406,7 +414,8 @@ export const PLUGIN_RPC_CONTEXT = {
DOCUMENTS_MAIN: createProxyIdentifier<DocumentsMain>('DocumentsMain'),
STATUS_BAR_MESSAGE_REGISTRY_MAIN: <ProxyIdentifier<StatusBarMessageRegistryMain>>createProxyIdentifier<StatusBarMessageRegistryMain>('StatusBarMessageRegistryMain'),
ENV_MAIN: createProxyIdentifier<EnvMain>('EnvMain'),
PREFERENCE_REGISTRY_MAIN: createProxyIdentifier<PreferenceRegistryMain>('PreferenceRegistryMain')
PREFERENCE_REGISTRY_MAIN: createProxyIdentifier<PreferenceRegistryMain>('PreferenceRegistryMain'),
OUTPUT_CHANNEL_REGISTRY_MAIN: <ProxyIdentifier<OutputChannelRegistryMain>>createProxyIdentifier<OutputChannelRegistryMain>('OutputChannelRegistryMain')
};

export const MAIN_RPC_CONTEXT = {
Expand Down
5 changes: 4 additions & 1 deletion packages/plugin-ext/src/main/browser/main-context.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License.
* You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
*/

import { interfaces } from 'inversify';
import { CommandRegistryMainImpl } from './command-registry-main';
import { PreferenceRegistryMainImpl } from './preference-registry-main';
Expand All @@ -16,6 +15,7 @@ import { WindowStateMain } from './window-state-main';
import { StatusBarMessageRegistryMainImpl } from './status-bar-message-registry-main';
import { EnvMainImpl } from './env-main';
import { EditorsAndDocumentsMain } from './editors-and-documents-main';
import {OutputChannelRegistryMainImpl} from "./output-channel-registry-main";

export function setUpPluginApi(rpc: RPCProtocol, container: interfaces.Container): void {
const commandRegistryMain = new CommandRegistryMainImpl(rpc, container);
Expand Down Expand Up @@ -43,4 +43,7 @@ export function setUpPluginApi(rpc: RPCProtocol, container: interfaces.Container

const envMain = new EnvMainImpl(rpc, container);
rpc.set(PLUGIN_RPC_CONTEXT.ENV_MAIN, envMain);

const outputChannelRegistryMain = new OutputChannelRegistryMainImpl(container);
rpc.set(PLUGIN_RPC_CONTEXT.OUTPUT_CHANNEL_REGISTRY_MAIN, outputChannelRegistryMain);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
/*
* Copyright (C) 2018 Red Hat, Inc. and others.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License.
* You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
*/
import {interfaces} from 'inversify';
import {OUTPUT_WIDGET_KIND} from '@theia/output/lib/browser/output-widget';
import {OutputChannel, OutputChannelManager} from '@theia/output/lib/common/output-channel';
import {OutputChannelRegistryMain} from '../../api/plugin-api';

export class OutputChannelRegistryMainImpl implements OutputChannelRegistryMain {
private delegate: OutputChannelManager;

private channels: Map<string, OutputChannel> = new Map();

constructor(container: interfaces.Container) {
this.delegate = container.get(OutputChannelManager);
}

$append(channelName: string, value: string): PromiseLike<void> {
const outputChannel = this.getChannels(channelName);
if (outputChannel) {
outputChannel.append(value);
}

return Promise.resolve();
}

$clear(channelName: string): PromiseLike<void> {
const outputChannel = this.getChannels(channelName);
if (outputChannel) {
outputChannel.clear();
}

return Promise.resolve();
}

$dispose(channelName: string): PromiseLike<void> {
this.delegate.deleteChannel(channelName);
if (this.channels.has(channelName)) {
this.channels.delete(channelName);
}

return Promise.resolve();
}

$reveal(channelName: string, preserveFocus: boolean): PromiseLike<void> {
const outputChannel = this.getChannels(channelName);
if (outputChannel) {
outputChannel.setVisibility(true);
if (!preserveFocus) {
this.setOutputChannelFocus();
}
}

return Promise.resolve();
}

$close(channelName: string): PromiseLike<void> {
const outputChannel = this.getChannels(channelName);
if (outputChannel) {
outputChannel.setVisibility(false);
}

return Promise.resolve();
}

private getChannels(channelName: string): OutputChannel | undefined {
let outputChannel: OutputChannel | undefined;
if (this.channels.has(channelName)) {
outputChannel = this.channels.get(channelName);
} else {
outputChannel = this.delegate.getChannel(channelName);
this.channels.set(channelName, outputChannel);
}

return outputChannel;
}

private setOutputChannelFocus(): void {
const outputWidget = document.getElementById(OUTPUT_WIDGET_KIND);
if (outputWidget) {
outputWidget.focus();
}
}
}
30 changes: 30 additions & 0 deletions packages/plugin-ext/src/plugin/output-channel-registry.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
/*
* Copyright (C) 2018 Red Hat, Inc. and others.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License.
* You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
*/
import {
PLUGIN_RPC_CONTEXT as Ext, OutputChannelRegistryMain
} from '../api/plugin-api';
import { RPCProtocol } from '../api/rpc-protocol';
import * as theia from '@theia/plugin';
import { OutputChannelImpl } from './output-channel/output-channel-item';

export class OutputChannelRegistryExt {

proxy: OutputChannelRegistryMain;

constructor(rpc: RPCProtocol) {
this.proxy = rpc.getProxy(Ext.OUTPUT_CHANNEL_REGISTRY_MAIN);
}

createOutputChannel(name: string): theia.OutputChannel {
name = name.trim();
if (!name) {
throw new Error('illegal argument \'name\'. must not be falsy');
} else {
return new OutputChannelImpl(name, this.proxy);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
/*
* Copyright (C) 2018 Red Hat, Inc. and others.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License.
* You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
*/
import * as theia from '@theia/plugin';
import {OutputChannelRegistryMain} from '../../api/plugin-api';

export class OutputChannelImpl implements theia.OutputChannel {

private disposed: boolean;

constructor(readonly name: string, private proxy: OutputChannelRegistryMain) {
}

dispose(): void {
if (!this.disposed) {
this.proxy.$dispose(this.name).then(() => {
this.disposed = true;
});
}
}

append(value: string): void {
this.validate();
this.proxy.$append(this.name, value);
}

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

clear(): void {
this.validate();
this.proxy.$clear(this.name);
}

show(preserveFocus: boolean | undefined): void {
this.validate();
this.proxy.$reveal(this.name, !!preserveFocus);
}

hide(): void {
this.validate();
this.proxy.$close(this.name);
}

private validate(): void {
if (this.disposed) {
throw new Error('Channel has been closed');
}
}
}
7 changes: 6 additions & 1 deletion packages/plugin-ext/src/plugin/plugin-context.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,18 +42,20 @@ import Uri from 'vscode-uri';
import { TextEditorCursorStyle } from '../common/editor-options';
import { PreferenceRegistryExtImpl } from './preference-registry';
import URI from 'vscode-uri';
import { OutputChannelRegistryExt } from './output-channel-registry';

export function createAPI(rpc: RPCProtocol): typeof theia {
const commandRegistryExt = rpc.set(MAIN_RPC_CONTEXT.COMMAND_REGISTRY_EXT, new CommandRegistryImpl(rpc));
const quickOpenExt = rpc.set(MAIN_RPC_CONTEXT.QUICK_OPEN_EXT, new QuickOpenExtImpl(rpc));
const messageRegistryExt = new MessageRegistryExt(rpc);
const windowStateExt = rpc.set(MAIN_RPC_CONTEXT.WINDOW_STATE_EXT, new WindowStateExtImpl(rpc));
const windowStateExt = rpc.set(MAIN_RPC_CONTEXT.WINDOW_STATE_EXT, new WindowStateExtImpl());
const editorsAndDocuments = rpc.set(MAIN_RPC_CONTEXT.EDITORS_AND_DOCUMENTS_EXT, new EditorsAndDocumentsExtImpl(rpc));
const editors = rpc.set(MAIN_RPC_CONTEXT.TEXT_EDITORS_EXT, new TextEditorsExtImpl(rpc, editorsAndDocuments));
const documents = rpc.set(MAIN_RPC_CONTEXT.DOCUMENTS_EXT, new DocumentsExtImpl(rpc, editorsAndDocuments));
const statusBarMessageRegistryExt = new StatusBarMessageRegistryExt(rpc);
const envExt = rpc.set(MAIN_RPC_CONTEXT.ENV_EXT, new EnvExtImpl(rpc));
const preferenceRegistryExt = rpc.set(MAIN_RPC_CONTEXT.PREFERENCE_REGISTRY_EXT, new PreferenceRegistryExtImpl(rpc));
const outputChannelRegistryExt = new OutputChannelRegistryExt(rpc);

const commands: typeof theia.commands = {
// tslint:disable-next-line:no-any
Expand Down Expand Up @@ -134,6 +136,9 @@ export function createAPI(rpc: RPCProtocol): typeof theia {
createStatusBarItem(alignment?: theia.StatusBarAlignment, priority?: number): theia.StatusBarItem {
return statusBarMessageRegistryExt.createStatusBarItem(alignment, priority);
},
createOutputChannel(name: string): theia.OutputChannel {
return outputChannelRegistryExt.createOutputChannel(name);
},

get state(): theia.WindowState {
return windowStateExt.getWindowState();
Expand Down
3 changes: 1 addition & 2 deletions packages/plugin-ext/src/plugin/window-state.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@

import { WindowState } from "@theia/plugin";
import { WindowStateExt } from "../api/plugin-api";
import { RPCProtocol } from "../api/rpc-protocol";
import { Event, Emitter } from "@theia/core/lib/common/event";

export class WindowStateExtImpl implements WindowStateExt {
Expand All @@ -17,7 +16,7 @@ export class WindowStateExtImpl implements WindowStateExt {
private windowStateChangedEmitter = new Emitter<WindowState>();
public readonly onDidChangeWindowState: Event<WindowState> = this.windowStateChangedEmitter.event;

constructor(rpc: RPCProtocol) {
constructor() {
this.windowStateCached = { focused: true }; // supposed tab is active on start
}

Expand Down
9 changes: 9 additions & 0 deletions packages/plugin/API.md
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,15 @@ Simple example that show a status bar message with statusBarItem:
item.text = 'test status bar item';
item.show();
```
#### Output channel API

It is possible to show a container for readonly textual information:

```typescript
const channel = theia.window.createOutputChannel('test channel');
channel.appendLine('test output');

```

#### Environment API

Expand Down
54 changes: 54 additions & 0 deletions packages/plugin/src/theia.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1644,6 +1644,54 @@ declare module '@theia/plugin' {
readonly focused: boolean;
}

/**
* An output channel is a container for readonly textual information.
*/
export interface OutputChannel {

/**
* The name of this output channel.
*/
readonly name: string;

/**
* Append the given value to the channel.
*
* @param value
*/
append(value: string): void;

/**
* Append the given value and a line feed character
* to the channel.
*
* @param value
*/
appendLine(value: string): void;

/**
* Removes all output from the channel.
*/
clear(): void;

/**
* Reveal this channel in the UI.
*
* @param preserveFocus When 'true' the channel will not take focus.
*/
show(preserveFocus?: boolean): void;

/**
* Hide this channel from the UI.
*/
hide(): void;

/**
* Dispose and free associated resources.
*/
dispose(): void;
}

/**
* Common namespace for dealing with window and editor, showing messages and user input.
*/
Expand Down Expand Up @@ -1890,6 +1938,12 @@ declare module '@theia/plugin' {
*/
export function createStatusBarItem(alignment?: StatusBarAlignment, priority?: number): StatusBarItem;

/**
* Create a new [output channel](#OutputChannel) with the given name.
*
* @param name String which will be used to represent the channel in the UI.
*/
export function createOutputChannel(name: string): OutputChannel;
}

/**
Expand Down

0 comments on commit b9a2ee8

Please sign in to comment.