mirror of
https://github.com/wavetermdev/xterm.js.git
synced 2026-08-05 13:43:48 -07:00
Merge pull request #3343 from silamon/strikethrough
Support strikethrough text style
This commit is contained in:
@@ -168,3 +168,7 @@
|
||||
.xterm-underline {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
.xterm-strikethrough {
|
||||
text-decoration: line-through;
|
||||
}
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
|
||||
Vendored
+1
@@ -117,6 +117,7 @@ export interface IAttributeData {
|
||||
isInvisible(): number;
|
||||
isItalic(): number;
|
||||
isDim(): number;
|
||||
isStrikethrough(): number;
|
||||
|
||||
// color modes
|
||||
getFgColorMode(): number;
|
||||
|
||||
@@ -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; }
|
||||
|
||||
@@ -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 {
|
||||
|
||||
Reference in New Issue
Block a user