提交 66ad2f83 编写于 作者: D Daniel Imms

Hook up actions for stale info, add relaunch command

上级 7e210596
......@@ -5,10 +5,13 @@
import { IEnvironmentVariableInfo, IMergedEnvironmentVariableCollection, IMergedEnvironmentVariableCollectionDiff, EnvironmentVariableMutatorType } from 'vs/workbench/contrib/terminal/common/environmentVariable';
import { format } from 'vs/base/common/strings';
import { TERMINAL_COMMAND_ID } from 'vs/workbench/contrib/terminal/common/terminal';
import { ITerminalService } from 'vs/workbench/contrib/terminal/browser/terminal';
export class EnvironmentVariableInfoStale implements IEnvironmentVariableInfo {
constructor(
private _diff: IMergedEnvironmentVariableCollectionDiff
private readonly _diff: IMergedEnvironmentVariableCollectionDiff,
@ITerminalService private readonly _terminalService: ITerminalService
) {
}
......@@ -23,6 +26,14 @@ export class EnvironmentVariableInfoStale implements IEnvironmentVariableInfo {
return 'warning';
}
getActions(): { label: string, iconClass?: string, run: (target: HTMLElement) => void, commandId: string }[] {
return [{
label: 'Relaunch terminal',
run: () => this._terminalService.getActiveInstance()?.relaunch(),
commandId: TERMINAL_COMMAND_ID.RELAUNCH
}];
}
private _summarizeDiff(): string {
const summary: string[] = [];
this._diff.added.forEach((mutators, variable) => {
......@@ -37,6 +48,7 @@ export class EnvironmentVariableInfoStale implements IEnvironmentVariableInfo {
});
this._diff.removed.forEach((mutators, variable) => {
mutators.forEach(mutator => {
// TODO: Localize
summary.push(`- Remove the change "${format(mutatorTypeLabel(mutator.type), mutator.value, variable)}"`);
});
});
......@@ -67,6 +79,7 @@ export class EnvironmentVariableInfoChangesActive implements IEnvironmentVariabl
}
function mutatorTypeLabel(type: EnvironmentVariableMutatorType): string {
// TODO: Localize
switch (type) {
case EnvironmentVariableMutatorType.Prepend: return 'Add `{0}` to the beginning of `{1}`';
case EnvironmentVariableMutatorType.Append: return 'Add `{0}` to the end of `{1}`';
......
......@@ -10,7 +10,8 @@
overflow: visible;
}
.monaco-workbench .terminal-message-widget {
.monaco-workbench .terminal-hover-widget {
position: fixed;
font-size: 14px;
line-height: 19px;
animation: fadein 100ms linear;
......@@ -23,7 +24,7 @@
padding: 4px 8px;
}
.monaco-workbench .terminal-message-widget a {
.monaco-workbench .terminal-hover-widget a {
color: #3794ff;
}
......
......@@ -471,6 +471,12 @@ export interface ITerminalInstance {
*/
reuseTerminal(shell: IShellLaunchConfig): void;
/**
* Relaunches the terminal, killing it and reusing the launch config used initially. Any
* environment variable changes will be recalculated when this happens.
*/
relaunch(): void;
/**
* Sets the title of the terminal instance.
*/
......
......@@ -1267,4 +1267,17 @@ export function registerTerminalActions() {
accessor.get(ITerminalService).findPrevious();
}
});
registerAction2(class extends Action2 {
constructor() {
super({
id: TERMINAL_COMMAND_ID.RELAUNCH,
title: localize('workbench.action.terminal.relaunch', "Terminal: Relaunch Active Terminal"),
f1: true,
category
});
}
run(accessor: ServicesAccessor) {
accessor.get(ITerminalService).getActiveInstance()?.relaunch();
}
});
}
......@@ -97,7 +97,7 @@ export class TerminalInstance extends Disposable implements ITerminalInstance {
private _messageTitleDisposable: IDisposable | undefined;
private _hoverManager: TerminalWidgetManager = new TerminalWidgetManager();
private _hoverManager: TerminalWidgetManager = this._instantiationService.createInstance(TerminalWidgetManager);
private _linkManager: TerminalLinkManager | undefined;
private _environmentVariableWidget: EnvironmentVariableInfoWidget | undefined;
private _commandTrackerAddon: CommandTrackerAddon | undefined;
......@@ -1021,7 +1021,7 @@ export class TerminalInstance extends Disposable implements ITerminalInstance {
}
}
public reuseTerminal(shell: IShellLaunchConfig): void {
public reuseTerminal(shell: IShellLaunchConfig, reset: boolean = false): void {
// Unsubscribe any key listener we may have.
this._pressAnyKeyToCloseListener?.dispose();
this._pressAnyKeyToCloseListener = undefined;
......@@ -1030,8 +1030,12 @@ export class TerminalInstance extends Disposable implements ITerminalInstance {
this._processManager.dispose();
if (this._xterm) {
// Ensure new processes' output starts at start of new line
this._xterm.write('\n\x1b[G');
if (reset) {
this._xterm.reset();
} else {
// Ensure new processes' output starts at start of new line
this._xterm.write('\n\x1b[G');
}
// Print initialText if specified
if (shell.initialText) {
......@@ -1045,11 +1049,13 @@ export class TerminalInstance extends Disposable implements ITerminalInstance {
}
}
// HACK: Force initialText to be non-falsy for reused terminals such that the
// conptyInheritCursor flag is passed to the node-pty, this flag can cause a Window to hang
// in Windows 10 1903 so we only want to use it when something is definitely written to the
// terminal.
shell.initialText = ' ';
if (!reset) {
// HACK: Force initialText to be non-falsy for reused terminals such that the
// conptyInheritCursor flag is passed to the node-pty, this flag can cause a Window to hang
// in Windows 10 1903 so we only want to use it when something is definitely written to the
// terminal.
shell.initialText = ' ';
}
// Set the new shell launch config
this._shellLaunchConfig = shell; // Must be done before calling _createProcess()
......@@ -1066,6 +1072,10 @@ export class TerminalInstance extends Disposable implements ITerminalInstance {
this._processManager.onProcessData(data => this._onProcessData(data));
}
public relaunch(): void {
this.reuseTerminal(this._shellLaunchConfig, true);
}
private _onLineFeed(): void {
const buffer = this._xterm!.buffer;
const newLine = buffer.active.getLine(buffer.active.baseY + buffer.active.cursorY);
......@@ -1349,10 +1359,9 @@ export class TerminalInstance extends Disposable implements ITerminalInstance {
}
private _onEnvironmentVariableInfoChanged(info: IEnvironmentVariableInfo): void {
if (!this._environmentVariableWidget) {
this._environmentVariableWidget = new EnvironmentVariableInfoWidget(info);
this._hoverManager.attachWidget(this._environmentVariableWidget);
}
this._environmentVariableWidget?.dispose();
this._environmentVariableWidget = this._instantiationService.createInstance(EnvironmentVariableInfoWidget, info);
this._hoverManager.attachWidget(this._environmentVariableWidget);
}
private _getXtermTheme(theme?: IColorTheme): any {
......
......@@ -25,7 +25,7 @@ import { Disposable } from 'vs/base/common/lifecycle';
import { withNullAsUndefined } from 'vs/base/common/types';
import { IEnvironmentVariableService, IMergedEnvironmentVariableCollection, IEnvironmentVariableInfo } from 'vs/workbench/contrib/terminal/common/environmentVariable';
import { IRemotePathService } from 'vs/workbench/services/path/common/remotePathService';
import { EnvironmentVariableInfoStale, EnvironmentVariableInfoChangesActive } from 'vs/workbench/contrib/terminal/common/environmentVariableInfo';
import { EnvironmentVariableInfoStale, EnvironmentVariableInfoChangesActive } from 'vs/workbench/contrib/terminal/browser/environmentVariableInfo';
/** The amount of time to consider terminal errors to be related to the launch */
const LAUNCHING_DURATION = 500;
......@@ -332,7 +332,7 @@ export class TerminalProcessManager extends Disposable implements ITerminalProce
return;
}
console.log('environments differ', diff);
const info = new EnvironmentVariableInfoStale(diff);
const info = this._instantiationService.createInstance(EnvironmentVariableInfoStale, diff);
this._onEnvironmentVariableInfoChange.fire(info);
// const promptChoices: IPromptChoice[] = [
// {
......
......@@ -354,18 +354,4 @@ registerThemingParticipant((theme: IColorTheme, collector: ICssStyleCollector) =
if (borderColor) {
collector.addRule(`.monaco-workbench .pane-body.integrated-terminal .split-view-view:not(:first-child) { border-color: ${borderColor.toString()}; }`);
}
// Borrow the editor's hover background for now
// const hoverBackground = theme.getColor(editorHoverBackground);
// if (hoverBackground) {
// collector.addRule(`.monaco-workbench .pane-body.integrated-terminal .terminal-message-widget { background-color: ${hoverBackground}; }`);
// }
// const hoverBorder = theme.getColor(editorHoverBorder);
// if (hoverBorder) {
// collector.addRule(`.monaco-workbench .pane-body.integrated-terminal .terminal-message-widget { border: 1px solid ${hoverBorder}; }`);
// }
// const hoverForeground = theme.getColor(editorHoverForeground);
// if (hoverForeground) {
// collector.addRule(`.monaco-workbench .pane-body.integrated-terminal .terminal-message-widget { color: ${hoverForeground}; }`);
// }
});
......@@ -9,6 +9,7 @@ import { IHoverTarget, IProposedAnchor, HorizontalAlignment, VerticalAlignment,
import { getDomNodePagePosition } from 'vs/base/browser/dom';
import { MarkdownString } from 'vs/base/common/htmlContent';
import { ITerminalWidget } from 'vs/workbench/contrib/terminal/browser/widgets/widgets';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
export class EnvironmentVariableInfoWidget extends Widget implements ITerminalWidget {
readonly id = 'env-var-info';
......@@ -18,7 +19,8 @@ export class EnvironmentVariableInfoWidget extends Widget implements ITerminalWi
private _hoverWidget: HoverWidget | undefined;
constructor(
private _info: IEnvironmentVariableInfo
private _info: IEnvironmentVariableInfo,
@IInstantiationService private readonly _instantiationService: IInstantiationService
) {
super();
}
......@@ -28,9 +30,7 @@ export class EnvironmentVariableInfoWidget extends Widget implements ITerminalWi
this._domNode = document.createElement('div');
this._domNode.classList.add('terminal-env-var-info', 'codicon', `codicon-${this._info.getIcon()}`);
container.appendChild(this._domNode);
this.onmouseover(this._domNode, () => {
this._showHover();
});
this.onmouseover(this._domNode, () => this._showHover());
}
dispose() {
......@@ -43,7 +43,8 @@ export class EnvironmentVariableInfoWidget extends Widget implements ITerminalWi
return;
}
const target = new ElementHoverTarget(this._domNode);
this._hoverWidget = new HoverWidget(this._container, target, new MarkdownString(this._info.getInfo()), () => { });
const actions = this._info.getActions ? this._info.getActions() : undefined;
this._hoverWidget = this._instantiationService.createInstance(HoverWidget, this._container, target, new MarkdownString(this._info.getInfo()), () => { }, actions);
this._register(this._hoverWidget);
this._register(this._hoverWidget.onDispose(() => this._hoverWidget = undefined));
}
......
......@@ -10,7 +10,10 @@ import { Widget } from 'vs/base/browser/ui/widget';
import { Event, Emitter } from 'vs/base/common/event';
import { registerThemingParticipant } from 'vs/platform/theme/common/themeService';
import { editorHoverHighlight, editorHoverBackground, editorHoverBorder, textLinkForeground, editorHoverForeground, editorHoverStatusBarBackground, textCodeBlockBackground } from 'vs/platform/theme/common/colorRegistry';
import { $ } from 'vs/base/browser/dom';
import * as dom from 'vs/base/browser/dom';
import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';
const $ = dom.$;
export enum HorizontalAlignment {
Left,
......@@ -55,12 +58,13 @@ export class HoverWidget extends Widget {
private _container: HTMLElement,
private _target: IHoverTarget,
private _text: IMarkdownString,
private _linkHandler: (url: string) => void
private _linkHandler: (url: string) => void,
private _actions: { label: string, iconClass?: string, run: (target: HTMLElement) => void, commandId: string }[] | undefined,
@IKeybindingService private readonly _keybindingService: IKeybindingService
) {
super();
this._domNode = document.createElement('div');
this._domNode.style.position = 'fixed';
this._domNode.classList.add('terminal-message-widget', 'fadeIn', 'monaco-editor-hover');
this._domNode.classList.add('terminal-hover-widget', 'fadeIn', 'monaco-editor-hover');
const rowElement = $('div.hover-row.markdown-hover');
const contentsElement = $('div.hover-contents');
......@@ -74,16 +78,13 @@ export class HoverWidget extends Widget {
rowElement.appendChild(contentsElement);
this._domNode.appendChild(rowElement);
const statusBarElement = document.createElement('div');
statusBarElement.classList.add('hover-row', 'status-bar');
const actionsElements = $('div.actions');
const actionsContainer = $('div.action-container');
const action = $('a.action');
action.textContent = 'Action example';
actionsContainer.appendChild(action);
actionsElements.appendChild(actionsContainer);
statusBarElement.appendChild(actionsElements);
this._domNode.appendChild(statusBarElement);
if (this._actions && this._actions.length > 0) {
const statusBarElement = $('div.hover-row.status-bar');
const actionsElement = $('div.actions');
this._actions.forEach(action => this._renderAction(actionsElement, action));
statusBarElement.appendChild(actionsElement);
this._domNode.appendChild(statusBarElement);
}
this._mouseTracker = new CompositeMouseTracker([this._domNode, ..._target.targetElements]);
this._register(this._mouseTracker.onMouseOut(() => this.dispose()));
......@@ -94,9 +95,25 @@ export class HoverWidget extends Widget {
this.layout();
}
private _renderAction(parent: HTMLElement, actionOptions: { label: string, iconClass?: string, run: (target: HTMLElement) => void, commandId: string }): IDisposable {
const actionContainer = dom.append(parent, $('div.action-container'));
const action = dom.append(actionContainer, $('a.action'));
if (actionOptions.iconClass) {
dom.append(action, $(`span.icon.${actionOptions.iconClass}`));
}
const label = dom.append(action, $('span'));
const keybinding = this._keybindingService.lookupKeybinding(actionOptions.commandId);
const keybindingLabel = keybinding ? keybinding.getLabel() : null;
label.textContent = keybindingLabel ? `${actionOptions.label} (${keybindingLabel})` : actionOptions.label;
return dom.addDisposableListener(actionContainer, dom.EventType.CLICK, e => {
e.stopPropagation();
e.preventDefault();
actionOptions.run(actionContainer);
});
}
public layout(): void {
const anchor = this._target.proposeIdealAnchor();
console.log('anchor', anchor);
this._domNode.style.maxWidth = `${document.documentElement.clientWidth - anchor.x - 1}px`;
if (anchor.horizontalAlignment === HorizontalAlignment.Left) {
this._domNode.style.left = `${anchor.x}px`;
......@@ -114,7 +131,7 @@ export class HoverWidget extends Widget {
public dispose(): void {
if (!this._isDisposed) {
this._onDispose.fire();
// this._domNode.parentElement?.removeChild(this.domNode);
this._domNode.parentElement?.removeChild(this.domNode);
this._messageListeners.dispose();
this._target.dispose();
super.dispose();
......
......@@ -10,6 +10,7 @@ import { IViewportRange } from 'xterm';
import { getDomNodePagePosition } from 'vs/base/browser/dom';
import { HoverWidget, HorizontalAlignment, VerticalAlignment, IProposedAnchor, IHoverTarget } from 'vs/workbench/contrib/terminal/browser/widgets/hoverWidget';
import { ITerminalWidget } from 'vs/workbench/contrib/terminal/browser/widgets/widgets';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
export class TerminalHover extends Disposable implements ITerminalWidget {
readonly id = 'hover';
......@@ -19,14 +20,15 @@ export class TerminalHover extends Disposable implements ITerminalWidget {
private _cellDimensions: { width: number, height: number },
private _terminalDimensions: { width: number, height: number },
private _text: IMarkdownString,
private _linkHandler: (url: string) => void
private _linkHandler: (url: string) => void,
@IInstantiationService private readonly _instantiationService: IInstantiationService
) {
super();
}
attach(container: HTMLElement): void {
const target = new CellHoverTarget(container, this._viewportRange, this._cellDimensions, this._terminalDimensions);
this._register(new HoverWidget(container, target, this._text, this._linkHandler));
this._register(this._instantiationService.createInstance(HoverWidget, container, target, this._text, this._linkHandler, []));
}
}
......
......@@ -9,6 +9,7 @@ import { IViewportRange } from 'xterm';
import { HoverWidget } from 'vs/workbench/contrib/terminal/browser/widgets/hoverWidget';
import { ITerminalWidget } from 'vs/workbench/contrib/terminal/browser/widgets/widgets';
import { TerminalHover } from 'vs/workbench/contrib/terminal/browser/widgets/terminalHoverWidget';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
export class TerminalWidgetManager implements IDisposable {
private _container: HTMLElement | undefined;
......@@ -18,7 +19,9 @@ export class TerminalWidgetManager implements IDisposable {
private _attached: Map<string, ITerminalWidget> = new Map();
constructor() {
constructor(
@IInstantiationService private readonly _instantiationService: IInstantiationService
) {
}
attachToElement(terminalWrapper: HTMLElement) {
......@@ -50,7 +53,7 @@ export class TerminalWidgetManager implements IDisposable {
}
// dispose(this._hoverWidget);
// this._hoverListeners.clear();
const widget = new TerminalHover(viewportRange, cellDimensions, terminalDimensions, text, linkHandler);
const widget = this._instantiationService.createInstance(TerminalHover, viewportRange, cellDimensions, terminalDimensions, text, linkHandler);
this.attachWidget(widget);
// const hoverTarget = new CellHoverTarget(this._container, viewportRange, cellDimensions, terminalDimensions);
// this._hoverWidget = new HoverWidget(this._container, hoverTarget, text, linkHandler);
......
......@@ -105,4 +105,6 @@ export interface IEnvironmentVariableInfo {
// TODO: Is this the right type for an icon?
getIcon(): string;
getActions?(): { label: string, iconClass?: string, run: (target: HTMLElement) => void, commandId: string }[];
}
......@@ -444,6 +444,7 @@ export const enum TERMINAL_COMMAND_ID {
NEW_IN_ACTIVE_WORKSPACE = 'workbench.action.terminal.newInActiveWorkspace',
SPLIT = 'workbench.action.terminal.split',
SPLIT_IN_ACTIVE_WORKSPACE = 'workbench.action.terminal.splitInActiveWorkspace',
RELAUNCH = 'workbench.action.terminal.relaunch',
FOCUS_PREVIOUS_PANE = 'workbench.action.terminal.focusPreviousPane',
FOCUS_NEXT_PANE = 'workbench.action.terminal.focusNextPane',
RESIZE_PANE_LEFT = 'workbench.action.terminal.resizePaneLeft',
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册