From 18871f0d3cf3fd41b641ec5dcfb809c3ddd82657 Mon Sep 17 00:00:00 2001 From: Alex Ross Date: Mon, 1 Oct 2018 13:30:13 -0700 Subject: [PATCH 01/15] Cleared terminal lines should have isWrapped reset Fixes #1710 --- src/InputHandler.ts | 21 ++++++++++++++++++--- src/addons/search/SearchHelper.ts | 2 +- src/addons/search/search.test.ts | 3 +++ 3 files changed, 22 insertions(+), 4 deletions(-) diff --git a/src/InputHandler.ts b/src/InputHandler.ts index ad5aad39..9a0aae08 100644 --- a/src/InputHandler.ts +++ b/src/InputHandler.ts @@ -730,6 +730,21 @@ export class InputHandler extends Disposable implements IInputHandler { ); } + /** + * Helper method to reset cells in a terminal row. + * The cell gets replaced with the eraseChar of the terminal and the isWrapped property is set to false. + * @param y row index + */ + private _resetBufferLine(y: number): void { + const line = this._terminal.buffer.lines.get(this._terminal.buffer.ybase + y); + line.replaceCells( + 0, + this._terminal.cols, + [this._terminal.eraseAttr(), NULL_CELL_CHAR, NULL_CELL_WIDTH, NULL_CELL_CODE] + ); + line.isWrapped = false; + } + /** * CSI Ps J Erase in Display (ED). * Ps = 0 -> Erase Below (default). @@ -750,7 +765,7 @@ export class InputHandler extends Disposable implements IInputHandler { this._terminal.updateRange(j); this._eraseInBufferLine(j++, this._terminal.buffer.x, this._terminal.cols); for (; j < this._terminal.rows; j++) { - this._eraseInBufferLine(j, 0, this._terminal.cols); + this._resetBufferLine(j); } this._terminal.updateRange(j); break; @@ -759,7 +774,7 @@ export class InputHandler extends Disposable implements IInputHandler { this._terminal.updateRange(j); this._eraseInBufferLine(j, 0, this._terminal.buffer.x + 1); while (j--) { - this._eraseInBufferLine(j, 0, this._terminal.cols); + this._resetBufferLine(j); } this._terminal.updateRange(0); break; @@ -767,7 +782,7 @@ export class InputHandler extends Disposable implements IInputHandler { j = this._terminal.rows; this._terminal.updateRange(j - 1); while (j--) { - this._eraseInBufferLine(j, 0, this._terminal.cols); + this._resetBufferLine(j); } this._terminal.updateRange(0); break; diff --git a/src/addons/search/SearchHelper.ts b/src/addons/search/SearchHelper.ts index d07c6b2c..da09f83f 100644 --- a/src/addons/search/SearchHelper.ts +++ b/src/addons/search/SearchHelper.ts @@ -191,7 +191,7 @@ export class SearchHelper implements ISearchHelper { do { const nextLine = this._terminal._core.buffer.lines.get(lineIndex + 1); lineWrapsToNext = nextLine ? nextLine.isWrapped : false; - lineString += this._terminal._core.buffer.translateBufferLineToString(lineIndex, !lineWrapsToNext && trimRight); + lineString += this._terminal._core.buffer.translateBufferLineToString(lineIndex, !lineWrapsToNext && trimRight).substring(0, this._terminal.cols); lineIndex++; } while (lineWrapsToNext); diff --git a/src/addons/search/search.test.ts b/src/addons/search/search.test.ts index ccdebaf3..b22c22a5 100644 --- a/src/addons/search/search.test.ts +++ b/src/addons/search/search.test.ts @@ -82,6 +82,9 @@ describe('search addon', () => { expect(hello3).eql(undefined); expect(llo).eql(undefined); expect(goodbye).eql({col: 0, row: 5, term: 'goodbye'}); + term.core.resize(9, 5); + const hello0Resize = term.searchHelper.findInLine('Hello', 0); + expect(hello0Resize).eql({col: 8, row: 0, term: 'Hello'}); }); it('should respect search regex', () => { search.apply(MockTerminal); From 0065682bd7ebda786628f16329ae88c0a5c52abd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B6rg=20Breitbart?= Date: Tue, 9 Oct 2018 21:17:33 +0200 Subject: [PATCH 02/15] resize should not alter length if shrink=false --- src/BufferLine.test.ts | 92 ++++++++++++++++++++++++++++++------------ src/BufferLine.ts | 22 +++++----- 2 files changed, 78 insertions(+), 36 deletions(-) diff --git a/src/BufferLine.test.ts b/src/BufferLine.test.ts index 2db69176..b824cc38 100644 --- a/src/BufferLine.test.ts +++ b/src/BufferLine.test.ts @@ -133,31 +133,71 @@ describe('BufferLine', function(): void { const line3 = line.clone(); chai.expect(TestBufferLine.prototype.toArray.apply(line3)).eql(line.toArray()); }); - it('resize enlarge', function(): void { - const line = new TestBufferLine(5, [1, 'a', 0, 'a'.charCodeAt(0)], false); - line.resize(10, [1, 'a', 0, 'a'.charCodeAt(0)]); - chai.expect(line.toArray()).eql(Array(10).fill([1, 'a', 0, 'a'.charCodeAt(0)])); - }); - it('resize shrink(true)', function(): void { - const line = new TestBufferLine(10, [1, 'a', 0, 'a'.charCodeAt(0)], false); - line.resize(5, [1, 'a', 0, 'a'.charCodeAt(0)], true); - chai.expect(line.toArray()).eql(Array(5).fill([1, 'a', 0, 'a'.charCodeAt(0)])); - }); - it('resize shrink(false)', function(): void { - const line = new TestBufferLine(10, [1, 'a', 0, 'a'.charCodeAt(0)], false); - line.resize(5, [1, 'a', 0, 'a'.charCodeAt(0)], false); - chai.expect(line.toArray()).eql(Array(5).fill([1, 'a', 0, 'a'.charCodeAt(0)])); - }); - it('resize shrink(false) + shrink(false)', function(): void { - const line = new TestBufferLine(20, [1, 'a', 0, 'a'.charCodeAt(0)], false); - line.resize(10, [1, 'a', 0, 'a'.charCodeAt(0)], false); - line.resize(5, [1, 'a', 0, 'a'.charCodeAt(0)], false); - chai.expect(line.toArray()).eql(Array(5).fill([1, 'a', 0, 'a'.charCodeAt(0)])); - }); - it('resize shrink(false) + enlarge', function(): void { - const line = new TestBufferLine(20, [1, 'a', 0, 'a'.charCodeAt(0)], false); - line.resize(10, [1, 'a', 0, 'a'.charCodeAt(0)], false); - line.resize(15, [1, 'a', 0, 'a'.charCodeAt(0)]); - chai.expect(line.toArray()).eql(Array(15).fill([1, 'a', 0, 'a'.charCodeAt(0)])); + describe('resize', function(): void { + it('enlarge(false)', function(): void { + const line = new TestBufferLine(5, [1, 'a', 0, 'a'.charCodeAt(0)], false); + line.resize(10, [1, 'a', 0, 'a'.charCodeAt(0)]); + chai.expect(line.toArray()).eql(Array(10).fill([1, 'a', 0, 'a'.charCodeAt(0)])); + }); + it('enlarge(true)', function(): void { + const line = new TestBufferLine(5, [1, 'a', 0, 'a'.charCodeAt(0)], false); + line.resize(10, [1, 'a', 0, 'a'.charCodeAt(0)], true); + chai.expect(line.toArray()).eql(Array(10).fill([1, 'a', 0, 'a'.charCodeAt(0)])); + }); + it('shrink(true) - should apply new size', function(): void { + const line = new TestBufferLine(10, [1, 'a', 0, 'a'.charCodeAt(0)], false); + line.resize(5, [1, 'a', 0, 'a'.charCodeAt(0)], true); + chai.expect(line.toArray()).eql(Array(5).fill([1, 'a', 0, 'a'.charCodeAt(0)])); + }); + it('shrink(false) - should not apply new size', function(): void { + const line = new TestBufferLine(10, [1, 'a', 0, 'a'.charCodeAt(0)], false); + line.resize(5, [1, 'a', 0, 'a'.charCodeAt(0)], false); + chai.expect(line.toArray()).eql(Array(10).fill([1, 'a', 0, 'a'.charCodeAt(0)])); + }); + it('shrink(false) + shrink(false) - should not apply new size', function(): void { + const line = new TestBufferLine(20, [1, 'a', 0, 'a'.charCodeAt(0)], false); + line.resize(10, [1, 'a', 0, 'a'.charCodeAt(0)], false); + line.resize(5, [1, 'a', 0, 'a'.charCodeAt(0)], false); + chai.expect(line.toArray()).eql(Array(20).fill([1, 'a', 0, 'a'.charCodeAt(0)])); + }); + it('shrink(false) + enlarge(false) to smaller than before', function(): void { + const line = new TestBufferLine(20, [1, 'a', 0, 'a'.charCodeAt(0)], false); + line.resize(10, [1, 'a', 0, 'a'.charCodeAt(0)], false); + line.resize(15, [1, 'a', 0, 'a'.charCodeAt(0)]); + chai.expect(line.toArray()).eql(Array(20).fill([1, 'a', 0, 'a'.charCodeAt(0)])); + }); + it('shrink(false) + enlarge(false) to bigger than before', function(): void { + const line = new TestBufferLine(20, [1, 'a', 0, 'a'.charCodeAt(0)], false); + line.resize(10, [1, 'a', 0, 'a'.charCodeAt(0)], false); + line.resize(25, [1, 'a', 0, 'a'.charCodeAt(0)]); + chai.expect(line.toArray()).eql(Array(25).fill([1, 'a', 0, 'a'.charCodeAt(0)])); + }); + it('shrink(false) + resize shrink=true should enforce shrinking', function(): void { + const line = new TestBufferLine(20, [1, 'a', 0, 'a'.charCodeAt(0)], false); + line.resize(10, [1, 'a', 0, 'a'.charCodeAt(0)], false); + line.resize(10, [1, 'a', 0, 'a'.charCodeAt(0)], true); + chai.expect(line.toArray()).eql(Array(10).fill([1, 'a', 0, 'a'.charCodeAt(0)])); + }); + it('enlarge from 0 length', function(): void { + const line = new TestBufferLine(0, [1, 'a', 0, 'a'.charCodeAt(0)], false); + line.resize(10, [1, 'a', 0, 'a'.charCodeAt(0)], false); + chai.expect(line.toArray()).eql(Array(10).fill([1, 'a', 0, 'a'.charCodeAt(0)])); + }); + it('shrink to 0 length', function(): void { + const line = new TestBufferLine(10, [1, 'a', 0, 'a'.charCodeAt(0)], false); + line.resize(0, [1, 'a', 0, 'a'.charCodeAt(0)], true); + chai.expect(line.toArray()).eql(Array(0).fill([1, 'a', 0, 'a'.charCodeAt(0)])); + }); + it('shrink(false) to 0 and enlarge to different sizes', function(): void { + const line = new TestBufferLine(10, [1, 'a', 0, 'a'.charCodeAt(0)], false); + line.resize(0, [1, 'a', 0, 'a'.charCodeAt(0)], false); + chai.expect(line.toArray()).eql(Array(10).fill([1, 'a', 0, 'a'.charCodeAt(0)])); + line.resize(5, [1, 'a', 0, 'a'.charCodeAt(0)], false); + chai.expect(line.toArray()).eql(Array(10).fill([1, 'a', 0, 'a'.charCodeAt(0)])); + line.resize(7, [1, 'a', 0, 'a'.charCodeAt(0)], false); + chai.expect(line.toArray()).eql(Array(10).fill([1, 'a', 0, 'a'.charCodeAt(0)])); + line.resize(7, [1, 'a', 0, 'a'.charCodeAt(0)], true); + chai.expect(line.toArray()).eql(Array(7).fill([1, 'a', 0, 'a'.charCodeAt(0)])); + }); }); }); diff --git a/src/BufferLine.ts b/src/BufferLine.ts index 53f5d4d4..f1ea9cf0 100644 --- a/src/BufferLine.ts +++ b/src/BufferLine.ts @@ -77,15 +77,15 @@ export class BufferLine implements IBufferLine { /** resize line to cols filling new cells with fill */ public resize(cols: number, fillCharData: CharData, shrink: boolean = false): void { + while (this._data.length < cols) { + this._data.push(fillCharData); + } if (shrink) { while (this._data.length > cols) { this._data.pop(); } } - while (this._data.length < cols) { - this._data.push(fillCharData); - } - this.length = cols; + this.length = this._data.length; } public fill(fillCharData: CharData): void { @@ -141,11 +141,13 @@ export class BufferLineTypedArray implements IBufferLine { if (!fillCharData) { fillCharData = [0, NULL_CELL_CHAR, NULL_CELL_WIDTH, NULL_CELL_CODE]; } - this._data = new Uint32Array(cols * CELL_SIZE); - for (let i = 0; i < cols; ++i) { - this.set(i, fillCharData); + if (cols) { + this._data = new Uint32Array(cols * CELL_SIZE); + for (let i = 0; i < cols; ++i) { + this.set(i, fillCharData); + } } - this.length = cols || 0; + this.length = cols; } public get(index: number): CharData { @@ -212,12 +214,12 @@ export class BufferLineTypedArray implements IBufferLine { } public resize(cols: number, fillCharData: CharData, shrink: boolean = false): void { - if (cols === this.length) { + if (cols === this.length || (!shrink && cols < this.length)) { return; } if (cols > this.length) { const data = new Uint32Array(cols * CELL_SIZE); - if (this._data) { + if (this.length) { if (cols * CELL_SIZE < this._data.length) { data.set(this._data.subarray(0, cols * CELL_SIZE)); } else { From f2ecd06e64dcbfdc3cbfdc24bac59f52d1255569 Mon Sep 17 00:00:00 2001 From: Alex Ross Date: Wed, 10 Oct 2018 15:31:49 +0200 Subject: [PATCH 03/15] Additional isWrapped clearing --- src/InputHandler.ts | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/src/InputHandler.ts b/src/InputHandler.ts index 9a0aae08..97001d0a 100644 --- a/src/InputHandler.ts +++ b/src/InputHandler.ts @@ -722,12 +722,16 @@ export class InputHandler extends Disposable implements IInputHandler { * @param start first cell index to be erased * @param end end - 1 is last erased cell */ - private _eraseInBufferLine(y: number, start: number, end: number): void { - this._terminal.buffer.lines.get(this._terminal.buffer.ybase + y).replaceCells( + private _eraseInBufferLine(y: number, start: number, end: number, clearWrap: boolean = false): void { + const line = this._terminal.buffer.lines.get(this._terminal.buffer.ybase + y); + line.replaceCells( start, end, [this._terminal.eraseAttr(), NULL_CELL_CHAR, NULL_CELL_WIDTH, NULL_CELL_CODE] ); + if (clearWrap) { + line.isWrapped = false; + } } /** @@ -736,13 +740,7 @@ export class InputHandler extends Disposable implements IInputHandler { * @param y row index */ private _resetBufferLine(y: number): void { - const line = this._terminal.buffer.lines.get(this._terminal.buffer.ybase + y); - line.replaceCells( - 0, - this._terminal.cols, - [this._terminal.eraseAttr(), NULL_CELL_CHAR, NULL_CELL_WIDTH, NULL_CELL_CODE] - ); - line.isWrapped = false; + this._eraseInBufferLine(y, 0, this._terminal.cols, true); } /** @@ -763,7 +761,11 @@ export class InputHandler extends Disposable implements IInputHandler { case 0: j = this._terminal.buffer.y; this._terminal.updateRange(j); - this._eraseInBufferLine(j++, this._terminal.buffer.x, this._terminal.cols); + if (this._terminal.buffer.x !== 0) { + this._eraseInBufferLine(j++, this._terminal.buffer.x, this._terminal.cols); + } else { + this._resetBufferLine(j++); + } for (; j < this._terminal.rows; j++) { this._resetBufferLine(j); } From 64d6354983600b7323b49d875405ff38f2379f18 Mon Sep 17 00:00:00 2001 From: Alex Ross Date: Thu, 11 Oct 2018 11:18:56 +0200 Subject: [PATCH 04/15] Added testing and better erase left and above handling --- src/InputHandler.test.ts | 30 ++++++++++++++++++++++++++++++ src/InputHandler.ts | 13 +++++++------ 2 files changed, 37 insertions(+), 6 deletions(-) diff --git a/src/InputHandler.test.ts b/src/InputHandler.test.ts index 722cc287..0e610fc0 100644 --- a/src/InputHandler.test.ts +++ b/src/InputHandler.test.ts @@ -444,6 +444,36 @@ describe('InputHandler', () => { termNew.buffer.x = 40; inputHandlerNew.eraseInDisplay([2]); expect(termContent(termNew)).eql(termContent(termOld)); + + // reset and add a wrapped line + termNew.buffer.y = 0; + termNew.buffer.x = 0; + inputHandlerNew.parse(Array(termNew.cols + 1).join('a')); // line 0 + inputHandlerNew.parse(Array(termNew.cols + 10).join('a')); // line 1 and 2 + for (let i = 3; i < termOld.rows; ++i) inputHandlerNew.parse(Array(termNew.cols + 1).join('a')); + + // params[1] left and above with wrap + // confirm precondition that line 2 is wrapped + expect(termNew.buffer.lines.get(2).isWrapped).true; + termNew.buffer.y = 2; + termNew.buffer.x = 40; + inputHandlerNew.eraseInDisplay([1]); + expect(termNew.buffer.lines.get(2).isWrapped).false; + + // reset and add a wrapped line + termNew.buffer.y = 0; + termNew.buffer.x = 0; + inputHandlerNew.parse(Array(termNew.cols + 1).join('a')); // line 0 + inputHandlerNew.parse(Array(termNew.cols + 10).join('a')); // line 1 and 2 + for (let i = 3; i < termOld.rows; ++i) inputHandlerNew.parse(Array(termNew.cols + 1).join('a')); + + // params[1] left and above with wrap + // confirm precondition that line 2 is wrapped + expect(termNew.buffer.lines.get(2).isWrapped).true; + termNew.buffer.y = 1; + termNew.buffer.x = 90; // Cursor is beyond last column + inputHandlerNew.eraseInDisplay([1]); + expect(termNew.buffer.lines.get(2).isWrapped).false; }); }); it('convertEol setting', function(): void { diff --git a/src/InputHandler.ts b/src/InputHandler.ts index 97001d0a..2fcfac27 100644 --- a/src/InputHandler.ts +++ b/src/InputHandler.ts @@ -761,11 +761,7 @@ export class InputHandler extends Disposable implements IInputHandler { case 0: j = this._terminal.buffer.y; this._terminal.updateRange(j); - if (this._terminal.buffer.x !== 0) { - this._eraseInBufferLine(j++, this._terminal.buffer.x, this._terminal.cols); - } else { - this._resetBufferLine(j++); - } + this._eraseInBufferLine(j++, this._terminal.buffer.x, this._terminal.cols, this._terminal.buffer.x === 0); for (; j < this._terminal.rows; j++) { this._resetBufferLine(j); } @@ -774,7 +770,12 @@ export class InputHandler extends Disposable implements IInputHandler { case 1: j = this._terminal.buffer.y; this._terminal.updateRange(j); - this._eraseInBufferLine(j, 0, this._terminal.buffer.x + 1); + // Deleted front part of line and everything before. This line will no longer be wrapped. + this._eraseInBufferLine(j, 0, this._terminal.buffer.x + 1, true); + if (this._terminal.buffer.x + 1 >= this._terminal.cols) { + // Deleted entire previous line. This next line can no longer be wrapped. + this._terminal.buffer.lines.get(j + 1).isWrapped = false; + } while (j--) { this._resetBufferLine(j); } From 375b5c5b4f1334ea06ad64d2a22af2c00d031e33 Mon Sep 17 00:00:00 2001 From: Daniel Imms Date: Thu, 11 Oct 2018 09:02:36 -0700 Subject: [PATCH 05/15] Fix indent --- src/InputHandler.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/InputHandler.test.ts b/src/InputHandler.test.ts index 0e610fc0..04b7a173 100644 --- a/src/InputHandler.test.ts +++ b/src/InputHandler.test.ts @@ -461,7 +461,7 @@ describe('InputHandler', () => { expect(termNew.buffer.lines.get(2).isWrapped).false; // reset and add a wrapped line - termNew.buffer.y = 0; + termNew.buffer.y = 0; termNew.buffer.x = 0; inputHandlerNew.parse(Array(termNew.cols + 1).join('a')); // line 0 inputHandlerNew.parse(Array(termNew.cols + 10).join('a')); // line 1 and 2 From 9e1551e2f14f76d098b2b8d293dd6c3ef57d7255 Mon Sep 17 00:00:00 2001 From: Daniel Imms Date: Thu, 11 Oct 2018 09:37:19 -0700 Subject: [PATCH 06/15] Fix NPE in DOM renderer underline Fixes #1747 --- src/renderer/dom/DomRenderer.ts | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/renderer/dom/DomRenderer.ts b/src/renderer/dom/DomRenderer.ts index 8f51c4ef..adce57bc 100644 --- a/src/renderer/dom/DomRenderer.ts +++ b/src/renderer/dom/DomRenderer.ts @@ -352,7 +352,11 @@ export class DomRenderer extends EventEmitter implements IRenderer { private _setCellUnderline(x: number, x2: number, y: number, y2: number, cols: number, enabled: boolean): void { while (x !== x2 || y !== y2) { - const span = this._rowElements[y].children[x]; + const row = this._rowElements[y]; + if (!row) { + return; + } + const span = row.children[x]; span.style.textDecoration = enabled ? 'underline' : 'none'; x = (x + 1) % cols; if (x === 0) { From f61ba9558b6820c52030aee122a8042518bc4a13 Mon Sep 17 00:00:00 2001 From: pkoushik Date: Mon, 15 Oct 2018 23:44:30 +0530 Subject: [PATCH 07/15] Fixes-1750 --- src/addons/search/SearchHelper.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/addons/search/SearchHelper.ts b/src/addons/search/SearchHelper.ts index f23a8c58..7dea831c 100644 --- a/src/addons/search/SearchHelper.ts +++ b/src/addons/search/SearchHelper.ts @@ -205,6 +205,7 @@ export class SearchHelper implements ISearchHelper { */ private _selectResult(result: ISearchResult): boolean { if (!result) { + this._terminal.clearSelection(); return false; } this._terminal._core.selectionManager.setSelection(result.col, result.row, result.term.length); From a53aaa5f25eec4e6e050b357f80d9ae3148aec61 Mon Sep 17 00:00:00 2001 From: Daniel Imms Date: Mon, 15 Oct 2018 11:35:21 -0700 Subject: [PATCH 08/15] Move dynamic atlas canCache check higher Fixes #1757 --- src/renderer/atlas/DynamicCharAtlas.ts | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/renderer/atlas/DynamicCharAtlas.ts b/src/renderer/atlas/DynamicCharAtlas.ts index e67fe4f0..63336900 100644 --- a/src/renderer/atlas/DynamicCharAtlas.ts +++ b/src/renderer/atlas/DynamicCharAtlas.ts @@ -129,12 +129,17 @@ export default class DynamicCharAtlas extends BaseCharAtlas { return true; } + // Exit early for uncachable glyphs + if (!this._canCache(glyph)) { + return false; + } + const glyphKey = getGlyphCacheKey(glyph); const cacheValue = this._cacheMap.get(glyphKey); if (cacheValue !== null && cacheValue !== undefined) { this._drawFromCache(ctx, cacheValue, x, y); return true; - } else if (this._canCache(glyph) && this._drawToCacheCount < FRAME_CACHE_DRAW_LIMIT) { + } else if (this._drawToCacheCount < FRAME_CACHE_DRAW_LIMIT) { let index; if (this._cacheMap.size < this._cacheMap.capacity) { index = this._cacheMap.size; From 161dfa8d2d7c516b49649f623f93b913c8316189 Mon Sep 17 00:00:00 2001 From: Stathis Kavros Date: Tue, 16 Oct 2018 14:23:58 +0300 Subject: [PATCH 09/15] Fix typos --- src/addons/search/SearchHelper.ts | 6 +++--- src/addons/search/search.ts | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/addons/search/SearchHelper.ts b/src/addons/search/SearchHelper.ts index 7dea831c..9f59a9fd 100644 --- a/src/addons/search/SearchHelper.ts +++ b/src/addons/search/SearchHelper.ts @@ -19,7 +19,7 @@ export class SearchHelper implements ISearchHelper { /** * Find the next instance of the term, then scroll to and select it. If it * doesn't exist, do nothing. - * @param term Tne search term. + * @param term The search term. * @param searchOptions Search options. * @return Whether a result was found. */ @@ -61,7 +61,7 @@ export class SearchHelper implements ISearchHelper { /** * Find the previous instance of the term, then scroll to and select it. If it * doesn't exist, do nothing. - * @param term Tne search term. + * @param term The search term. * @param searchOptions Search options. * @return Whether a result was found. */ @@ -116,7 +116,7 @@ export class SearchHelper implements ISearchHelper { * subsequent terminal lines if the text is wrapped. If the provided line number is part of a wrapped text line that * started on an earlier line then it is skipped since it will be properly searched when the terminal line that the * text starts on is searched. - * @param term Tne search term. + * @param term The search term. * @param y The line to search. * @param searchOptions Search options. * @return The search result if it was found. diff --git a/src/addons/search/search.ts b/src/addons/search/search.ts index 9be0b33b..c274f28a 100644 --- a/src/addons/search/search.ts +++ b/src/addons/search/search.ts @@ -10,7 +10,7 @@ import { ISearchAddonTerminal, ISearchOptions } from './Interfaces'; /** * Find the next instance of the term, then scroll to and select it. If it * doesn't exist, do nothing. - * @param term Tne search term. + * @param term The search term. * @param searchOptions Search options * @return Whether a result was found. */ @@ -25,7 +25,7 @@ export function findNext(terminal: Terminal, term: string, searchOptions: ISearc /** * Find the previous instance of the term, then scroll to and select it. If it * doesn't exist, do nothing. - * @param term Tne search term. + * @param term The search term. * @param searchOptions Search options * @return Whether a result was found. */ From 74664a91611d4ae718012097f11e0f58f65989e9 Mon Sep 17 00:00:00 2001 From: pkoushik Date: Wed, 17 Oct 2018 10:48:46 +0530 Subject: [PATCH 10/15] Fix-1749 --- src/addons/search/SearchHelper.ts | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/addons/search/SearchHelper.ts b/src/addons/search/SearchHelper.ts index 7dea831c..6829ef4c 100644 --- a/src/addons/search/SearchHelper.ts +++ b/src/addons/search/SearchHelper.ts @@ -33,7 +33,9 @@ export class SearchHelper implements ISearchHelper { let startRow = this._terminal._core.buffer.ydisp; if (this._terminal._core.selectionManager.selectionEnd) { // Start from the selection end if there is a selection - startRow = this._terminal._core.selectionManager.selectionEnd[1]; + if (this._terminal.getSelection().length !== 0) { + startRow = this._terminal._core.selectionManager.selectionEnd[1]; + } } // Search from ydisp + 1 to end @@ -75,7 +77,9 @@ export class SearchHelper implements ISearchHelper { let startRow = this._terminal._core.buffer.ydisp; if (this._terminal._core.selectionManager.selectionStart) { // Start from the selection end if there is a selection - startRow = this._terminal._core.selectionManager.selectionStart[1]; + if (this._terminal.getSelection().length !== 0) { + startRow = this._terminal._core.selectionManager.selectionStart[1]; + } } // Search from ydisp + 1 to end @@ -108,7 +112,7 @@ export class SearchHelper implements ISearchHelper { */ private _isWholeWord(searchIndex: number, line: string, term: string): boolean { return (((searchIndex === 0) || (nonWordCharacters.indexOf(line[searchIndex - 1]) !== -1)) && - (((searchIndex + term.length) === line.length) || (nonWordCharacters.indexOf(line[searchIndex + term.length]) !== -1))); + (((searchIndex + term.length) === line.length) || (nonWordCharacters.indexOf(line[searchIndex + term.length]) !== -1))); } /** From 8bd49cba35617699f6c69bf7b648b66b6cb17057 Mon Sep 17 00:00:00 2001 From: Jeff Smith Date: Fri, 21 Sep 2018 23:20:38 -0500 Subject: [PATCH 11/15] Fill inserted lines with background color When scrolling occurs due to a LF or scroll code, fill the new line with the currently-set background color. --- src/Terminal.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Terminal.ts b/src/Terminal.ts index c995af62..55e212e0 100644 --- a/src/Terminal.ts +++ b/src/Terminal.ts @@ -1174,7 +1174,7 @@ export class Terminal extends EventEmitter implements ITerminal, IDisposable, II * @param isWrapped Whether the new line is wrapped from the previous line. */ public scroll(isWrapped?: boolean): void { - const newLine = this.buffer.getBlankLine(DEFAULT_ATTR, isWrapped); + const newLine = this.buffer.getBlankLine(this.eraseAttr(), isWrapped); const topRow = this.buffer.ybase + this.buffer.scrollTop; const bottomRow = this.buffer.ybase + this.buffer.scrollBottom; From 35db216f649006ca5d35dd1d51a1f5f0d5841ea9 Mon Sep 17 00:00:00 2001 From: Daniel Imms Date: Sat, 20 Oct 2018 13:55:13 -0700 Subject: [PATCH 12/15] Fix indent --- src/addons/search/SearchHelper.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/addons/search/SearchHelper.ts b/src/addons/search/SearchHelper.ts index cd867824..938887d8 100644 --- a/src/addons/search/SearchHelper.ts +++ b/src/addons/search/SearchHelper.ts @@ -112,7 +112,7 @@ export class SearchHelper implements ISearchHelper { */ private _isWholeWord(searchIndex: number, line: string, term: string): boolean { return (((searchIndex === 0) || (nonWordCharacters.indexOf(line[searchIndex - 1]) !== -1)) && - (((searchIndex + term.length) === line.length) || (nonWordCharacters.indexOf(line[searchIndex + term.length]) !== -1))); + (((searchIndex + term.length) === line.length) || (nonWordCharacters.indexOf(line[searchIndex + term.length]) !== -1))); } /** From 4d556fcaf0b6158d5327ef6df61b908bb01893db Mon Sep 17 00:00:00 2001 From: Jeff Smith Date: Tue, 23 Oct 2018 11:57:20 -0500 Subject: [PATCH 13/15] Check for focus on document as well as on textarea When clicking outside of the browser document area, the cursor does not appear to get 'blurred'. This can be confusing as it implies that the cursor is still active. This is caused by Terminal's isFocused getter only checking if the textarea is the active element of the document. Expand isFocused to also check that the document itself has focus. --- src/Terminal.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Terminal.ts b/src/Terminal.ts index c995af62..a7b87027 100644 --- a/src/Terminal.ts +++ b/src/Terminal.ts @@ -342,7 +342,7 @@ export class Terminal extends EventEmitter implements ITerminal, IDisposable, II } public get isFocused(): boolean { - return document.activeElement === this.textarea; + return document.activeElement === this.textarea && document.hasFocus(); } /** From c2994b0ae1b72fffe95312ef74c5d32897ac82a7 Mon Sep 17 00:00:00 2001 From: Daniel Imms Date: Tue, 23 Oct 2018 15:45:52 -0700 Subject: [PATCH 14/15] Remove request term info handler We're not supporting it anyway, no point having it. --- src/InputHandler.ts | 23 +---------------------- 1 file changed, 1 insertion(+), 22 deletions(-) diff --git a/src/InputHandler.ts b/src/InputHandler.ts index ddb20527..a282031b 100644 --- a/src/InputHandler.ts +++ b/src/InputHandler.ts @@ -24,26 +24,6 @@ const GLEVEL: {[key: string]: number} = {'(': 0, ')': 1, '*': 2, '+': 3, '-': 1, * DCS subparser implementations */ - /** - * DCS + q Pt ST (xterm) - * Request Terminfo String - * not supported - */ -class RequestTerminfo implements IDcsHandler { - private _data: string; - constructor(private _terminal: any) { } - hook(collect: string, params: number[], flag: number): void { - this._data = ''; - } - put(data: string, start: number, end: number): void { - this._data += data.substring(start, end); - } - unhook(): void { - // invalid: DCS 0 + r Pt ST - this._terminal.handler(`${C0.ESC}P0+r${this._data}${C0.ESC}\\`); - } -} - /** * DCS $ q Pt ST * DECRQSS (https://vt100.net/docs/vt510-rm/DECRQSS.html) @@ -86,7 +66,7 @@ class DECRQSS implements IDcsHandler { default: // invalid: DCS 0 $ r Pt ST (xterm) this._terminal.error('Unknown DCS $q %s', this._data); - this._terminal.handler(`${C0.ESC}P0$r${this._data}${C0.ESC}\\`); + this._terminal.handler(`${C0.ESC}P0$r${C0.ESC}\\`); } } } @@ -287,7 +267,6 @@ export class InputHandler extends Disposable implements IInputHandler { * DCS handler */ this._parser.setDcsHandler('$q', new DECRQSS(this._terminal)); - this._parser.setDcsHandler('+q', new RequestTerminfo(this._terminal)); } public dispose(): void { From 213dadf1bd12a5ca796214a796f4c6443b5b75b5 Mon Sep 17 00:00:00 2001 From: Shengdun Hua Date: Thu, 25 Oct 2018 23:01:03 +0800 Subject: [PATCH 15/15] Update README.md --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 17833598..551a94f4 100644 --- a/README.md +++ b/README.md @@ -171,6 +171,7 @@ computational environment for Jupyter, supporting interactive data science and s - [**SSH Web Client**](https://github.com/roke22/PHP-SSH2-Web-Client): SSH Web Client with PHP. - [**Shellvault**](https://www.shellvault.io): The cloud-based SSH terminal you can access from anywhere. - [**Juno**](http://junolab.org/): A flexible Julia IDE, based on Atom. +- [**webssh**](https://github.com/huashengdun/webssh): Web based ssh client. [And much more...](https://github.com/xtermjs/xterm.js/network/dependents)