Skip to content

Commit

Permalink
vscode: Support location in TerminalOptions
Browse files Browse the repository at this point in the history
* Add support for TerminalOptions.location
* Add definitions for TerminalLocation, TerminalEditorLocationOptions, and TerminalSplitLocationOptions
  This is needed for VSCode compatibility
* Keep (bottom) as default target

Fixes eclipse-theia#11506

Contributed on behalf of STMicroelectronics

Signed-off-by: Olaf Lessenich <[email protected]>
  • Loading branch information
xai committed Dec 9, 2022
1 parent 4440abd commit 727976d
Show file tree
Hide file tree
Showing 7 changed files with 111 additions and 7 deletions.
24 changes: 22 additions & 2 deletions packages/plugin-ext/src/main/browser/terminal-main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,9 @@

import { interfaces } from '@theia/core/shared/inversify';
import { ApplicationShell, WidgetOpenerOptions } from '@theia/core/lib/browser';
import { TerminalOptions } from '@theia/plugin';
import { CancellationToken } from '@theia/core/shared/vscode-languageserver-protocol';
import { TerminalWidget } from '@theia/terminal/lib/browser/base/terminal-widget';
import { TerminalEditorLocationOptions, TerminalOptions, TerminalSplitLocationOptions } from '@theia/plugin';
import { TerminalLocation, TerminalWidget } from '@theia/terminal/lib/browser/base/terminal-widget';
import { TerminalService } from '@theia/terminal/lib/browser/base/terminal-service';
import { TerminalServiceMain, TerminalServiceExt, MAIN_RPC_CONTEXT } from '../../common/plugin-api-rpc';
import { RPCProtocol } from '../../common/rpc-protocol';
Expand Down Expand Up @@ -141,13 +141,33 @@ export class TerminalServiceMainImpl implements TerminalServiceMain, TerminalLin
if (options.message) {
terminal.writeLine(options.message);
}
terminal.target = await this.determineWidgetTarget(options.location);
terminal.start();
return terminal.id;
} catch (error) {
throw new Error('Failed to create terminal. Cause: ' + error);
}
}

protected async determineWidgetTarget(location?: TerminalLocation |
TerminalEditorLocationOptions | TerminalSplitLocationOptions | undefined):
Promise<TerminalLocation | TerminalEditorLocationOptions> {
const defaultLocation = TerminalLocation.Panel;

if (!location) {
return defaultLocation;
} else if (typeof location === 'object' && 'parentTerminal' in location) {
const parentTerminalId = (await location.parentTerminal.processId);
if (parentTerminalId) {
const parentTerminal = this.terminals.getById(parentTerminalId.toString());
return !parentTerminal || !parentTerminal.target ? defaultLocation : parentTerminal.target;
}
return defaultLocation;
}

return location;
}

$sendText(id: string, text: string, addNewLine?: boolean): void {
const terminal = this.terminals.getById(id);
if (terminal) {
Expand Down
4 changes: 3 additions & 1 deletion packages/plugin-ext/src/plugin/plugin-context.ts
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,7 @@ import {
TextDocumentChangeReason,
InputBoxValidationSeverity,
TerminalLink,
TerminalLocation,
InlayHint,
InlayHintKind,
InlayHintLabelPart,
Expand Down Expand Up @@ -1133,7 +1134,8 @@ export function createAPIFactory(
ExtensionKind,
InlineCompletionItem,
InlineCompletionList,
InlineCompletionTriggerKind
InlineCompletionTriggerKind,
TerminalLocation
};
};
}
Expand Down
5 changes: 5 additions & 0 deletions packages/plugin-ext/src/plugin/types-impl.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1695,6 +1695,11 @@ export class TerminalLink {
}
}

export enum TerminalLocation {
Panel = 1,
Editor = 2
}

@es5ClassCompat
export class FileDecoration {

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 @@ -3001,6 +3001,11 @@ export module '@theia/plugin' {
*/
message?: string;

/**
* The {@link TerminalLocation} or {@link TerminalEditorLocationOptions} or {@link TerminalSplitLocationOptions} for the terminal.
*/
location?: TerminalLocation | TerminalEditorLocationOptions | TerminalSplitLocationOptions;

/**
* Terminal attributes. Can be useful to apply some implementation specific information.
*/
Expand Down Expand Up @@ -3067,6 +3072,11 @@ export module '@theia/plugin' {
* control it.
*/
pty: Pseudoterminal;

/**
* The {@link TerminalLocation} or {@link TerminalEditorLocationOptions} or {@link TerminalSplitLocationOptions} for the terminal.
*/
location?: TerminalLocation | TerminalEditorLocationOptions | TerminalSplitLocationOptions;
}

/**
Expand Down Expand Up @@ -3207,6 +3217,50 @@ export module '@theia/plugin' {
constructor(startIndex: number, length: number, tooltip?: string);
}

/**
* The location of the {@link Terminal}.
*/
export enum TerminalLocation {
/**
* In the terminal view
*/
Panel = 1,
/**
* In the editor area
*/
Editor = 2,
}

/**
* Assumes a {@link TerminalLocation} of editor and allows specifying a {@link ViewColumn} and
* {@link TerminalEditorLocationOptions.preserveFocus preserveFocus } property
*/
export interface TerminalEditorLocationOptions {
/**
* A view column in which the {@link Terminal terminal} should be shown in the editor area.
* Use {@link ViewColumn.Active active} to open in the active editor group, other values are
* adjusted to be `Min(column, columnCount + 1)`, the
* {@link ViewColumn.Active active}-column is not adjusted. Use
* {@linkcode ViewColumn.Beside} to open the editor to the side of the currently active one.
*/
viewColumn: ViewColumn;
/**
* An optional flag that when `true` will stop the {@link Terminal} from taking focus.
*/
preserveFocus?: boolean;
}

/**
* Uses the parent {@link Terminal}'s location for the terminal
*/
export interface TerminalSplitLocationOptions {
/**
* The parent terminal to split this terminal beside. This works whether the parent terminal
* is in the panel or the editor area.
*/
parentTerminal: Terminal;
}

/**
* A file decoration represents metadata that can be rendered with a file.
*/
Expand Down
14 changes: 13 additions & 1 deletion packages/terminal/src/browser/base/terminal-widget.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,13 +30,22 @@ export interface TerminalExitStatus {
readonly code: number | undefined;
}

export enum TerminalLocation {
Panel = 1,
Editor = 2
}

export interface TerminalEditorLocationOptions {
readonly viewColumn: number;
readonly preserveFocus?: boolean;
}

/**
* Terminal UI widget.
*/
export abstract class TerminalWidget extends BaseWidget {

abstract processId: Promise<number>;

/**
* Get the current executable and arguments.
*/
Expand All @@ -54,6 +63,9 @@ export abstract class TerminalWidget extends BaseWidget {
/** Terminal widget can be hidden from users until explicitly shown once. */
abstract readonly hiddenFromUser: boolean;

/** The position of the terminal widget. */
abstract target?: TerminalLocation | TerminalEditorLocationOptions;

/** The last CWD assigned to the terminal, useful when attempting getCwdURI on a task terminal fails */
lastCwd: URI;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ import { TabBarToolbarContribution, TabBarToolbarRegistry } from '@theia/core/li
import { TERMINAL_WIDGET_FACTORY_ID, TerminalWidgetFactoryOptions, TerminalWidgetImpl } from './terminal-widget-impl';
import { TerminalKeybindingContexts } from './terminal-keybinding-contexts';
import { TerminalService } from './base/terminal-service';
import { TerminalWidgetOptions, TerminalWidget } from './base/terminal-widget';
import { TerminalWidgetOptions, TerminalWidget, TerminalLocation } from './base/terminal-widget';
import { UriAwareCommandHandler } from '@theia/core/lib/common/uri-command-handler';
import { ShellTerminalServerProxy } from '../common/shell-terminal-protocol';
import URI from '@theia/core/lib/common/uri';
Expand Down Expand Up @@ -644,11 +644,13 @@ export class TerminalFrontendContribution implements FrontendApplicationContribu

// TODO: reuse WidgetOpenHandler.open
open(widget: TerminalWidget, options?: WidgetOpenerOptions): void {
const area = widget.target === TerminalLocation.Editor ? 'main' : 'bottom';

const op: WidgetOpenerOptions = {
mode: 'activate',
...options,
widgetOptions: {
area: 'bottom',
area: area,
...(options && options.widgetOptions)
}
};
Expand Down
11 changes: 10 additions & 1 deletion packages/terminal/src/browser/terminal-widget-impl.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ import { ShellTerminalServerProxy, IShellTerminalPreferences } from '../common/s
import { terminalsPath } from '../common/terminal-protocol';
import { IBaseTerminalServer, TerminalProcessInfo } from '../common/base-terminal-protocol';
import { TerminalWatcher } from '../common/terminal-watcher';
import { TerminalWidgetOptions, TerminalWidget, TerminalDimensions, TerminalExitStatus } from './base/terminal-widget';
import { TerminalWidgetOptions, TerminalWidget, TerminalDimensions, TerminalExitStatus, TerminalLocation } from './base/terminal-widget';
import { Deferred } from '@theia/core/lib/common/promise-util';
import { TerminalPreferences, TerminalRendererType, isTerminalRendererType, DEFAULT_TERMINAL_RENDERER_TYPE, CursorStyle } from './terminal-preferences';
import URI from '@theia/core/lib/common/uri';
Expand Down Expand Up @@ -73,6 +73,7 @@ export class TerminalWidgetImpl extends TerminalWidget implements StatefulWidget
protected lastMousePosition: { x: number, y: number } | undefined;
protected isAttachedCloseListener: boolean = false;
protected shown = false;
protected _target: TerminalLocation|undefined;
override lastCwd = new URI();

@inject(WorkspaceService) protected readonly workspaceService: WorkspaceService;
Expand Down Expand Up @@ -382,6 +383,14 @@ export class TerminalWidgetImpl extends TerminalWidget implements StatefulWidget
return this.shellTerminalServer.getProcessId(this.terminalId);
}

get target(): TerminalLocation | undefined {
return this._target;
}

set target(target: TerminalLocation | undefined) {
this._target = target;
}

get processInfo(): Promise<TerminalProcessInfo> {
if (!IBaseTerminalServer.validateId(this.terminalId)) {
return Promise.reject(new Error('terminal is not started'));
Expand Down

0 comments on commit 727976d

Please sign in to comment.