Skip to content

Commit

Permalink
fix BCE
Browse files Browse the repository at this point in the history
  • Loading branch information
jerch committed Jul 24, 2023
1 parent 90f1318 commit 3715301
Show file tree
Hide file tree
Showing 7 changed files with 76 additions and 60 deletions.
18 changes: 17 additions & 1 deletion demo/client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -228,6 +228,7 @@ if (document.location.pathname === '/test') {
document.getElementById('add-decoration').addEventListener('click', addDecoration);
document.getElementById('add-overview-ruler').addEventListener('click', addOverviewRuler);
document.getElementById('weblinks-test').addEventListener('click', testWeblinks);
document.getElementById('bce').addEventListener('click', coloredErase);
addVtButtons();
}

Expand Down Expand Up @@ -1186,6 +1187,21 @@ ipv6 https://[::1]/with/some?vars=and&a#hash aaa
stop at final '.': This is a sentence with an url to http://example.com.
stop at final '?': Is this the right url http://example.com/?
stop at final '?': Maybe this one http://example.com/with?arguments=false?
`;
`;
term.write(linkExamples.split('\n').join('\r\n'));
}


function coloredErase(): void {
const data = `
Test BG-colored Erase (BCE):
The color block in the following lines should look identical.
For newly created rows at the bottom the last color should be applied
for all cells to the right.
def 41 42 43 44 45 46 47\x1b[47m
\x1b[m \x1b[41m \x1b[42m \x1b[43m \x1b[44m \x1b[45m \x1b[46m \x1b[47m
\x1b[m\x1b[5X\x1b[41m\x1b[5C\x1b[5X\x1b[42m\x1b[5C\x1b[5X\x1b[43m\x1b[5C\x1b[5X\x1b[44m\x1b[5C\x1b[5X\x1b[45m\x1b[5C\x1b[5X\x1b[46m\x1b[5C\x1b[5X\x1b[47m\x1b[5C\x1b[5X\x1b[m
`;
term.write(data.split('\n').join('\r\n'));
}
1 change: 1 addition & 0 deletions demo/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@ <h3>Test</h3>
<dd><button id="sgr-test" title="Write text with SGR attribute">SGR test</button></dd>
<dd><button id="ansi-colors" title="Write a wide range of ansi colors">Ansi colors test</button></dd>
<dd><button id="osc-hyperlinks" title="Write some OSC 8 hyperlinks">Ansi hyperlinks test</button></dd>
<dd><button id="bce" title="Test colored erase">Colored Erase (BCE)</button></dd>

<dt>Decorations</dt>
<dd><button id="add-decoration" title="Add a decoration to the terminal">Decoration</button></dd>
Expand Down
3 changes: 1 addition & 2 deletions src/browser/renderer/dom/DomRenderer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -444,7 +444,6 @@ export class DomRenderer extends Disposable implements IRenderer {
cursorX,
cursorBlink,
this.dimensions.css.cell.width,
this._bufferService.cols,
this._fontMetrics,
this._linkState
)
Expand Down Expand Up @@ -476,6 +475,7 @@ export class DomRenderer extends Disposable implements IRenderer {
const cursorX = Math.min(this._bufferService.buffer.x, this._bufferService.cols - 1);
const cursorBlink = this._optionsService.rawOptions.cursorBlink;
const cursorStyle = this._optionsService.rawOptions.cursorStyle;
cols = Math.min(cols, this._bufferService.cols);

// refresh rows within link range
this._linkState[0] = +enabled;
Expand All @@ -499,7 +499,6 @@ export class DomRenderer extends Disposable implements IRenderer {
cursorX,
cursorBlink,
this.dimensions.css.cell.width,
this._bufferService.cols,
this._fontMetrics,
this._linkState
)
Expand Down
57 changes: 24 additions & 33 deletions src/browser/renderer/dom/DomRendererRowFactory.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ describe('DomRendererRowFactory', () => {

describe('createRow', () => {
it('should not create anything for an empty row', () => {
const fragment = rowFactory.createRow(lineData, 0, false, undefined, 0, false, 5, 20, EMPTY_METRICS, EMPTY_LINKSTATE);
const fragment = rowFactory.createRow(lineData, 0, false, undefined, 0, false, 5, EMPTY_METRICS, EMPTY_LINKSTATE);
assert.equal(getFragmentHtml(fragment),
''
);
Expand All @@ -49,43 +49,34 @@ describe('DomRendererRowFactory', () => {
lineData.setCell(0, CellData.fromCharData([DEFAULT_ATTR, '語', 2, '語'.charCodeAt(0)]));
// There should be no element for the following "empty" cell
lineData.setCell(1, CellData.fromCharData([DEFAULT_ATTR, '', 0, 0]));
const fragment = rowFactory.createRow(lineData, 0, false, undefined, 0, false, 5, 20, EMPTY_METRICS, EMPTY_LINKSTATE);
const fragment = rowFactory.createRow(lineData, 0, false, undefined, 0, false, 5, EMPTY_METRICS, EMPTY_LINKSTATE);
assert.equal(getFragmentHtml(fragment),
'<span style="width: 10px;">語</span>'
);
});

it('should add class for cursor and cursor style', () => {
for (const style of ['block', 'bar', 'underline']) {
const fragment = rowFactory.createRow(lineData, 0, true, style, 0, false, 5, 20, EMPTY_METRICS, EMPTY_LINKSTATE);
const fragment = rowFactory.createRow(lineData, 0, true, style, 0, false, 5, EMPTY_METRICS, EMPTY_LINKSTATE);
assert.equal(getFragmentHtml(fragment),
`<span class="xterm-cursor xterm-cursor-${style}"> </span>`
);
}
});

it('should add class for cursor blink', () => {
const fragment = rowFactory.createRow(lineData, 0, true, 'block', 0, true, 5, 20, EMPTY_METRICS, EMPTY_LINKSTATE);
const fragment = rowFactory.createRow(lineData, 0, true, 'block', 0, true, 5, EMPTY_METRICS, EMPTY_LINKSTATE);
assert.equal(getFragmentHtml(fragment),
`<span class="xterm-cursor xterm-cursor-blink xterm-cursor-block"> </span>`
);
});

it('should not render cells that go beyond the terminal\'s columns', () => {
lineData.setCell(0, CellData.fromCharData([DEFAULT_ATTR, 'a', 1, 'a'.charCodeAt(0)]));
lineData.setCell(1, CellData.fromCharData([DEFAULT_ATTR, 'b', 1, 'b'.charCodeAt(0)]));
const fragment = rowFactory.createRow(lineData, 0, false, undefined, 0, false, 5, 1, EMPTY_METRICS, EMPTY_LINKSTATE);
assert.equal(getFragmentHtml(fragment),
'<span>a</span>'
);
});

describe('attributes', () => {
it('should add class for bold', () => {
const cell = CellData.fromCharData([0, 'a', 1, 'a'.charCodeAt(0)]);
cell.fg = DEFAULT_ATTR_DATA.fg | FgFlags.BOLD;
lineData.setCell(0, cell);
const fragment = rowFactory.createRow(lineData, 0, false, undefined, 0, false, 5, 20, EMPTY_METRICS, EMPTY_LINKSTATE);
const fragment = rowFactory.createRow(lineData, 0, false, undefined, 0, false, 5, EMPTY_METRICS, EMPTY_LINKSTATE);
assert.equal(getFragmentHtml(fragment),
'<span class="xterm-bold">a</span>'
);
Expand All @@ -95,7 +86,7 @@ describe('DomRendererRowFactory', () => {
const cell = CellData.fromCharData([0, 'a', 1, 'a'.charCodeAt(0)]);
cell.bg = DEFAULT_ATTR_DATA.bg | BgFlags.ITALIC;
lineData.setCell(0, cell);
const fragment = rowFactory.createRow(lineData, 0, false, undefined, 0, false, 5, 20, EMPTY_METRICS, EMPTY_LINKSTATE);
const fragment = rowFactory.createRow(lineData, 0, false, undefined, 0, false, 5, EMPTY_METRICS, EMPTY_LINKSTATE);
assert.equal(getFragmentHtml(fragment),
'<span class="xterm-italic">a</span>'
);
Expand All @@ -105,7 +96,7 @@ describe('DomRendererRowFactory', () => {
const cell = CellData.fromCharData([0, 'a', 1, 'a'.charCodeAt(0)]);
cell.bg = DEFAULT_ATTR_DATA.bg | BgFlags.DIM;
lineData.setCell(0, cell);
const fragment = rowFactory.createRow(lineData, 0, false, undefined, 0, false, 5, 20, EMPTY_METRICS, EMPTY_LINKSTATE);
const fragment = rowFactory.createRow(lineData, 0, false, undefined, 0, false, 5, EMPTY_METRICS, EMPTY_LINKSTATE);
assert.equal(getFragmentHtml(fragment),
'<span class="xterm-dim">a</span>'
);
Expand All @@ -118,7 +109,7 @@ describe('DomRendererRowFactory', () => {
cell.bg = DEFAULT_ATTR_DATA.bg | BgFlags.HAS_EXTENDED;
cell.extended.underlineStyle = UnderlineStyle.SINGLE;
lineData.setCell(0, cell);
const fragment = rowFactory.createRow(lineData, 0, false, undefined, 0, false, 5, 20, EMPTY_METRICS, EMPTY_LINKSTATE);
const fragment = rowFactory.createRow(lineData, 0, false, undefined, 0, false, 5, EMPTY_METRICS, EMPTY_LINKSTATE);
assert.equal(getFragmentHtml(fragment),
'<span class="xterm-underline-1">a</span>'
);
Expand All @@ -129,7 +120,7 @@ describe('DomRendererRowFactory', () => {
cell.bg = DEFAULT_ATTR_DATA.bg | BgFlags.HAS_EXTENDED;
cell.extended.underlineStyle = UnderlineStyle.DOUBLE;
lineData.setCell(0, cell);
const fragment = rowFactory.createRow(lineData, 0, false, undefined, 0, false, 5, 20, EMPTY_METRICS, EMPTY_LINKSTATE);
const fragment = rowFactory.createRow(lineData, 0, false, undefined, 0, false, 5, EMPTY_METRICS, EMPTY_LINKSTATE);
assert.equal(getFragmentHtml(fragment),
'<span class="xterm-underline-2">a</span>'
);
Expand All @@ -140,7 +131,7 @@ describe('DomRendererRowFactory', () => {
cell.bg = DEFAULT_ATTR_DATA.bg | BgFlags.HAS_EXTENDED;
cell.extended.underlineStyle = UnderlineStyle.CURLY;
lineData.setCell(0, cell);
const fragment = rowFactory.createRow(lineData, 0, false, undefined, 0, false, 5, 20, EMPTY_METRICS, EMPTY_LINKSTATE);
const fragment = rowFactory.createRow(lineData, 0, false, undefined, 0, false, 5, EMPTY_METRICS, EMPTY_LINKSTATE);
assert.equal(getFragmentHtml(fragment),
'<span class="xterm-underline-3">a</span>'
);
Expand All @@ -151,7 +142,7 @@ describe('DomRendererRowFactory', () => {
cell.bg = DEFAULT_ATTR_DATA.bg | BgFlags.HAS_EXTENDED;
cell.extended.underlineStyle = UnderlineStyle.DOTTED;
lineData.setCell(0, cell);
const fragment = rowFactory.createRow(lineData, 0, false, undefined, 0, false, 5, 20, EMPTY_METRICS, EMPTY_LINKSTATE);
const fragment = rowFactory.createRow(lineData, 0, false, undefined, 0, false, 5, EMPTY_METRICS, EMPTY_LINKSTATE);
assert.equal(getFragmentHtml(fragment),
'<span class="xterm-underline-4">a</span>'
);
Expand All @@ -162,7 +153,7 @@ describe('DomRendererRowFactory', () => {
cell.bg = DEFAULT_ATTR_DATA.bg | BgFlags.HAS_EXTENDED;
cell.extended.underlineStyle = UnderlineStyle.DASHED;
lineData.setCell(0, cell);
const fragment = rowFactory.createRow(lineData, 0, false, undefined, 0, false, 5, 20, EMPTY_METRICS, EMPTY_LINKSTATE);
const fragment = rowFactory.createRow(lineData, 0, false, undefined, 0, false, 5, EMPTY_METRICS, EMPTY_LINKSTATE);
assert.equal(getFragmentHtml(fragment),
'<span class="xterm-underline-5">a</span>'
);
Expand All @@ -173,7 +164,7 @@ describe('DomRendererRowFactory', () => {
const cell = CellData.fromCharData([0, 'a', 1, 'a'.charCodeAt(0)]);
cell.bg = DEFAULT_ATTR_DATA.bg | BgFlags.OVERLINE;
lineData.setCell(0, cell);
const fragment = rowFactory.createRow(lineData, 0, false, undefined, 0, false, 5, 20, EMPTY_METRICS, EMPTY_LINKSTATE);
const fragment = rowFactory.createRow(lineData, 0, false, undefined, 0, false, 5, EMPTY_METRICS, EMPTY_LINKSTATE);
assert.equal(getFragmentHtml(fragment),
'<span class="xterm-overline">a</span>'
);
Expand All @@ -183,7 +174,7 @@ describe('DomRendererRowFactory', () => {
const cell = CellData.fromCharData([0, 'a', 1, 'a'.charCodeAt(0)]);
cell.fg = DEFAULT_ATTR_DATA.fg | FgFlags.STRIKETHROUGH;
lineData.setCell(0, cell);
const fragment = rowFactory.createRow(lineData, 0, false, undefined, 0, false, 5, 20, EMPTY_METRICS, EMPTY_LINKSTATE);
const fragment = rowFactory.createRow(lineData, 0, false, undefined, 0, false, 5, EMPTY_METRICS, EMPTY_LINKSTATE);
assert.equal(getFragmentHtml(fragment),
'<span class="xterm-strikethrough">a</span>'
);
Expand All @@ -196,7 +187,7 @@ describe('DomRendererRowFactory', () => {
cell.fg &= ~Attributes.PCOLOR_MASK;
cell.fg |= i;
lineData.setCell(0, cell);
const fragment = rowFactory.createRow(lineData, 0, false, undefined, 0, false, 5, 20, EMPTY_METRICS, EMPTY_LINKSTATE);
const fragment = rowFactory.createRow(lineData, 0, false, undefined, 0, false, 5, EMPTY_METRICS, EMPTY_LINKSTATE);
assert.equal(getFragmentHtml(fragment),
`<span class="xterm-fg-${i}">a</span>`
);
Expand All @@ -210,7 +201,7 @@ describe('DomRendererRowFactory', () => {
cell.bg &= ~Attributes.PCOLOR_MASK;
cell.bg |= i;
lineData.setCell(0, cell);
const fragment = rowFactory.createRow(lineData, 0, false, undefined, 0, false, 5, 20, EMPTY_METRICS, EMPTY_LINKSTATE);
const fragment = rowFactory.createRow(lineData, 0, false, undefined, 0, false, 5, EMPTY_METRICS, EMPTY_LINKSTATE);
assert.equal(getFragmentHtml(fragment),
`<span class="xterm-bg-${i}">a</span>`
);
Expand All @@ -222,7 +213,7 @@ describe('DomRendererRowFactory', () => {
cell.fg |= Attributes.CM_P16 | 2 | FgFlags.INVERSE;
cell.bg |= Attributes.CM_P16 | 1;
lineData.setCell(0, cell);
const fragment = rowFactory.createRow(lineData, 0, false, undefined, 0, false, 5, 20, EMPTY_METRICS, EMPTY_LINKSTATE);
const fragment = rowFactory.createRow(lineData, 0, false, undefined, 0, false, 5, EMPTY_METRICS, EMPTY_LINKSTATE);
assert.equal(getFragmentHtml(fragment),
'<span class="xterm-bg-2 xterm-fg-1">a</span>'
);
Expand All @@ -233,7 +224,7 @@ describe('DomRendererRowFactory', () => {
cell.fg |= FgFlags.INVERSE;
cell.bg |= Attributes.CM_P16 | 1;
lineData.setCell(0, cell);
const fragment = rowFactory.createRow(lineData, 0, false, undefined, 0, false, 5, 20, EMPTY_METRICS, EMPTY_LINKSTATE);
const fragment = rowFactory.createRow(lineData, 0, false, undefined, 0, false, 5, EMPTY_METRICS, EMPTY_LINKSTATE);
assert.equal(getFragmentHtml(fragment),
'<span class="xterm-bg-257 xterm-fg-1">a</span>'
);
Expand All @@ -243,7 +234,7 @@ describe('DomRendererRowFactory', () => {
const cell = CellData.fromCharData([0, 'a', 1, 'a'.charCodeAt(0)]);
cell.fg |= Attributes.CM_P16 | 1 | FgFlags.INVERSE;
lineData.setCell(0, cell);
const fragment = rowFactory.createRow(lineData, 0, false, undefined, 0, false, 5, 20, EMPTY_METRICS, EMPTY_LINKSTATE);
const fragment = rowFactory.createRow(lineData, 0, false, undefined, 0, false, 5, EMPTY_METRICS, EMPTY_LINKSTATE);
assert.equal(getFragmentHtml(fragment),
'<span class="xterm-bg-1 xterm-fg-257">a</span>'
);
Expand All @@ -256,7 +247,7 @@ describe('DomRendererRowFactory', () => {
cell.fg &= ~Attributes.PCOLOR_MASK;
cell.fg |= i;
lineData.setCell(0, cell);
const fragment = rowFactory.createRow(lineData, 0, false, undefined, 0, false, 5, 20, EMPTY_METRICS, EMPTY_LINKSTATE);
const fragment = rowFactory.createRow(lineData, 0, false, undefined, 0, false, 5, EMPTY_METRICS, EMPTY_LINKSTATE);
assert.equal(getFragmentHtml(fragment),
`<span class="xterm-bold xterm-fg-${i + 8}">a</span>`
);
Expand All @@ -268,7 +259,7 @@ describe('DomRendererRowFactory', () => {
cell.fg |= Attributes.CM_RGB | 1 << 16 | 2 << 8 | 3;
cell.bg |= Attributes.CM_RGB | 4 << 16 | 5 << 8 | 6;
lineData.setCell(0, cell);
const fragment = rowFactory.createRow(lineData, 0, false, undefined, 0, false, 5, 20, EMPTY_METRICS, EMPTY_LINKSTATE);
const fragment = rowFactory.createRow(lineData, 0, false, undefined, 0, false, 5, EMPTY_METRICS, EMPTY_LINKSTATE);
assert.equal(getFragmentHtml(fragment),
'<span style="background-color:#040506;color:#010203;">a</span>'
);
Expand All @@ -279,7 +270,7 @@ describe('DomRendererRowFactory', () => {
cell.fg |= Attributes.CM_RGB | 1 << 16 | 2 << 8 | 3 | FgFlags.INVERSE;
cell.bg |= Attributes.CM_RGB | 4 << 16 | 5 << 8 | 6;
lineData.setCell(0, cell);
const fragment = rowFactory.createRow(lineData, 0, false, undefined, 0, false, 5, 20, EMPTY_METRICS, EMPTY_LINKSTATE);
const fragment = rowFactory.createRow(lineData, 0, false, undefined, 0, false, 5, EMPTY_METRICS, EMPTY_LINKSTATE);
assert.equal(getFragmentHtml(fragment),
'<span style="background-color:#010203;color:#040506;">a</span>'
);
Expand All @@ -291,15 +282,15 @@ describe('DomRendererRowFactory', () => {
lineData.setCell(0, CellData.fromCharData([DEFAULT_ATTR, 'a', 1, 'a'.charCodeAt(0)]));
lineData.setCell(1, CellData.fromCharData([DEFAULT_ATTR, 'b', 1, 'b'.charCodeAt(0)]));
rowFactory.handleSelectionChanged([1, 0], [2, 0], false);
const fragment = rowFactory.createRow(lineData, 0, false, undefined, 0, false, 5, 20, EMPTY_METRICS, EMPTY_LINKSTATE);
const fragment = rowFactory.createRow(lineData, 0, false, undefined, 0, false, 5, EMPTY_METRICS, EMPTY_LINKSTATE);
assert.equal(getFragmentHtml(fragment),
'<span>a</span><span class="xterm-decoration-top">b</span>'
);
});
it('should force whitespace cells to be rendered above the background', () => {
lineData.setCell(1, CellData.fromCharData([DEFAULT_ATTR, 'a', 1, 'a'.charCodeAt(0)]));
rowFactory.handleSelectionChanged([0, 0], [2, 0], false);
const fragment = rowFactory.createRow(lineData, 0, false, undefined, 0, false, 5, 20, EMPTY_METRICS, EMPTY_LINKSTATE);
const fragment = rowFactory.createRow(lineData, 0, false, undefined, 0, false, 5, EMPTY_METRICS, EMPTY_LINKSTATE);
assert.equal(getFragmentHtml(fragment),
'<span class="xterm-decoration-top"> </span><span class="xterm-decoration-top">a</span>'
);
Expand Down
Loading

0 comments on commit 3715301

Please sign in to comment.