Merge branch 'master' into 2333_sendfocus

This commit is contained in:
Daniel Imms
2021-10-12 09:38:45 -07:00
committed by GitHub
57 changed files with 871 additions and 511 deletions
+1
View File
@@ -53,6 +53,7 @@ export class AccessibilityManager extends Disposable {
) {
super();
this._accessibilityTreeRoot = document.createElement('div');
this._accessibilityTreeRoot.setAttribute('role', 'document');
this._accessibilityTreeRoot.classList.add('xterm-accessibility');
this._rowContainer = document.createElement('div');
+71 -73
View File
@@ -732,80 +732,78 @@ describe('Terminal', () => {
});
describe('unicode - surrogates', () => {
it('2 characters per cell', async function (): Promise<void> {
this.timeout(10000); // This is needed because istanbul patches code and slows it down
const high = String.fromCharCode(0xD800);
const cell = new CellData();
for (let i = 0xDC00; i <= 0xDCFF; ++i) {
await term.writeP(high + String.fromCharCode(i));
const tchar = term.buffer.lines.get(0)!.loadCell(0, cell);
assert.equal(tchar.getChars(), high + String.fromCharCode(i));
assert.equal(tchar.getChars().length, 2);
assert.equal(tchar.getWidth(), 1);
assert.equal(term.buffer.lines.get(0)!.loadCell(1, cell).getChars(), '');
term.reset();
}
});
it('2 characters at last cell', async () => {
const high = String.fromCharCode(0xD800);
const cell = new CellData();
for (let i = 0xDC00; i <= 0xDCFF; ++i) {
term.buffer.x = term.cols - 1;
await term.writeP(high + String.fromCharCode(i));
assert.equal(term.buffer.lines.get(0)!.loadCell(term.buffer.x - 1, cell).getChars(), high + String.fromCharCode(i));
assert.equal(term.buffer.lines.get(0)!.loadCell(term.buffer.x - 1, cell).getChars().length, 2);
assert.equal(term.buffer.lines.get(1)!.loadCell(0, cell).getChars(), '');
term.reset();
}
});
it('2 characters per cell over line end with autowrap', async function (): Promise<void> {
this.timeout(10000);
const high = String.fromCharCode(0xD800);
const cell = new CellData();
for (let i = 0xDC00; i <= 0xDCFF; ++i) {
term.buffer.x = term.cols - 1;
await term.writeP('a' + high + String.fromCharCode(i));
assert.equal(term.buffer.lines.get(0)!.loadCell(term.cols - 1, cell).getChars(), 'a');
assert.equal(term.buffer.lines.get(1)!.loadCell(0, cell).getChars(), high + String.fromCharCode(i));
assert.equal(term.buffer.lines.get(1)!.loadCell(0, cell).getChars().length, 2);
assert.equal(term.buffer.lines.get(1)!.loadCell(1, cell).getChars(), '');
term.reset();
}
});
it('2 characters per cell over line end without autowrap', async function (): Promise<void> {
this.timeout(10000);
const high = String.fromCharCode(0xD800);
const cell = new CellData();
for (let i = 0xDC00; i <= 0xDCFF; ++i) {
term.buffer.x = term.cols - 1;
await term.writeP('\x1b[?7l'); // Disable wraparound mode
const width = wcwidth((0xD800 - 0xD800) * 0x400 + i - 0xDC00 + 0x10000);
if (width !== 1) {
continue;
for (let i = 0xDC00; i <= 0xDCF0; i += 0x10) {
const range = `0x${i.toString(16).toUpperCase()}-0x${(i + 0xF).toString(16).toUpperCase()}`;
it(`${range}: 2 characters per cell`, async function (): Promise<void> {
const high = String.fromCharCode(0xD800);
const cell = new CellData();
for (let j = i; j <= i + 0xF; j++) {
await term.writeP(high + String.fromCharCode(j));
const tchar = term.buffer.lines.get(0)!.loadCell(0, cell);
assert.equal(tchar.getChars(), high + String.fromCharCode(j));
assert.equal(tchar.getChars().length, 2);
assert.equal(tchar.getWidth(), 1);
assert.equal(term.buffer.lines.get(0)!.loadCell(1, cell).getChars(), '');
term.reset();
}
await term.writeP('a' + high + String.fromCharCode(i));
// auto wraparound mode should cut off the rest of the line
assert.equal(term.buffer.lines.get(0)!.loadCell(term.cols - 1, cell).getChars(), high + String.fromCharCode(i));
assert.equal(term.buffer.lines.get(0)!.loadCell(term.cols - 1, cell).getChars().length, 2);
assert.equal(term.buffer.lines.get(1)!.loadCell(1, cell).getChars(), '');
term.reset();
}
});
it('splitted surrogates', async function (): Promise<void> {
this.timeout(10000);
const high = String.fromCharCode(0xD800);
const cell = new CellData();
for (let i = 0xDC00; i <= 0xDCFF; ++i) {
await term.writeP(high + String.fromCharCode(i));
const tchar = term.buffer.lines.get(0)!.loadCell(0, cell);
assert.equal(tchar.getChars(), high + String.fromCharCode(i));
assert.equal(tchar.getChars().length, 2);
assert.equal(tchar.getWidth(), 1);
assert.equal(term.buffer.lines.get(0)!.loadCell(1, cell).getChars(), '');
term.reset();
}
});
});
it(`${range}: 2 characters at last cell`, async () => {
const high = String.fromCharCode(0xD800);
const cell = new CellData();
term.buffer.x = term.cols - 1;
for (let j = i; j <= i + 0xF; j++) {
await term.writeP(high + String.fromCharCode(j));
assert.equal(term.buffer.lines.get(0)!.loadCell(term.buffer.x - 1, cell).getChars(), high + String.fromCharCode(j));
assert.equal(term.buffer.lines.get(0)!.loadCell(term.buffer.x - 1, cell).getChars().length, 2);
assert.equal(term.buffer.lines.get(1)!.loadCell(0, cell).getChars(), '');
term.reset();
}
});
it(`${range}: 2 characters per cell over line end with autowrap`, async function (): Promise<void> {
const high = String.fromCharCode(0xD800);
const cell = new CellData();
for (let j = i; j <= i + 0xF; j++) {
term.buffer.x = term.cols - 1;
await term.writeP('a' + high + String.fromCharCode(j));
assert.equal(term.buffer.lines.get(0)!.loadCell(term.cols - 1, cell).getChars(), 'a');
assert.equal(term.buffer.lines.get(1)!.loadCell(0, cell).getChars(), high + String.fromCharCode(j));
assert.equal(term.buffer.lines.get(1)!.loadCell(0, cell).getChars().length, 2);
assert.equal(term.buffer.lines.get(1)!.loadCell(1, cell).getChars(), '');
term.reset();
}
});
it(`${range}: 2 characters per cell over line end without autowrap`, async function (): Promise<void> {
const high = String.fromCharCode(0xD800);
const cell = new CellData();
for (let j = i; j <= i + 0xF; j++) {
term.buffer.x = term.cols - 1;
await term.writeP('\x1b[?7l'); // Disable wraparound mode
const width = wcwidth((0xD800 - 0xD800) * 0x400 + j - 0xDC00 + 0x10000);
if (width !== 1) {
continue;
}
await term.writeP('a' + high + String.fromCharCode(j));
// auto wraparound mode should cut off the rest of the line
assert.equal(term.buffer.lines.get(0)!.loadCell(term.cols - 1, cell).getChars(), high + String.fromCharCode(j));
assert.equal(term.buffer.lines.get(0)!.loadCell(term.cols - 1, cell).getChars().length, 2);
assert.equal(term.buffer.lines.get(1)!.loadCell(1, cell).getChars(), '');
term.reset();
}
});
it(`${range}: splitted surrogates`, async function (): Promise<void> {
const high = String.fromCharCode(0xD800);
const cell = new CellData();
for (let j = i; j <= i + 0xF; j++) {
await term.writeP(high + String.fromCharCode(j));
const tchar = term.buffer.lines.get(0)!.loadCell(0, cell);
assert.equal(tchar.getChars(), high + String.fromCharCode(j));
assert.equal(tchar.getChars().length, 2);
assert.equal(tchar.getWidth(), 1);
assert.equal(term.buffer.lines.get(0)!.loadCell(1, cell).getChars(), '');
term.reset();
}
});
}
});
describe('unicode - combining characters', () => {
+60 -2
View File
@@ -94,6 +94,20 @@ export class Terminal extends CoreTerminal implements ITerminal {
*/
private _keyDownHandled: boolean = false;
/**
* Records whether the keypress event has already been handled and triggered a data event, if so
* the input event should not trigger a data event but should still print to the textarea so
* screen readers will announce it.
*/
private _keyPressHandled: boolean = false;
/**
* Records whether there has been a keydown event for a dead key without a corresponding keydown
* event for the composed/alternative character. If we cancel the keydown event for the dead key,
* no events will be emitted for the final character.
*/
private _unprocessedDeadKey: boolean = false;
public linkifier: ILinkifier;
public linkifier2: ILinkifier2;
public viewport: IViewport | undefined;
@@ -384,6 +398,7 @@ export class Terminal extends CoreTerminal implements ITerminal {
this.register(addDisposableDomListener(this.textarea!, 'compositionstart', () => this._compositionHelper!.compositionstart()));
this.register(addDisposableDomListener(this.textarea!, 'compositionupdate', (e: CompositionEvent) => this._compositionHelper!.compositionupdate(e)));
this.register(addDisposableDomListener(this.textarea!, 'compositionend', () => this._compositionHelper!.compositionend()));
this.register(addDisposableDomListener(this.textarea!, 'input', (ev: InputEvent) => this._inputEvent(ev), true));
this.register(this.onRender(() => this._compositionHelper!.updateCompositionElements()));
this.register(this.onRender(e => this._queueLinkification(e.start, e.end)));
}
@@ -1026,6 +1041,10 @@ export class Terminal extends CoreTerminal implements ITerminal {
return false;
}
if (event.key === 'Dead' || event.key === 'AltGraph') {
this._unprocessedDeadKey = true;
}
const result = evaluateKeyboardEvent(event, this.coreService.decPrivateModes.applicationCursorKeys, this.browser.isMac, this.options.macOptionIsMeta);
this.updateCursorStyle(event);
@@ -1053,6 +1072,11 @@ export class Terminal extends CoreTerminal implements ITerminal {
return true;
}
if (this._unprocessedDeadKey) {
this._unprocessedDeadKey = false;
return true;
}
// If ctrl+c or enter is being sent, clear out the textarea. This is done so that screen readers
// will announce deleted characters. This will not work 100% of the time but it should cover
// most scenarios.
@@ -1075,10 +1099,11 @@ export class Terminal extends CoreTerminal implements ITerminal {
this._keyDownHandled = true;
}
private _isThirdLevelShift(browser: IBrowser, ev: IKeyboardEvent): boolean {
private _isThirdLevelShift(browser: IBrowser, ev: KeyboardEvent): boolean {
const thirdLevelKey =
(browser.isMac && !this.options.macOptionIsMeta && ev.altKey && !ev.ctrlKey && !ev.metaKey) ||
(browser.isWindows && ev.altKey && ev.ctrlKey && !ev.metaKey);
(browser.isWindows && ev.altKey && ev.ctrlKey && !ev.metaKey) ||
(browser.isWindows && ev.getModifierState('AltGraph'));
if (ev.type === 'keypress') {
return thirdLevelKey;
@@ -1098,6 +1123,7 @@ export class Terminal extends CoreTerminal implements ITerminal {
}
this.updateCursorStyle(ev);
this._keyPressHandled = false;
}
/**
@@ -1109,6 +1135,8 @@ export class Terminal extends CoreTerminal implements ITerminal {
protected _keyPress(ev: KeyboardEvent): boolean {
let key;
this._keyPressHandled = false;
if (this._keyDownHandled) {
return false;
}
@@ -1141,9 +1169,35 @@ export class Terminal extends CoreTerminal implements ITerminal {
this._showCursor();
this.coreService.triggerDataEvent(key, true);
this._keyPressHandled = true;
return true;
}
/**
* Handle an input event.
* Key Resources:
* - https://developer.mozilla.org/en-US/docs/Web/API/InputEvent
* @param ev The input event to be handled.
*/
protected _inputEvent(ev: InputEvent): boolean {
// Only support emoji IMEs when screen reader mode is disabled as the event must bubble up to
// support reading out character input which can doubling up input characters
if (ev.data && ev.inputType === 'insertText' && !this.optionsService.options.screenReaderMode) {
if (this._keyPressHandled) {
return false;
}
const text = ev.data;
this.coreService.triggerDataEvent(text, true);
this.cancel(ev);
return true;
}
return false;
}
/**
* Ring the bell.
* Note: We could do sweet things with webaudio here
@@ -1239,6 +1293,10 @@ export class Terminal extends CoreTerminal implements ITerminal {
this.viewport?.syncScrollArea();
}
public clearTextureAtlas(): void {
this._renderService?.clearTextureAtlas();
}
private _reportFocus(): void {
if (this.element?.classList.contains('focus')) {
this.coreService.triggerDataEvent(C0.ESC + '[I');
+6
View File
@@ -195,6 +195,9 @@ export class MockTerminal implements ITerminal {
public reset(): void {
throw new Error('Method not implemented.');
}
public clearTextureAtlas(): void {
throw new Error('Method not implemented.');
}
public refresh(start: number, end: number): void {
throw new Error('Method not implemented.');
}
@@ -374,6 +377,9 @@ export class MockRenderService implements IRenderService {
public refreshRows(start: number, end: number): void {
throw new Error('Method not implemented.');
}
public clearTextureAtlas(): void {
throw new Error('Method not implemented.');
}
public resize(cols: number, rows: number): void {
throw new Error('Method not implemented.');
}
+1
View File
@@ -79,6 +79,7 @@ export interface IPublicTerminal extends IDisposable {
write(data: string | Uint8Array, callback?: () => void): void;
paste(data: string): void;
refresh(start: number, end: number): void;
clearTextureAtlas(): void;
reset(): void;
}
+31 -9
View File
@@ -8,6 +8,8 @@ import { addDisposableDomListener } from 'browser/Lifecycle';
import { IColorSet, IViewport } from 'browser/Types';
import { ICharSizeService, IRenderService } from 'browser/services/Services';
import { IBufferService, IOptionsService } from 'common/services/Services';
import { IBuffer } from 'common/buffer/Types';
import { IRenderDimensions } from 'browser/renderer/Types';
const FALLBACK_SCROLL_BAR_WIDTH = 15;
@@ -18,11 +20,15 @@ const FALLBACK_SCROLL_BAR_WIDTH = 15;
export class Viewport extends Disposable implements IViewport {
public scrollBarWidth: number = 0;
private _currentRowHeight: number = 0;
private _currentScaledCellHeight: number = 0;
private _lastRecordedBufferLength: number = 0;
private _lastRecordedViewportHeight: number = 0;
private _lastRecordedBufferHeight: number = 0;
private _lastTouchY: number = 0;
private _lastScrollTop: number = 0;
private _lastHadScrollBar: boolean = false;
private _activeBuffer: IBuffer;
private _renderDimensions: IRenderDimensions;
// Stores a partial line amount when scrolling, this is used to keep track of how much of a line
// is scrolled so we can "scroll" over partial lines and feel natural on touchpads. This is a
@@ -47,8 +53,15 @@ export class Viewport extends Disposable implements IViewport {
// Unfortunately the overlay scrollbar would be hidden underneath the screen element in that case,
// therefore we account for a standard amount to make it visible
this.scrollBarWidth = (this._viewportElement.offsetWidth - this._scrollArea.offsetWidth) || FALLBACK_SCROLL_BAR_WIDTH;
this._lastHadScrollBar = true;
this.register(addDisposableDomListener(this._viewportElement, 'scroll', this._onScroll.bind(this)));
// Track properties used in performance critical code manually to avoid using slow getters
this._activeBuffer = this._bufferService.buffer;
this.register(this._bufferService.buffers.onBufferActivate(e => this._activeBuffer = e.activeBuffer));
this._renderDimensions = this._renderService.dimensions;
this.register(this._renderService.onDimensionsChange(e => this._renderDimensions = e));
// Perform this async to ensure the ICharSizeService is ready.
setTimeout(() => this.syncScrollArea(), 0);
}
@@ -77,6 +90,7 @@ export class Viewport extends Disposable implements IViewport {
private _innerRefresh(): void {
if (this._charSizeService.height > 0) {
this._currentRowHeight = this._renderService.dimensions.scaledCellHeight / window.devicePixelRatio;
this._currentScaledCellHeight = this._renderService.dimensions.scaledCellHeight;
this._lastRecordedViewportHeight = this._viewportElement.offsetHeight;
const newBufferHeight = Math.round(this._currentRowHeight * this._lastRecordedBufferLength) + (this._lastRecordedViewportHeight - this._renderService.dimensions.canvasHeight);
if (this._lastRecordedBufferHeight !== newBufferHeight) {
@@ -94,8 +108,18 @@ export class Viewport extends Disposable implements IViewport {
this._viewportElement.scrollTop = scrollTop;
}
// Update scroll bar width
if (this._optionsService.options.scrollback === 0) {
this.scrollBarWidth = 0;
} else {
this.scrollBarWidth = (this._viewportElement.offsetWidth - this._scrollArea.offsetWidth) || FALLBACK_SCROLL_BAR_WIDTH;
}
this._lastHadScrollBar = this.scrollBarWidth > 0;
this._viewportElement.style.width = (this._renderService.dimensions.actualCellWidth * (this._bufferService.cols) + this.scrollBarWidth).toString() + 'px';
this._refreshAnimationFrame = null;
}
/**
* Updates dimensions and synchronizes the scroll area if necessary.
*/
@@ -114,23 +138,21 @@ export class Viewport extends Disposable implements IViewport {
}
// If the buffer position doesn't match last scroll top
const newScrollTop = this._bufferService.buffer.ydisp * this._currentRowHeight;
if (this._lastScrollTop !== newScrollTop) {
this._refresh(immediate);
return;
}
// If element's scroll top changed, this can happen when hiding the element
if (this._lastScrollTop !== this._viewportElement.scrollTop) {
if (this._lastScrollTop !== this._activeBuffer.ydisp * this._currentRowHeight) {
this._refresh(immediate);
return;
}
// If row height changed
if (this._renderService.dimensions.scaledCellHeight / window.devicePixelRatio !== this._currentRowHeight) {
if (this._renderDimensions.scaledCellHeight !== this._currentScaledCellHeight) {
this._refresh(immediate);
return;
}
// If the scroll bar visibility changed
if (this._lastHadScrollBar !== (this._optionsService.options.scrollback > 0)) {
this._refresh(immediate);
}
}
/**
+3
View File
@@ -222,6 +222,9 @@ export class Terminal implements ITerminalApi {
public reset(): void {
this._core.reset();
}
public clearTextureAtlas(): void {
this._core.clearTextureAtlas();
}
public loadAddon(addon: ITerminalAddon): void {
return this._addonManager.loadAddon(this, addon);
}
+4
View File
@@ -138,6 +138,10 @@ export abstract class BaseRenderLayer implements IRenderLayer {
public abstract reset(): void;
public clearTextureAtlas(): void {
this._charAtlas?.clear();
}
/**
* Fills 1+ cells completely. This uses the existing fillStyle on the context.
* @param x The column to start at.
+6
View File
@@ -149,6 +149,12 @@ export class Renderer extends Disposable implements IRenderer {
}
}
public clearTextureAtlas(): void {
for (const layer of this._renderLayers) {
layer.clearTextureAtlas();
}
}
/**
* Recalculates the character and canvas dimensions.
*/
+6
View File
@@ -52,6 +52,7 @@ export interface IRenderer extends IDisposable {
onOptionsChanged(): void;
clear(): void;
renderRows(start: number, end: number): void;
clearTextureAtlas?(): void;
}
export interface IRenderLayer extends IDisposable {
@@ -100,4 +101,9 @@ export interface IRenderLayer extends IDisposable {
* Clear the state of the render layer.
*/
reset(): void;
/**
* Clears the texture atlas.
*/
clearTextureAtlas(): void;
}
@@ -28,6 +28,8 @@ export abstract class BaseCharAtlas implements IDisposable {
*/
private _doWarmUp(): void { }
public clear(): void { }
/**
* Called when we start drawing a new frame.
*
+32 -2
View File
@@ -119,6 +119,16 @@ export class DynamicCharAtlas extends BaseCharAtlas {
this._drawToCacheCount = 0;
}
public clear(): void {
if (this._cacheMap.size > 0) {
const capacity = this._width * this._height;
this._cacheMap = new LRUMap(capacity);
this._cacheMap.prealloc(capacity);
}
this._cacheCtx.clearRect(0, 0, TEXTURE_WIDTH, TEXTURE_HEIGHT);
this._tmpCtx.clearRect(0, 0, this._config.scaledCharWidth, this._config.scaledCharHeight);
}
public draw(
ctx: CanvasRenderingContext2D,
glyph: IGlyphIdentifier,
@@ -266,11 +276,10 @@ export class DynamicCharAtlas extends BaseCharAtlas {
}
// Draw the character
this._tmpCtx.fillText(glyph.chars, 0, this._config.scaledCharHeight);
this._tmpCtx.restore();
// clear the background from the character to avoid issues with drawing over the previous
// character if it extends past it's bounds
const imageData = this._tmpCtx.getImageData(
let imageData = this._tmpCtx.getImageData(
0, 0, this._config.scaledCharWidth, this._config.scaledCharHeight
);
let isEmpty = false;
@@ -278,6 +287,27 @@ export class DynamicCharAtlas extends BaseCharAtlas {
isEmpty = clearColor(imageData, backgroundColor);
}
// If this charcater is underscore and empty, shift it up until it is visible, try for a maximum
// of 5 pixels.
if (isEmpty && glyph.chars === '_' && !this._config.allowTransparency) {
for (let offset = 1; offset <= 5; offset++) {
// Draw the character
this._tmpCtx.fillText(glyph.chars, 0, this._config.scaledCharHeight - offset);
// clear the background from the character to avoid issues with drawing over the previous
// character if it extends past it's bounds
imageData = this._tmpCtx.getImageData(
0, 0, this._config.scaledCharWidth, this._config.scaledCharHeight
);
isEmpty = clearColor(imageData, backgroundColor);
if (!isEmpty) {
break;
}
}
}
this._tmpCtx.restore();
// copy the data from imageData to _cacheCanvas
const x = this._toCoordinateX(index);
const y = this._toCoordinateY(index);
@@ -10,7 +10,7 @@ import { NULL_CELL_CODE, NULL_CELL_WIDTH, NULL_CELL_CHAR, DEFAULT_ATTR, FgFlags,
import { BufferLine, DEFAULT_ATTR_DATA } from 'common/buffer/BufferLine';
import { IBufferLine } from 'common/Types';
import { CellData } from 'common/buffer/CellData';
import { MockOptionsService } from 'common/TestUtils.test';
import { MockCoreService, MockOptionsService } from 'common/TestUtils.test';
import { css } from 'browser/Color';
import { MockCharacterJoinerService } from 'browser/TestUtils.test';
@@ -21,30 +21,36 @@ describe('DomRendererRowFactory', () => {
beforeEach(() => {
dom = new jsdom.JSDOM('');
rowFactory = new DomRendererRowFactory(dom.window.document, {
background: css.toColor('#010101'),
foreground: css.toColor('#020202'),
ansi: [
// dark:
css.toColor('#2e3436'),
css.toColor('#cc0000'),
css.toColor('#4e9a06'),
css.toColor('#c4a000'),
css.toColor('#3465a4'),
css.toColor('#75507b'),
css.toColor('#06989a'),
css.toColor('#d3d7cf'),
// bright:
css.toColor('#555753'),
css.toColor('#ef2929'),
css.toColor('#8ae234'),
css.toColor('#fce94f'),
css.toColor('#729fcf'),
css.toColor('#ad7fa8'),
css.toColor('#34e2e2'),
css.toColor('#eeeeec')
]
} as any, new MockCharacterJoinerService(), new MockOptionsService({ drawBoldTextInBrightColors: true }));
rowFactory = new DomRendererRowFactory(
dom.window.document,
{
background: css.toColor('#010101'),
foreground: css.toColor('#020202'),
ansi: [
// dark:
css.toColor('#2e3436'),
css.toColor('#cc0000'),
css.toColor('#4e9a06'),
css.toColor('#c4a000'),
css.toColor('#3465a4'),
css.toColor('#75507b'),
css.toColor('#06989a'),
css.toColor('#d3d7cf'),
// bright:
css.toColor('#555753'),
css.toColor('#ef2929'),
css.toColor('#8ae234'),
css.toColor('#fce94f'),
css.toColor('#729fcf'),
css.toColor('#ad7fa8'),
css.toColor('#34e2e2'),
css.toColor('#eeeeec')
]
} as any,
new MockCharacterJoinerService(),
new MockOptionsService({ drawBoldTextInBrightColors: true }),
new MockCoreService()
);
lineData = createEmptyLineData(2);
});
@@ -7,7 +7,7 @@ import { IBufferLine } from 'common/Types';
import { INVERTED_DEFAULT_COLOR } from 'browser/renderer/atlas/Constants';
import { NULL_CELL_CODE, WHITESPACE_CELL_CHAR, Attributes } from 'common/buffer/Constants';
import { CellData } from 'common/buffer/CellData';
import { IOptionsService } from 'common/services/Services';
import { ICoreService, IOptionsService } from 'common/services/Services';
import { color, rgba } from 'browser/Color';
import { IColorSet, IColor } from 'browser/Types';
import { ICharacterJoinerService } from 'browser/services/Services';
@@ -31,7 +31,8 @@ export class DomRendererRowFactory {
private readonly _document: Document,
private _colors: IColorSet,
@ICharacterJoinerService private readonly _characterJoinerService: ICharacterJoinerService,
@IOptionsService private readonly _optionsService: IOptionsService
@IOptionsService private readonly _optionsService: IOptionsService,
@ICoreService private readonly _coreService: ICoreService
) {
}
@@ -110,7 +111,7 @@ export class DomRendererRowFactory {
}
}
if (isCursorRow && x === cursorX) {
if (!this._coreService.isCursorHidden && isCursorRow && x === cursorX) {
charElement.classList.add(CURSOR_CLASS);
if (cursorBlink) {
+5
View File
@@ -168,6 +168,11 @@ export class RenderService extends Disposable implements IRenderService {
}
}
public clearTextureAtlas(): void {
this._renderer?.clearTextureAtlas?.();
this._fullRefresh();
}
public setColors(colors: IColorSet): void {
this._renderer.setColors(colors);
this._fullRefresh();
+1
View File
@@ -53,6 +53,7 @@ export interface IRenderService extends IDisposable {
dimensions: IRenderDimensions;
refreshRows(start: number, end: number): void;
clearTextureAtlas(): void;
resize(cols: number, rows: number): void;
changeOptions(): void;
setRenderer(renderer: IRenderer): void;