Skip to content

Commit e260816

Browse files
committed
Support padding on the .xterm element
1 parent cc80114 commit e260816

File tree

12 files changed

+71
-26
lines changed

12 files changed

+71
-26
lines changed

Diff for: demo/index.html

+4
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,10 @@ <h3>Size</h3>
6161
<label for="rows">Rows</label>
6262
<input type="number" id="rows" />
6363
</div>
64+
<div style="display: inline-block; margin-right: 16px;">
65+
<label for="padding">Padding</label>
66+
<input type="number" id="padding" />
67+
</div>
6468
</div>
6569
</div>
6670
</div>

Diff for: demo/main.js

+11-6
Original file line numberDiff line numberDiff line change
@@ -32,23 +32,27 @@ var terminalContainer = document.getElementById('terminal-container'),
3232
bellStyle: document.querySelector('#option-bell-style')
3333
},
3434
colsElement = document.getElementById('cols'),
35-
rowsElement = document.getElementById('rows');
35+
rowsElement = document.getElementById('rows'),
36+
paddingElement = document.getElementById('padding');
3637

3738
function setTerminalSize() {
3839
var cols = parseInt(colsElement.value, 10);
3940
var rows = parseInt(rowsElement.value, 10);
40-
var viewportElement = document.querySelector('.xterm-viewport');
41-
var scrollBarWidth = viewportElement.offsetWidth - viewportElement.clientWidth;
42-
var width = (cols * term.renderer.dimensions.actualCellWidth + 20 /*room for scrollbar*/).toString() + 'px';
41+
var width = (cols * term.renderer.dimensions.actualCellWidth + term.viewport.scrollBarWidth).toString() + 'px';
4342
var height = (rows * term.renderer.dimensions.actualCellHeight).toString() + 'px';
44-
4543
terminalContainer.style.width = width;
4644
terminalContainer.style.height = height;
47-
term.resize(cols, rows);
45+
term.fit();
46+
}
47+
48+
function setPadding() {
49+
term.element.style.padding = parseInt(paddingElement.value, 10).toString() + 'px';
50+
term.fit();
4851
}
4952

5053
colsElement.addEventListener('change', setTerminalSize);
5154
rowsElement.addEventListener('change', setTerminalSize);
55+
paddingElement.addEventListener('change', setPadding);
5256

5357
actionElements.findNext.addEventListener('keypress', function (e) {
5458
if (e.key === "Enter") {
@@ -114,6 +118,7 @@ function createTerminal() {
114118
setTimeout(function () {
115119
colsElement.value = term.cols;
116120
rowsElement.value = term.rows;
121+
paddingElement.value = 0;
117122

118123
// Set terminal size again to set the specific dimensions on the demo
119124
setTerminalSize();

Diff for: src/Interfaces.ts

+3
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ export interface ILinkifierAccessor {
3333
}
3434

3535
export interface ITerminal extends ILinkifierAccessor, IBufferAccessor, IElementAccessor, IEventEmitter {
36+
screenElement: HTMLElement;
3637
selectionManager: ISelectionManager;
3738
charMeasure: ICharMeasure;
3839
textarea: HTMLTextAreaElement;
@@ -48,6 +49,7 @@ export interface ITerminal extends ILinkifierAccessor, IBufferAccessor, IElement
4849
buffers: IBufferSet;
4950
isFocused: boolean;
5051
mouseHelper: IMouseHelper;
52+
viewport: IViewport;
5153
bracketedPasteMode: boolean;
5254

5355
/**
@@ -184,6 +186,7 @@ export interface IMouseHelper {
184186
}
185187

186188
export interface IViewport {
189+
scrollBarWidth: number;
187190
syncScrollArea(): void;
188191
onWheel(ev: WheelEvent): void;
189192
onTouchStart(ev: TouchEvent): void;

Diff for: src/SelectionManager.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -274,7 +274,7 @@ export class SelectionManager extends EventEmitter implements ISelectionManager
274274
* @param event The mouse event.
275275
*/
276276
private _getMouseBufferCoords(event: MouseEvent): [number, number] {
277-
const coords = this._terminal.mouseHelper.getCoords(event, this._terminal.element, this._charMeasure, this._terminal.options.lineHeight, this._terminal.cols, this._terminal.rows, true);
277+
const coords = this._terminal.mouseHelper.getCoords(event, this._terminal.screenElement, this._charMeasure, this._terminal.options.lineHeight, this._terminal.cols, this._terminal.rows, true);
278278
if (!coords) {
279279
return null;
280280
}
@@ -294,7 +294,7 @@ export class SelectionManager extends EventEmitter implements ISelectionManager
294294
* @param event The mouse event.
295295
*/
296296
private _getMouseEventScrollAmount(event: MouseEvent): number {
297-
let offset = MouseHelper.getCoordsRelativeToElement(event, this._terminal.element)[1];
297+
let offset = MouseHelper.getCoordsRelativeToElement(event, this._terminal.screenElement)[1];
298298
const terminalHeight = this._terminal.rows * Math.ceil(this._charMeasure.height * this._terminal.options.lineHeight);
299299
if (offset >= 0 && offset <= terminalHeight) {
300300
return 0;

Diff for: src/Terminal.ts

+7-2
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,7 @@ const DEFAULT_OPTIONS: ITerminalOptions = {
9292
export class Terminal extends EventEmitter implements ITerminal, IInputHandlingTerminal {
9393
public textarea: HTMLTextAreaElement;
9494
public element: HTMLElement;
95+
public screenElement: HTMLElement;
9596

9697
/**
9798
* The HTMLElement that the terminal is created in, set by Terminal.open.
@@ -593,6 +594,10 @@ export class Terminal extends EventEmitter implements ITerminal, IInputHandlingT
593594
this.viewportScrollArea.classList.add('xterm-scroll-area');
594595
this.viewportElement.appendChild(this.viewportScrollArea);
595596

597+
this.screenElement = document.createElement('div');
598+
this.screenElement.classList.add('xterm-screen');
599+
fragment.appendChild(this.screenElement);
600+
596601
this._mouseZoneManager = new MouseZoneManager(this);
597602
this.on('scroll', () => this._mouseZoneManager.clearAll());
598603
this.linkifier.attachToDom(this._mouseZoneManager);
@@ -719,7 +724,7 @@ export class Terminal extends EventEmitter implements ITerminal, IInputHandlingT
719724
button = getButton(ev);
720725

721726
// get mouse coordinates
722-
pos = self.mouseHelper.getRawByteCoords(ev, self.element, self.charMeasure, self.options.lineHeight, self.cols, self.rows);
727+
pos = self.mouseHelper.getRawByteCoords(ev, self.screenElement, self.charMeasure, self.options.lineHeight, self.cols, self.rows);
723728
if (!pos) return;
724729

725730
sendEvent(button, pos);
@@ -745,7 +750,7 @@ export class Terminal extends EventEmitter implements ITerminal, IInputHandlingT
745750
// ^[[M 3<^[[M@4<^[[M@5<^[[M@6<^[[M@7<^[[M#7<
746751
function sendMove(ev: MouseEvent): void {
747752
let button = pressed;
748-
let pos = self.mouseHelper.getRawByteCoords(ev, self.element, self.charMeasure, self.options.lineHeight, self.cols, self.rows);
753+
let pos = self.mouseHelper.getRawByteCoords(ev, self.screenElement, self.charMeasure, self.options.lineHeight, self.cols, self.rows);
749754
if (!pos) return;
750755

751756
// buttons marked as motions

Diff for: src/Viewport.ts

+7-7
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import { IColorSet } from './renderer/Interfaces';
1212
* Logic for the virtual scroll bar is included in this object.
1313
*/
1414
export class Viewport implements IViewport {
15+
public scrollBarWidth: number = 0;
1516
private currentRowHeight: number = 0;
1617
private lastRecordedBufferLength: number = 0;
1718
private lastRecordedViewportHeight: number = 0;
@@ -31,6 +32,10 @@ export class Viewport implements IViewport {
3132
private scrollArea: HTMLElement,
3233
private charMeasure: CharMeasure
3334
) {
35+
// Measure the width of the scrollbar. If it is 0 we can assume it's an OSX overlay scrollbar.
36+
// Unfortunately the overlay scrollbar would be hidden underneath the screen element in that case,
37+
// therefore we account 15px to make it visible
38+
this.scrollBarWidth = (this.viewportElement.offsetWidth - this.scrollArea.offsetWidth) || 15;
3439
this.viewportElement.addEventListener('scroll', this.onScroll.bind(this));
3540

3641
// Perform this async to ensure the CharMeasure is ready.
@@ -48,13 +53,8 @@ export class Viewport implements IViewport {
4853
private refresh(): void {
4954
if (this.charMeasure.height > 0) {
5055
this.currentRowHeight = this.terminal.renderer.dimensions.scaledCellHeight / window.devicePixelRatio;
51-
52-
if (this.lastRecordedViewportHeight !== this.terminal.renderer.dimensions.canvasHeight) {
53-
this.lastRecordedViewportHeight = this.terminal.renderer.dimensions.canvasHeight;
54-
this.viewportElement.style.height = this.lastRecordedViewportHeight + 'px';
55-
}
56-
57-
const newBufferHeight = Math.round(this.currentRowHeight * this.lastRecordedBufferLength);
56+
this.lastRecordedViewportHeight = this.viewportElement.offsetHeight;
57+
const newBufferHeight = Math.round(this.currentRowHeight * this.lastRecordedBufferLength) + (this.lastRecordedViewportHeight - this.terminal.renderer.dimensions.canvasHeight);
5858
if (this.lastRecordedBufferHeight !== newBufferHeight) {
5959
this.lastRecordedBufferHeight = newBufferHeight;
6060
this.scrollArea.style.height = this.lastRecordedBufferHeight + 'px';

Diff for: src/addons/fit/fit.ts

+9-3
Original file line numberDiff line numberDiff line change
@@ -21,10 +21,16 @@ export function proposeGeometry(term) {
2121
var parentElementHeight = parseInt(parentElementStyle.getPropertyValue('height'));
2222
var parentElementWidth = Math.max(0, parseInt(parentElementStyle.getPropertyValue('width')) - 17);
2323
var elementStyle = window.getComputedStyle(term.element);
24-
var elementPaddingVer = parseInt(elementStyle.getPropertyValue('padding-top')) + parseInt(elementStyle.getPropertyValue('padding-bottom'));
25-
var elementPaddingHor = parseInt(elementStyle.getPropertyValue('padding-right')) + parseInt(elementStyle.getPropertyValue('padding-left'));
24+
var elementPadding = {
25+
top: parseInt(elementStyle.getPropertyValue('padding-top')),
26+
bottom: parseInt(elementStyle.getPropertyValue('padding-bottom')),
27+
right: parseInt(elementStyle.getPropertyValue('padding-right')),
28+
left: parseInt(elementStyle.getPropertyValue('padding-left'))
29+
}
30+
var elementPaddingVer = elementPadding.top + elementPadding.bottom;
31+
var elementPaddingHor = elementPadding.right + elementPadding.left;
2632
var availableHeight = parentElementHeight - elementPaddingVer;
27-
var availableWidth = parentElementWidth - elementPaddingHor;
33+
var availableWidth = parentElementWidth - elementPaddingHor - term.viewport.scrollBarWidth;
2834
var geometry = {
2935
cols: Math.floor(availableWidth / term.renderer.dimensions.actualCellWidth),
3036
rows: Math.floor(availableHeight / term.renderer.dimensions.actualCellHeight)

Diff for: src/input/MouseZoneManager.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -169,7 +169,7 @@ export class MouseZoneManager implements IMouseZoneManager {
169169
}
170170

171171
private _findZoneEventAt(e: MouseEvent): IMouseZone {
172-
const coords = this._terminal.mouseHelper.getCoords(e, this._terminal.element, this._terminal.charMeasure, this._terminal.options.lineHeight, this._terminal.cols, this._terminal.rows);
172+
const coords = this._terminal.mouseHelper.getCoords(e, this._terminal.screenElement, this._terminal.charMeasure, this._terminal.options.lineHeight, this._terminal.cols, this._terminal.rows);
173173
if (!coords) {
174174
return null;
175175
}

Diff for: src/renderer/Renderer.ts

+8-4
Original file line numberDiff line numberDiff line change
@@ -36,10 +36,10 @@ export class Renderer extends EventEmitter implements IRenderer {
3636
this.colorManager.setTheme(theme);
3737
}
3838
this._renderLayers = [
39-
new TextRenderLayer(this._terminal.element, 0, this.colorManager.colors),
40-
new SelectionRenderLayer(this._terminal.element, 1, this.colorManager.colors),
41-
new LinkRenderLayer(this._terminal.element, 2, this.colorManager.colors, this._terminal),
42-
new CursorRenderLayer(this._terminal.element, 3, this.colorManager.colors)
39+
new TextRenderLayer(this._terminal.screenElement, 0, this.colorManager.colors),
40+
new SelectionRenderLayer(this._terminal.screenElement, 1, this.colorManager.colors),
41+
new LinkRenderLayer(this._terminal.screenElement, 2, this.colorManager.colors, this._terminal),
42+
new CursorRenderLayer(this._terminal.screenElement, 3, this.colorManager.colors)
4343
];
4444
this.dimensions = {
4545
scaledCharWidth: null,
@@ -117,6 +117,10 @@ export class Renderer extends EventEmitter implements IRenderer {
117117
this._terminal.refresh(0, this._terminal.rows - 1);
118118
}
119119

120+
// Resize the screen
121+
this._terminal.screenElement.style.width = `${this.dimensions.canvasWidth + this._terminal.viewport.scrollBarWidth}px`;
122+
this._terminal.screenElement.style.height = `${this.dimensions.canvasHeight}px`;
123+
120124
this.emit('resize', {
121125
width: this.dimensions.canvasWidth,
122126
height: this.dimensions.canvasHeight

Diff for: src/utils/TestUtils.test.ts

+3
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ export class MockTerminal implements ITerminal {
1717
isFocused: boolean;
1818
options: ITerminalOptions = {};
1919
element: HTMLElement;
20+
screenElement: HTMLElement;
2021
rowContainer: HTMLElement;
2122
selectionContainer: HTMLElement;
2223
selectionManager: ISelectionManager;
@@ -33,6 +34,7 @@ export class MockTerminal implements ITerminal {
3334
scrollback: number;
3435
buffers: IBufferSet;
3536
buffer: IBuffer;
37+
viewport: IViewport;
3638
handler(data: string): void {
3739
throw new Error('Method not implemented.');
3840
}
@@ -244,6 +246,7 @@ export class MockRenderer implements IRenderer {
244246
}
245247

246248
export class MockViewport implements IViewport {
249+
scrollBarWidth: number = 0;
247250
onThemeChanged(colors: IColorSet): void {
248251
throw new Error('Method not implemented.');
249252
}

Diff for: src/xterm.css

+11-1
Original file line numberDiff line numberDiff line change
@@ -96,9 +96,19 @@
9696
background-color: #000;
9797
overflow-y: scroll;
9898
cursor: default;
99+
position: absolute;
100+
right: 0;
101+
left: 0;
102+
top: 0;
103+
bottom: 0;
104+
}
105+
106+
.xterm .xterm-screen {
107+
position: relative;
108+
pointer-events: none;
99109
}
100110

101-
.xterm canvas {
111+
.xterm .xterm-screen canvas {
102112
position: absolute;
103113
left: 0;
104114
top: 0;

Diff for: typings/xterm.d.ts

+5
Original file line numberDiff line numberDiff line change
@@ -180,6 +180,11 @@ declare module 'xterm' {
180180
* The element containing the terminal.
181181
*/
182182
element: HTMLElement;
183+
184+
/**
185+
* The element containing the rendered screen content.
186+
*/
187+
screenElement: HTMLElement;
183188

184189
/**
185190
* The textarea that accepts input for the terminal.

0 commit comments

Comments
 (0)