Merge from vscode c58aaab8a1cc22a7139b761166a0d4f37d41e998 (#7880)

* Merge from vscode c58aaab8a1cc22a7139b761166a0d4f37d41e998

* fix pipelines

* fix strict-null-checks

* add missing files
This commit is contained in:
Anthony Dresser
2019-10-21 22:12:22 -07:00
committed by GitHub
parent 7c9be74970
commit 1e22f47304
913 changed files with 18898 additions and 16536 deletions

View File

@@ -30,7 +30,7 @@ export class NavigationModeAddon implements INavigationMode, ITerminalAddon {
}
focusPreviousLine(): void {
if (!this._terminal) {
if (!this._terminal || !this._terminal.element) {
return;
}
@@ -73,7 +73,7 @@ export class NavigationModeAddon implements INavigationMode, ITerminalAddon {
}
focusNextLine(): void {
if (!this._terminal) {
if (!this._terminal || !this._terminal.element) {
return;
}

View File

@@ -251,6 +251,11 @@ configurationRegistry.registerConfiguration({
},
default: []
},
'terminal.integrated.allowChords': {
markdownDescription: nls.localize('terminal.integrated.allowChords', "Whether or not to allow chord keybindings in the terminal. Note that when this is true and the keystroke results in a chord it will bypass `terminal.integrated.commandsToSkipShell`, setting this to false is particularly useful when you want ctrl+k to go to your shell (not VS Code)."),
type: 'boolean',
default: true
},
'terminal.integrated.inheritEnv': {
markdownDescription: nls.localize('terminal.integrated.inheritEnv', "Whether new shells should inherit their environment from Azure Data Studio. This is not supported on Windows."), // {{SQL CARBON EDIT}} Change product name to ADS
type: 'boolean',

View File

@@ -10,7 +10,6 @@ import { IWindowsShellHelper, ITerminalConfigHelper, ITerminalChildProcess, IShe
import { createDecorator } from 'vs/platform/instantiation/common/instantiation';
import { IProcessEnvironment, Platform } from 'vs/base/common/platform';
import { Event } from 'vs/base/common/event';
import { IContextKey } from 'vs/platform/contextkey/common/contextkey';
import { IDisposable } from 'vs/base/common/lifecycle';
import { FindReplaceState } from 'vs/editor/contrib/find/findState';
import { URI } from 'vs/base/common/uri';
@@ -65,7 +64,7 @@ export interface ITerminalTab {
setVisible(visible: boolean): void;
layout(width: number, height: number): void;
addDisposable(disposable: IDisposable): void;
split(terminalFocusContextKey: IContextKey<boolean>, configHelper: ITerminalConfigHelper, shellLaunchConfig: IShellLaunchConfig): ITerminalInstance | undefined;
split(shellLaunchConfig: IShellLaunchConfig): ITerminalInstance;
}
export interface ITerminalService {
@@ -227,7 +226,7 @@ export interface ITerminalInstance {
* is the processes' exit code, an exit code of null means the process was killed as a result of
* the ITerminalInstance being disposed.
*/
onExit: Event<number>;
onExit: Event<number | undefined>;
processReady: Promise<void>;

View File

@@ -25,7 +25,7 @@ import { activeContrastBorder, scrollbarSliderActiveBackground, scrollbarSliderB
import { ICssStyleCollector, ITheme, IThemeService, registerThemingParticipant } from 'vs/platform/theme/common/themeService';
import { PANEL_BACKGROUND } from 'vs/workbench/common/theme';
import { TerminalWidgetManager } from 'vs/workbench/contrib/terminal/browser/terminalWidgetManager';
import { IShellLaunchConfig, ITerminalDimensions, ITerminalProcessManager, KEYBINDING_CONTEXT_TERMINAL_TEXT_SELECTED, NEVER_MEASURE_RENDER_TIME_STORAGE_KEY, ProcessState, TERMINAL_PANEL_ID, IWindowsShellHelper, SHELL_PATH_INVALID_EXIT_CODE, SHELL_PATH_DIRECTORY_EXIT_CODE, SHELL_CWD_INVALID_EXIT_CODE, KEYBINDING_CONTEXT_TERMINAL_A11Y_TREE_FOCUS, INavigationMode, TitleEventSource, TERMINAL_COMMAND_ID } from 'vs/workbench/contrib/terminal/common/terminal';
import { IShellLaunchConfig, ITerminalDimensions, ITerminalProcessManager, KEYBINDING_CONTEXT_TERMINAL_TEXT_SELECTED, NEVER_MEASURE_RENDER_TIME_STORAGE_KEY, ProcessState, TERMINAL_PANEL_ID, IWindowsShellHelper, SHELL_PATH_INVALID_EXIT_CODE, SHELL_PATH_DIRECTORY_EXIT_CODE, SHELL_CWD_INVALID_EXIT_CODE, KEYBINDING_CONTEXT_TERMINAL_A11Y_TREE_FOCUS, INavigationMode, TitleEventSource, TERMINAL_COMMAND_ID, LEGACY_CONSOLE_MODE_EXIT_CODE } from 'vs/workbench/contrib/terminal/common/terminal';
import { ansiColorIdentifiers, TERMINAL_BACKGROUND_COLOR, TERMINAL_CURSOR_BACKGROUND_COLOR, TERMINAL_CURSOR_FOREGROUND_COLOR, TERMINAL_FOREGROUND_COLOR, TERMINAL_SELECTION_BACKGROUND_COLOR } from 'vs/workbench/contrib/terminal/common/terminalColorRegistry';
import { TerminalConfigHelper } from 'vs/workbench/contrib/terminal/browser/terminalConfigHelper';
import { TerminalLinkHandler } from 'vs/workbench/contrib/terminal/browser/terminalLinkHandler';
@@ -38,6 +38,7 @@ import { SearchAddon, ISearchOptions } from 'xterm-addon-search';
import { CommandTrackerAddon } from 'vs/workbench/contrib/terminal/browser/addons/commandTrackerAddon';
import { NavigationModeAddon } from 'vs/workbench/contrib/terminal/browser/addons/navigationModeAddon';
import { XTermCore } from 'vs/workbench/contrib/terminal/browser/xterm-private';
import { IEditorOptions } from 'vs/editor/common/config/editorOptions';
// How long in milliseconds should an average frame take to render for a notification to appear
// which suggests the fallback DOM-based renderer
@@ -232,8 +233,8 @@ export class TerminalInstance extends Disposable implements ITerminalInstance {
public get commandTracker(): CommandTrackerAddon | undefined { return this._commandTrackerAddon; }
public get navigationMode(): INavigationMode | undefined { return this._navigationModeAddon; }
private readonly _onExit = new Emitter<number>();
public get onExit(): Event<number> { return this._onExit.event; }
private readonly _onExit = new Emitter<number | undefined>();
public get onExit(): Event<number | undefined> { return this._onExit.event; }
private readonly _onDisposed = new Emitter<ITerminalInstance>();
public get onDisposed(): Event<ITerminalInstance> { return this._onDisposed.event; }
private readonly _onFocused = new Emitter<ITerminalInstance>();
@@ -258,7 +259,7 @@ export class TerminalInstance extends Disposable implements ITerminalInstance {
public constructor(
private readonly _terminalFocusContextKey: IContextKey<boolean>,
private readonly _configHelper: TerminalConfigHelper,
private _container: HTMLElement,
private _container: HTMLElement | undefined,
private _shellLaunchConfig: IShellLaunchConfig,
@ITerminalInstanceService private readonly _terminalInstanceService: ITerminalInstanceService,
@IContextKeyService private readonly _contextKeyService: IContextKeyService,
@@ -408,14 +409,6 @@ export class TerminalInstance extends Disposable implements ITerminalInstance {
// The panel is minimized
if (!this._isVisible) {
return TerminalInstance._lastKnownCanvasDimensions;
} else {
// Trigger scroll event manually so that the viewport's scroll area is synced. This
// needs to happen otherwise its scrollTop value is invalid when the panel is toggled as
// it gets removed and then added back to the DOM (resetting scrollTop to 0).
// Upstream issue: https://github.com/sourcelair/xterm.js/issues/291
if (this._xterm && this._xtermCore) {
this._xtermCore._onScroll.fire(this._xterm.buffer.viewportY);
}
}
if (!this._wrapperElement) {
@@ -455,6 +448,7 @@ export class TerminalInstance extends Disposable implements ITerminalInstance {
const Terminal = await this._getXtermConstructor();
const font = this._configHelper.getFont(undefined, true);
const config = this._configHelper.config;
const fastScrollSensitivity = this._configurationService.getValue<IEditorOptions>('editor.fastScrollSensitivity').fastScrollSensitivity;
const xterm = new Terminal({
scrollback: config.scrollback,
theme: this._getXtermTheme(),
@@ -469,6 +463,8 @@ export class TerminalInstance extends Disposable implements ITerminalInstance {
macOptionIsMeta: config.macOptionIsMeta,
macOptionClickForcesSelection: config.macOptionClickForcesSelection,
rightClickSelectsWord: config.rightClickBehavior === 'selectWord',
fastScrollModifier: 'alt',
fastScrollSensitivity,
// TODO: Guess whether to use canvas or dom better
rendererType: config.rendererType === 'auto' ? 'canvas' : config.rendererType
});
@@ -507,7 +503,7 @@ export class TerminalInstance extends Disposable implements ITerminalInstance {
return false;
});
}
this._linkHandler = this._instantiationService.createInstance(TerminalLinkHandler, this._xterm, this._processManager, this._configHelper);
this._linkHandler = this._instantiationService.createInstance(TerminalLinkHandler, xterm, this._processManager, this._configHelper);
});
this._commandTrackerAddon = new CommandTrackerAddon();
@@ -548,7 +544,9 @@ export class TerminalInstance extends Disposable implements ITerminalInstance {
}
// The container changed, reattach
this._container.removeChild(this._wrapperElement);
if (this._container) {
this._container.removeChild(this._wrapperElement);
}
this._container = container;
this._container.appendChild(this._wrapperElement);
}
@@ -567,7 +565,14 @@ export class TerminalInstance extends Disposable implements ITerminalInstance {
// Attach the xterm object to the DOM, exposing it to the smoke tests
this._wrapperElement.xterm = this._xterm;
this._wrapperElement.appendChild(this._xtermElement);
this._container.appendChild(this._wrapperElement);
xterm.open(this._xtermElement);
if (!xterm.element || !xterm.textarea) {
throw new Error('xterm elements not set after open');
}
xterm.textarea.addEventListener('focus', () => this._onFocus.fire(this));
xterm.attachCustomKeyEventHandler((event: KeyboardEvent): boolean => {
// Disable all input if the terminal is exiting
@@ -579,7 +584,8 @@ export class TerminalInstance extends Disposable implements ITerminalInstance {
// within commandsToSkipShell
const standardKeyboardEvent = new StandardKeyboardEvent(event);
const resolveResult = this._keybindingService.softDispatch(standardKeyboardEvent, standardKeyboardEvent.target);
if (resolveResult && this._skipTerminalCommands.some(k => k === resolveResult.commandId)) {
const allowChords = resolveResult && resolveResult.enterChord && this._configHelper.config.allowChords;
if (allowChords || resolveResult && this._skipTerminalCommands.some(k => k === resolveResult.commandId)) {
event.preventDefault();
return false;
}
@@ -644,9 +650,6 @@ export class TerminalInstance extends Disposable implements ITerminalInstance {
this._refreshSelectionContextKey();
}));
this._wrapperElement.appendChild(this._xtermElement);
this._container.appendChild(this._wrapperElement);
const widgetManager = new TerminalWidgetManager(this._wrapperElement);
this._widgetManager = widgetManager;
this._processManager.onProcessReady(() => {
@@ -801,7 +804,7 @@ export class TerminalInstance extends Disposable implements ITerminalInstance {
if (this._wrapperElement.xterm) {
this._wrapperElement.xterm = undefined;
}
if (this._wrapperElement.parentElement) {
if (this._wrapperElement.parentElement && this._container) {
this._container.removeChild(this._wrapperElement);
}
}
@@ -900,6 +903,8 @@ export class TerminalInstance extends Disposable implements ITerminalInstance {
// necessary if the number of rows in the terminal has decreased while it was in the
// background since scrollTop changes take no effect but the terminal's position does
// change since the number of visible rows decreases.
// This can likely be removed after https://github.com/xtermjs/xterm.js/issues/291 is
// fixed upstream.
this._xtermCore._onScroll.fire(this._xterm.buffer.viewportY);
if (this._container && this._container.parentElement) {
// Force a layout when the instance becomes invisible. This is particularly important
@@ -1047,6 +1052,8 @@ export class TerminalInstance extends Disposable implements ITerminalInstance {
exitCodeMessage = nls.localize('terminal.integrated.exitedWithInvalidPathDirectory', 'The terminal shell path "{0}" is a directory', this._shellLaunchConfig.executable);
} else if (exitCode === SHELL_CWD_INVALID_EXIT_CODE && this._shellLaunchConfig.cwd) {
exitCodeMessage = nls.localize('terminal.integrated.exitedWithInvalidCWD', 'The terminal shell CWD "{0}" does not exist', this._shellLaunchConfig.cwd.toString());
} else if (exitCode === LEGACY_CONSOLE_MODE_EXIT_CODE) {
exitCodeMessage = nls.localize('terminal.integrated.legacyConsoleModeError', 'The terminal failed to launch properly because your system has legacy console mode enabled, uncheck "Use legacy console" cmd.exe\'s properties to fix this.');
} else if (this._processManager.processState === ProcessState.KILLED_DURING_LAUNCH) {
let args = '';
if (typeof this._shellLaunchConfig.args === 'string') {
@@ -1105,11 +1112,11 @@ export class TerminalInstance extends Disposable implements ITerminalInstance {
}
}
this._onExit.fire(exitCode || 0);
this._onExit.fire(exitCode);
}
private _attachPressAnyKeyToCloseListener(xterm: XTermTerminal) {
if (!this._pressAnyKeyToCloseListener) {
if (xterm.textarea && !this._pressAnyKeyToCloseListener) {
this._pressAnyKeyToCloseListener = dom.addDisposableListener(xterm.textarea, 'keypress', (event: KeyboardEvent) => {
if (this._pressAnyKeyToCloseListener) {
this._pressAnyKeyToCloseListener.dispose();
@@ -1240,6 +1247,7 @@ export class TerminalInstance extends Disposable implements ITerminalInstance {
this._safeSetOption('macOptionClickForcesSelection', config.macOptionClickForcesSelection);
this._safeSetOption('rightClickSelectsWord', config.rightClickBehavior === 'selectWord');
this._safeSetOption('rendererType', config.rendererType === 'auto' ? 'canvas' : config.rendererType);
this._safeSetOption('fastScrollSensitivity', this._configurationService.getValue<IEditorOptions>('editor.fastScrollSensitivity').fastScrollSensitivity);
}
public updateAccessibilitySupport(): void {
@@ -1312,7 +1320,7 @@ export class TerminalInstance extends Disposable implements ITerminalInstance {
return;
}
if (this._xterm) {
if (this._xterm && this._xterm.element) {
this._xterm.element.style.width = terminalWidth + 'px';
}

View File

@@ -25,6 +25,7 @@ import { DataTransfers } from 'vs/base/browser/dnd';
import { INotificationService, IPromptChoice, Severity } from 'vs/platform/notification/common/notification';
import { IStorageService } from 'vs/platform/storage/common/storage';
import { ITerminalService } from 'vs/workbench/contrib/terminal/browser/terminal';
import { assertIsDefined } from 'vs/base/common/types';
const FIND_FOCUS_CLASS = 'find-focused';
@@ -70,7 +71,8 @@ export class TerminalPanel extends Panel {
this._attachEventListeners(this._parentDomElement, this._terminalContainer);
this._terminalService.setContainers(this.getContainer(), this._terminalContainer);
const container = assertIsDefined(this.getContainer());
this._terminalService.setContainers(container, this._terminalContainer);
this._register(this.themeService.onThemeChange(theme => this._updateTheme(theme)));
this._register(this._configurationService.onDidChangeConfiguration(e => {

View File

@@ -11,13 +11,12 @@ import { IWorkbenchLayoutService } from 'vs/workbench/services/layout/browser/la
import { ILifecycleService } from 'vs/platform/lifecycle/common/lifecycle';
import { TerminalPanel } from 'vs/workbench/contrib/terminal/browser/terminalPanel';
import { IDialogService } from 'vs/platform/dialogs/common/dialogs';
import { INotificationService } from 'vs/platform/notification/common/notification';
import { TerminalTab } from 'vs/workbench/contrib/terminal/browser/terminalTab';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions';
import { IFileService } from 'vs/platform/files/common/files';
import { TerminalInstance } from 'vs/workbench/contrib/terminal/browser/terminalInstance';
import { IBrowserTerminalConfigHelper, ITerminalService, ITerminalInstance, ITerminalTab } from 'vs/workbench/contrib/terminal/browser/terminal';
import { ITerminalService, ITerminalInstance, ITerminalTab } from 'vs/workbench/contrib/terminal/browser/terminal';
import { IRemoteAgentService } from 'vs/workbench/services/remote/common/remoteAgentService';
import { TerminalConfigHelper } from 'vs/workbench/contrib/terminal/browser/terminalConfigHelper';
import { IQuickInputService, IQuickPickItem, IPickOptions } from 'vs/platform/quickinput/common/quickInput';
@@ -29,6 +28,7 @@ import { escapeNonWindowsPath } from 'vs/workbench/contrib/terminal/common/termi
import { isWindows, isMacintosh, OperatingSystem } from 'vs/base/common/platform';
import { basename } from 'vs/base/common/path';
import { IOpenFileRequest } from 'vs/platform/windows/common/windows';
import { find } from 'vs/base/common/arrays';
interface IExtHostReadyEntry {
promise: Promise<void>;
@@ -54,7 +54,7 @@ export class TerminalService implements ITerminalService {
public get terminalInstances(): ITerminalInstance[] { return this._terminalInstances; }
public get terminalTabs(): ITerminalTab[] { return this._terminalTabs; }
private _configHelper: IBrowserTerminalConfigHelper;
private _configHelper: TerminalConfigHelper;
private _terminalContainer: HTMLElement | undefined;
public get configHelper(): ITerminalConfigHelper { return this._configHelper; }
@@ -91,7 +91,6 @@ export class TerminalService implements ITerminalService {
@IPanelService private _panelService: IPanelService,
@IWorkbenchLayoutService private _layoutService: IWorkbenchLayoutService,
@ILifecycleService lifecycleService: ILifecycleService,
@INotificationService private _notificationService: INotificationService,
@IDialogService private _dialogService: IDialogService,
@IInstantiationService private _instantiationService: IInstantiationService,
@IExtensionService private _extensionService: IExtensionService,
@@ -392,12 +391,7 @@ export class TerminalService implements ITerminalService {
return null;
}
const instance = tab.split(this._terminalFocusContextKey, this.configHelper, shellLaunchConfig);
if (!instance) {
this._showNotEnoughSpaceToast();
return null;
}
const instance = tab.split(shellLaunchConfig);
this._initInstanceListeners(instance);
this._onInstancesChanged.fire();
@@ -414,13 +408,8 @@ export class TerminalService implements ITerminalService {
instance.addDisposable(instance.onFocus(this._onActiveInstanceChanged.fire, this._onActiveInstanceChanged));
}
private _getTabForInstance(instance: ITerminalInstance): ITerminalTab | null {
for (const tab of this._terminalTabs) {
if (tab.terminalInstances.indexOf(instance) !== -1) {
return tab;
}
}
return null;
private _getTabForInstance(instance: ITerminalInstance): ITerminalTab | undefined {
return find(this._terminalTabs, tab => tab.terminalInstances.indexOf(instance) !== -1);
}
public showPanel(focus?: boolean): Promise<void> {
@@ -499,10 +488,6 @@ export class TerminalService implements ITerminalService {
return !res.confirmed;
}
protected _showNotEnoughSpaceToast(): void {
this._notificationService.info(nls.localize('terminal.minWidth', "Not enough space to split terminal."));
}
protected _validateShellPaths(label: string, potentialPaths: string[]): Promise<[string, string] | null> {
if (potentialPaths.length === 0) {
return Promise.resolve(null);

View File

@@ -14,7 +14,6 @@ import { IInstantiationService } from 'vs/platform/instantiation/common/instanti
import { ITerminalInstance, Direction, ITerminalTab, ITerminalService } from 'vs/workbench/contrib/terminal/browser/terminal';
const SPLIT_PANE_MIN_SIZE = 120;
const TERMINAL_MIN_USEFUL_SIZE = 250;
class SplitPaneContainer extends Disposable {
private _height: number;
@@ -370,18 +369,11 @@ export class TerminalTab extends Disposable implements ITerminalTab {
this.terminalInstances.forEach(i => i.setVisible(visible));
}
public split(
terminalFocusContextKey: IContextKey<boolean>,
configHelper: ITerminalConfigHelper,
shellLaunchConfig: IShellLaunchConfig
): ITerminalInstance | undefined {
public split(shellLaunchConfig: IShellLaunchConfig): ITerminalInstance {
if (!this._container) {
throw new Error('Cannot split terminal that has not been attached');
}
const newTerminalSize = ((this._panelPosition === Position.BOTTOM ? this._container.clientWidth : this._container.clientHeight) / (this._terminalInstances.length + 1));
if (newTerminalSize < TERMINAL_MIN_USEFUL_SIZE) {
return undefined;
}
const instance = this._terminalService.createInstance(undefined, shellLaunchConfig);
this._terminalInstances.splice(this._activeInstanceIndex + 1, 0, instance);
this._initInstanceListeners(instance);

View File

@@ -65,6 +65,7 @@ export const DEFAULT_LINE_HEIGHT = 1;
export const SHELL_PATH_INVALID_EXIT_CODE = -1;
export const SHELL_PATH_DIRECTORY_EXIT_CODE = -2;
export const SHELL_CWD_INVALID_EXIT_CODE = -3;
export const LEGACY_CONSOLE_MODE_EXIT_CODE = 3221225786; // microsoft/vscode#73790
export type FontWeight = 'normal' | 'bold' | '100' | '200' | '300' | '400' | '500' | '600' | '700' | '800' | '900';
@@ -101,6 +102,7 @@ export interface ITerminalConfiguration {
detectLocale: 'auto' | 'off' | 'on';
scrollback: number;
commandsToSkipShell: string[];
allowChords: boolean;
cwd: string;
confirmOnExit: boolean;
enableBell: boolean;

View File

@@ -282,7 +282,6 @@ export function getDefaultShell(
executable = configurationResolverService.resolve(lastActiveWorkspace, executable);
} catch (e) {
logService.error(`Could not resolve shell`, e);
executable = executable;
}
}

View File

@@ -237,7 +237,14 @@ export class TerminalProcess extends Disposable implements ITerminalChildProcess
cols = Math.max(cols, 1);
rows = Math.max(rows, 1);
this._logService.trace('IPty#resize', cols, rows);
this._ptyProcess.resize(cols, rows);
try {
this._ptyProcess.resize(cols, rows);
} catch (e) {
// Swallow error if the pty has already exited
if (this._exitCode !== undefined) {
throw e;
}
}
}
}

View File

@@ -20,10 +20,138 @@ function writePromise(term: Terminal, data: string): Promise<void> {
const ROWS = 10;
const COLS = 10;
suite('Workbench - TerminalCommandTracker', () => {
suite.skip('Workbench - TerminalCommandTracker', () => { // {{SQL CARBON EDIT}} skip suite
let xterm: TestTerminal;
let commandTracker: CommandTrackerAddon;
setup(async () => {
xterm = (<TestTerminal>new Terminal({
cols: COLS,
rows: ROWS
}));
// Fill initial viewport
for (let i = 0; i < ROWS - 1; i++) {
await writePromise(xterm, `${i}\n`);
}
commandTracker = new CommandTrackerAddon();
xterm.loadAddon(commandTracker);
});
suite('Command tracking', () => {
test('should track commands when the prompt is of sufficient size', () => {
assert.equal(0, 0);
test('should track commands when the prompt is of sufficient size', async () => {
assert.equal(xterm.markers.length, 0);
await writePromise(xterm, '\x1b[3G'); // Move cursor to column 3
xterm._core._onKey.fire({ key: '\x0d' });
assert.equal(xterm.markers.length, 1);
});
test('should not track commands when the prompt is too small', async () => {
assert.equal(xterm.markers.length, 0);
await writePromise(xterm, '\x1b[2G'); // Move cursor to column 2
xterm._core._onKey.fire({ key: '\x0d' });
assert.equal(xterm.markers.length, 0);
});
});
suite('Commands', () => {
test('should scroll to the next and previous commands', async () => {
await writePromise(xterm, '\x1b[3G'); // Move cursor to column 3
xterm._core._onKey.fire({ key: '\x0d' }); // Mark line #10
assert.equal(xterm.markers[0].line, 9);
for (let i = 0; i < 20; i++) {
await writePromise(xterm, `\r\n`);
}
assert.equal(xterm.buffer.baseY, 20);
assert.equal(xterm.buffer.viewportY, 20);
// Scroll to marker
commandTracker.scrollToPreviousCommand();
assert.equal(xterm.buffer.viewportY, 9);
// Scroll to top boundary
commandTracker.scrollToPreviousCommand();
assert.equal(xterm.buffer.viewportY, 0);
// Scroll to marker
commandTracker.scrollToNextCommand();
assert.equal(xterm.buffer.viewportY, 9);
// Scroll to bottom boundary
commandTracker.scrollToNextCommand();
assert.equal(xterm.buffer.viewportY, 20);
});
test('should select to the next and previous commands', async () => {
(<any>window).matchMedia = () => {
return { addListener: () => { } };
};
const e = document.createElement('div');
document.body.appendChild(e);
xterm.open(e);
await writePromise(xterm, '\r0');
await writePromise(xterm, '\n\r1');
await writePromise(xterm, '\x1b[3G'); // Move cursor to column 3
xterm._core._onKey.fire({ key: '\x0d' }); // Mark line
assert.equal(xterm.markers[0].line, 10);
await writePromise(xterm, '\n\r2');
await writePromise(xterm, '\x1b[3G'); // Move cursor to column 3
xterm._core._onKey.fire({ key: '\x0d' }); // Mark line
assert.equal(xterm.markers[1].line, 11);
await writePromise(xterm, '\n\r3');
assert.equal(xterm.buffer.baseY, 3);
assert.equal(xterm.buffer.viewportY, 3);
assert.equal(xterm.getSelection(), '');
commandTracker.selectToPreviousCommand();
assert.equal(xterm.getSelection(), '2');
commandTracker.selectToPreviousCommand();
assert.equal(xterm.getSelection(), isWindows ? '1\r\n2' : '1\n2');
commandTracker.selectToNextCommand();
assert.equal(xterm.getSelection(), '2');
commandTracker.selectToNextCommand();
assert.equal(xterm.getSelection(), isWindows ? '\r\n' : '\n');
document.body.removeChild(e);
});
test('should select to the next and previous lines & commands', async () => {
(<any>window).matchMedia = () => {
return { addListener: () => { } };
};
const e = document.createElement('div');
document.body.appendChild(e);
xterm.open(e);
await writePromise(xterm, '\r0');
await writePromise(xterm, '\n\r1');
await writePromise(xterm, '\x1b[3G'); // Move cursor to column 3
xterm._core._onKey.fire({ key: '\x0d' }); // Mark line
assert.equal(xterm.markers[0].line, 10);
await writePromise(xterm, '\n\r2');
await writePromise(xterm, '\x1b[3G'); // Move cursor to column 3
xterm._core._onKey.fire({ key: '\x0d' }); // Mark line
assert.equal(xterm.markers[1].line, 11);
await writePromise(xterm, '\n\r3');
assert.equal(xterm.buffer.baseY, 3);
assert.equal(xterm.buffer.viewportY, 3);
assert.equal(xterm.getSelection(), '');
commandTracker.selectToPreviousLine();
assert.equal(xterm.getSelection(), '2');
commandTracker.selectToNextLine();
commandTracker.selectToNextLine();
assert.equal(xterm.getSelection(), '3');
commandTracker.selectToPreviousCommand();
commandTracker.selectToPreviousCommand();
commandTracker.selectToNextLine();
assert.equal(xterm.getSelection(), '2');
commandTracker.selectToPreviousCommand();
assert.equal(xterm.getSelection(), isWindows ? '1\r\n2' : '1\n2');
commandTracker.selectToPreviousLine();
assert.equal(xterm.getSelection(), isWindows ? '0\r\n1\r\n2' : '0\n1\n2');
document.body.removeChild(e);
});
});
});