From 3571a45574fd96610f6df5821f0fd6004c1e2929 Mon Sep 17 00:00:00 2001 From: Tony Brix Date: Mon, 3 Aug 2020 10:45:19 -0500 Subject: [PATCH 1/4] fix: don't resize terminal when hidden --- src/element.js | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/src/element.js b/src/element.js index 86e7bc3a..3fcf1899 100644 --- a/src/element.js +++ b/src/element.js @@ -72,6 +72,7 @@ class XTerminalElementImpl extends HTMLElement { this.atomXtermProfileMenuElement = new XTerminalProfileMenuElement() this.hoveredLink = null this.pendingTerminalProfileOptions = {} + this.mainDivContentRect = null this.terminalDivInitiallyVisible = false this.isInitialized = false let resolveInit, rejectInit @@ -89,7 +90,9 @@ class XTerminalElementImpl extends HTMLElement { // An element resize detector is used to check when this element is // resized due to the pane resizing or due to the entire window // resizing. - this.mainDivResizeObserver = new ResizeObserver((entries, observer) => { + this.mainDivResizeObserver = new ResizeObserver(entries => { + const lastEntry = entries.pop() + this.mainDivContentRect = lastEntry.contentRect this.refitTerminal() }) this.mainDivResizeObserver.observe(this.mainDiv) @@ -99,11 +102,9 @@ class XTerminalElementImpl extends HTMLElement { })) // Add an IntersectionObserver in order to apply new options and // refit as soon as the terminal is visible. - this.terminalDivIntersectionObserver = new IntersectionObserver((entries, observer) => { - // NOTE: Only the terminal div should be observed therefore there - // should only be one entry. - const visible = entries.some(e => e.intersectionRatio === 1.0) - if (visible) { + this.terminalDivIntersectionObserver = new IntersectionObserver(entries => { + const lastEntry = entries.pop() + if (lastEntry.intersectionRatio === 1.0) { this.terminalDivInitiallyVisible = true this.applyPendingTerminalProfileOptions() // Remove observer once visible @@ -678,7 +679,12 @@ class XTerminalElementImpl extends HTMLElement { refitTerminal () { // Only refit the terminal when it is completely visible. - if (this.terminalDivInitiallyVisible) { + if ( + this.terminalDivInitiallyVisible && + this.mainDivContentRect && + this.mainDivContentRect.width > 0 && + this.mainDivContentRect.height > 0 + ) { this.fitAddon.fit() const geometry = this.fitAddon.proposeDimensions() if (geometry && this.isPtyProcessRunning()) { From 8117fc59a7f14cfcf7cc8b44696162ef029b1b45 Mon Sep 17 00:00:00 2001 From: Tony Brix Date: Mon, 3 Aug 2020 10:56:20 -0500 Subject: [PATCH 2/4] test: test terminal resize width/height --- spec/element-spec.js | 37 +++++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/spec/element-spec.js b/spec/element-spec.js index 0c042a57..c44a7482 100644 --- a/spec/element-spec.js +++ b/spec/element-spec.js @@ -1592,13 +1592,31 @@ describe('XTerminalElement', () => { it('refitTerminal() terminal not visible', () => { spyOn(this.element.fitAddon, 'proposeDimensions') + this.element.mainDivContentRect = { width: 1, height: 1 } this.element.terminalDivInitiallyVisible = false this.element.refitTerminal() expect(this.element.fitAddon.proposeDimensions).not.toHaveBeenCalled() }) + it('refitTerminal() terminal no width', () => { + spyOn(this.element.fitAddon, 'proposeDimensions') + this.element.mainDivContentRect = { width: 0, height: 1 } + this.element.terminalDivInitiallyVisible = true + this.element.refitTerminal() + expect(this.element.fitAddon.proposeDimensions).not.toHaveBeenCalled() + }) + + it('refitTerminal() terminal no height', () => { + spyOn(this.element.fitAddon, 'proposeDimensions') + this.element.mainDivContentRect = { width: 1, height: 0 } + this.element.terminalDivInitiallyVisible = true + this.element.refitTerminal() + expect(this.element.fitAddon.proposeDimensions).not.toHaveBeenCalled() + }) + it('refitTerminal() terminal completely visible', () => { spyOn(this.element.fitAddon, 'proposeDimensions').and.returnValue(null) + this.element.mainDivContentRect = { width: 1, height: 1 } this.element.terminalDivInitiallyVisible = true this.element.refitTerminal() expect(this.element.fitAddon.proposeDimensions).toHaveBeenCalled() @@ -1610,6 +1628,7 @@ describe('XTerminalElement', () => { rows: this.element.terminal.rows, }) spyOn(this.element.terminal, 'resize') + this.element.mainDivContentRect = { width: 1, height: 1 } this.element.terminalDivInitiallyVisible = true this.element.ptyProcessRunning = false this.element.refitTerminal() @@ -1622,6 +1641,7 @@ describe('XTerminalElement', () => { rows: this.element.terminal.rows, }) spyOn(this.element.terminal, 'resize') + this.element.mainDivContentRect = { width: 1, height: 1 } this.element.terminalDivInitiallyVisible = true this.element.ptyProcessRunning = false this.element.refitTerminal() @@ -1634,6 +1654,7 @@ describe('XTerminalElement', () => { rows: this.element.terminal.rows + 1, }) spyOn(this.element.terminal, 'resize') + this.element.mainDivContentRect = { width: 1, height: 1 } this.element.terminalDivInitiallyVisible = true this.element.ptyProcessRunning = false this.element.refitTerminal() @@ -1646,6 +1667,7 @@ describe('XTerminalElement', () => { rows: this.element.terminal.rows + 1, }) spyOn(this.element.terminal, 'resize') + this.element.mainDivContentRect = { width: 1, height: 1 } this.element.terminalDivInitiallyVisible = true this.element.ptyProcessRunning = false this.element.refitTerminal() @@ -1658,6 +1680,7 @@ describe('XTerminalElement', () => { rows: this.element.terminal.rows - 1, }) spyOn(this.element.terminal, 'resize') + this.element.mainDivContentRect = { width: 1, height: 1 } this.element.terminalDivInitiallyVisible = true this.element.ptyProcessRunning = false this.element.refitTerminal() @@ -1670,6 +1693,7 @@ describe('XTerminalElement', () => { rows: this.element.terminal.rows - 1, }) spyOn(this.element.terminal, 'resize') + this.element.mainDivContentRect = { width: 1, height: 1 } this.element.terminalDivInitiallyVisible = true this.element.ptyProcessRunning = false this.element.refitTerminal() @@ -1682,6 +1706,7 @@ describe('XTerminalElement', () => { rows: this.element.ptyProcessRows, }) spyOn(this.element.terminal, 'resize') + this.element.mainDivContentRect = { width: 1, height: 1 } this.element.terminalDivInitiallyVisible = true this.element.ptyProcessRunning = true this.element.refitTerminal() @@ -1694,6 +1719,7 @@ describe('XTerminalElement', () => { rows: this.element.ptyProcessRows, }) spyOn(this.element.terminal, 'resize') + this.element.mainDivContentRect = { width: 1, height: 1 } this.element.terminalDivInitiallyVisible = true this.element.ptyProcessRunning = true this.element.refitTerminal() @@ -1706,6 +1732,7 @@ describe('XTerminalElement', () => { rows: this.element.ptyProcessRows + 1, }) spyOn(this.element.terminal, 'resize') + this.element.mainDivContentRect = { width: 1, height: 1 } this.element.terminalDivInitiallyVisible = true this.element.ptyProcessRunning = true this.element.refitTerminal() @@ -1718,6 +1745,7 @@ describe('XTerminalElement', () => { rows: this.element.ptyProcessRows + 1, }) spyOn(this.element.terminal, 'resize') + this.element.mainDivContentRect = { width: 1, height: 1 } this.element.terminalDivInitiallyVisible = true this.element.ptyProcessRunning = true this.element.refitTerminal() @@ -1730,6 +1758,7 @@ describe('XTerminalElement', () => { rows: this.element.ptyProcessRows, }) spyOn(this.element.terminal, 'resize') + this.element.mainDivContentRect = { width: 1, height: 1 } this.element.terminalDivInitiallyVisible = true this.element.ptyProcessRunning = true this.element.refitTerminal() @@ -1742,6 +1771,7 @@ describe('XTerminalElement', () => { rows: this.element.ptyProcessRows - 1, }) spyOn(this.element.terminal, 'resize') + this.element.mainDivContentRect = { width: 1, height: 1 } this.element.terminalDivInitiallyVisible = true this.element.ptyProcessRunning = true this.element.refitTerminal() @@ -1754,6 +1784,7 @@ describe('XTerminalElement', () => { rows: this.element.ptyProcessRows - 1, }) spyOn(this.element.terminal, 'resize') + this.element.mainDivContentRect = { width: 1, height: 1 } this.element.terminalDivInitiallyVisible = true this.element.ptyProcessRunning = true this.element.refitTerminal() @@ -1767,6 +1798,7 @@ describe('XTerminalElement', () => { } spyOn(this.element.fitAddon, 'proposeDimensions').and.returnValue(expected) spyOn(this.element.terminal, 'resize') + this.element.mainDivContentRect = { width: 1, height: 1 } this.element.terminalDivInitiallyVisible = true this.element.ptyProcessRunning = true this.element.refitTerminal() @@ -1780,6 +1812,7 @@ describe('XTerminalElement', () => { } spyOn(this.element.fitAddon, 'proposeDimensions').and.returnValue(expected) spyOn(this.element.terminal, 'resize') + this.element.mainDivContentRect = { width: 1, height: 1 } this.element.terminalDivInitiallyVisible = true this.element.ptyProcessRunning = true this.element.refitTerminal() @@ -1793,6 +1826,7 @@ describe('XTerminalElement', () => { } spyOn(this.element.fitAddon, 'proposeDimensions').and.returnValue(expected) spyOn(this.element.terminal, 'resize') + this.element.mainDivContentRect = { width: 1, height: 1 } this.element.terminalDivInitiallyVisible = true this.element.ptyProcessRunning = true this.element.refitTerminal() @@ -1806,6 +1840,7 @@ describe('XTerminalElement', () => { } spyOn(this.element.fitAddon, 'proposeDimensions').and.returnValue(expected) spyOn(this.element.terminal, 'resize') + this.element.mainDivContentRect = { width: 1, height: 1 } this.element.terminalDivInitiallyVisible = true this.element.ptyProcessRunning = true this.element.refitTerminal() @@ -1819,6 +1854,7 @@ describe('XTerminalElement', () => { } spyOn(this.element.fitAddon, 'proposeDimensions').and.returnValue(expected) spyOn(this.element.terminal, 'resize') + this.element.mainDivContentRect = { width: 1, height: 1 } this.element.terminalDivInitiallyVisible = true this.element.ptyProcessRunning = true this.element.refitTerminal() @@ -1832,6 +1868,7 @@ describe('XTerminalElement', () => { } spyOn(this.element.fitAddon, 'proposeDimensions').and.returnValue(expected) spyOn(this.element.terminal, 'resize') + this.element.mainDivContentRect = { width: 1, height: 1 } this.element.terminalDivInitiallyVisible = true this.element.ptyProcessRunning = true this.element.refitTerminal() From 06667c1643fad98cf9a278f4f002f169afafbcd3 Mon Sep 17 00:00:00 2001 From: Tony Brix Date: Tue, 4 Aug 2020 23:42:43 -0500 Subject: [PATCH 3/4] fix: create terminal after visible --- src/element.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/element.js b/src/element.js index 3fcf1899..bedac9ba 100644 --- a/src/element.js +++ b/src/element.js @@ -86,7 +86,6 @@ class XTerminalElementImpl extends HTMLElement { this.setAttribute('session-id', this.model.getSessionId()) await this.atomXtermProfileMenuElement.initialize(new XTerminalProfileMenuModel(this.model)) this.menuDiv.append(this.atomXtermProfileMenuElement) - await this.createTerminal() // An element resize detector is used to check when this element is // resized due to the pane resizing or due to the entire window // resizing. @@ -102,10 +101,11 @@ class XTerminalElementImpl extends HTMLElement { })) // Add an IntersectionObserver in order to apply new options and // refit as soon as the terminal is visible. - this.terminalDivIntersectionObserver = new IntersectionObserver(entries => { + this.terminalDivIntersectionObserver = new IntersectionObserver(async entries => { const lastEntry = entries.pop() if (lastEntry.intersectionRatio === 1.0) { this.terminalDivInitiallyVisible = true + await this.createTerminal() this.applyPendingTerminalProfileOptions() // Remove observer once visible this.terminalDivIntersectionObserver.disconnect() From ace59a62862cfdb9fb7f55579cfb88b2a3765fc1 Mon Sep 17 00:00:00 2001 From: Tony Brix Date: Wed, 5 Aug 2020 00:11:57 -0500 Subject: [PATCH 4/4] test: create terminal in tests --- spec/element-spec.js | 1 + 1 file changed, 1 insertion(+) diff --git a/spec/element-spec.js b/spec/element-spec.js index c44a7482..c6f07af1 100644 --- a/spec/element-spec.js +++ b/spec/element-spec.js @@ -49,6 +49,7 @@ describe('XTerminalElement', () => { ['removeItem', 'getActiveItem', 'destroyItem']) const element = new XTerminalElement() await element.initialize(model) + await element.createTerminal() return element }