Merge pull request #2650 from Tyriar/2599_inverse_selection

Set glyph fg color based on original bg, not selection
This commit is contained in:
Daniel Imms
2019-12-27 03:06:05 +11:00
committed by GitHub
2 changed files with 61 additions and 5 deletions
+37 -5
View File
@@ -6,13 +6,14 @@
import { createProgram, PROJECTION_MATRIX, throwIfFalsy } from './WebglUtils';
import { WebglCharAtlas } from './atlas/WebglCharAtlas';
import { IWebGL2RenderingContext, IWebGLVertexArrayObject, IRenderModel, IRasterizedGlyph } from './Types';
import { COMBINED_CHAR_BIT_MASK, RENDER_MODEL_INDICIES_PER_CELL, RENDER_MODEL_FG_OFFSET } from './RenderModel';
import { COMBINED_CHAR_BIT_MASK, RENDER_MODEL_INDICIES_PER_CELL, RENDER_MODEL_FG_OFFSET, RENDER_MODEL_BG_OFFSET } from './RenderModel';
import { fill } from 'common/TypedArrayUtils';
import { slice } from './TypedArray';
import { NULL_CELL_CODE, WHITESPACE_CELL_CODE, Attributes } from 'common/buffer/Constants';
import { NULL_CELL_CODE, WHITESPACE_CELL_CODE, Attributes, FgFlags } from 'common/buffer/Constants';
import { Terminal, IBufferLine } from 'xterm';
import { IColorSet } from 'browser/Types';
import { IColorSet, IColor } from 'browser/Types';
import { IRenderDimensions } from 'browser/renderer/Types';
import { AttributeData } from 'common/buffer/AttributeData';
interface IVertices {
attributes: Float32Array;
@@ -254,18 +255,49 @@ export class GlyphRenderer {
for (let x = startCol; x < endCol; x++) {
const offset = (y * this._terminal.cols + x) * RENDER_MODEL_INDICIES_PER_CELL;
const code = model.cells[offset];
let fg = model.cells[offset + RENDER_MODEL_FG_OFFSET];
if (fg & FgFlags.INVERSE) {
const workCell = new AttributeData();
workCell.fg = fg;
workCell.bg = model.cells[offset + RENDER_MODEL_BG_OFFSET];
// Get attributes from fg (excluding inverse) and resolve inverse by pullibng rgb colors
// from bg. This is needed since the inverse fg color should be based on the original bg
// color, not on the selection color
fg = (fg & ~(Attributes.CM_MASK | Attributes.RGB_MASK | FgFlags.INVERSE));
switch (workCell.getBgColorMode()) {
case Attributes.CM_P16:
case Attributes.CM_P256:
const c = this._getColorFromAnsiIndex(workCell.getBgColor()).rgba;
fg |= (c >> 8) & Attributes.RED_MASK | (c >> 8) & Attributes.GREEN_MASK | (c >> 8) & Attributes.BLUE_MASK;
case Attributes.CM_RGB:
const arr = AttributeData.toColorRGB(workCell.getBgColor());
fg |= arr[0] << Attributes.RED_SHIFT | arr[1] << Attributes.GREEN_SHIFT | arr[2] << Attributes.BLUE_SHIFT;
case Attributes.CM_DEFAULT:
default:
const c2 = this._colors.background.rgba;
fg |= (c2 >> 8) & Attributes.RED_MASK | (c2 >> 8) & Attributes.GREEN_MASK | (c2 >> 8) & Attributes.BLUE_MASK;
}
fg |= Attributes.CM_RGB;
}
if (code & COMBINED_CHAR_BIT_MASK) {
if (!line) {
line = terminal.buffer.getLine(row);
}
const chars = line!.getCell(x)!.char;
this._updateCell(this._vertices.selectionAttributes, x, y, model.cells[offset], bg, model.cells[offset + RENDER_MODEL_FG_OFFSET], chars);
this._updateCell(this._vertices.selectionAttributes, x, y, model.cells[offset], bg, fg, chars);
} else {
this._updateCell(this._vertices.selectionAttributes, x, y, model.cells[offset], bg, model.cells[offset + RENDER_MODEL_FG_OFFSET]);
this._updateCell(this._vertices.selectionAttributes, x, y, model.cells[offset], bg, fg);
}
}
}
private _getColorFromAnsiIndex(idx: number): IColor {
if (idx >= this._colors.ansi.length) {
throw new Error('No color found for idx ' + idx);
}
return this._colors.ansi[idx];
}
public onResize(): void {
const terminal = this._terminal;
const gl = this._gl;
@@ -825,6 +825,30 @@ describe('WebGL Renderer Integration Tests', function(): void {
});
});
describe('selection', async () => {
before(async () => setupBrowser());
after(async () => browser.close());
beforeEach(async () => page.evaluate(`window.term.reset()`));
it('should resolve the inverse foreground color based on the original background color, not the selection', async () => {
const theme: ITheme = {
foreground: '#FF0000',
background: '#00FF00',
selection: '#0000FF'
};
await page.evaluate(`window.term.setOption('theme', ${JSON.stringify(theme)});`);
await writeSync(`\\x1b[7m█\\x1b[0m`);
await pollFor(page, () => getCellColor(1, 1), [0, 255, 0, 255]);
await pollFor(page, () => getCellColor(2, 1), [255, 0, 0, 255]);
await pollFor(page, () => getCellColor(3, 1), [0, 255, 0, 255]);
await page.evaluate(`window.term.selectAll()`);
// Selection only cell needs to be first to ensure renderer has kicked in
await pollFor(page, () => getCellColor(1, 1), [0, 0, 255, 255]);
await pollFor(page, () => getCellColor(2, 1), [255, 0, 0, 255]);
await pollFor(page, () => getCellColor(3, 1), [0, 255, 0, 255]);
});
});
describe('allowTransparency', async () => {
before(async () => setupBrowser({ rendererType: 'dom', allowTransparency: true}));
after(async () => browser.close());