change WindowOptions type

This commit is contained in:
Jörg Breitbart
2019-11-14 11:23:21 +01:00
parent 8fc2d22b28
commit eeb9270882
8 changed files with 82 additions and 130 deletions
+3 -3
View File
@@ -244,7 +244,8 @@ function initOptions(term: TerminalType): void {
'termName',
'useFlowControl',
// Complex option
'theme'
'theme',
'windowOptions'
];
const stringOptions = {
bellSound: null,
@@ -256,8 +257,7 @@ function initOptions(term: TerminalType): void {
fontWeightBold: ['normal', 'bold', '100', '200', '300', '400', '500', '600', '700', '800', '900'],
logLevel: ['debug', 'info', 'warn', 'error', 'off'],
rendererType: ['dom', 'canvas'],
wordSeparator: null,
allowedWindowOps: ''
wordSeparator: null
};
const options = Object.keys((<any>term)._core.options);
const booleanOptions = [];
+20 -19
View File
@@ -17,6 +17,7 @@ import { MockCoreService, MockBufferService, MockDirtyRowService, MockOptionsSer
import { IBufferService } from 'common/services/Services';
import { DEFAULT_OPTIONS } from 'common/services/OptionsService';
import { clone } from 'common/Clone';
import { WindowOptions } from 'common/WindowOptions';
function getCursor(term: TestTerminal): number[] {
return [
@@ -1266,10 +1267,10 @@ describe('InputHandler', () => {
[131072, 131072], [131072, 131072], [131072, 300000 - 131072 - 131072]
]);
});
describe('windowOps', () => {
describe('windowOptions', () => {
it('all should be disabled by default and not report', () => {
const term = new TestTerminal({cols: 10, rows: 10});
assert.deepEqual(term.options.allowedWindowOps, []);
assert.deepEqual(term.options.windowOptions, 0);
const stack: string[] = [];
term.onData(data => stack.push(data));
term.writeSync('\x1b[14t');
@@ -1280,8 +1281,8 @@ describe('InputHandler', () => {
assert.deepEqual(stack, []);
});
it('14 - GetWinSizePixels', () => {
const term = new TestTerminal({cols: 10, rows: 10, allowedWindowOps: [14]});
assert.deepEqual(term.options.allowedWindowOps, [14]);
const term = new TestTerminal({cols: 10, rows: 10, windowOptions: WindowOptions.getWinSizePixels});
assert.deepEqual(term.options.windowOptions, 1 << 14);
const stack: string[] = [];
term.onData(data => stack.push(data));
term.writeSync('\x1b[14t');
@@ -1289,8 +1290,8 @@ describe('InputHandler', () => {
assert.deepEqual(stack, []);
});
it('16 - GetCellSizePixels', () => {
const term = new TestTerminal({cols: 10, rows: 10, allowedWindowOps: [16]});
assert.deepEqual(term.options.allowedWindowOps, [16]);
const term = new TestTerminal({cols: 10, rows: 10, windowOptions: WindowOptions.getCellSizePixels});
assert.deepEqual(term.options.windowOptions, 1 << 16);
const stack: string[] = [];
term.onData(data => stack.push(data));
term.writeSync('\x1b[16t');
@@ -1298,8 +1299,8 @@ describe('InputHandler', () => {
assert.deepEqual(stack, []);
});
it('18 - GetWinSizeChars', () => {
const term = new TestTerminal({cols: 10, rows: 10, allowedWindowOps: [18]});
assert.deepEqual(term.options.allowedWindowOps, [18]);
const term = new TestTerminal({cols: 10, rows: 10, windowOptions: WindowOptions.getWinSizeChars});
assert.deepEqual(term.options.windowOptions, 1 << 18);
const stack: string[] = [];
term.onData(data => stack.push(data));
term.writeSync('\x1b[18t');
@@ -1309,8 +1310,8 @@ describe('InputHandler', () => {
assert.deepEqual(stack, ['\x1b[8;10;10t', '\x1b[8;20;50t']);
});
it('20 - GetIconTitle', () => {
const term = new TestTerminal({cols: 10, rows: 10, allowedWindowOps: [20]});
assert.deepEqual(term.options.allowedWindowOps, [20]);
const term = new TestTerminal({cols: 10, rows: 10, windowOptions: WindowOptions.getIconTitle});
assert.deepEqual(term.options.windowOptions, 1 << 20);
const stack: string[] = [];
term.onData(data => stack.push(data));
term.writeSync('\x1b]1;hello world!\x07');
@@ -1321,8 +1322,8 @@ describe('InputHandler', () => {
assert.deepEqual(stack, ['\x1b]Lhello world!\x1b\\', '\x1b]Lsome other\x1b\\']);
});
it('21 - GetWinTitle', () => {
const term = new TestTerminal({cols: 10, rows: 10, allowedWindowOps: [21]});
assert.deepEqual(term.options.allowedWindowOps, [21]);
const term = new TestTerminal({cols: 10, rows: 10, windowOptions: WindowOptions.getWinTitle});
assert.deepEqual(term.options.windowOptions, 1 << 21);
const stack: string[] = [];
term.onData(data => stack.push(data));
term.writeSync('\x1b]2;hello world!\x07');
@@ -1333,8 +1334,8 @@ describe('InputHandler', () => {
assert.deepEqual(stack, ['\x1b]lhello world!\x1b\\', '\x1b]lsome other\x1b\\']);
});
it('22/23 - PushTitle/PopTitle', () => {
const term = new TestTerminal({cols: 10, rows: 10, allowedWindowOps: [22, 23]});
assert.deepEqual(term.options.allowedWindowOps, [22, 23]);
const term = new TestTerminal({cols: 10, rows: 10, windowOptions: WindowOptions.pushTitle | WindowOptions.popTitle});
assert.deepEqual(term.options.windowOptions, (1 << 22) | (1 << 23));
const stack: string[] = [];
term.onTitleChange(data => stack.push(data));
term.writeSync('\x1b]0;1\x07');
@@ -1355,8 +1356,8 @@ describe('InputHandler', () => {
assert.deepEqual(stack, ['1', '2', '3', '3', '2', '1']);
});
it('22/23 - PushTitle/PopTitle with ;1', () => {
const term = new TestTerminal({cols: 10, rows: 10, allowedWindowOps: [22, 23]});
assert.deepEqual(term.options.allowedWindowOps, [22, 23]);
const term = new TestTerminal({cols: 10, rows: 10, windowOptions: WindowOptions.pushTitle | WindowOptions.popTitle});
assert.deepEqual(term.options.windowOptions, (1 << 22) | (1 << 23));
const stack: string[] = [];
term.onTitleChange(data => stack.push(data));
term.writeSync('\x1b]0;1\x07');
@@ -1377,8 +1378,8 @@ describe('InputHandler', () => {
assert.deepEqual(stack, ['1', '2', '3']);
});
it('22/23 - PushTitle/PopTitle with ;2', () => {
const term = new TestTerminal({cols: 10, rows: 10, allowedWindowOps: [22, 23]});
assert.deepEqual(term.options.allowedWindowOps, [22, 23]);
const term = new TestTerminal({cols: 10, rows: 10, windowOptions: WindowOptions.pushTitle | WindowOptions.popTitle});
assert.deepEqual(term.options.windowOptions, (1 << 22) | (1 << 23));
const stack: string[] = [];
term.onTitleChange(data => stack.push(data));
term.writeSync('\x1b]0;1\x07');
@@ -1406,7 +1407,7 @@ describe('InputHandler', () => {
term.writeSync('\x1b[?3h');
assert.equal((term as any)._bufferService.cols, 10);
// enabled
const term2 = new TestTerminal({cols: 10, rows: 10, allowedWindowOps: [24]});
const term2 = new TestTerminal({cols: 10, rows: 10, windowOptions: WindowOptions.setWinLines});
term2.writeSync('\x1b[?3l');
assert.equal((term2 as any)._bufferService.cols, 80);
term2.writeSync('\x1b[?3h');
+13 -11
View File
@@ -22,6 +22,7 @@ import { IAttributeData, IDisposable } from 'common/Types';
import { ICoreService, IBufferService, IOptionsService, ILogService, IDirtyRowService, ICoreMouseService } from 'common/services/Services';
import { OscHandler } from 'common/parser/OscParser';
import { DcsHandler } from 'common/parser/DcsParser';
import { hasWindowOption, WindowOptions } from 'common/WindowOptions';
/**
* Map collect to glevel. Used in `selectCharset`.
@@ -520,7 +521,7 @@ export class InputHandler extends Disposable implements IInputHandler {
if (id.final === 't' && !id.prefix && !id.intermediates) {
// security: always check whether window option is allowed
return this._parser.addCsiHandler(id, params => {
if (!~this._optionsService.options.allowedWindowOps.indexOf(params.params[0])) {
if (!hasWindowOption(params.params[0], this._optionsService.options.windowOptions)) {
return true;
}
return callback(params);
@@ -1419,9 +1420,9 @@ export class InputHandler extends Disposable implements IInputHandler {
/**
* DECCOLM - 132 column mode.
* This is only active if 'SetWinLines' (24) is listed
* in `options.allowedWindowOps`.
* in `options.windowsOptions`.
*/
if (~this._optionsService.options.allowedWindowOps.indexOf(24)) {
if (this._optionsService.options.windowOptions & WindowOptions.setWinLines) {
this._terminal.resize(132, this._bufferService.rows);
this._terminal.reset();
}
@@ -1606,9 +1607,9 @@ export class InputHandler extends Disposable implements IInputHandler {
/**
* DECCOLM - 80 column mode.
* This is only active if 'SetWinLines' (24) is listed
* in `options.allowedWindowOps`.
* in `options.windowsOptions`.
*/
if (~this._optionsService.options.allowedWindowOps.indexOf(24)) {
if (this._optionsService.options.windowOptions & WindowOptions.setWinLines) {
this._terminal.resize(80, this._bufferService.rows);
this._terminal.reset();
}
@@ -2081,8 +2082,8 @@ export class InputHandler extends Disposable implements IInputHandler {
* Ps = 23 ; 2 -> Restore xterm window title from stack. supported
* Ps >= 24 not implemented
*/
public windowOptions(params?: IParams): void {
if (!~this._optionsService.options.allowedWindowOps.indexOf(params.params[0])) {
public windowOptions(params: IParams): void {
if (!hasWindowOption(params.params[0], this._optionsService.options.windowOptions)) {
return;
}
const second = (params.length > 1) ? params.params[1] : 0;
@@ -2090,15 +2091,16 @@ export class InputHandler extends Disposable implements IInputHandler {
switch (params.params[0]) {
case 14: // GetWinSizePixels, returns CSI 4 ; height ; width t
if (rs && second !== 2) {
const w = rs.dimensions.canvasWidth.toFixed(0);
const h = rs.dimensions.canvasHeight.toFixed(0);
console.log(rs.dimensions);
const w = rs.dimensions.scaledCanvasWidth.toFixed(0);
const h = rs.dimensions.scaledCanvasHeight.toFixed(0);
this._coreService.triggerDataEvent(`${C0.ESC}[4;${h};${w}t`);
}
break;
case 16: // GetCellSizePixels, returns CSI 6 ; height ; width t
if (rs) {
const w = rs.dimensions.actualCellWidth.toFixed(0);
const h = rs.dimensions.actualCellHeight.toFixed(0);
const w = rs.dimensions.scaledCellWidth.toFixed(0);
const h = rs.dimensions.scaledCellHeight.toFixed(0);
this._coreService.triggerDataEvent(`${C0.ESC}[6;${h};${w}t`);
}
break;
+29
View File
@@ -251,3 +251,32 @@ export interface ICoreMouseProtocol {
* with the active encoding and sent out.
*/
export type CoreMouseEncoding = (event: ICoreMouseEvent) => string;
/**
* WindowOption settings.
*/
export interface IWindowOptions {
[key: string]: boolean | undefined;
restoreWin?: boolean;
minimizeWin?: boolean;
setWinPosition?: boolean;
setWinSizePixels?: boolean;
raiseWin?: boolean;
lowerWin?: boolean;
refreshWin?: boolean;
setWinSizeChars?: boolean;
maximizeWin?: boolean;
fullscreenWin?: boolean;
getWinState?: boolean;
getWinPosition?: boolean;
getWinSizePixels?: boolean;
getScreenSizePixels?: boolean;
getCellSizePixels?: boolean;
getWinSizeChars?: boolean;
getScreenSizeChars?: boolean;
getIconTitle?: boolean;
getWinTitle?: boolean;
pushTitle?: boolean;
popTitle?: boolean;
setWinLines?: boolean;
}
@@ -2,34 +2,9 @@
* Copyright (c) 2019 The xterm.js authors. All rights reserved.
* @license MIT
*/
import { IWindowOptions } from 'common/Types';
interface IWindowOptions {
[key: string]: boolean | undefined;
restoreWin?: boolean;
minimizeWin?: boolean;
setWinPosition?: boolean;
setWinSizePixels?: boolean;
raiseWin?: boolean;
lowerWin?: boolean;
refreshWin?: boolean;
setWinSizeChars?: boolean;
maximizeWin?: boolean;
fullscreenWin?: boolean;
getWinState?: boolean;
getWinPosition?: boolean;
getWinSizePixels?: boolean;
getScreenSizePixels?: boolean;
getCellSizePixels?: boolean;
getWinSizeChars?: boolean;
getScreenSizeChars?: boolean;
getIconTitle?: boolean;
getWinTitle?: boolean;
pushTitle?: boolean;
popTitle?: boolean;
setWinLines?: boolean;
}
const enum WindowOptions {
export const enum WindowOptions {
restoreWin = 1 << 1,
minimizeWin = 1 << 2,
setWinPosition = 1 << 3,
@@ -54,21 +29,11 @@ const enum WindowOptions {
setWinLines = 1 << 24 // any param >= 24, also handles DECCOLM
}
let layer: {[key in keyof typeof WindowOptions]?: boolean}
function hasOption(n: number, opts: WindowOptions): boolean {
return !!(opts & (1 << Math.max(n, 24)));
export function hasWindowOption(n: number, opts: WindowOptions): boolean {
return !!(opts & (1 << Math.min(n, 24)));
}
function getOptions(opts: WindowOptions): IWindowOptions {
/*
const result: IWindowOptions = {};
for (const key in WindowOptions) {
if (parseInt(key)) continue;
result[key] = !!(opts & WindowOptions[key as any] as unknown as number);
}
return result;
*/
export function getWindowOptions(opts: WindowOptions): IWindowOptions {
return {
restoreWin: !!(opts & WindowOptions.restoreWin),
minimizeWin: !!(opts & WindowOptions.minimizeWin),
@@ -95,11 +60,9 @@ function getOptions(opts: WindowOptions): IWindowOptions {
};
}
function setOptions(v: IWindowOptions & {[key: string]: boolean}, opts: WindowOptions): WindowOptions {
export function setWindowOptions(v: IWindowOptions & {[key: string]: boolean}, opts: WindowOptions): WindowOptions {
for (const optionName in v) {
const value = v[optionName];
//const option = WindowOptions[optionName as any] as unknown as number;
//opts = value ? opts | option : opts & ~option;
switch (optionName) {
case 'restoreWin': opts = value ? opts | WindowOptions.restoreWin : opts & ~WindowOptions.restoreWin; break;
case 'minimizeWin': opts = value ? opts | WindowOptions.minimizeWin : opts & ~WindowOptions.minimizeWin; break;
@@ -128,10 +91,3 @@ function setOptions(v: IWindowOptions & {[key: string]: boolean}, opts: WindowOp
}
return opts;
}
declare const console: any;
let opts: WindowOptions = 0;
opts = setOptions({refreshWin: true, pushTitle: true, popTitle: true}, opts);
console.log(opts);
console.log(getOptions(opts));
+6 -44
View File
@@ -7,6 +7,7 @@ import { IOptionsService, ITerminalOptions, IPartialTerminalOptions } from 'comm
import { EventEmitter, IEvent } from 'common/EventEmitter';
import { isMac } from 'common/Platform';
import { clone } from 'common/Clone';
import { setWindowOptions, getWindowOptions } from 'common/WindowOptions';
// Source: https://freesound.org/people/altemark/sounds/45759/
// This sound is released under the Creative Commons Attribution 3.0 Unported
@@ -14,33 +15,6 @@ import { clone } from 'common/Clone';
// made, apart from the conversion to base64.
export const DEFAULT_BELL_SOUND = 'data:audio/mp3;base64,SUQzBAAAAAAAI1RTU0UAAAAPAAADTGF2ZjU4LjMyLjEwNAAAAAAAAAAAAAAA//tQxAADB8AhSmxhIIEVCSiJrDCQBTcu3UrAIwUdkRgQbFAZC1CQEwTJ9mjRvBA4UOLD8nKVOWfh+UlK3z/177OXrfOdKl7pyn3Xf//WreyTRUoAWgBgkOAGbZHBgG1OF6zM82DWbZaUmMBptgQhGjsyYqc9ae9XFz280948NMBWInljyzsNRFLPWdnZGWrddDsjK1unuSrVN9jJsK8KuQtQCtMBjCEtImISdNKJOopIpBFpNSMbIHCSRpRR5iakjTiyzLhchUUBwCgyKiweBv/7UsQbg8isVNoMPMjAAAA0gAAABEVFGmgqK////9bP/6XCykxBTUUzLjEwMKqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq';
// setting names controlled by allowedWindowOps
// not supported: GetChecksum, GetSelection, SetChecksum, SetSelection, SetXprop
export const WINDOW_OPTIONS: {[key: string]: number} = {
'RestoreWin': 1,
'MinimizeWin': 2,
'SetWinPosition': 3,
'SetWinSizePixels': 4,
'RaiseWin': 5,
'LowerWin': 6,
'RefreshWin': 7,
'SetWinSizeChars': 8,
'MaximizeWin': 9,
'FullscreenWin': 10,
'GetWinState': 11,
'GetWinPosition': 13,
'GetWinSizePixels': 14,
'GetScreenSizePixels': 15, // note: name not in xterm
'GetCellSizePixels': 16, // note: name not in xterm
'GetWinSizeChars': 18,
'GetScreenSizeChars': 19,
'GetIconTitle': 20,
'GetWinTitle': 21,
'PushTitle': 22,
'PopTitle': 23,
'SetWinLines': 24 // any param >= 24, also handles DECCOLM
};
// TODO: Freeze?
export const DEFAULT_OPTIONS: ITerminalOptions = Object.freeze({
@@ -79,7 +53,7 @@ export const DEFAULT_OPTIONS: ITerminalOptions = Object.freeze({
cancelEvents: false,
useFlowControl: false,
wordSeparator: ' ()[]{}\',:;"',
allowedWindowOps: []
windowOptions: 0
});
/**
@@ -157,20 +131,8 @@ export class OptionsService implements IOptionsService {
throw new Error(`${key} cannot be less than or equal to 0, value: ${value}`);
}
break;
case 'allowedWindowOps':
const values = (value as string).split(',');
const cleaned: number[] = [];
for (let i = 0; i < values.length; ++i) {
const option = parseInt(values[i].trim()) || WINDOW_OPTIONS[values[i].trim()];
if (!option || option < 0 || option > 24) {
throw new Error(`unknown window option "${values[i]}"`);
}
if (!~cleaned.indexOf(option)) {
cleaned.push(option);
}
}
value = cleaned;
break;
case 'windowOptions':
value = setWindowOptions(value, this.options.windowOptions);
}
return value;
}
@@ -179,8 +141,8 @@ export class OptionsService implements IOptionsService {
if (!(key in DEFAULT_OPTIONS)) {
throw new Error(`No option with key "${key}"`);
}
if (key === 'allowedWindowOps') {
return this.options[key].join();
if (key === 'windowOptions') {
return getWindowOptions(this.options.windowOptions);
}
return this.options[key];
}
+4 -2
View File
@@ -7,6 +7,7 @@ import { IEvent } from 'common/EventEmitter';
import { IBuffer, IBufferSet } from 'common/buffer/Types';
import { IDecPrivateModes, ICoreMouseEvent, CoreMouseEncoding, ICoreMouseProtocol, CoreMouseEventType } from 'common/Types';
import { createDecorator } from 'common/services/ServiceRegistry';
import { WindowOptions } from 'common/WindowOptions';
export const IBufferService = createDecorator<IBufferService>('BufferService');
export interface IBufferService {
@@ -207,7 +208,7 @@ export interface IPartialTerminalOptions {
theme?: ITheme;
windowsMode?: boolean;
wordSeparator?: string;
allowedWindowOps?: number[];
windowOptions?: WindowOptions;
}
export interface ITerminalOptions {
@@ -247,7 +248,7 @@ export interface ITerminalOptions {
screenKeys: boolean;
termName: string;
useFlowControl: boolean;
allowedWindowOps: number[];
windowOptions: WindowOptions;
}
export interface ITheme {
@@ -273,3 +274,4 @@ export interface ITheme {
brightCyan?: string;
brightWhite?: string;
}
+1 -1
View File
@@ -440,7 +440,7 @@ declare module 'xterm' {
/**
* Ps=14 Report xterm text area size in pixels. Result is "CSI 4 ; height ; width t".
* Ps=14 ; 2 Report xterm window size in pixels. Result is "CSI 4 ; height ; width t".
* Ps=14 has a default implementation.
* Ps=14 has a default implementation (also handles Ps=14 ; 2 if not overwritten by custom implementation).
*/
getWinSizePixels?: boolean;
/** Ps=15 Report size of the screen in pixels. Result is "CSI 5 ; height ; width t". */