Merge pull request #3343 from silamon/strikethrough

Support strikethrough text style
This commit is contained in:
Daniel Imms
2021-07-09 07:03:02 -07:00
committed by GitHub
10 changed files with 67 additions and 13 deletions
+4
View File
@@ -168,3 +168,7 @@
.xterm-underline {
text-decoration: underline;
}
.xterm-strikethrough {
text-decoration: line-through;
}
+15
View File
@@ -152,6 +152,21 @@ export abstract class BaseRenderLayer implements IRenderLayer {
height * this._scaledCellHeight);
}
/**
* Fills a 1px line (2px on HDPI) at the middle of the cell. This uses the
* existing fillStyle on the context.
* @param x The column to fill.
* @param y The row to fill.
*/
protected _fillMiddleLineAtCells(x: number, y: number, width: number = 1): void {
const cellOffset = Math.ceil(this._scaledCellHeight * 0.5);
this._ctx.fillRect(
x * this._scaledCellWidth,
(y + 1) * this._scaledCellHeight - cellOffset - window.devicePixelRatio,
width * this._scaledCellWidth,
window.devicePixelRatio);
}
/**
* Fills a 1px line (2px on HDPI) at the bottom of the cell. This uses the
* existing fillStyle on the context.
+7 -2
View File
@@ -215,7 +215,7 @@ export class TextRenderLayer extends BaseRenderLayer {
return;
}
this._drawChars(cell, x, y);
if (cell.isUnderline()) {
if (cell.isUnderline() || cell.isStrikethrough()) {
this._ctx.save();
if (cell.isInverse()) {
@@ -244,7 +244,12 @@ export class TextRenderLayer extends BaseRenderLayer {
}
}
this._fillBottomLineAtCells(x, y, cell.getWidth());
if (cell.isStrikethrough()) {
this._fillMiddleLineAtCells(x, y, cell.getWidth());
}
if (cell.isUnderline()) {
this._fillBottomLineAtCells(x, y, cell.getWidth());
}
this._ctx.restore();
}
});
@@ -132,6 +132,16 @@ describe('DomRendererRowFactory', () => {
);
});
it('should add class for strikethrough', () => {
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);
assert.equal(getFragmentHtml(fragment),
'<span class="xterm-strikethrough">a</span>'
);
});
it('should add classes for 256 foreground colors', () => {
const cell = CellData.fromCharData([0, 'a', 1, 'a'.charCodeAt(0)]);
cell.fg |= Attributes.CM_P256;
@@ -17,6 +17,7 @@ export const BOLD_CLASS = 'xterm-bold';
export const DIM_CLASS = 'xterm-dim';
export const ITALIC_CLASS = 'xterm-italic';
export const UNDERLINE_CLASS = 'xterm-underline';
export const STRIKETHROUGH_CLASS = 'xterm-strikethrough';
export const CURSOR_CLASS = 'xterm-cursor';
export const CURSOR_BLINK_CLASS = 'xterm-cursor-blink';
export const CURSOR_STYLE_BLOCK_CLASS = 'xterm-cursor-block';
@@ -151,6 +152,10 @@ export class DomRendererRowFactory {
charElement.textContent = cell.getChars() || WHITESPACE_CELL_CHAR;
}
if (cell.isStrikethrough()) {
charElement.classList.add(STRIKETHROUGH_CLASS);
}
let fg = cell.getFgColor();
let fgColorMode = cell.getFgColorMode();
let bg = cell.getBgColor();
+6
View File
@@ -636,6 +636,12 @@ describe('InputHandler', () => {
await inputHandler.parseP('\x1b[28m');
assert.equal(!!inputHandler.curAttrData.isInvisible(), false);
});
it('strikethrough', async () => {
await inputHandler.parseP('\x1b[9m');
assert.equal(!!inputHandler.curAttrData.isStrikethrough(), true);
await inputHandler.parseP('\x1b[29m');
assert.equal(!!inputHandler.curAttrData.isStrikethrough(), false);
});
it('colormode palette 16', async () => {
assert.equal(inputHandler.curAttrData.getFgColorMode(), 0); // DEFAULT
assert.equal(inputHandler.curAttrData.getBgColorMode(), 0); // DEFAULT
+8 -2
View File
@@ -2365,7 +2365,7 @@ export class InputHandler extends Disposable implements IInputHandler {
* | 6 | Rapidly blinking. | #N |
* | 7 | Inverse. Flips foreground and background color. | #Y |
* | 8 | Invisible (hidden). | #Y |
* | 9 | Crossed-out characters. | #N |
* | 9 | Crossed-out characters (strikethrough). | #P[Support in DOM and Canvas renderers, not WebGL] |
* | 21 | Doubly underlined. | #P[Currently outputs a single underline.] |
* | 22 | Normal (neither bold nor faint). | #Y |
* | 23 | No italic. | #Y |
@@ -2373,7 +2373,7 @@ export class InputHandler extends Disposable implements IInputHandler {
* | 25 | Steady (not blinking). | #Y |
* | 27 | Positive (not inverse). | #Y |
* | 28 | Visible (not hidden). | #Y |
* | 29 | Not Crossed-out. | #N |
* | 29 | Not Crossed-out (strikethrough). | #Y |
* | 30 | Foreground color: Black. | #Y |
* | 31 | Foreground color: Red. | #Y |
* | 32 | Foreground color: Green. | #Y |
@@ -2478,6 +2478,9 @@ export class InputHandler extends Disposable implements IInputHandler {
} else if (p === 8) {
// invisible
attr.fg |= FgFlags.INVISIBLE;
} else if (p === 9) {
// strikethrough
attr.fg |= FgFlags.STRIKETHROUGH;
} else if (p === 2) {
// dimmed text
attr.bg |= BgFlags.DIM;
@@ -2503,6 +2506,9 @@ export class InputHandler extends Disposable implements IInputHandler {
} else if (p === 28) {
// not invisible
attr.fg &= ~FgFlags.INVISIBLE;
} else if (p === 29) {
// not strikethrough
attr.fg &= ~FgFlags.STRIKETHROUGH;
} else if (p === 39) {
// reset fg
attr.fg &= ~(Attributes.CM_MASK | Attributes.RGB_MASK);
+1
View File
@@ -117,6 +117,7 @@ export interface IAttributeData {
isInvisible(): number;
isItalic(): number;
isDim(): number;
isStrikethrough(): number;
// color modes
getFgColorMode(): number;
+8 -7
View File
@@ -33,13 +33,14 @@ export class AttributeData implements IAttributeData {
public extended = new ExtendedAttrs();
// flags
public isInverse(): number { return this.fg & FgFlags.INVERSE; }
public isBold(): number { return this.fg & FgFlags.BOLD; }
public isUnderline(): number { return this.fg & FgFlags.UNDERLINE; }
public isBlink(): number { return this.fg & FgFlags.BLINK; }
public isInvisible(): number { return this.fg & FgFlags.INVISIBLE; }
public isItalic(): number { return this.bg & BgFlags.ITALIC; }
public isDim(): number { return this.bg & BgFlags.DIM; }
public isInverse(): number { return this.fg & FgFlags.INVERSE; }
public isBold(): number { return this.fg & FgFlags.BOLD; }
public isUnderline(): number { return this.fg & FgFlags.UNDERLINE; }
public isBlink(): number { return this.fg & FgFlags.BLINK; }
public isInvisible(): number { return this.fg & FgFlags.INVISIBLE; }
public isItalic(): number { return this.bg & BgFlags.ITALIC; }
public isDim(): number { return this.bg & BgFlags.DIM; }
public isStrikethrough(): number { return this.fg & FgFlags.STRIKETHROUGH; }
// color modes
public getFgColorMode(): number { return this.fg & Attributes.CM_MASK; }
+3 -2
View File
@@ -110,13 +110,14 @@ export const enum Attributes {
export const enum FgFlags {
/**
* bit 27..31 (32th bit unused)
* bit 27..32
*/
INVERSE = 0x4000000,
BOLD = 0x8000000,
UNDERLINE = 0x10000000,
BLINK = 0x20000000,
INVISIBLE = 0x40000000
INVISIBLE = 0x40000000,
STRIKETHROUGH = 0x80000000,
}
export const enum BgFlags {