diff --git a/src/renderer/dom/DomRenderer.ts b/src/renderer/dom/DomRenderer.ts
index fadd9b72..73c63b46 100644
--- a/src/renderer/dom/DomRenderer.ts
+++ b/src/renderer/dom/DomRenderer.ts
@@ -111,6 +111,8 @@ export class DomRenderer extends EventEmitter implements IRenderer {
element.style.width = `${this.dimensions.canvasWidth}px`;
element.style.height = `${this.dimensions.actualCellHeight}px`;
element.style.lineHeight = `${this.dimensions.actualCellHeight}px`;
+ // Make sure rows don't overflow onto following row
+ element.style.overflow = 'hidden';
});
if (!this._dimensionsStyleElement) {
@@ -330,7 +332,7 @@ export class DomRenderer extends EventEmitter implements IRenderer {
const row = y + terminal.buffer.ydisp;
const lineData = terminal.buffer.lines.get(row);
const cursorStyle = terminal.options.cursorStyle;
- rowElement.appendChild(this._rowFactory.createRow(lineData, row === cursorAbsoluteY, cursorStyle, cursorX, terminal.charMeasure.width, terminal.cols));
+ rowElement.appendChild(this._rowFactory.createRow(lineData, row === cursorAbsoluteY, cursorStyle, cursorX, this.dimensions.actualCellWidth, terminal.cols));
}
this._terminal.emit('refresh', {start, end});
diff --git a/src/renderer/dom/DomRendererRowFactory.test.ts b/src/renderer/dom/DomRendererRowFactory.test.ts
index 2c46d8cc..03f41784 100644
--- a/src/renderer/dom/DomRendererRowFactory.test.ts
+++ b/src/renderer/dom/DomRendererRowFactory.test.ts
@@ -23,11 +23,10 @@ describe('DomRendererRowFactory', () => {
});
describe('createRow', () => {
- it('should create an element for every character in the row', () => {
+ it('should not create anything for an empty row', () => {
const fragment = rowFactory.createRow(lineData, false, undefined, 0, 5, 20);
assert.equal(getFragmentHtml(fragment),
- ' ' +
- ' '
+ ''
);
});
@@ -45,8 +44,7 @@ describe('DomRendererRowFactory', () => {
for (const style of ['block', 'bar', 'underline']) {
const fragment = rowFactory.createRow(lineData, true, style, 0, 5, 20);
assert.equal(getFragmentHtml(fragment),
- ` ` +
- ' '
+ ` `
);
}
});
@@ -65,8 +63,7 @@ describe('DomRendererRowFactory', () => {
lineData.set(0, [DEFAULT_ATTR | (FLAGS.BOLD << 18), 'a', 1, 'a'.charCodeAt(0)]);
const fragment = rowFactory.createRow(lineData, false, undefined, 0, 5, 20);
assert.equal(getFragmentHtml(fragment),
- 'a' +
- ' '
+ 'a'
);
});
@@ -74,8 +71,7 @@ describe('DomRendererRowFactory', () => {
lineData.set(0, [DEFAULT_ATTR | (FLAGS.ITALIC << 18), 'a', 1, 'a'.charCodeAt(0)]);
const fragment = rowFactory.createRow(lineData, false, undefined, 0, 5, 20);
assert.equal(getFragmentHtml(fragment),
- 'a' +
- ' '
+ 'a'
);
});
@@ -85,8 +81,7 @@ describe('DomRendererRowFactory', () => {
lineData.set(0, [defaultAttrNoFgColor | (i << 9), 'a', 1, 'a'.charCodeAt(0)]);
const fragment = rowFactory.createRow(lineData, false, undefined, 0, 5, 20);
assert.equal(getFragmentHtml(fragment),
- `a` +
- ' '
+ `a`
);
}
});
@@ -97,8 +92,7 @@ describe('DomRendererRowFactory', () => {
lineData.set(0, [defaultAttrNoBgColor | (i << 0), 'a', 1, 'a'.charCodeAt(0)]);
const fragment = rowFactory.createRow(lineData, false, undefined, 0, 5, 20);
assert.equal(getFragmentHtml(fragment),
- `a` +
- ' '
+ `a`
);
}
});
@@ -107,8 +101,7 @@ describe('DomRendererRowFactory', () => {
lineData.set(0, [(FLAGS.INVERSE << 18) | (2 << 9) | (1 << 0), 'a', 1, 'a'.charCodeAt(0)]);
const fragment = rowFactory.createRow(lineData, false, undefined, 0, 5, 20);
assert.equal(getFragmentHtml(fragment),
- 'a' +
- ' '
+ 'a'
);
});
@@ -116,8 +109,7 @@ describe('DomRendererRowFactory', () => {
lineData.set(0, [(FLAGS.INVERSE << 18) | (257 << 9) | (1 << 0), 'a', 1, 'a'.charCodeAt(0)]);
const fragment = rowFactory.createRow(lineData, false, undefined, 0, 5, 20);
assert.equal(getFragmentHtml(fragment),
- 'a' +
- ' '
+ 'a'
);
});
@@ -125,8 +117,7 @@ describe('DomRendererRowFactory', () => {
lineData.set(0, [(FLAGS.INVERSE << 18) | (1 << 9) | (256 << 0), 'a', 1, 'a'.charCodeAt(0)]);
const fragment = rowFactory.createRow(lineData, false, undefined, 0, 5, 20);
assert.equal(getFragmentHtml(fragment),
- 'a' +
- ' '
+ 'a'
);
});
@@ -135,8 +126,7 @@ describe('DomRendererRowFactory', () => {
lineData.set(0, [(FLAGS.BOLD << 18) | (i << 9) | (256 << 0), 'a', 1, 'a'.charCodeAt(0)]);
const fragment = rowFactory.createRow(lineData, false, undefined, 0, 5, 20);
assert.equal(getFragmentHtml(fragment),
- `a` +
- ' '
+ `a`
);
}
});
diff --git a/src/renderer/dom/DomRendererRowFactory.ts b/src/renderer/dom/DomRendererRowFactory.ts
index 4bb59902..07303e24 100644
--- a/src/renderer/dom/DomRendererRowFactory.ts
+++ b/src/renderer/dom/DomRendererRowFactory.ts
@@ -3,7 +3,7 @@
* @license MIT
*/
-import { CHAR_DATA_CHAR_INDEX, CHAR_DATA_ATTR_INDEX, CHAR_DATA_WIDTH_INDEX } from '../../Buffer';
+import { CHAR_DATA_CHAR_INDEX, CHAR_DATA_ATTR_INDEX, CHAR_DATA_WIDTH_INDEX, CHAR_DATA_CODE_INDEX, NULL_CELL_CODE } from '../../Buffer';
import { FLAGS } from '../Types';
import { IBufferLine } from '../../Types';
@@ -22,18 +22,27 @@ export class DomRendererRowFactory {
public createRow(lineData: IBufferLine, isCursorRow: boolean, cursorStyle: string | undefined, cursorX: number, cellWidth: number, cols: number): DocumentFragment {
const fragment = this._document.createDocumentFragment();
- let colCount = 0;
-
- for (let x = 0; x < lineData.length; x++) {
- // Don't allow any buffer to the right to be displayed
- if (colCount >= cols) {
- continue;
- }
+ // Find the line length first, this prevents the need to output a bunch of
+ // empty cells at the end. This cannot easily be integrated into the main
+ // loop below because of the colCount feature (which can be removed after we
+ // properly support reflow and disallow data to go beyond the right-side of
+ // the viewport).
+ let lineLength = 0;
+ for (let x = Math.min(lineData.length, cols) - 1; x >= 0; x--) {
const charData = lineData.get(x);
- const char: string = charData[CHAR_DATA_CHAR_INDEX];
- const attr: number = charData[CHAR_DATA_ATTR_INDEX];
- const width: number = charData[CHAR_DATA_WIDTH_INDEX];
+ const code = charData[CHAR_DATA_CODE_INDEX];
+ if (code !== NULL_CELL_CODE || (isCursorRow && x === cursorX)) {
+ lineLength = x + 1;
+ break;
+ }
+ }
+
+ for (let x = 0; x < lineLength; x++) {
+ const charData = lineData.get(x);
+ const char = charData[CHAR_DATA_CHAR_INDEX];
+ const attr = charData[CHAR_DATA_ATTR_INDEX];
+ const width = charData[CHAR_DATA_WIDTH_INDEX];
// The character to the left is a wide character, drawing is owned by the char at x-1
if (width === 0) {
@@ -98,7 +107,6 @@ export class DomRendererRowFactory {
charElement.classList.add(`xterm-bg-${bg}`);
}
fragment.appendChild(charElement);
- colCount += width;
}
return fragment;
}