From 1f4780a71ae4b5532a9597a569a819184de0c9ad Mon Sep 17 00:00:00 2001 From: Geraldo Neto Date: Sat, 2 Nov 2019 18:58:04 -0300 Subject: [PATCH 01/31] #2444: Fix wrapped lines search --- addons/xterm-addon-search/src/SearchAddon.ts | 57 +++++++++++++++----- 1 file changed, 43 insertions(+), 14 deletions(-) diff --git a/addons/xterm-addon-search/src/SearchAddon.ts b/addons/xterm-addon-search/src/SearchAddon.ts index 5893f79ff..9d553d761 100644 --- a/addons/xterm-addon-search/src/SearchAddon.ts +++ b/addons/xterm-addon-search/src/SearchAddon.ts @@ -12,6 +12,11 @@ export interface ISearchOptions { incremental?: boolean; } +export interface ISearchPosition { + startCol: number; + startRow: number; +} + export interface ISearchResult { term: string; col: number; @@ -71,17 +76,23 @@ export class SearchAddon implements ITerminalAddon { this._initLinesCache(); + const searchPosition: ISearchPosition = { + startRow, + startCol + }; + // Search startRow - let result = this._findInLine(term, startRow, startCol, searchOptions); + let result = this._findInLine(term, searchPosition, searchOptions); // Search from startRow + 1 to end if (!result) { for (let y = startRow + 1; y < this._terminal.buffer.baseY + this._terminal.rows; y++) { - + searchPosition.startRow = y; + searchPosition.startCol = 0; // If the current line is wrapped line, increase index of column to ignore the previous scan // Otherwise, reset beginning column index to zero with set new unwrapped line index - result = this._findInLine(term, y, 0, searchOptions); + result = this._findInLine(term, searchPosition, searchOptions); if (result) { break; } @@ -90,7 +101,9 @@ export class SearchAddon implements ITerminalAddon { // If we hit the bottom and didn't search from the very top wrap back up if (!result && startRow !== 0) { for (let y = 0; y < startRow; y++) { - result = this._findInLine(term, y, 0, searchOptions); + searchPosition.startRow = y; + searchPosition.startCol = 0; + result = this._findInLine(term, searchPosition, searchOptions); if (result) { break; } @@ -131,21 +144,26 @@ export class SearchAddon implements ITerminalAddon { } this._initLinesCache(); + const searchPosition: ISearchPosition = { + startRow, + startCol + }; if (incremental) { - result = this._findInLine(term, startRow, startCol, searchOptions, false); + result = this._findInLine(term, searchPosition, searchOptions, false); if (!(result && result.row === startRow && result.col === startCol)) { - result = this._findInLine(term, startRow, startCol, searchOptions, true); + result = this._findInLine(term, searchPosition, searchOptions, true); } } else { - result = this._findInLine(term, startRow, startCol, searchOptions, isReverseSearch); + result = this._findInLine(term, searchPosition, searchOptions, isReverseSearch); } // Search from startRow - 1 to top if (!result) { - startCol = this._terminal.cols; + searchPosition.startCol = Math.max(searchPosition.startCol, this._terminal.cols); for (let y = startRow - 1; y >= 0; y--) { - result = this._findInLine(term, y, startCol, searchOptions, isReverseSearch); + searchPosition.startRow = y; + result = this._findInLine(term, searchPosition, searchOptions, isReverseSearch); if (result) { break; } @@ -154,7 +172,8 @@ export class SearchAddon implements ITerminalAddon { // If we hit the top and didn't search from the very bottom wrap back down if (!result && startRow !== (this._terminal.buffer.baseY + this._terminal.rows)) { for (let y = (this._terminal.buffer.baseY + this._terminal.rows); y > startRow; y--) { - result = this._findInLine(term, y, startCol, searchOptions, isReverseSearch); + searchPosition.startRow = y; + result = this._findInLine(term, searchPosition, searchOptions, isReverseSearch); if (result) { break; } @@ -213,18 +232,28 @@ export class SearchAddon implements ITerminalAddon { * 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 The search term. - * @param row The line to start the search from. - * @param col The column to start the search from. + * @param {ISearchPosition} position The position to start the search. * @param searchOptions Search options. * @return The search result if it was found. */ - protected _findInLine(term: string, row: number, col: number, searchOptions: ISearchOptions = {}, isReverseSearch: boolean = false): ISearchResult | undefined { + protected _findInLine(term: string, searchPosition: ISearchPosition, searchOptions: ISearchOptions = {}, isReverseSearch: boolean = false): ISearchResult | undefined { const terminal = this._terminal!; + let row = searchPosition.startRow; + const col = searchPosition.startCol; // Ignore wrapped lines, only consider on unwrapped line (first row of command string). const firstLine = terminal.buffer.getLine(row); if (firstLine && firstLine.isWrapped) { - return; + if (isReverseSearch) { + searchPosition.startCol += terminal.cols; + } + else { + // This will iterate until we find the line start. + // When we find it, we will search using the calculated start column. + searchPosition.startRow--; + searchPosition.startCol += terminal.cols; + return this._findInLine(term, searchPosition, searchOptions); + } } let stringLine = this._linesCache ? this._linesCache[row] : void 0; if (stringLine === void 0) { From 9d50d106e38e900d54155e1f1f24cc3bbd50ec4f Mon Sep 17 00:00:00 2001 From: Geraldo Neto Date: Sat, 2 Nov 2019 19:21:58 -0300 Subject: [PATCH 02/31] 2444: Return after calculating startCol in reverse search --- addons/xterm-addon-search/src/SearchAddon.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/addons/xterm-addon-search/src/SearchAddon.ts b/addons/xterm-addon-search/src/SearchAddon.ts index 9d553d761..3db1d6e11 100644 --- a/addons/xterm-addon-search/src/SearchAddon.ts +++ b/addons/xterm-addon-search/src/SearchAddon.ts @@ -246,6 +246,7 @@ export class SearchAddon implements ITerminalAddon { if (firstLine && firstLine.isWrapped) { if (isReverseSearch) { searchPosition.startCol += terminal.cols; + return; } else { // This will iterate until we find the line start. From 9358718b5ff767a427503c66eeaa4dff423747a9 Mon Sep 17 00:00:00 2001 From: Geraldo Neto Date: Sat, 2 Nov 2019 19:33:21 -0300 Subject: [PATCH 03/31] 2444: Fix no-else-return lint --- addons/xterm-addon-search/src/SearchAddon.ts | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/addons/xterm-addon-search/src/SearchAddon.ts b/addons/xterm-addon-search/src/SearchAddon.ts index b869209f4..67f1ad6e5 100644 --- a/addons/xterm-addon-search/src/SearchAddon.ts +++ b/addons/xterm-addon-search/src/SearchAddon.ts @@ -255,13 +255,12 @@ export class SearchAddon implements ITerminalAddon { searchPosition.startCol += terminal.cols; return; } - else { - // This will iterate until we find the line start. - // When we find it, we will search using the calculated start column. - searchPosition.startRow--; - searchPosition.startCol += terminal.cols; - return this._findInLine(term, searchPosition, searchOptions); - } + + // This will iterate until we find the line start. + // When we find it, we will search using the calculated start column. + searchPosition.startRow--; + searchPosition.startCol += terminal.cols; + return this._findInLine(term, searchPosition, searchOptions); } let stringLine = this._linesCache ? this._linesCache[row] : void 0; if (stringLine === void 0) { From 3dca46619c8ad4d6ca1879e24208e349ef26db62 Mon Sep 17 00:00:00 2001 From: Daniel Imms Date: Tue, 5 Nov 2019 11:30:11 -0800 Subject: [PATCH 04/31] Skip puppeteer download on unit test runs Fixes #2539 --- azure-pipelines.yml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 177f581f4..2326e9814 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -7,6 +7,8 @@ jobs: - job: Linux pool: vmImage: 'ubuntu-16.04' + variables: + PUPPETEER_SKIP_CHROMIUM_DOWNLOAD: 1 steps: - task: NodeTool@0 inputs: @@ -42,6 +44,8 @@ jobs: - job: macOS pool: vmImage: 'xcode9-macos10.13' + variables: + PUPPETEER_SKIP_CHROMIUM_DOWNLOAD: 1 steps: - task: NodeTool@0 inputs: @@ -57,6 +61,8 @@ jobs: - job: Windows pool: vmImage: 'vs2017-win2016' + variables: + PUPPETEER_SKIP_CHROMIUM_DOWNLOAD: 1 steps: - task: NodeTool@0 inputs: From 70500e31ac4da4468af267c2e3a0113ba4151d00 Mon Sep 17 00:00:00 2001 From: Daniel Imms Date: Tue, 5 Nov 2019 11:36:54 -0800 Subject: [PATCH 05/31] Add yarn cache caching --- azure-pipelines.yml | 42 ++++++++++++++++++++++++++++++++++++------ 1 file changed, 36 insertions(+), 6 deletions(-) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 2326e9814..247395b3b 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -18,7 +18,12 @@ jobs: inputs: versionSpec: '1.x' displayName: 'Install Yarn' - - script: yarn + - task: CacheBeta@1 + inputs: + key: yarn | $(Agent.OS) | yarn.lock + path: $(YARN_CACHE_FOLDER) + displayName: Cache Yarn packages + - script: yarn --frozen-lockfile displayName: 'Install dependencies and build' - script: yarn test-unit --forbid-only displayName: 'Unit tests' @@ -51,7 +56,12 @@ jobs: inputs: versionSpec: '8.x' displayName: 'Install Node.js' - - script: yarn + - task: CacheBeta@1 + inputs: + key: yarn | $(Agent.OS) | yarn.lock + path: $(YARN_CACHE_FOLDER) + displayName: Cache Yarn packages + - script: yarn --frozen-lockfile displayName: 'Install dependencies and build' - script: yarn test-unit --forbid-only displayName: 'Unit tests' @@ -68,7 +78,12 @@ jobs: inputs: versionSpec: '8.x' displayName: 'Install Node.js' - - script: yarn + - task: CacheBeta@1 + inputs: + key: yarn | $(Agent.OS) | yarn.lock + path: $(YARN_CACHE_FOLDER) + displayName: Cache Yarn packages + - script: yarn --frozen-lockfile displayName: 'Install dependencies and build' - script: yarn test-unit --forbid-only displayName: 'Unit tests' @@ -87,7 +102,12 @@ jobs: inputs: versionSpec: '1.x' displayName: 'Install Yarn' - - script: yarn + - task: CacheBeta@1 + inputs: + key: yarn | $(Agent.OS) | yarn.lock + path: $(YARN_CACHE_FOLDER) + displayName: Cache Yarn packages + - script: yarn --frozen-lockfile displayName: 'Install dependencies and build' - script: | yarn start & @@ -103,7 +123,12 @@ jobs: inputs: versionSpec: '8.x' displayName: 'Install Node.js' - - script: yarn + - task: CacheBeta@1 + inputs: + key: yarn | $(Agent.OS) | yarn.lock + path: $(YARN_CACHE_FOLDER) + displayName: Cache Yarn packages + - script: yarn --frozen-lockfile displayName: 'Install dependencies and build' - script: | yarn start & @@ -130,7 +155,12 @@ jobs: inputs: versionSpec: '1.x' displayName: 'Install Yarn' - - script: yarn + - task: CacheBeta@1 + inputs: + key: yarn | $(Agent.OS) | yarn.lock + path: $(YARN_CACHE_FOLDER) + displayName: Cache Yarn packages + - script: yarn --frozen-lockfile displayName: 'Install dependencies and build' - script: NPM_AUTH_TOKEN="$(NPM_AUTH_TOKEN)" node ./bin/publish.js displayName: 'Package and publish to npm' From 86264d47635a8c360e7fecad10fa3fcfb2af58ee Mon Sep 17 00:00:00 2001 From: Daniel Imms Date: Tue, 5 Nov 2019 11:42:35 -0800 Subject: [PATCH 06/31] Specify yarn cache folder --- azure-pipelines.yml | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 247395b3b..0998781fa 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -9,6 +9,7 @@ jobs: vmImage: 'ubuntu-16.04' variables: PUPPETEER_SKIP_CHROMIUM_DOWNLOAD: 1 + YARN_CACHE_FOLDER: .yarn-cache steps: - task: NodeTool@0 inputs: @@ -51,6 +52,7 @@ jobs: vmImage: 'xcode9-macos10.13' variables: PUPPETEER_SKIP_CHROMIUM_DOWNLOAD: 1 + YARN_CACHE_FOLDER: .yarn-cache steps: - task: NodeTool@0 inputs: @@ -73,6 +75,7 @@ jobs: vmImage: 'vs2017-win2016' variables: PUPPETEER_SKIP_CHROMIUM_DOWNLOAD: 1 + YARN_CACHE_FOLDER: .yarn-cache steps: - task: NodeTool@0 inputs: @@ -93,6 +96,8 @@ jobs: - job: Linux_IntegrationTests pool: vmImage: 'ubuntu-16.04' + variables: + YARN_CACHE_FOLDER: .yarn-cache steps: - task: NodeTool@0 inputs: @@ -118,6 +123,8 @@ jobs: - job: macOS_IntegrationTests pool: vmImage: 'xcode9-macos10.13' + variables: + YARN_CACHE_FOLDER: .yarn-cache steps: - task: NodeTool@0 inputs: From 5411f60f44c71a4ecf9b3a9e125bf3afa66f700e Mon Sep 17 00:00:00 2001 From: Daniel Imms Date: Tue, 5 Nov 2019 11:54:32 -0800 Subject: [PATCH 07/31] Try cache node_modules --- azure-pipelines.yml | 17 ++++++----------- 1 file changed, 6 insertions(+), 11 deletions(-) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 0998781fa..9ccc83939 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -9,7 +9,6 @@ jobs: vmImage: 'ubuntu-16.04' variables: PUPPETEER_SKIP_CHROMIUM_DOWNLOAD: 1 - YARN_CACHE_FOLDER: .yarn-cache steps: - task: NodeTool@0 inputs: @@ -22,7 +21,7 @@ jobs: - task: CacheBeta@1 inputs: key: yarn | $(Agent.OS) | yarn.lock - path: $(YARN_CACHE_FOLDER) + path: node_modules displayName: Cache Yarn packages - script: yarn --frozen-lockfile displayName: 'Install dependencies and build' @@ -52,7 +51,6 @@ jobs: vmImage: 'xcode9-macos10.13' variables: PUPPETEER_SKIP_CHROMIUM_DOWNLOAD: 1 - YARN_CACHE_FOLDER: .yarn-cache steps: - task: NodeTool@0 inputs: @@ -61,7 +59,7 @@ jobs: - task: CacheBeta@1 inputs: key: yarn | $(Agent.OS) | yarn.lock - path: $(YARN_CACHE_FOLDER) + path: node_modules displayName: Cache Yarn packages - script: yarn --frozen-lockfile displayName: 'Install dependencies and build' @@ -75,7 +73,6 @@ jobs: vmImage: 'vs2017-win2016' variables: PUPPETEER_SKIP_CHROMIUM_DOWNLOAD: 1 - YARN_CACHE_FOLDER: .yarn-cache steps: - task: NodeTool@0 inputs: @@ -84,7 +81,7 @@ jobs: - task: CacheBeta@1 inputs: key: yarn | $(Agent.OS) | yarn.lock - path: $(YARN_CACHE_FOLDER) + path: node_modules displayName: Cache Yarn packages - script: yarn --frozen-lockfile displayName: 'Install dependencies and build' @@ -97,7 +94,6 @@ jobs: pool: vmImage: 'ubuntu-16.04' variables: - YARN_CACHE_FOLDER: .yarn-cache steps: - task: NodeTool@0 inputs: @@ -110,7 +106,7 @@ jobs: - task: CacheBeta@1 inputs: key: yarn | $(Agent.OS) | yarn.lock - path: $(YARN_CACHE_FOLDER) + path: node_modules displayName: Cache Yarn packages - script: yarn --frozen-lockfile displayName: 'Install dependencies and build' @@ -124,7 +120,6 @@ jobs: pool: vmImage: 'xcode9-macos10.13' variables: - YARN_CACHE_FOLDER: .yarn-cache steps: - task: NodeTool@0 inputs: @@ -133,7 +128,7 @@ jobs: - task: CacheBeta@1 inputs: key: yarn | $(Agent.OS) | yarn.lock - path: $(YARN_CACHE_FOLDER) + path: node_modules displayName: Cache Yarn packages - script: yarn --frozen-lockfile displayName: 'Install dependencies and build' @@ -165,7 +160,7 @@ jobs: - task: CacheBeta@1 inputs: key: yarn | $(Agent.OS) | yarn.lock - path: $(YARN_CACHE_FOLDER) + path: node_modules displayName: Cache Yarn packages - script: yarn --frozen-lockfile displayName: 'Install dependencies and build' From 2960d5df53fd7626e121fdf1fe951bb93d75bf2d Mon Sep 17 00:00:00 2001 From: Daniel Imms Date: Tue, 5 Nov 2019 11:55:06 -0800 Subject: [PATCH 08/31] New cache key --- azure-pipelines.yml | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 9ccc83939..4eb350793 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -20,7 +20,7 @@ jobs: displayName: 'Install Yarn' - task: CacheBeta@1 inputs: - key: yarn | $(Agent.OS) | yarn.lock + key: yarn1 | $(Agent.OS) | yarn.lock path: node_modules displayName: Cache Yarn packages - script: yarn --frozen-lockfile @@ -58,7 +58,7 @@ jobs: displayName: 'Install Node.js' - task: CacheBeta@1 inputs: - key: yarn | $(Agent.OS) | yarn.lock + key: yarn1 | $(Agent.OS) | yarn.lock path: node_modules displayName: Cache Yarn packages - script: yarn --frozen-lockfile @@ -80,7 +80,7 @@ jobs: displayName: 'Install Node.js' - task: CacheBeta@1 inputs: - key: yarn | $(Agent.OS) | yarn.lock + key: yarn1 | $(Agent.OS) | yarn.lock path: node_modules displayName: Cache Yarn packages - script: yarn --frozen-lockfile @@ -105,7 +105,7 @@ jobs: displayName: 'Install Yarn' - task: CacheBeta@1 inputs: - key: yarn | $(Agent.OS) | yarn.lock + key: yarn1 | $(Agent.OS) | yarn.lock path: node_modules displayName: Cache Yarn packages - script: yarn --frozen-lockfile @@ -127,7 +127,7 @@ jobs: displayName: 'Install Node.js' - task: CacheBeta@1 inputs: - key: yarn | $(Agent.OS) | yarn.lock + key: yarn1 | $(Agent.OS) | yarn.lock path: node_modules displayName: Cache Yarn packages - script: yarn --frozen-lockfile @@ -159,7 +159,7 @@ jobs: displayName: 'Install Yarn' - task: CacheBeta@1 inputs: - key: yarn | $(Agent.OS) | yarn.lock + key: yarn1 | $(Agent.OS) | yarn.lock path: node_modules displayName: Cache Yarn packages - script: yarn --frozen-lockfile From d2164584d53dfc59362f0e5702b45a6f56554488 Mon Sep 17 00:00:00 2001 From: Daniel Imms Date: Tue, 5 Nov 2019 11:56:44 -0800 Subject: [PATCH 09/31] Fix error in yml --- azure-pipelines.yml | 2 -- 1 file changed, 2 deletions(-) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 4eb350793..9117b8859 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -93,7 +93,6 @@ jobs: - job: Linux_IntegrationTests pool: vmImage: 'ubuntu-16.04' - variables: steps: - task: NodeTool@0 inputs: @@ -119,7 +118,6 @@ jobs: - job: macOS_IntegrationTests pool: vmImage: 'xcode9-macos10.13' - variables: steps: - task: NodeTool@0 inputs: From c974b273d40c6e2f595539bcc2fa07152ce51fa3 Mon Sep 17 00:00:00 2001 From: Daniel Imms Date: Tue, 5 Nov 2019 12:41:03 -0800 Subject: [PATCH 10/31] Install puppeteer explicitly --- azure-pipelines.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 9117b8859..ff13e6165 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -109,6 +109,8 @@ jobs: displayName: Cache Yarn packages - script: yarn --frozen-lockfile displayName: 'Install dependencies and build' + - script: yarn add puppeteer + displayName: 'Install puppeteer' - script: | yarn start & sleep 10 @@ -130,6 +132,8 @@ jobs: displayName: Cache Yarn packages - script: yarn --frozen-lockfile displayName: 'Install dependencies and build' + - script: yarn add puppeteer + displayName: 'Install puppeteer' - script: | yarn start & sleep 10 From 0630baaf0295d4100c5d40e87463070c3fe316d3 Mon Sep 17 00:00:00 2001 From: Daniel Imms Date: Tue, 5 Nov 2019 12:50:37 -0800 Subject: [PATCH 11/31] Don't cache on integration tests --- azure-pipelines.yml | 18 ++++-------------- 1 file changed, 4 insertions(+), 14 deletions(-) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index ff13e6165..aaa2b6ea7 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -20,7 +20,7 @@ jobs: displayName: 'Install Yarn' - task: CacheBeta@1 inputs: - key: yarn1 | $(Agent.OS) | yarn.lock + key: yarn2 | $(Agent.OS) | yarn.lock path: node_modules displayName: Cache Yarn packages - script: yarn --frozen-lockfile @@ -58,7 +58,7 @@ jobs: displayName: 'Install Node.js' - task: CacheBeta@1 inputs: - key: yarn1 | $(Agent.OS) | yarn.lock + key: yarn2 | $(Agent.OS) | yarn.lock path: node_modules displayName: Cache Yarn packages - script: yarn --frozen-lockfile @@ -80,7 +80,7 @@ jobs: displayName: 'Install Node.js' - task: CacheBeta@1 inputs: - key: yarn1 | $(Agent.OS) | yarn.lock + key: yarn2 | $(Agent.OS) | yarn.lock path: node_modules displayName: Cache Yarn packages - script: yarn --frozen-lockfile @@ -102,11 +102,6 @@ jobs: inputs: versionSpec: '1.x' displayName: 'Install Yarn' - - task: CacheBeta@1 - inputs: - key: yarn1 | $(Agent.OS) | yarn.lock - path: node_modules - displayName: Cache Yarn packages - script: yarn --frozen-lockfile displayName: 'Install dependencies and build' - script: yarn add puppeteer @@ -125,11 +120,6 @@ jobs: inputs: versionSpec: '8.x' displayName: 'Install Node.js' - - task: CacheBeta@1 - inputs: - key: yarn1 | $(Agent.OS) | yarn.lock - path: node_modules - displayName: Cache Yarn packages - script: yarn --frozen-lockfile displayName: 'Install dependencies and build' - script: yarn add puppeteer @@ -161,7 +151,7 @@ jobs: displayName: 'Install Yarn' - task: CacheBeta@1 inputs: - key: yarn1 | $(Agent.OS) | yarn.lock + key: yarn2 | $(Agent.OS) | yarn.lock path: node_modules displayName: Cache Yarn packages - script: yarn --frozen-lockfile From fc0568074ffb7577680c6646725ce2053a145ada Mon Sep 17 00:00:00 2001 From: Daniel Imms Date: Wed, 6 Nov 2019 10:37:00 -0800 Subject: [PATCH 12/31] Cache node modules with puppeteer --- azure-pipelines.yml | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index aaa2b6ea7..b4a6d9409 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -98,6 +98,11 @@ jobs: inputs: versionSpec: '8.x' displayName: 'Install Node.js' + - task: CacheBeta@1 + inputs: + key: yarn_puppeteer | $(Agent.OS) | yarn.lock + path: node_modules + displayName: Cache Yarn packages - task: YarnInstaller@3 inputs: versionSpec: '1.x' @@ -120,6 +125,11 @@ jobs: inputs: versionSpec: '8.x' displayName: 'Install Node.js' + - task: CacheBeta@1 + inputs: + key: yarn_puppeteer | $(Agent.OS) | yarn.lock + path: node_modules + displayName: Cache Yarn packages - script: yarn --frozen-lockfile displayName: 'Install dependencies and build' - script: yarn add puppeteer From d4dbdac73f6bd20764ee2e1626c0f9a4265502c6 Mon Sep 17 00:00:00 2001 From: Daniel Imms Date: Wed, 6 Nov 2019 10:53:42 -0800 Subject: [PATCH 13/31] Don't cache integration test modules --- azure-pipelines.yml | 18 ++++-------------- 1 file changed, 4 insertions(+), 14 deletions(-) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index b4a6d9409..7ddb534f0 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -22,7 +22,7 @@ jobs: inputs: key: yarn2 | $(Agent.OS) | yarn.lock path: node_modules - displayName: Cache Yarn packages + displayName: Cache node modules - script: yarn --frozen-lockfile displayName: 'Install dependencies and build' - script: yarn test-unit --forbid-only @@ -60,7 +60,7 @@ jobs: inputs: key: yarn2 | $(Agent.OS) | yarn.lock path: node_modules - displayName: Cache Yarn packages + displayName: Cache node modules - script: yarn --frozen-lockfile displayName: 'Install dependencies and build' - script: yarn test-unit --forbid-only @@ -82,7 +82,7 @@ jobs: inputs: key: yarn2 | $(Agent.OS) | yarn.lock path: node_modules - displayName: Cache Yarn packages + displayName: Cache node modules - script: yarn --frozen-lockfile displayName: 'Install dependencies and build' - script: yarn test-unit --forbid-only @@ -102,7 +102,7 @@ jobs: inputs: key: yarn_puppeteer | $(Agent.OS) | yarn.lock path: node_modules - displayName: Cache Yarn packages + displayName: Cache node modules - task: YarnInstaller@3 inputs: versionSpec: '1.x' @@ -125,11 +125,6 @@ jobs: inputs: versionSpec: '8.x' displayName: 'Install Node.js' - - task: CacheBeta@1 - inputs: - key: yarn_puppeteer | $(Agent.OS) | yarn.lock - path: node_modules - displayName: Cache Yarn packages - script: yarn --frozen-lockfile displayName: 'Install dependencies and build' - script: yarn add puppeteer @@ -159,11 +154,6 @@ jobs: inputs: versionSpec: '1.x' displayName: 'Install Yarn' - - task: CacheBeta@1 - inputs: - key: yarn2 | $(Agent.OS) | yarn.lock - path: node_modules - displayName: Cache Yarn packages - script: yarn --frozen-lockfile displayName: 'Install dependencies and build' - script: NPM_AUTH_TOKEN="$(NPM_AUTH_TOKEN)" node ./bin/publish.js From d079775690a5e93f4d06971c7cc151912a7e569b Mon Sep 17 00:00:00 2001 From: Daniel Imms Date: Wed, 6 Nov 2019 11:04:37 -0800 Subject: [PATCH 14/31] Merge coverage check into regular unit test check Fixes #2542 --- azure-pipelines.yml | 17 +++-------------- bin/test.js | 21 ++++++++++++++++++++- package.json | 1 + 3 files changed, 24 insertions(+), 15 deletions(-) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 7ddb534f0..415f1fb2b 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -25,26 +25,15 @@ jobs: displayName: Cache node modules - script: yarn --frozen-lockfile displayName: 'Install dependencies and build' - - script: yarn test-unit --forbid-only + - script: yarn test-coverage --forbid-only displayName: 'Unit tests' - script: yarn lint displayName: 'Lint' - - script: | - NODE_PATH=$(pwd)/out ./node_modules/.bin/nyc ./node_modules/.bin/mocha './out/*test.js' './out/**/*test.js' - ./node_modules/.bin/nyc report --reporter=cobertura - displayName: 'Coverage report' - task: PublishCodeCoverageResults@1 inputs: codeCoverageTool: Cobertura summaryFileLocation: '$(System.DefaultWorkingDirectory)/**/*coverage.xml' displayName: 'Publish coverage' - - task: mspremier.BuildQualityChecks.QualityChecks-task.BuildQualityChecks@6 - displayName: 'Check build quality' - inputs: - checkCoverage: true - coverageType: lines - coverageThreshold: 60 - coverageFailOption: fixed - job: macOS pool: @@ -63,7 +52,7 @@ jobs: displayName: Cache node modules - script: yarn --frozen-lockfile displayName: 'Install dependencies and build' - - script: yarn test-unit --forbid-only + - script: yarn test-coverage --forbid-only displayName: 'Unit tests' - script: yarn lint displayName: 'Lint' @@ -85,7 +74,7 @@ jobs: displayName: Cache node modules - script: yarn --frozen-lockfile displayName: 'Install dependencies and build' - - script: yarn test-unit --forbid-only + - script: yarn test-coverage --forbid-only displayName: 'Unit tests' - script: yarn lint displayName: 'Lint' diff --git a/bin/test.js b/bin/test.js index 3b08d4a15..2b15e9078 100644 --- a/bin/test.js +++ b/bin/test.js @@ -28,6 +28,26 @@ if (process.argv.length > 2) { } } +const checkCoverage = flagArgs.indexOf('--coverage') >= 0; + +if (checkCoverage) { + flagArgs.splice(flagArgs.indexOf('--coverage'), 1); + const executable = path.resolve(__dirname, '../node_modules/.bin/nyc'); + const args = ['--check-coverage', '--lines=100', path.resolve(__dirname, '../node_modules/.bin/mocha'), ...testFiles, ...flagArgs]; + console.info('executable', executable); + console.info('args', args); + const run = cp.spawnSync( + executable, + args, + { + cwd: path.resolve(__dirname, '..'), + env, + stdio: 'inherit' + } + ); + process.exit(run.status); +} + const run = cp.spawnSync( path.resolve(__dirname, '../node_modules/.bin/mocha'), [...testFiles, ...flagArgs], @@ -37,5 +57,4 @@ const run = cp.spawnSync( stdio: 'inherit' } ); - process.exit(run.status); diff --git a/package.json b/package.json index 0150569d3..c33c48bdb 100644 --- a/package.json +++ b/package.json @@ -16,6 +16,7 @@ "posttest": "npm run lint", "test-api": "mocha \"**/*.api.js\"", "test-unit": "node ./bin/test.js", + "test-coverage": "node ./bin/test.js --coverage", "build": "tsc -b ./tsconfig.all.json", "prepare": "npm run setup", "setup": "npm run build", From 030a8bda80359623fd4a80cce7ee2c8d5dd2508f Mon Sep 17 00:00:00 2001 From: Daniel Imms Date: Wed, 6 Nov 2019 11:08:39 -0800 Subject: [PATCH 15/31] Set coverage lines threshold to 60% --- bin/test.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/bin/test.js b/bin/test.js index 2b15e9078..94b4ac7b4 100644 --- a/bin/test.js +++ b/bin/test.js @@ -6,6 +6,8 @@ const cp = require('child_process'); const path = require('path'); +const COVERAGE_LINES_THRESHOLD = 60; + // Add `out` to the NODE_PATH so absolute paths can be resolved. const env = { ...process.env }; env.NODE_PATH = path.resolve(__dirname, '../out'); @@ -33,7 +35,7 @@ const checkCoverage = flagArgs.indexOf('--coverage') >= 0; if (checkCoverage) { flagArgs.splice(flagArgs.indexOf('--coverage'), 1); const executable = path.resolve(__dirname, '../node_modules/.bin/nyc'); - const args = ['--check-coverage', '--lines=100', path.resolve(__dirname, '../node_modules/.bin/mocha'), ...testFiles, ...flagArgs]; + const args = ['--check-coverage', `--lines=${COVERAGE_LINES_THRESHOLD}`, path.resolve(__dirname, '../node_modules/.bin/mocha'), ...testFiles, ...flagArgs]; console.info('executable', executable); console.info('args', args); const run = cp.spawnSync( From 48b20e32005d98a905c463c1acf9acc0bd9fd6b7 Mon Sep 17 00:00:00 2001 From: Daniel Imms Date: Wed, 6 Nov 2019 11:08:47 -0800 Subject: [PATCH 16/31] Don't run through nyc on mac and Windows --- azure-pipelines.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 415f1fb2b..a4f6ede8b 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -52,7 +52,7 @@ jobs: displayName: Cache node modules - script: yarn --frozen-lockfile displayName: 'Install dependencies and build' - - script: yarn test-coverage --forbid-only + - script: yarn test-unit --forbid-only displayName: 'Unit tests' - script: yarn lint displayName: 'Lint' @@ -74,7 +74,7 @@ jobs: displayName: Cache node modules - script: yarn --frozen-lockfile displayName: 'Install dependencies and build' - - script: yarn test-coverage --forbid-only + - script: yarn test-unit --forbid-only displayName: 'Unit tests' - script: yarn lint displayName: 'Lint' From fe2f1ea4df1b0b426057944af9d5d352bbd96fc7 Mon Sep 17 00:00:00 2001 From: Daniel Imms Date: Wed, 6 Nov 2019 11:20:52 -0800 Subject: [PATCH 17/31] Get Windows unit tests running again Fixes #2543 --- bin/test.js | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/bin/test.js b/bin/test.js index 94b4ac7b4..bd1784fbb 100644 --- a/bin/test.js +++ b/bin/test.js @@ -34,8 +34,8 @@ const checkCoverage = flagArgs.indexOf('--coverage') >= 0; if (checkCoverage) { flagArgs.splice(flagArgs.indexOf('--coverage'), 1); - const executable = path.resolve(__dirname, '../node_modules/.bin/nyc'); - const args = ['--check-coverage', `--lines=${COVERAGE_LINES_THRESHOLD}`, path.resolve(__dirname, '../node_modules/.bin/mocha'), ...testFiles, ...flagArgs]; + const executable = npmBinScript('nyc'); + const args = ['--check-coverage', `--lines=${COVERAGE_LINES_THRESHOLD}`, npmBinScript('mocha'), ...testFiles, ...flagArgs]; console.info('executable', executable); console.info('args', args); const run = cp.spawnSync( @@ -51,7 +51,7 @@ if (checkCoverage) { } const run = cp.spawnSync( - path.resolve(__dirname, '../node_modules/.bin/mocha'), + npmBinScript('mocha'), [...testFiles, ...flagArgs], { cwd: path.resolve(__dirname, '..'), @@ -59,4 +59,9 @@ const run = cp.spawnSync( stdio: 'inherit' } ); + +function npmBinScript(script) { + return path.resolve(__dirname, `../node_modules/.bin/` + (process.platform === 'win32' ? `${script}.cmd` : script)); +} + process.exit(run.status); From 31afe5b30545da59a965ff69ba756c54bbe02308 Mon Sep 17 00:00:00 2001 From: Daniel Imms Date: Wed, 6 Nov 2019 11:23:42 -0800 Subject: [PATCH 18/31] test-coverage -> test-unit-coverage --- azure-pipelines.yml | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index a4f6ede8b..1ee66ddb7 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -25,7 +25,7 @@ jobs: displayName: Cache node modules - script: yarn --frozen-lockfile displayName: 'Install dependencies and build' - - script: yarn test-coverage --forbid-only + - script: yarn test-unit-coverage --forbid-only displayName: 'Unit tests' - script: yarn lint displayName: 'Lint' diff --git a/package.json b/package.json index c33c48bdb..7ed717419 100644 --- a/package.json +++ b/package.json @@ -16,7 +16,7 @@ "posttest": "npm run lint", "test-api": "mocha \"**/*.api.js\"", "test-unit": "node ./bin/test.js", - "test-coverage": "node ./bin/test.js --coverage", + "test-unit-coverage": "node ./bin/test.js --coverage", "build": "tsc -b ./tsconfig.all.json", "prepare": "npm run setup", "setup": "npm run build", From 08782949648f064620a1cc646d7199cd70842c36 Mon Sep 17 00:00:00 2001 From: Daniel Imms Date: Wed, 6 Nov 2019 11:24:34 -0800 Subject: [PATCH 19/31] Skip Terminal2 tests on Windows --- src/Terminal2.test.ts | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/Terminal2.test.ts b/src/Terminal2.test.ts index efb2a4462..f7046240b 100644 --- a/src/Terminal2.test.ts +++ b/src/Terminal2.test.ts @@ -34,7 +34,6 @@ if (os.platform() === 'darwin') { // filter skipFilenames const FILES = TESTFILES.filter(value => SKIP_FILES.indexOf(value.split('/').slice(-1)[0]) === -1); - describe('Escape Sequence Files', function(): void { this.timeout(1000); @@ -44,6 +43,9 @@ describe('Escape Sequence Files', function(): void { let customHandler: IDisposable | undefined; before(() => { + if (process.platform === 'win32') { + return; + } ptyTerm = (pty as any).open({cols: COLS, rows: ROWS}); slaveEnd = ptyTerm._slave; term = new Terminal({cols: COLS, rows: ROWS}); @@ -51,12 +53,15 @@ describe('Escape Sequence Files', function(): void { }); after(() => { + if (process.platform === 'win32') { + return; + } ptyTerm._master.end(); ptyTerm._master.destroy(); }); FILES.forEach(filename => { - it(filename.split('/').slice(-1)[0], async () => { + (process.platform === 'win32' ? it.skip : it)(filename.split('/').slice(-1)[0], async () => { // reset terminal and handler if (customHandler) { customHandler.dispose(); From 94ce037eb8d750839ea8ddaa87e712ab042a2f58 Mon Sep 17 00:00:00 2001 From: Daniel Imms Date: Thu, 7 Nov 2019 13:00:43 -0800 Subject: [PATCH 20/31] Add integration tests for regression in #2444 --- addons/xterm-addon-search/fixtures/issue-2444 | 70 ++++++++++++++++ .../xterm-addon-search/src/SearchAddon.api.ts | 84 ++++++++++++++++++- 2 files changed, 153 insertions(+), 1 deletion(-) create mode 100644 addons/xterm-addon-search/fixtures/issue-2444 diff --git a/addons/xterm-addon-search/fixtures/issue-2444 b/addons/xterm-addon-search/fixtures/issue-2444 new file mode 100644 index 000000000..cb7f78783 --- /dev/null +++ b/addons/xterm-addon-search/fixtures/issue-2444 @@ -0,0 +1,70 @@ +/usr/bin/cmake -E cmake_progress_report /home/yan/ssd/searchtrunk/tmp/release/CMakeFiles +make[3]: Entering directory `/home/yan/ssd/searchtrunk/tmp/release' +make[3]: Nothing to be done for `libsrc/wrap_curl/CMakeFiles/wrap_curl.dir/build'. +make[3]: Leaving directory `/home/yan/ssd/searchtrunk/tmp/release' +[ 0%] /usr/bin/cmake -E cmake_progress_report /home/yan/ssd/searchtrunk/tmp/release/CMakeFiles +[ 0%] [ 0%] /usr/bin/cmake -E cmake_progress_report /home/yan/ssd/searchtrunk/tmp/release/CMakeFiles +Built target config_utils +[ 0%] make[3]: Entering directory `/home/yan/ssd/searchtrunk/tmp/release' +/usr/bin/cmake -E cmake_progress_report /home/yan/ssd/searchtrunk/tmp/release/CMakeFiles +Built target omega +make[3]: Entering directory `/home/yan/ssd/searchtrunk/tmp/release' +cd /home/yan/ssd/searchtrunk/tmp/release && /usr/bin/cmake -E cmake_depends "Unix Makefiles" /home/yan/ssd/searchtrunk /home/yan/ssd/searchtrunk/projects/protogen/cpp /home/yan/ssd/searchtrunk/tmp/release /home/yan/ssd/searchtrunk/tmp/release/projects/protogen/cpp /home/yan/ssd/searchtrunk/tmp/release/projects/protogen/cpp/CMakeFiles/protogen.dir/DependInfo.cmake --color= +/usr/bin/cmake -E cmake_progress_report /home/yan/ssd/searchtrunk/tmp/release/CMakeFiles +Built target morpheus +make[3]: Leaving directory `/home/yan/ssd/searchtrunk/tmp/release' +make -f libsrc/base/CMakeFiles/base.dir/build.make libsrc/base/CMakeFiles/base.dir/build +make[3]: Entering directory `/home/yan/ssd/searchtrunk/tmp/release' +make[3]: Nothing to be done for `libsrc/coroutine/CMakeFiles/coroutine.dir/build'. +Built target wrap_curl +make[3]: Leaving directory `/home/yan/ssd/searchtrunk/tmp/release' +/usr/bin/cmake -E cmake_progress_report /home/yan/ssd/searchtrunk/tmp/release/CMakeFiles +/usr/bin/cmake -E cmake_progress_report /home/yan/ssd/searchtrunk/tmp/release/CMakeFiles +[ 0%] [ 0%] [ 0%] [ 0%] Building CXX object libsrc/image_crop/CMakeFiles/image_crop.dir/src/crop_context.cpp.o +cd /home/yan/ssd/searchtrunk/tmp/release/libsrc/image_crop && /opt/rh/devtoolset-7/root/usr/bin/c++ -DGOGO_USE_LIBEVENT2=1 -DGOGO_USE_OPENSSL_SNI=1 -DHAVE_BOOST -DHAVE_GLIBC -DHAVE_MALLOC_TRIM -DHAVE_PREAD -DHAVE_READAHEAD -D_FILE_OFFSET_BITS=64 -D_STAT_LEMM -pipe -Wall -Wextra -Werror=multichar -Wno-deprecated -Wno-unused-parameter -pthread -fPIC -Woverloaded-virtual -Wnon-virtual-dtor -Werror -std=gnu++11 -Wno-unknown-pragmas -DBOOST_FILESYSTEM_VERSION=3 -DBOOST_NO_CXX11_HDR_CODECVT -DMAGICKCORE_QUANTUM_DEPTH=8 -DMAGICKCORE_HDRI_ENABLE=0 -Wno-unused-local-typedefs -D_GLIBCXX_USE_CXX11_ABI=0 -std=gnu++14 -DCXXHASH128_EXIST -static-libstdc++ -Wno-implicit-fallthrough -Wno-stringop-overflow -O3 -DNDEBUG -DBOOST_UBLAS_NDEBUG -g0 -march=core2 -mssse3 -msse4.1 -I/home/yan/ssd/searchtrunk/tmp/release/__inc -I/home/yan/ssd/searchtrunk/libsrc/image_crop/src -I/home/yan/ssd/searchtrunk/include -isystem /home/yan/ssd/searchtrunk/tmp/release/contrib/boost_1_69_0/include -isystem /home/yan/ssd/searchtrunk/tmp/release/contrib/icu-49.1.2/include -isystem /home/yan/ssd/searchtrunk/tmp/release/contrib/protobuf-3.4.0/include -I/home/yan/ssd/searchtrunk/tmp/release -isystem /home/yan/ssd/searchtrunk/tmp/release/contrib/opencv-3.0.0m2/include -isystem /home/yan/ssd/searchtrunk/tmp/release/contrib/dlib-19.7p1/include -Wno-array-bounds -o CMakeFiles/image_crop.dir/src/crop_context.cpp.o -c /home/yan/ssd/searchtrunk/libsrc/image_crop/src/crop_context.cpp +Building CXX object libsrc/image_crop/CMakeFiles/image_crop.dir/src/detector.cpp.o +Building CXX object libsrc/image_crop/CMakeFiles/image_crop.dir/src/image_crop.cpp.o +cd /home/yan/ssd/searchtrunk/tmp/release/libsrc/image_crop && /opt/rh/devtoolset-7/root/usr/bin/c++ -DGOGO_USE_LIBEVENT2=1 -DGOGO_USE_OPENSSL_SNI=1 -DHAVE_BOOST -DHAVE_GLIBC -DHAVE_MALLOC_TRIM -DHAVE_PREAD -DHAVE_READAHEAD -D_FILE_OFFSET_BITS=64 -D_STAT_LEMM -pipe -Wall -Wextra -Werror=multichar -Wno-deprecated -Wno-unused-parameter -pthread -fPIC -Woverloaded-virtual -Wnon-virtual-dtor -Werror -std=gnu++11 -Wno-unknown-pragmas -DBOOST_FILESYSTEM_VERSION=3 -DBOOST_NO_CXX11_HDR_CODECVT -DMAGICKCORE_QUANTUM_DEPTH=8 -DMAGICKCORE_HDRI_ENABLE=0 -Wno-unused-local-typedefs -D_GLIBCXX_USE_CXX11_ABI=0 -std=gnu++14 -DCXXHASH128_EXIST -static-libstdc++ -Wno-implicit-fallthrough -Wno-stringop-overflow -O3 -DNDEBUG -DBOOST_UBLAS_NDEBUG -g0 -march=core2 -mssse3 -msse4.1 -I/home/yan/ssd/searchtrunk/tmp/release/__inc -I/home/yan/ssd/searchtrunk/libsrc/image_crop/src -I/home/yan/ssd/searchtrunk/include -isystem /home/yan/ssd/searchtrunk/tmp/release/contrib/boost_1_69_0/include -isystem /home/yan/ssd/searchtrunk/tmp/release/contrib/icu-49.1.2/include -isystem /home/yan/ssd/searchtrunk/tmp/release/contrib/protobuf-3.4.0/include -I/home/yan/ssd/searchtrunk/tmp/release -isystem /home/yan/ssd/searchtrunk/tmp/release/contrib/opencv-3.0.0m2/include -isystem /home/yan/ssd/searchtrunk/tmp/release/contrib/dlib-19.7p1/include -Wno-array-bounds -o CMakeFiles/image_crop.dir/src/detector.cpp.o -c /home/yan/ssd/searchtrunk/libsrc/image_crop/src/detector.cpp +Built target coroutine +cd /home/yan/ssd/searchtrunk/tmp/release/libsrc/image_crop && /opt/rh/devtoolset-7/root/usr/bin/c++ -DGOGO_USE_LIBEVENT2=1 -DGOGO_USE_OPENSSL_SNI=1 -DHAVE_BOOST -DHAVE_GLIBC -DHAVE_MALLOC_TRIM -DHAVE_PREAD -DHAVE_READAHEAD -D_FILE_OFFSET_BITS=64 -D_STAT_LEMM -pipe -Wall -Wextra -Werror=multichar -Wno-deprecated -Wno-unused-parameter -pthread -fPIC -Woverloaded-virtual -Wnon-virtual-dtor -Werror -std=gnu++11 -Wno-unknown-pragmas -DBOOST_FILESYSTEM_VERSION=3 -DBOOST_NO_CXX11_HDR_CODECVT -DMAGICKCORE_QUANTUM_DEPTH=8 -DMAGICKCORE_HDRI_ENABLE=0 -Wno-unused-local-typedefs -D_GLIBCXX_USE_CXX11_ABI=0 -std=gnu++14 -DCXXHASH128_EXIST -static-libstdc++ -Wno-implicit-fallthrough -Wno-stringop-overflow -O3 -DNDEBUG -DBOOST_UBLAS_NDEBUG -g0 -march=core2 -mssse3 -msse4.1 -I/home/yan/ssd/searchtrunk/tmp/release/__inc -I/home/yan/ssd/searchtrunk/libsrc/image_crop/src -I/home/yan/ssd/searchtrunk/include -isystem /home/yan/ssd/searchtrunk/tmp/release/contrib/boost_1_69_0/include -isystem /home/yan/ssd/searchtrunk/tmp/release/contrib/icu-49.1.2/include -isystem /home/yan/ssd/searchtrunk/tmp/release/contrib/protobuf-3.4.0/include -I/home/yan/ssd/searchtrunk/tmp/release -isystem /home/yan/ssd/searchtrunk/tmp/release/contrib/opencv-3.0.0m2/include -isystem /home/yan/ssd/searchtrunk/tmp/release/contrib/dlib-19.7p1/include -Wno-array-bounds -o CMakeFiles/image_crop.dir/src/image_crop.cpp.o -c /home/yan/ssd/searchtrunk/libsrc/image_crop/src/image_crop.cpp +make[3]: Entering directory `/home/yan/ssd/searchtrunk/tmp/release' +make[3]: Nothing to be done for `libsrc/base/CMakeFiles/base.dir/build'. +make[3]: Leaving directory `/home/yan/ssd/searchtrunk/tmp/release' +/usr/bin/cmake -E cmake_progress_report /home/yan/ssd/searchtrunk/tmp/release/CMakeFiles +make[3]: Leaving directory `/home/yan/ssd/searchtrunk/tmp/release' +make -f projects/protogen/cpp/CMakeFiles/protogen.dir/build.make projects/protogen/cpp/CMakeFiles/protogen.dir/build +[ 0%] Built target base +In file included from /home/yan/ssd/searchtrunk/include/image_crop/detector.hpp:3:0, + from /home/yan/ssd/searchtrunk/libsrc/image_crop/src/detector.cpp:2: +/home/yan/ssd/searchtrunk/include/image_crop/crop_context.hpp:6:10: fatal error: opencv2/dnn.hpp: No such file or directory + #include + ^~~~~~~~~~~~~~~~~ +compilation terminated. +make[3]: *** [libsrc/image_crop/CMakeFiles/image_crop.dir/src/detector.cpp.o] Error 1 +make[3]: *** Waiting for unfinished jobs.... +In file included from /home/yan/ssd/searchtrunk/include/image_crop/image_crop.hpp:3:0, + from /home/yan/ssd/searchtrunk/libsrc/image_crop/src/image_crop.cpp:1: +/home/yan/ssd/searchtrunk/include/image_crop/crop_context.hpp:6:10: fatal error: opencv2/dnn.hpp: No such file or directory + #include + ^~~~~~~~~~~~~~~~~ +compilation terminated. +make[3]: *** [libsrc/image_crop/CMakeFiles/image_crop.dir/src/image_crop.cpp.o] Error 1 +In file included from /home/yan/ssd/searchtrunk/libsrc/image_crop/src/crop_context.cpp:1:0: +/home/yan/ssd/searchtrunk/include/image_crop/crop_context.hpp:6:10: fatal error: opencv2/dnn.hpp: No such file or directory + #include + ^~~~~~~~~~~~~~~~~ +compilation terminated. +make[3]: *** [libsrc/image_crop/CMakeFiles/image_crop.dir/src/crop_context.cpp.o] Error 1 +make[3]: Leaving directory `/home/yan/ssd/searchtrunk/tmp/release' +make[2]: *** [libsrc/image_crop/CMakeFiles/image_crop.dir/all] Error 2 +make[2]: *** Waiting for unfinished jobs.... +make[3]: Entering directory `/home/yan/ssd/searchtrunk/tmp/release' +make[3]: Nothing to be done for `projects/protogen/cpp/CMakeFiles/protogen.dir/build'. +make[3]: Leaving directory `/home/yan/ssd/searchtrunk/tmp/release' +/usr/bin/cmake -E cmake_progress_report /home/yan/ssd/searchtrunk/tmp/release/CMakeFiles 63 64 65 66 +[ 25%] Built target protogen +make[2]: Leaving directory `/home/yan/ssd/searchtrunk/tmp/release' +make[1]: *** [all] Error 2 +make[1]: Leaving directory `/home/yan/ssd/searchtrunk/tmp/release/projects/projectX' +make: *** [install] Error 2 +yan@yPC:~/ssd/searchtrunk/projects/projectX$ diff --git a/addons/xterm-addon-search/src/SearchAddon.api.ts b/addons/xterm-addon-search/src/SearchAddon.api.ts index e3520116c..ff195f5e9 100644 --- a/addons/xterm-addon-search/src/SearchAddon.api.ts +++ b/addons/xterm-addon-search/src/SearchAddon.api.ts @@ -6,6 +6,8 @@ import * as puppeteer from 'puppeteer'; import { assert } from 'chai'; import { ITerminalOptions } from 'xterm'; +import { readFile } from 'fs'; +import { resolve } from 'path'; const APP = 'http://127.0.0.1:3000/test'; @@ -91,7 +93,7 @@ describe('Search Tests', function (): void { selectionPosition = await page.evaluate(`window.term.getSelectionPosition()`); assert.deepEqual(line.substring(selectionPosition.startColumn, selectionPosition.endColumn), 'package.jsonc'); }); - it ('Simple Regex', async () => { + it('Simple Regex', async () => { await writeSync('abc123defABCD'); await page.evaluate(`window.search.findNext('[a-z]+', {regex: true})`); assert.deepEqual(await page.evaluate(`window.term.getSelection()`), 'abc'); @@ -106,6 +108,86 @@ describe('Search Tests', function (): void { assert.deepEqual(await page.evaluate(`window.search.findNext('abc')`), true); assert.deepEqual(await page.evaluate(`window.term.getSelection()`), 'abc'); }); + + describe('Regression tests', () => { + describe('#2444 wrapped line content not being found', () => { + let fixture: string; + before(async () => { + const rawFixture = await new Promise(r => readFile(resolve(__dirname, '../fixtures/issue-2444'), (err, data) => r(data))); + fixture = rawFixture.toString() + .replace(/\n/g, '\\n\\r') + .replace(/'/g, '\\\''); + }); + it('should find all occurrences using findNext', async () => { + await writeSync(fixture); + assert.deepEqual(await page.evaluate(`window.search.findNext('opencv')`), true); + let selectionPosition = await page.evaluate(`window.term.getSelectionPosition()`); + assert.deepEqual(selectionPosition, { startColumn: 24, startRow: 53, endColumn: 30, endRow: 53 }); + assert.deepEqual(await page.evaluate(`window.search.findNext('opencv')`), true); + selectionPosition = await page.evaluate(`window.term.getSelectionPosition()`); + assert.deepEqual(selectionPosition, { startColumn: 24, startRow: 76, endColumn: 30, endRow: 76 }); + assert.deepEqual(await page.evaluate(`window.search.findNext('opencv')`), true); + selectionPosition = await page.evaluate(`window.term.getSelectionPosition()`); + assert.deepEqual(selectionPosition, { startColumn: 24, startRow: 96, endColumn: 30, endRow: 96 }); + assert.deepEqual(await page.evaluate(`window.search.findNext('opencv')`), true); + selectionPosition = await page.evaluate(`window.term.getSelectionPosition()`); + assert.deepEqual(selectionPosition, { startColumn: 1, startRow: 114, endColumn: 7, endRow: 114 }); + assert.deepEqual(await page.evaluate(`window.search.findNext('opencv')`), true); + selectionPosition = await page.evaluate(`window.term.getSelectionPosition()`); + assert.deepEqual(selectionPosition, { startColumn: 11, startRow: 115, endColumn: 17, endRow: 115 }); + assert.deepEqual(await page.evaluate(`window.search.findNext('opencv')`), true); + selectionPosition = await page.evaluate(`window.term.getSelectionPosition()`); + assert.deepEqual(selectionPosition, { startColumn: 1, startRow: 126, endColumn: 7, endRow: 126 }); + assert.deepEqual(await page.evaluate(`window.search.findNext('opencv')`), true); + selectionPosition = await page.evaluate(`window.term.getSelectionPosition()`); + assert.deepEqual(selectionPosition, { startColumn: 11, startRow: 127, endColumn: 17, endRow: 127 }); + assert.deepEqual(await page.evaluate(`window.search.findNext('opencv')`), true); + selectionPosition = await page.evaluate(`window.term.getSelectionPosition()`); + assert.deepEqual(selectionPosition, { startColumn: 1, startRow: 135, endColumn: 7, endRow: 135 }); + assert.deepEqual(await page.evaluate(`window.search.findNext('opencv')`), true); + selectionPosition = await page.evaluate(`window.term.getSelectionPosition()`); + assert.deepEqual(selectionPosition, { startColumn: 11, startRow: 136, endColumn: 17, endRow: 136 }); + // Wrap around to first result + assert.deepEqual(await page.evaluate(`window.search.findNext('opencv')`), true); + selectionPosition = await page.evaluate(`window.term.getSelectionPosition()`); + assert.deepEqual(selectionPosition, { startColumn: 24, startRow: 53, endColumn: 30, endRow: 53 }); + }); + it('should find all occurrences using findPrevious', async () => { + await writeSync(fixture); + assert.deepEqual(await page.evaluate(`window.search.findPrevious('opencv')`), true); + let selectionPosition = await page.evaluate(`window.term.getSelectionPosition()`); + assert.deepEqual(selectionPosition, { startColumn: 11, startRow: 136, endColumn: 17, endRow: 136 }); + assert.deepEqual(await page.evaluate(`window.search.findPrevious('opencv')`), true); + selectionPosition = await page.evaluate(`window.term.getSelectionPosition()`); + assert.deepEqual(selectionPosition, { startColumn: 1, startRow: 135, endColumn: 7, endRow: 135 }); + assert.deepEqual(await page.evaluate(`window.search.findPrevious('opencv')`), true); + selectionPosition = await page.evaluate(`window.term.getSelectionPosition()`); + assert.deepEqual(selectionPosition, { startColumn: 11, startRow: 127, endColumn: 17, endRow: 127 }); + assert.deepEqual(await page.evaluate(`window.search.findPrevious('opencv')`), true); + selectionPosition = await page.evaluate(`window.term.getSelectionPosition()`); + assert.deepEqual(selectionPosition, { startColumn: 1, startRow: 126, endColumn: 7, endRow: 126 }); + assert.deepEqual(await page.evaluate(`window.search.findPrevious('opencv')`), true); + selectionPosition = await page.evaluate(`window.term.getSelectionPosition()`); + assert.deepEqual(selectionPosition, { startColumn: 11, startRow: 115, endColumn: 17, endRow: 115 }); + assert.deepEqual(await page.evaluate(`window.search.findPrevious('opencv')`), true); + selectionPosition = await page.evaluate(`window.term.getSelectionPosition()`); + assert.deepEqual(selectionPosition, { startColumn: 1, startRow: 114, endColumn: 7, endRow: 114 }); + assert.deepEqual(await page.evaluate(`window.search.findPrevious('opencv')`), true); + selectionPosition = await page.evaluate(`window.term.getSelectionPosition()`); + assert.deepEqual(selectionPosition, { startColumn: 24, startRow: 96, endColumn: 30, endRow: 96 }); + assert.deepEqual(await page.evaluate(`window.search.findPrevious('opencv')`), true); + selectionPosition = await page.evaluate(`window.term.getSelectionPosition()`); + assert.deepEqual(selectionPosition, { startColumn: 24, startRow: 76, endColumn: 30, endRow: 76 }); + assert.deepEqual(await page.evaluate(`window.search.findPrevious('opencv')`), true); + selectionPosition = await page.evaluate(`window.term.getSelectionPosition()`); + assert.deepEqual(selectionPosition, { startColumn: 24, startRow: 53, endColumn: 30, endRow: 53 }); + // Wrap around to first result + assert.deepEqual(await page.evaluate(`window.search.findPrevious('opencv')`), true); + selectionPosition = await page.evaluate(`window.term.getSelectionPosition()`); + assert.deepEqual(selectionPosition, { startColumn: 11, startRow: 136, endColumn: 17, endRow: 136 }); + }); + }); + }); }); async function openTerminal(options: ITerminalOptions = {}): Promise { From fce7a67c8e73b9a7eba8767e5c1205f7dbf5bf5b Mon Sep 17 00:00:00 2001 From: Daniel Imms Date: Thu, 7 Nov 2019 13:39:42 -0800 Subject: [PATCH 21/31] Remove type jsdoc --- addons/xterm-addon-search/src/SearchAddon.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/addons/xterm-addon-search/src/SearchAddon.ts b/addons/xterm-addon-search/src/SearchAddon.ts index 67f1ad6e5..db2968e69 100644 --- a/addons/xterm-addon-search/src/SearchAddon.ts +++ b/addons/xterm-addon-search/src/SearchAddon.ts @@ -239,7 +239,7 @@ export class SearchAddon implements ITerminalAddon { * 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 The search term. - * @param {ISearchPosition} position The position to start the search. + * @param position The position to start the search. * @param searchOptions Search options. * @return The search result if it was found. */ From 1d63be0506e70cd9ab36c4ea8f9f6478a09a8422 Mon Sep 17 00:00:00 2001 From: Daniel Imms Date: Thu, 7 Nov 2019 13:51:51 -0800 Subject: [PATCH 22/31] Reduce duplicate in pipeline, cache in release job --- azure-pipelines.yml | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 1ee66ddb7..4daa09618 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -87,19 +87,12 @@ jobs: inputs: versionSpec: '8.x' displayName: 'Install Node.js' - - task: CacheBeta@1 - inputs: - key: yarn_puppeteer | $(Agent.OS) | yarn.lock - path: node_modules - displayName: Cache node modules - task: YarnInstaller@3 inputs: versionSpec: '1.x' displayName: 'Install Yarn' - script: yarn --frozen-lockfile displayName: 'Install dependencies and build' - - script: yarn add puppeteer - displayName: 'Install puppeteer' - script: | yarn start & sleep 10 @@ -116,8 +109,6 @@ jobs: displayName: 'Install Node.js' - script: yarn --frozen-lockfile displayName: 'Install dependencies and build' - - script: yarn add puppeteer - displayName: 'Install puppeteer' - script: | yarn start & sleep 10 @@ -143,6 +134,10 @@ jobs: inputs: versionSpec: '1.x' displayName: 'Install Yarn' + - task: CacheBeta@1 + inputs: + key: yarn2 | $(Agent.OS) | yarn.lock + path: node_modules - script: yarn --frozen-lockfile displayName: 'Install dependencies and build' - script: NPM_AUTH_TOKEN="$(NPM_AUTH_TOKEN)" node ./bin/publish.js From 7c39217392e498442fdf64e3cac1ec6489e13136 Mon Sep 17 00:00:00 2001 From: Daniel Imms Date: Thu, 7 Nov 2019 17:35:22 -0800 Subject: [PATCH 23/31] Break DomRenderer dependency on ITerminal Part of #1507 --- src/Terminal.ts | 2 +- src/renderer/dom/DomRenderer.ts | 102 ++++++++++++++++---------------- 2 files changed, 53 insertions(+), 51 deletions(-) diff --git a/src/Terminal.ts b/src/Terminal.ts index 537ecb74c..5e2fa04ef 100644 --- a/src/Terminal.ts +++ b/src/Terminal.ts @@ -638,7 +638,7 @@ export class Terminal extends Disposable implements ITerminal, IDisposable, IInp private _createRenderer(): IRenderer { switch (this.options.rendererType) { case 'canvas': return new Renderer(this._colorManager.colors, this, this._bufferService, this._charSizeService, this.optionsService); - case 'dom': return new DomRenderer(this, this._colorManager.colors, this._charSizeService, this.optionsService); + case 'dom': return new DomRenderer(this._colorManager.colors, this.element, this.screenElement, this._viewportElement, this.linkifier, this._charSizeService, this.optionsService, this._bufferService, this._renderService); default: throw new Error(`Unrecognized rendererType "${this.options.rendererType}"`); } } diff --git a/src/renderer/dom/DomRenderer.ts b/src/renderer/dom/DomRenderer.ts index ef927f208..1beaadcdc 100644 --- a/src/renderer/dom/DomRenderer.ts +++ b/src/renderer/dom/DomRenderer.ts @@ -4,13 +4,12 @@ */ import { IRenderer, IRenderDimensions, CharacterJoinerHandler } from 'browser/renderer/Types'; -import { ITerminal } from '../../Types'; import { BOLD_CLASS, ITALIC_CLASS, CURSOR_CLASS, CURSOR_STYLE_BLOCK_CLASS, CURSOR_BLINK_CLASS, CURSOR_STYLE_BAR_CLASS, CURSOR_STYLE_UNDERLINE_CLASS, DomRendererRowFactory } from 'browser/renderer/dom/DomRendererRowFactory'; import { INVERTED_DEFAULT_COLOR } from 'browser/renderer/atlas/Constants'; import { Disposable } from 'common/Lifecycle'; -import { IColorSet, ILinkifierEvent } from 'browser/Types'; -import { ICharSizeService } from 'browser/services/Services'; -import { IOptionsService } from 'common/services/Services'; +import { IColorSet, ILinkifierEvent, ILinkifier } from 'browser/Types'; +import { ICharSizeService, IRenderService } from 'browser/services/Services'; +import { IOptionsService, IBufferService } from 'common/services/Services'; const TERMINAL_CLASS_PREFIX = 'xterm-dom-renderer-owner-'; const ROW_CONTAINER_CLASS = 'xterm-rows'; @@ -39,10 +38,15 @@ export class DomRenderer extends Disposable implements IRenderer { public dimensions: IRenderDimensions; constructor( - private _terminal: ITerminal, private _colors: IColorSet, - private _charSizeService: ICharSizeService, - private _optionsService: IOptionsService + private readonly _element: HTMLElement, + private readonly _screenElement: HTMLElement, + private readonly _viewportElement: HTMLElement, + private readonly _linkifier: ILinkifier, + private readonly _charSizeService: ICharSizeService, + private readonly _optionsService: IOptionsService, + private readonly _bufferService: IBufferService, + private readonly _renderService: IRenderService ) { super(); @@ -50,7 +54,7 @@ export class DomRenderer extends Disposable implements IRenderer { this._rowContainer.classList.add(ROW_CONTAINER_CLASS); this._rowContainer.style.lineHeight = 'normal'; this._rowContainer.setAttribute('aria-hidden', 'true'); - this._refreshRowElements(this._terminal.cols, this._terminal.rows); + this._refreshRowElements(this._bufferService.cols, this._bufferService.rows); this._selectionContainer = document.createElement('div'); this._selectionContainer.classList.add(SELECTION_CLASS); this._selectionContainer.setAttribute('aria-hidden', 'true'); @@ -74,36 +78,36 @@ export class DomRenderer extends Disposable implements IRenderer { this._rowFactory = new DomRendererRowFactory(document, this._optionsService); - this._terminal.element.classList.add(TERMINAL_CLASS_PREFIX + this._terminalClass); - this._terminal.screenElement.appendChild(this._rowContainer); - this._terminal.screenElement.appendChild(this._selectionContainer); + this._element.classList.add(TERMINAL_CLASS_PREFIX + this._terminalClass); + this._screenElement.appendChild(this._rowContainer); + this._screenElement.appendChild(this._selectionContainer); - this._terminal.linkifier.onLinkHover(e => this._onLinkHover(e)); - this._terminal.linkifier.onLinkLeave(e => this._onLinkLeave(e)); + this._linkifier.onLinkHover(e => this._onLinkHover(e)); + this._linkifier.onLinkLeave(e => this._onLinkLeave(e)); } public dispose(): void { - this._terminal.element.classList.remove(TERMINAL_CLASS_PREFIX + this._terminalClass); - this._terminal.screenElement.removeChild(this._rowContainer); - this._terminal.screenElement.removeChild(this._selectionContainer); - this._terminal.screenElement.removeChild(this._themeStyleElement); - this._terminal.screenElement.removeChild(this._dimensionsStyleElement); + this._element.classList.remove(TERMINAL_CLASS_PREFIX + this._terminalClass); + this._screenElement.removeChild(this._rowContainer); + this._screenElement.removeChild(this._selectionContainer); + this._screenElement.removeChild(this._themeStyleElement); + this._screenElement.removeChild(this._dimensionsStyleElement); super.dispose(); } private _updateDimensions(): void { this.dimensions.scaledCharWidth = this._charSizeService.width * window.devicePixelRatio; this.dimensions.scaledCharHeight = Math.ceil(this._charSizeService.height * window.devicePixelRatio); - this.dimensions.scaledCellWidth = this.dimensions.scaledCharWidth + Math.round(this._terminal.options.letterSpacing); - this.dimensions.scaledCellHeight = Math.floor(this.dimensions.scaledCharHeight * this._terminal.options.lineHeight); + this.dimensions.scaledCellWidth = this.dimensions.scaledCharWidth + Math.round(this._optionsService.options.letterSpacing); + this.dimensions.scaledCellHeight = Math.floor(this.dimensions.scaledCharHeight * this._optionsService.options.lineHeight); this.dimensions.scaledCharLeft = 0; this.dimensions.scaledCharTop = 0; - this.dimensions.scaledCanvasWidth = this.dimensions.scaledCellWidth * this._terminal.cols; - this.dimensions.scaledCanvasHeight = this.dimensions.scaledCellHeight * this._terminal.rows; + this.dimensions.scaledCanvasWidth = this.dimensions.scaledCellWidth * this._bufferService.cols; + this.dimensions.scaledCanvasHeight = this.dimensions.scaledCellHeight * this._bufferService.rows; this.dimensions.canvasWidth = Math.round(this.dimensions.scaledCanvasWidth / window.devicePixelRatio); this.dimensions.canvasHeight = Math.round(this.dimensions.scaledCanvasHeight / window.devicePixelRatio); - this.dimensions.actualCellWidth = this.dimensions.canvasWidth / this._terminal.cols; - this.dimensions.actualCellHeight = this.dimensions.canvasHeight / this._terminal.rows; + this.dimensions.actualCellWidth = this.dimensions.canvasWidth / this._bufferService.cols; + this.dimensions.actualCellHeight = this.dimensions.canvasHeight / this._bufferService.rows; this._rowElements.forEach(element => { element.style.width = `${this.dimensions.canvasWidth}px`; @@ -115,7 +119,7 @@ export class DomRenderer extends Disposable implements IRenderer { if (!this._dimensionsStyleElement) { this._dimensionsStyleElement = document.createElement('style'); - this._terminal.screenElement.appendChild(this._dimensionsStyleElement); + this._screenElement.appendChild(this._dimensionsStyleElement); } const styles = @@ -128,9 +132,9 @@ export class DomRenderer extends Disposable implements IRenderer { this._dimensionsStyleElement.innerHTML = styles; - this._selectionContainer.style.height = (this._terminal)._viewportElement.style.height; - this._terminal.screenElement.style.width = `${this.dimensions.canvasWidth}px`; - this._terminal.screenElement.style.height = `${this.dimensions.canvasHeight}px`; + this._selectionContainer.style.height = this._viewportElement.style.height; + this._screenElement.style.width = `${this.dimensions.canvasWidth}px`; + this._screenElement.style.height = `${this.dimensions.canvasHeight}px`; } public setColors(colors: IColorSet): void { @@ -141,7 +145,7 @@ export class DomRenderer extends Disposable implements IRenderer { private _injectCss(): void { if (!this._themeStyleElement) { this._themeStyleElement = document.createElement('style'); - this._terminal.screenElement.appendChild(this._themeStyleElement); + this._screenElement.appendChild(this._themeStyleElement); } // Base CSS @@ -149,16 +153,16 @@ export class DomRenderer extends Disposable implements IRenderer { `${this._terminalSelector} .${ROW_CONTAINER_CLASS} {` + ` color: ${this._colors.foreground.css};` + ` background-color: ${this._colors.background.css};` + - ` font-family: ${this._terminal.options.fontFamily};` + - ` font-size: ${this._terminal.options.fontSize}px;` + + ` font-family: ${this._optionsService.options.fontFamily};` + + ` font-size: ${this._optionsService.options.fontSize}px;` + `}`; // Text styles styles += `${this._terminalSelector} span:not(.${BOLD_CLASS}) {` + - ` font-weight: ${this._terminal.options.fontWeight};` + + ` font-weight: ${this._optionsService.options.fontWeight};` + `}` + `${this._terminalSelector} span.${BOLD_CLASS} {` + - ` font-weight: ${this._terminal.options.fontWeightBold};` + + ` font-weight: ${this._optionsService.options.fontWeightBold};` + `}` + `${this._terminalSelector} span.${ITALIC_CLASS} {` + ` font-style: italic;` + @@ -275,13 +279,13 @@ export class DomRenderer extends Disposable implements IRenderer { } // Translate from buffer position to viewport position - const viewportStartRow = start[1] - this._terminal.buffer.ydisp; - const viewportEndRow = end[1] - this._terminal.buffer.ydisp; + const viewportStartRow = start[1] - this._bufferService.buffer.ydisp; + const viewportEndRow = end[1] - this._bufferService.buffer.ydisp; const viewportCappedStartRow = Math.max(viewportStartRow, 0); - const viewportCappedEndRow = Math.min(viewportEndRow, this._terminal.rows - 1); + const viewportCappedEndRow = Math.min(viewportEndRow, this._bufferService.rows - 1); // No need to draw the selection - if (viewportCappedStartRow >= this._terminal.rows || viewportCappedEndRow < 0) { + if (viewportCappedStartRow >= this._bufferService.rows || viewportCappedEndRow < 0) { return; } @@ -295,15 +299,15 @@ export class DomRenderer extends Disposable implements IRenderer { } else { // Draw first row const startCol = viewportStartRow === viewportCappedStartRow ? start[0] : 0; - const endCol = viewportCappedStartRow === viewportCappedEndRow ? end[0] : this._terminal.cols; + const endCol = viewportCappedStartRow === viewportCappedEndRow ? end[0] : this._bufferService.cols; documentFragment.appendChild(this._createSelectionElement(viewportCappedStartRow, startCol, endCol)); // Draw middle rows const middleRowsCount = viewportCappedEndRow - viewportCappedStartRow - 1; - documentFragment.appendChild(this._createSelectionElement(viewportCappedStartRow + 1, 0, this._terminal.cols, middleRowsCount)); + documentFragment.appendChild(this._createSelectionElement(viewportCappedStartRow + 1, 0, this._bufferService.cols, middleRowsCount)); // Draw final row if (viewportCappedStartRow !== viewportCappedEndRow) { // Only draw viewportEndRow if it's not the same as viewporttartRow - const endCol = viewportEndRow === viewportCappedEndRow ? end[0] : this._terminal.cols; + const endCol = viewportEndRow === viewportCappedEndRow ? end[0] : this._bufferService.cols; documentFragment.appendChild(this._createSelectionElement(viewportCappedEndRow, 0, endCol)); } } @@ -333,7 +337,7 @@ export class DomRenderer extends Disposable implements IRenderer { // Force a refresh this._updateDimensions(); this._injectCss(); - this._terminal.refresh(0, this._terminal.rows - 1); + this._renderService.refreshRows(0, this._bufferService.rows - 1); } public clear(): void { @@ -341,20 +345,18 @@ export class DomRenderer extends Disposable implements IRenderer { } public renderRows(start: number, end: number): void { - const terminal = this._terminal; - - const cursorAbsoluteY = terminal.buffer.ybase + terminal.buffer.y; - const cursorX = this._terminal.buffer.x; - const cursorBlink = this._terminal.options.cursorBlink; + const cursorAbsoluteY = this._bufferService.buffer.ybase + this._bufferService.buffer.y; + const cursorX = this._bufferService.buffer.x; + const cursorBlink = this._optionsService.options.cursorBlink; for (let y = start; y <= end; y++) { const rowElement = this._rowElements[y]; rowElement.innerHTML = ''; - const row = y + terminal.buffer.ydisp; - const lineData = terminal.buffer.lines.get(row); - const cursorStyle = terminal.options.cursorStyle; - rowElement.appendChild(this._rowFactory.createRow(lineData, row === cursorAbsoluteY, cursorStyle, cursorX, cursorBlink, this.dimensions.actualCellWidth, terminal.cols)); + const row = y + this._bufferService.buffer.ydisp; + const lineData = this._bufferService.buffer.lines.get(row); + const cursorStyle = this._optionsService.options.cursorStyle; + rowElement.appendChild(this._rowFactory.createRow(lineData, row === cursorAbsoluteY, cursorStyle, cursorX, cursorBlink, this.dimensions.actualCellWidth, this._bufferService.cols)); } } From 82e18d7aaa4cb9219bcce0acd1de6298635bbf88 Mon Sep 17 00:00:00 2001 From: Daniel Imms Date: Thu, 7 Nov 2019 17:41:29 -0800 Subject: [PATCH 24/31] Move DomRenderer to browser, fix strict errors --- src/Terminal.ts | 4 +- src/{ => browser}/renderer/dom/DomRenderer.ts | 40 +++++++++---------- 2 files changed, 22 insertions(+), 22 deletions(-) rename src/{ => browser}/renderer/dom/DomRenderer.ts (94%) diff --git a/src/Terminal.ts b/src/Terminal.ts index 5e2fa04ef..6626b966f 100644 --- a/src/Terminal.ts +++ b/src/Terminal.ts @@ -38,7 +38,7 @@ import { SoundService } from 'browser/services/SoundService'; import { MouseZoneManager } from 'browser/MouseZoneManager'; import { AccessibilityManager } from './AccessibilityManager'; import { ITheme, IMarker, IDisposable, ISelectionPosition } from 'xterm'; -import { DomRenderer } from './renderer/dom/DomRenderer'; +import { DomRenderer } from 'browser/renderer/dom/DomRenderer'; import { IKeyboardEvent, KeyboardResultType, ICharset, IBufferLine, IAttributeData, CoreMouseEventType, CoreMouseButton, CoreMouseAction } from 'common/Types'; import { evaluateKeyboardEvent } from 'common/input/Keyboard'; import { EventEmitter, IEvent } from 'common/EventEmitter'; @@ -638,7 +638,7 @@ export class Terminal extends Disposable implements ITerminal, IDisposable, IInp private _createRenderer(): IRenderer { switch (this.options.rendererType) { case 'canvas': return new Renderer(this._colorManager.colors, this, this._bufferService, this._charSizeService, this.optionsService); - case 'dom': return new DomRenderer(this._colorManager.colors, this.element, this.screenElement, this._viewportElement, this.linkifier, this._charSizeService, this.optionsService, this._bufferService, this._renderService); + case 'dom': return this._instantiationService.createInstance(DomRenderer, this._colorManager.colors, this.element, this.screenElement, this._viewportElement, this.linkifier); default: throw new Error(`Unrecognized rendererType "${this.options.rendererType}"`); } } diff --git a/src/renderer/dom/DomRenderer.ts b/src/browser/renderer/dom/DomRenderer.ts similarity index 94% rename from src/renderer/dom/DomRenderer.ts rename to src/browser/renderer/dom/DomRenderer.ts index 1beaadcdc..b512aa70f 100644 --- a/src/renderer/dom/DomRenderer.ts +++ b/src/browser/renderer/dom/DomRenderer.ts @@ -29,8 +29,8 @@ export class DomRenderer extends Disposable implements IRenderer { private _rowFactory: DomRendererRowFactory; private _terminalClass: number = nextTerminalId++; - private _themeStyleElement: HTMLStyleElement; - private _dimensionsStyleElement: HTMLStyleElement; + private _themeStyleElement!: HTMLStyleElement; + private _dimensionsStyleElement!: HTMLStyleElement; private _rowContainer: HTMLElement; private _rowElements: HTMLElement[] = []; private _selectionContainer: HTMLElement; @@ -43,10 +43,10 @@ export class DomRenderer extends Disposable implements IRenderer { private readonly _screenElement: HTMLElement, private readonly _viewportElement: HTMLElement, private readonly _linkifier: ILinkifier, - private readonly _charSizeService: ICharSizeService, - private readonly _optionsService: IOptionsService, - private readonly _bufferService: IBufferService, - private readonly _renderService: IRenderService + @ICharSizeService private readonly _charSizeService: ICharSizeService, + @IOptionsService private readonly _optionsService: IOptionsService, + @IBufferService private readonly _bufferService: IBufferService, + @IRenderService private readonly _renderService: IRenderService ) { super(); @@ -60,18 +60,18 @@ export class DomRenderer extends Disposable implements IRenderer { this._selectionContainer.setAttribute('aria-hidden', 'true'); this.dimensions = { - scaledCharWidth: null, - scaledCharHeight: null, - scaledCellWidth: null, - scaledCellHeight: null, - scaledCharLeft: null, - scaledCharTop: null, - scaledCanvasWidth: null, - scaledCanvasHeight: null, - canvasWidth: null, - canvasHeight: null, - actualCellWidth: null, - actualCellHeight: null + scaledCharWidth: 0, + scaledCharHeight: 0, + scaledCellWidth: 0, + scaledCellHeight: 0, + scaledCharLeft: 0, + scaledCharTop: 0, + scaledCanvasWidth: 0, + scaledCanvasHeight: 0, + canvasWidth: 0, + canvasHeight: 0, + actualCellWidth: 0, + actualCellHeight: 0 }; this._updateDimensions(); this._injectCss(); @@ -246,7 +246,7 @@ export class DomRenderer extends Disposable implements IRenderer { } // Remove excess elements while (this._rowElements.length > rows) { - this._rowContainer.removeChild(this._rowElements.pop()); + this._rowContainer.removeChild(this._rowElements.pop()!); } } @@ -356,7 +356,7 @@ export class DomRenderer extends Disposable implements IRenderer { const row = y + this._bufferService.buffer.ydisp; const lineData = this._bufferService.buffer.lines.get(row); const cursorStyle = this._optionsService.options.cursorStyle; - rowElement.appendChild(this._rowFactory.createRow(lineData, row === cursorAbsoluteY, cursorStyle, cursorX, cursorBlink, this.dimensions.actualCellWidth, this._bufferService.cols)); + rowElement.appendChild(this._rowFactory.createRow(lineData!, row === cursorAbsoluteY, cursorStyle, cursorX, cursorBlink, this.dimensions.actualCellWidth, this._bufferService.cols)); } } From 509d0e701945c7313dae4d8ef7cfdfc2c91487a9 Mon Sep 17 00:00:00 2001 From: Daniel Imms Date: Thu, 7 Nov 2019 17:44:03 -0800 Subject: [PATCH 25/31] Remove some ITerminal usage from Renderer --- src/renderer/Renderer.ts | 36 ++++++++++++++++++------------------ 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/src/renderer/Renderer.ts b/src/renderer/Renderer.ts index d3977af37..5bc9d0048 100644 --- a/src/renderer/Renderer.ts +++ b/src/renderer/Renderer.ts @@ -30,19 +30,19 @@ export class Renderer extends Disposable implements IRenderer { constructor( private _colors: IColorSet, private readonly _terminal: ITerminal, - readonly bufferService: IBufferService, + private readonly _bufferService: IBufferService, private readonly _charSizeService: ICharSizeService, - readonly optionsService: IOptionsService + private readonly _optionsService: IOptionsService ) { super(); - const allowTransparency = this._terminal.options.allowTransparency; - this._characterJoinerRegistry = new CharacterJoinerRegistry(bufferService); + const allowTransparency = this._optionsService.options.allowTransparency; + this._characterJoinerRegistry = new CharacterJoinerRegistry(this._bufferService); this._renderLayers = [ - new TextRenderLayer(this._terminal.screenElement, 0, this._colors, this._characterJoinerRegistry, allowTransparency, this._id, bufferService, optionsService), - new SelectionRenderLayer(this._terminal.screenElement, 1, this._colors, this._id, bufferService, optionsService), - new LinkRenderLayer(this._terminal.screenElement, 2, this._colors, this._id, this._terminal.linkifier, bufferService, optionsService), - new CursorRenderLayer(this._terminal.screenElement, 3, this._colors, this._terminal, this._id, bufferService, optionsService) + new TextRenderLayer(this._terminal.screenElement, 0, this._colors, this._characterJoinerRegistry, allowTransparency, this._id, this._bufferService, _optionsService), + new SelectionRenderLayer(this._terminal.screenElement, 1, this._colors, this._id, this._bufferService, _optionsService), + new LinkRenderLayer(this._terminal.screenElement, 2, this._colors, this._id, this._terminal.linkifier, this._bufferService, _optionsService), + new CursorRenderLayer(this._terminal.screenElement, 3, this._colors, this._terminal, this._id, this._bufferService, _optionsService) ]; this.dimensions = { scaledCharWidth: null, @@ -74,7 +74,7 @@ export class Renderer extends Disposable implements IRenderer { // and the terminal needs to refreshed if (this._devicePixelRatio !== window.devicePixelRatio) { this._devicePixelRatio = window.devicePixelRatio; - this.onResize(this._terminal.cols, this._terminal.rows); + this.onResize(this._bufferService.cols, this._bufferService.rows); } } @@ -101,7 +101,7 @@ export class Renderer extends Disposable implements IRenderer { } public onCharSizeChanged(): void { - this.onResize(this._terminal.cols, this._terminal.rows); + this.onResize(this._bufferService.cols, this._bufferService.rows); } public onBlur(): void { @@ -163,23 +163,23 @@ export class Renderer extends Disposable implements IRenderer { // will be floored because since lineHeight can never be lower then 1, there // is a guarentee that the scaled line height will always be larger than // scaled char height. - this.dimensions.scaledCellHeight = Math.floor(this.dimensions.scaledCharHeight * this._terminal.options.lineHeight); + this.dimensions.scaledCellHeight = Math.floor(this.dimensions.scaledCharHeight * this._optionsService.options.lineHeight); // Calculate the y coordinate within a cell that text should draw from in // order to draw in the center of a cell. - this.dimensions.scaledCharTop = this._terminal.options.lineHeight === 1 ? 0 : Math.round((this.dimensions.scaledCellHeight - this.dimensions.scaledCharHeight) / 2); + this.dimensions.scaledCharTop = this._optionsService.options.lineHeight === 1 ? 0 : Math.round((this.dimensions.scaledCellHeight - this.dimensions.scaledCharHeight) / 2); // Calculate the scaled cell width, taking the letterSpacing into account. - this.dimensions.scaledCellWidth = this.dimensions.scaledCharWidth + Math.round(this._terminal.options.letterSpacing); + this.dimensions.scaledCellWidth = this.dimensions.scaledCharWidth + Math.round(this._optionsService.options.letterSpacing); // Calculate the x coordinate with a cell that text should draw from in // order to draw in the center of a cell. - this.dimensions.scaledCharLeft = Math.floor(this._terminal.options.letterSpacing / 2); + this.dimensions.scaledCharLeft = Math.floor(this._optionsService.options.letterSpacing / 2); // Recalculate the canvas dimensions; scaled* define the actual number of // pixel in the canvas - this.dimensions.scaledCanvasHeight = this._terminal.rows * this.dimensions.scaledCellHeight; - this.dimensions.scaledCanvasWidth = this._terminal.cols * this.dimensions.scaledCellWidth; + this.dimensions.scaledCanvasHeight = this._bufferService.rows * this.dimensions.scaledCellHeight; + this.dimensions.scaledCanvasWidth = this._bufferService.cols * this.dimensions.scaledCellWidth; // The the size of the canvas on the page. It's very important that this // rounds to nearest integer and not ceils as browsers often set @@ -194,8 +194,8 @@ export class Renderer extends Disposable implements IRenderer { // account window.devicePixelRatio. ICharSizeService.width/height by itself // is insufficient when the page is not at 100% zoom level as it's measured // in CSS pixels, but the actual char size on the canvas can differ. - this.dimensions.actualCellHeight = this.dimensions.canvasHeight / this._terminal.rows; - this.dimensions.actualCellWidth = this.dimensions.canvasWidth / this._terminal.cols; + this.dimensions.actualCellHeight = this.dimensions.canvasHeight / this._bufferService.rows; + this.dimensions.actualCellWidth = this.dimensions.canvasWidth / this._bufferService.cols; } public registerCharacterJoiner(handler: CharacterJoinerHandler): number { From 1e1038b2c7787ed0e050d8286d3e4fff7a7b61c8 Mon Sep 17 00:00:00 2001 From: Daniel Imms Date: Thu, 7 Nov 2019 18:09:13 -0800 Subject: [PATCH 26/31] Remove renderer circular dep on renderservice Also fix super.dispose not being called correctly on RenderService --- addons/xterm-addon-webgl/src/WebglRenderer.ts | 12 ++++++++---- .../src/renderLayer/CursorRenderLayer.ts | 16 +++++++++++----- src/TestUtils.test.ts | 3 ++- src/browser/renderer/Types.d.ts | 8 ++++++++ src/browser/renderer/dom/DomRenderer.ts | 13 ++++++++----- src/browser/services/RenderService.ts | 5 +++++ src/renderer/CursorRenderLayer.ts | 10 ++++++---- src/renderer/Renderer.ts | 8 ++++++-- 8 files changed, 54 insertions(+), 21 deletions(-) diff --git a/addons/xterm-addon-webgl/src/WebglRenderer.ts b/addons/xterm-addon-webgl/src/WebglRenderer.ts index 3f8163ba0..1f28d5893 100644 --- a/addons/xterm-addon-webgl/src/WebglRenderer.ts +++ b/addons/xterm-addon-webgl/src/WebglRenderer.ts @@ -15,13 +15,14 @@ import { INVERTED_DEFAULT_COLOR } from 'browser/renderer/atlas/Constants'; import { RenderModel, COMBINED_CHAR_BIT_MASK } from './RenderModel'; import { Disposable } from 'common/Lifecycle'; import { DEFAULT_COLOR, CHAR_DATA_CHAR_INDEX, CHAR_DATA_CODE_INDEX, NULL_CELL_CODE } from 'common/buffer/Constants'; -import { Terminal } from 'xterm'; +import { Terminal, IEvent } from 'xterm'; import { getLuminance } from './ColorUtils'; import { IRenderLayer } from './renderLayer/Types'; -import { IRenderDimensions, IRenderer } from 'browser/renderer/Types'; +import { IRenderDimensions, IRenderer, IRequestRefreshRowsEvent } from 'browser/renderer/Types'; import { IColorSet } from 'browser/Types'; import { FLAGS } from './Constants'; import { getCompatAttr } from './CharDataCompat'; +import { EventEmitter } from 'common/EventEmitter'; export const INDICIES_PER_CELL = 4; @@ -41,6 +42,9 @@ export class WebglRenderer extends Disposable implements IRenderer { private _core: ITerminal; + private _onRequestRefreshRows = new EventEmitter(); + public get onRequestRefreshRows(): IEvent { return this._onRequestRefreshRows.event; } + constructor( private _terminal: Terminal, private _colors: IColorSet, @@ -54,7 +58,7 @@ export class WebglRenderer extends Disposable implements IRenderer { this._renderLayers = [ new LinkRenderLayer(this._core.screenElement, 2, this._colors, this._core), - new CursorRenderLayer(this._core.screenElement, 3, this._colors) + new CursorRenderLayer(this._core.screenElement, 3, this._colors, this._onRequestRefreshRows) ]; this.dimensions = { scaledCharWidth: 0, @@ -186,7 +190,7 @@ export class WebglRenderer extends Disposable implements IRenderer { this._glyphRenderer.updateSelection(this._model, columnSelectMode); // TODO: #2102 Should this move to RenderCoordinator? - this._core.refresh(0, this._terminal.rows - 1); + this._onRequestRefreshRows.fire({ start: 0, end: this._terminal.rows - 1 }); } public onCursorMove(): void { diff --git a/addons/xterm-addon-webgl/src/renderLayer/CursorRenderLayer.ts b/addons/xterm-addon-webgl/src/renderLayer/CursorRenderLayer.ts index 8a67526e7..c7c68ff6f 100644 --- a/addons/xterm-addon-webgl/src/renderLayer/CursorRenderLayer.ts +++ b/addons/xterm-addon-webgl/src/renderLayer/CursorRenderLayer.ts @@ -8,7 +8,8 @@ import { BaseRenderLayer } from './BaseRenderLayer'; import { ICellData } from 'common/Types'; import { CellData } from 'common/buffer/CellData'; import { IColorSet } from 'browser/Types'; -import { IRenderDimensions } from 'browser/renderer/Types'; +import { IRenderDimensions, IRequestRefreshRowsEvent } from 'browser/renderer/Types'; +import { IEventEmitter } from 'common/EventEmitter'; interface ICursorState { x: number; @@ -29,7 +30,12 @@ export class CursorRenderLayer extends BaseRenderLayer { private _cursorBlinkStateManager: CursorBlinkStateManager | undefined; private _cell: ICellData = new CellData(); - constructor(container: HTMLElement, zIndex: number, colors: IColorSet) { + constructor( + container: HTMLElement, + zIndex: number, + colors: IColorSet, + private _onRequestRefreshRowsEvent: IEventEmitter + ) { super(container, 'cursor', zIndex, true, colors); this._state = { x: 0, @@ -70,14 +76,14 @@ export class CursorRenderLayer extends BaseRenderLayer { if (this._cursorBlinkStateManager) { this._cursorBlinkStateManager.pause(); } - terminal.refresh(terminal.buffer.cursorY, terminal.buffer.cursorY); + this._onRequestRefreshRowsEvent.fire({ start: terminal.buffer.cursorY, end: terminal.buffer.cursorY }); } public onFocus(terminal: Terminal): void { if (this._cursorBlinkStateManager) { this._cursorBlinkStateManager.resume(terminal); } else { - terminal.refresh(terminal.buffer.cursorY, terminal.buffer.cursorY); + this._onRequestRefreshRowsEvent.fire({ start: terminal.buffer.cursorY, end: terminal.buffer.cursorY }); } } @@ -95,7 +101,7 @@ export class CursorRenderLayer extends BaseRenderLayer { } // Request a refresh from the terminal as management of rendering is being // moved back to the terminal - terminal.refresh(terminal.buffer.cursorY, terminal.buffer.cursorY); + this._onRequestRefreshRowsEvent.fire({ start: terminal.buffer.cursorY, end: terminal.buffer.cursorY }); } public onCursorMove(terminal: Terminal): void { diff --git a/src/TestUtils.test.ts b/src/TestUtils.test.ts index a70f751c5..e7c483811 100644 --- a/src/TestUtils.test.ts +++ b/src/TestUtils.test.ts @@ -3,7 +3,7 @@ * @license MIT */ -import { IRenderer, IRenderDimensions, CharacterJoinerHandler } from 'browser/renderer/Types'; +import { IRenderer, IRenderDimensions, CharacterJoinerHandler, IRequestRefreshRowsEvent } from 'browser/renderer/Types'; import { IInputHandlingTerminal, ICompositionHelper, ITerminal, IBrowser, ITerminalOptions } from './Types'; import { IBuffer, IBufferStringIterator, IBufferSet } from 'common/buffer/Types'; import { IBufferLine, ICellData, IAttributeData, ICircularList, XtermListener, ICharset, CoreMouseEventType } from 'common/Types'; @@ -362,6 +362,7 @@ export class MockBuffer implements IBuffer { } export class MockRenderer implements IRenderer { + onRequestRefreshRows: IEvent; onCanvasResize: IEvent<{ width: number; height: number; }>; onRender: IEvent<{ start: number; end: number; }>; dispose(): void { diff --git a/src/browser/renderer/Types.d.ts b/src/browser/renderer/Types.d.ts index 7f84dfd49..b4c321a19 100644 --- a/src/browser/renderer/Types.d.ts +++ b/src/browser/renderer/Types.d.ts @@ -5,6 +5,7 @@ import { IDisposable } from 'common/Types'; import { IColorSet } from 'browser/Types'; +import { IEvent } from 'common/EventEmitter'; export type CharacterJoinerHandler = (text: string) => [number, number][]; @@ -23,6 +24,11 @@ export interface IRenderDimensions { actualCellHeight: number; } +export interface IRequestRefreshRowsEvent { + start: number; + end: number; +} + /** * Note that IRenderer implementations should emit the refresh event after * rendering rows to the screen. @@ -30,6 +36,8 @@ export interface IRenderDimensions { export interface IRenderer extends IDisposable { readonly dimensions: IRenderDimensions; + readonly onRequestRefreshRows: IEvent; + dispose(): void; setColors(colors: IColorSet): void; onDevicePixelRatioChange(): void; diff --git a/src/browser/renderer/dom/DomRenderer.ts b/src/browser/renderer/dom/DomRenderer.ts index b512aa70f..3d544a902 100644 --- a/src/browser/renderer/dom/DomRenderer.ts +++ b/src/browser/renderer/dom/DomRenderer.ts @@ -3,13 +3,14 @@ * @license MIT */ -import { IRenderer, IRenderDimensions, CharacterJoinerHandler } from 'browser/renderer/Types'; +import { IRenderer, IRenderDimensions, CharacterJoinerHandler, IRequestRefreshRowsEvent } from 'browser/renderer/Types'; import { BOLD_CLASS, ITALIC_CLASS, CURSOR_CLASS, CURSOR_STYLE_BLOCK_CLASS, CURSOR_BLINK_CLASS, CURSOR_STYLE_BAR_CLASS, CURSOR_STYLE_UNDERLINE_CLASS, DomRendererRowFactory } from 'browser/renderer/dom/DomRendererRowFactory'; import { INVERTED_DEFAULT_COLOR } from 'browser/renderer/atlas/Constants'; import { Disposable } from 'common/Lifecycle'; import { IColorSet, ILinkifierEvent, ILinkifier } from 'browser/Types'; -import { ICharSizeService, IRenderService } from 'browser/services/Services'; +import { ICharSizeService } from 'browser/services/Services'; import { IOptionsService, IBufferService } from 'common/services/Services'; +import { EventEmitter, IEvent } from 'common/EventEmitter'; const TERMINAL_CLASS_PREFIX = 'xterm-dom-renderer-owner-'; const ROW_CONTAINER_CLASS = 'xterm-rows'; @@ -37,6 +38,9 @@ export class DomRenderer extends Disposable implements IRenderer { public dimensions: IRenderDimensions; + private _onRequestRefreshRows = new EventEmitter(); + public get onRequestRefreshRows(): IEvent { return this._onRequestRefreshRows.event; } + constructor( private _colors: IColorSet, private readonly _element: HTMLElement, @@ -45,8 +49,7 @@ export class DomRenderer extends Disposable implements IRenderer { private readonly _linkifier: ILinkifier, @ICharSizeService private readonly _charSizeService: ICharSizeService, @IOptionsService private readonly _optionsService: IOptionsService, - @IBufferService private readonly _bufferService: IBufferService, - @IRenderService private readonly _renderService: IRenderService + @IBufferService private readonly _bufferService: IBufferService ) { super(); @@ -337,7 +340,7 @@ export class DomRenderer extends Disposable implements IRenderer { // Force a refresh this._updateDimensions(); this._injectCss(); - this._renderService.refreshRows(0, this._bufferService.rows - 1); + this._onRequestRefreshRows.fire({ start: 0, end: this._bufferService.rows - 1 }); } public clear(): void { diff --git a/src/browser/services/RenderService.ts b/src/browser/services/RenderService.ts index 63084f545..b28c99713 100644 --- a/src/browser/services/RenderService.ts +++ b/src/browser/services/RenderService.ts @@ -51,6 +51,9 @@ export class RenderService extends Disposable implements IRenderService { this.register(optionsService.onOptionChange(() => this._renderer.onOptionsChanged())); this.register(charSizeService.onCharSizeChange(() => this.onCharSizeChanged())); + // No need to register this as renderer is explicitly disposed in RenderService.dispose + this._renderer.onRequestRefreshRows(e => this.refreshRows(e.start, e.end)); + // dprchange should handle this case, we need this as well for browsers that don't support the // matchMedia query. this.register(addDisposableDomListener(window, 'resize', () => this.onDevicePixelRatioChange())); @@ -105,12 +108,14 @@ export class RenderService extends Disposable implements IRenderService { public dispose(): void { this._renderer.dispose(); + super.dispose(); } public setRenderer(renderer: IRenderer): void { // TODO: RenderService should be the only one to dispose the renderer this._renderer.dispose(); this._renderer = renderer; + this._renderer.onRequestRefreshRows(e => this.refreshRows(e.start, e.end)); this.refreshRows(0, this._rowCount - 1); } diff --git a/src/renderer/CursorRenderLayer.ts b/src/renderer/CursorRenderLayer.ts index 1f2791f16..d2278983f 100644 --- a/src/renderer/CursorRenderLayer.ts +++ b/src/renderer/CursorRenderLayer.ts @@ -3,13 +3,14 @@ * @license MIT */ -import { IRenderDimensions } from 'browser/renderer/Types'; +import { IRenderDimensions, IRequestRefreshRowsEvent } from 'browser/renderer/Types'; import { BaseRenderLayer } from '../browser/renderer/BaseRenderLayer'; import { ITerminal } from '../Types'; import { ICellData } from 'common/Types'; import { CellData } from 'common/buffer/CellData'; import { IColorSet } from 'browser/Types'; import { IBufferService, IOptionsService } from 'common/services/Services'; +import { IEventEmitter } from 'common/EventEmitter'; interface ICursorState { x: number; @@ -36,6 +37,7 @@ export class CursorRenderLayer extends BaseRenderLayer { colors: IColorSet, private _terminal: ITerminal, rendererId: number, + private _onRequestRefreshRowsEvent: IEventEmitter, readonly bufferService: IBufferService, readonly optionsService: IOptionsService ) { @@ -80,14 +82,14 @@ export class CursorRenderLayer extends BaseRenderLayer { if (this._cursorBlinkStateManager) { this._cursorBlinkStateManager.pause(); } - this._terminal.refresh(this._bufferService.buffer.y, this._bufferService.buffer.y); + this._onRequestRefreshRowsEvent.fire({ start: this._bufferService.buffer.y, end: this._bufferService.buffer.y }); } public onFocus(): void { if (this._cursorBlinkStateManager) { this._cursorBlinkStateManager.resume(); } else { - this._terminal.refresh(this._bufferService.buffer.y, this._bufferService.buffer.y); + this._onRequestRefreshRowsEvent.fire({ start: this._bufferService.buffer.y, end: this._bufferService.buffer.y }); } } @@ -106,7 +108,7 @@ export class CursorRenderLayer extends BaseRenderLayer { } // Request a refresh from the terminal as management of rendering is being // moved back to the terminal - this._terminal.refresh(this._bufferService.buffer.y, this._bufferService.buffer.y); + this._onRequestRefreshRowsEvent.fire({ start: this._bufferService.buffer.y, end: this._bufferService.buffer.y }); } public onCursorMove(): void { diff --git a/src/renderer/Renderer.ts b/src/renderer/Renderer.ts index 5bc9d0048..45abbb828 100644 --- a/src/renderer/Renderer.ts +++ b/src/renderer/Renderer.ts @@ -6,7 +6,7 @@ import { TextRenderLayer } from '../browser/renderer/TextRenderLayer'; import { SelectionRenderLayer } from '../browser/renderer/SelectionRenderLayer'; import { CursorRenderLayer } from './CursorRenderLayer'; -import { IRenderLayer, IRenderer, IRenderDimensions, CharacterJoinerHandler, ICharacterJoinerRegistry } from 'browser/renderer/Types'; +import { IRenderLayer, IRenderer, IRenderDimensions, CharacterJoinerHandler, ICharacterJoinerRegistry, IRequestRefreshRowsEvent } from 'browser/renderer/Types'; import { ITerminal } from '../Types'; import { LinkRenderLayer } from '../browser/renderer/LinkRenderLayer'; import { CharacterJoinerRegistry } from 'browser/renderer/CharacterJoinerRegistry'; @@ -15,6 +15,7 @@ import { IColorSet } from 'browser/Types'; import { ICharSizeService } from 'browser/services/Services'; import { IBufferService, IOptionsService } from 'common/services/Services'; import { removeTerminalFromCache } from 'browser/renderer/atlas/CharAtlasCache'; +import { EventEmitter, IEvent } from 'common/EventEmitter'; let nextRendererId = 1; @@ -27,6 +28,9 @@ export class Renderer extends Disposable implements IRenderer { public dimensions: IRenderDimensions; + private _onRequestRefreshRows = new EventEmitter(); + public get onRequestRefreshRows(): IEvent { return this._onRequestRefreshRows.event; } + constructor( private _colors: IColorSet, private readonly _terminal: ITerminal, @@ -42,7 +46,7 @@ export class Renderer extends Disposable implements IRenderer { new TextRenderLayer(this._terminal.screenElement, 0, this._colors, this._characterJoinerRegistry, allowTransparency, this._id, this._bufferService, _optionsService), new SelectionRenderLayer(this._terminal.screenElement, 1, this._colors, this._id, this._bufferService, _optionsService), new LinkRenderLayer(this._terminal.screenElement, 2, this._colors, this._id, this._terminal.linkifier, this._bufferService, _optionsService), - new CursorRenderLayer(this._terminal.screenElement, 3, this._colors, this._terminal, this._id, this._bufferService, _optionsService) + new CursorRenderLayer(this._terminal.screenElement, 3, this._colors, this._terminal, this._id, this._onRequestRefreshRows, this._bufferService, _optionsService) ]; this.dimensions = { scaledCharWidth: null, From 9d7935f8bdce02f669ffa757f1e2413ef6c3e1fe Mon Sep 17 00:00:00 2001 From: Daniel Imms Date: Thu, 7 Nov 2019 18:21:06 -0800 Subject: [PATCH 27/31] Move cursorState into core service --- src/Terminal.test.ts | 11 --------- src/Terminal.ts | 11 +++------ src/Types.d.ts | 1 - src/common/TestUtils.test.ts | 3 +++ src/common/services/CoreService.test.ts | 32 +++++++++++++++++++++++++ src/common/services/CoreService.ts | 3 +++ src/common/services/Services.ts | 7 ++++++ src/renderer/CursorRenderLayer.ts | 7 +++--- src/renderer/Renderer.ts | 7 +++--- 9 files changed, 56 insertions(+), 26 deletions(-) create mode 100644 src/common/services/CoreService.test.ts diff --git a/src/Terminal.test.ts b/src/Terminal.test.ts index 667bf0764..b55a516b2 100644 --- a/src/Terminal.test.ts +++ b/src/Terminal.test.ts @@ -163,17 +163,6 @@ describe('Terminal', () => { }); }); - describe('reset', () => { - it('should not affect cursorState', () => { - term.cursorState = 1; - term.reset(); - assert.equal(term.cursorState, 1); - term.cursorState = 0; - term.reset(); - assert.equal(term.cursorState, 0); - }); - }); - describe('clear', () => { it('should clear a buffer equal to rows', () => { const promptLine = term.buffer.lines.get(term.buffer.ybase + term.buffer.y); diff --git a/src/Terminal.ts b/src/Terminal.ts index 6626b966f..f8f2c9462 100644 --- a/src/Terminal.ts +++ b/src/Terminal.ts @@ -90,8 +90,6 @@ export class Terminal extends Disposable implements ITerminal, IDisposable, IInp // TODO: We should remove options once components adopt optionsService public get options(): ITerminalOptions { return this.optionsService.options; } - // TODO: This can be changed to an enum or boolean, 0 and 1 seem to be the only options - public cursorState: number; public cursorHidden: boolean; private _customKeyEventHandler: CustomKeyEventHandler; @@ -251,7 +249,6 @@ export class Terminal extends Disposable implements ITerminal, IDisposable, IInp private _setup(): void { this._parent = document ? document.body : null; - this.cursorState = 0; this.cursorHidden = false; this._customKeyEventHandler = null; @@ -637,7 +634,7 @@ export class Terminal extends Disposable implements ITerminal, IDisposable, IInp private _createRenderer(): IRenderer { switch (this.options.rendererType) { - case 'canvas': return new Renderer(this._colorManager.colors, this, this._bufferService, this._charSizeService, this.optionsService); + case 'canvas': return new Renderer(this._colorManager.colors, this, this._bufferService, this._charSizeService, this.optionsService, this._coreService); case 'dom': return this._instantiationService.createInstance(DomRenderer, this._colorManager.colors, this.element, this.screenElement, this._viewportElement, this.linkifier); default: throw new Error(`Unrecognized rendererType "${this.options.rendererType}"`); } @@ -945,8 +942,8 @@ export class Terminal extends Disposable implements ITerminal, IDisposable, IInp * Display the cursor element */ public showCursor(): void { - if (!this.cursorState) { - this.cursorState = 1; + if (!this._coreService.isCursorInitialized) { + this._coreService.isCursorInitialized = true; this.refresh(this.buffer.y, this.buffer.y); } } @@ -1510,7 +1507,6 @@ export class Terminal extends Disposable implements ITerminal, IDisposable, IInp this.options.cols = this.cols; const customKeyEventHandler = this._customKeyEventHandler; const inputHandler = this._inputHandler; - const cursorState = this.cursorState; const userScrolling = this._userScrolling; this._setup(); @@ -1522,7 +1518,6 @@ export class Terminal extends Disposable implements ITerminal, IDisposable, IInp // reattach this._customKeyEventHandler = customKeyEventHandler; this._inputHandler = inputHandler; - this.cursorState = cursorState; this._userScrolling = userScrolling; // do a full screen refresh diff --git a/src/Types.d.ts b/src/Types.d.ts index be1019e58..113620584 100644 --- a/src/Types.d.ts +++ b/src/Types.d.ts @@ -155,7 +155,6 @@ export interface ITerminal extends IPublicTerminal, IElementAccessor, IBufferAcc screenElement: HTMLElement; browser: IBrowser; cursorHidden: boolean; - cursorState: number; buffer: IBuffer; buffers: IBufferSet; isFocused: boolean; diff --git a/src/common/TestUtils.test.ts b/src/common/TestUtils.test.ts index f2721bbe9..7d9c3aa60 100644 --- a/src/common/TestUtils.test.ts +++ b/src/common/TestUtils.test.ts @@ -43,6 +43,9 @@ export class MockCoreMouseService implements ICoreMouseService { } export class MockCoreService implements ICoreService { + isCursorInitialized: boolean = false; + isCursorHidden: boolean = false; + isFocused: boolean = false; serviceBrand: any; decPrivateModes: IDecPrivateModes = {} as any; onData: IEvent = new EventEmitter().event; diff --git a/src/common/services/CoreService.test.ts b/src/common/services/CoreService.test.ts new file mode 100644 index 000000000..00be49538 --- /dev/null +++ b/src/common/services/CoreService.test.ts @@ -0,0 +1,32 @@ +/** + * Copyright (c) 2019 The xterm.js authors. All rights reserved. + * @license MIT + */ + +import { ICoreService } from 'common/services/Services'; +import { CoreService } from 'common/services/CoreService'; +import { MockBufferService, MockLogService, MockOptionsService } from 'common/TestUtils.test'; +import { assert } from 'chai'; + +describe('CoreService', () => { + let coreService: ICoreService; + + beforeEach(() => { + coreService = new CoreService( + () => {}, + new MockBufferService(80, 30), + new MockLogService(), + new MockOptionsService()); + }); + + describe('reset', () => { + it('should not affect isCursorInitialized', () => { + coreService.isCursorInitialized = true; + coreService.reset(); + assert.equal(coreService.isCursorInitialized, true); + coreService.isCursorInitialized = false; + coreService.reset(); + assert.equal(coreService.isCursorInitialized, false); + }); + }); +}); diff --git a/src/common/services/CoreService.ts b/src/common/services/CoreService.ts index 0e0ba6091..a235e5390 100644 --- a/src/common/services/CoreService.ts +++ b/src/common/services/CoreService.ts @@ -15,6 +15,9 @@ const DEFAULT_DEC_PRIVATE_MODES: IDecPrivateModes = Object.freeze({ export class CoreService implements ICoreService { serviceBrand: any; + public isCursorInitialized: boolean = false; + public isCursorHidden: boolean = false; + public isFocused: boolean = false; public decPrivateModes: IDecPrivateModes; private _onData = new EventEmitter(); diff --git a/src/common/services/Services.ts b/src/common/services/Services.ts index 0872d3db7..c067448d6 100644 --- a/src/common/services/Services.ts +++ b/src/common/services/Services.ts @@ -58,6 +58,13 @@ export const ICoreService = createDecorator('CoreService'); export interface ICoreService { serviceBrand: any; + /** + * Initially the cursor will not be visible until the first time the terminal + * is focused. + */ + isCursorInitialized: boolean; + isCursorHidden: boolean; + isFocused: boolean; readonly decPrivateModes: IDecPrivateModes; readonly onData: IEvent; diff --git a/src/renderer/CursorRenderLayer.ts b/src/renderer/CursorRenderLayer.ts index d2278983f..bbbbcea41 100644 --- a/src/renderer/CursorRenderLayer.ts +++ b/src/renderer/CursorRenderLayer.ts @@ -9,7 +9,7 @@ import { ITerminal } from '../Types'; import { ICellData } from 'common/Types'; import { CellData } from 'common/buffer/CellData'; import { IColorSet } from 'browser/Types'; -import { IBufferService, IOptionsService } from 'common/services/Services'; +import { IBufferService, IOptionsService, ICoreService } from 'common/services/Services'; import { IEventEmitter } from 'common/EventEmitter'; interface ICursorState { @@ -39,7 +39,8 @@ export class CursorRenderLayer extends BaseRenderLayer { rendererId: number, private _onRequestRefreshRowsEvent: IEventEmitter, readonly bufferService: IBufferService, - readonly optionsService: IOptionsService + readonly optionsService: IOptionsService, + private readonly _coreService: ICoreService ) { super(container, 'cursor', zIndex, true, colors, rendererId, bufferService, optionsService); this._state = { @@ -127,7 +128,7 @@ export class CursorRenderLayer extends BaseRenderLayer { private _render(triggeredByAnimationFrame: boolean): void { // Don't draw the cursor if it's hidden - if (!this._terminal.cursorState || this._terminal.cursorHidden) { + if (!this._coreService.isCursorInitialized || this._terminal.cursorHidden) { this._clearCursor(); return; } diff --git a/src/renderer/Renderer.ts b/src/renderer/Renderer.ts index 45abbb828..28c4ce03a 100644 --- a/src/renderer/Renderer.ts +++ b/src/renderer/Renderer.ts @@ -13,7 +13,7 @@ import { CharacterJoinerRegistry } from 'browser/renderer/CharacterJoinerRegistr import { Disposable } from 'common/Lifecycle'; import { IColorSet } from 'browser/Types'; import { ICharSizeService } from 'browser/services/Services'; -import { IBufferService, IOptionsService } from 'common/services/Services'; +import { IBufferService, IOptionsService, ICoreService } from 'common/services/Services'; import { removeTerminalFromCache } from 'browser/renderer/atlas/CharAtlasCache'; import { EventEmitter, IEvent } from 'common/EventEmitter'; @@ -36,7 +36,8 @@ export class Renderer extends Disposable implements IRenderer { private readonly _terminal: ITerminal, private readonly _bufferService: IBufferService, private readonly _charSizeService: ICharSizeService, - private readonly _optionsService: IOptionsService + private readonly _optionsService: IOptionsService, + readonly coreService: ICoreService ) { super(); const allowTransparency = this._optionsService.options.allowTransparency; @@ -46,7 +47,7 @@ export class Renderer extends Disposable implements IRenderer { new TextRenderLayer(this._terminal.screenElement, 0, this._colors, this._characterJoinerRegistry, allowTransparency, this._id, this._bufferService, _optionsService), new SelectionRenderLayer(this._terminal.screenElement, 1, this._colors, this._id, this._bufferService, _optionsService), new LinkRenderLayer(this._terminal.screenElement, 2, this._colors, this._id, this._terminal.linkifier, this._bufferService, _optionsService), - new CursorRenderLayer(this._terminal.screenElement, 3, this._colors, this._terminal, this._id, this._onRequestRefreshRows, this._bufferService, _optionsService) + new CursorRenderLayer(this._terminal.screenElement, 3, this._colors, this._terminal, this._id, this._onRequestRefreshRows, this._bufferService, _optionsService, coreService) ]; this.dimensions = { scaledCharWidth: null, From c204ab00e04908d4c2e808457d058ae69b2710a7 Mon Sep 17 00:00:00 2001 From: Daniel Imms Date: Thu, 7 Nov 2019 18:22:18 -0800 Subject: [PATCH 28/31] Move cursorHidden into core service --- src/InputHandler.ts | 6 +++--- src/Terminal.ts | 3 --- src/Types.d.ts | 2 -- src/renderer/CursorRenderLayer.ts | 2 +- 4 files changed, 4 insertions(+), 9 deletions(-) diff --git a/src/InputHandler.ts b/src/InputHandler.ts index 74208482f..3994d532c 100644 --- a/src/InputHandler.ts +++ b/src/InputHandler.ts @@ -1449,7 +1449,7 @@ export class InputHandler extends Disposable implements IInputHandler { this._logService.debug('DECSET 1015 not supported (see #2507)'); break; case 25: // show cursor - this._terminal.cursorHidden = false; + this._coreService.isCursorHidden = false; break; case 1048: // alt screen cursor this.saveCursor(); @@ -1620,7 +1620,7 @@ export class InputHandler extends Disposable implements IInputHandler { this._logService.debug('DECRST 1015 not supported (see #2507)'); break; case 25: // hide cursor - this._terminal.cursorHidden = true; + this._coreService.isCursorHidden = true; break; case 1048: // alt screen cursor this.restoreCursor(); @@ -1954,7 +1954,7 @@ export class InputHandler extends Disposable implements IInputHandler { * http://vt100.net/docs/vt220-rm/table4-10.html */ public softReset(params: IParams): void { - this._terminal.cursorHidden = false; + this._coreService.isCursorHidden = false; this._terminal.insertMode = false; this._terminal.originMode = false; this._terminal.wraparoundMode = true; // defaults: xterm - true, vt100 - false diff --git a/src/Terminal.ts b/src/Terminal.ts index f8f2c9462..e19901b4b 100644 --- a/src/Terminal.ts +++ b/src/Terminal.ts @@ -90,8 +90,6 @@ export class Terminal extends Disposable implements ITerminal, IDisposable, IInp // TODO: We should remove options once components adopt optionsService public get options(): ITerminalOptions { return this.optionsService.options; } - public cursorHidden: boolean; - private _customKeyEventHandler: CustomKeyEventHandler; // common services @@ -249,7 +247,6 @@ export class Terminal extends Disposable implements ITerminal, IDisposable, IInp private _setup(): void { this._parent = document ? document.body : null; - this.cursorHidden = false; this._customKeyEventHandler = null; // modes diff --git a/src/Types.d.ts b/src/Types.d.ts index 113620584..4f6ce40f3 100644 --- a/src/Types.d.ts +++ b/src/Types.d.ts @@ -38,7 +38,6 @@ export interface IInputHandlingTerminal { savedCols: number; mouseEvents: CoreMouseEventType; sendFocus: boolean; - cursorHidden: boolean; buffers: IBufferSet; buffer: IBuffer; @@ -154,7 +153,6 @@ export interface IInputHandler { export interface ITerminal extends IPublicTerminal, IElementAccessor, IBufferAccessor, ILinkifierAccessor { screenElement: HTMLElement; browser: IBrowser; - cursorHidden: boolean; buffer: IBuffer; buffers: IBufferSet; isFocused: boolean; diff --git a/src/renderer/CursorRenderLayer.ts b/src/renderer/CursorRenderLayer.ts index bbbbcea41..0bfdd35b5 100644 --- a/src/renderer/CursorRenderLayer.ts +++ b/src/renderer/CursorRenderLayer.ts @@ -128,7 +128,7 @@ export class CursorRenderLayer extends BaseRenderLayer { private _render(triggeredByAnimationFrame: boolean): void { // Don't draw the cursor if it's hidden - if (!this._coreService.isCursorInitialized || this._terminal.cursorHidden) { + if (!this._coreService.isCursorInitialized || this._coreService.isCursorHidden) { this._clearCursor(); return; } From 873de2b127fb8f36ecefd5def0137258555bcbd5 Mon Sep 17 00:00:00 2001 From: Daniel Imms Date: Thu, 7 Nov 2019 18:39:46 -0800 Subject: [PATCH 29/31] Move cursor render layer to browser --- .../src/renderLayer/CursorRenderLayer.ts | 5 +- src/Terminal.ts | 12 +-- src/Types.d.ts | 1 - .../renderer/CursorRenderLayer.ts | 88 +++++++++---------- src/browser/services/CoreBrowserService.ts | 19 ++++ src/browser/services/Services.ts | 7 ++ src/common/services/CoreService.ts | 1 - src/common/services/Services.ts | 1 - src/renderer/Renderer.ts | 31 +++---- 9 files changed, 93 insertions(+), 72 deletions(-) rename src/{ => browser}/renderer/CursorRenderLayer.ts (85%) create mode 100644 src/browser/services/CoreBrowserService.ts diff --git a/addons/xterm-addon-webgl/src/renderLayer/CursorRenderLayer.ts b/addons/xterm-addon-webgl/src/renderLayer/CursorRenderLayer.ts index c7c68ff6f..b018cf2b6 100644 --- a/addons/xterm-addon-webgl/src/renderLayer/CursorRenderLayer.ts +++ b/addons/xterm-addon-webgl/src/renderLayer/CursorRenderLayer.ts @@ -95,9 +95,8 @@ export class CursorRenderLayer extends BaseRenderLayer { }); } } else { - if (this._cursorBlinkStateManager) { - this._cursorBlinkStateManager.dispose(); - } + this._cursorBlinkStateManager?.dispose(); + this._cursorBlinkStateManager = undefined; } // Request a refresh from the terminal as management of rendering is being // moved back to the terminal diff --git a/src/Terminal.ts b/src/Terminal.ts index e19901b4b..f9adacc1d 100644 --- a/src/Terminal.ts +++ b/src/Terminal.ts @@ -48,7 +48,7 @@ import { ColorManager } from 'browser/ColorManager'; import { RenderService } from 'browser/services/RenderService'; import { IOptionsService, IBufferService, ICoreMouseService, ICoreService, ILogService, IDirtyRowService, IInstantiationService } from 'common/services/Services'; import { OptionsService } from 'common/services/OptionsService'; -import { ICharSizeService, IRenderService, IMouseService, ISelectionService, ISoundService } from 'browser/services/Services'; +import { ICharSizeService, IRenderService, IMouseService, ISelectionService, ISoundService, ICoreBrowserService } from 'browser/services/Services'; import { CharSizeService } from 'browser/services/CharSizeService'; import { BufferService, MINIMUM_COLS, MINIMUM_ROWS } from 'common/services/BufferService'; import { Disposable } from 'common/Lifecycle'; @@ -63,6 +63,7 @@ import { DirtyRowService } from 'common/services/DirtyRowService'; import { InstantiationService } from 'common/services/InstantiationService'; import { CoreMouseService } from 'common/services/CoreMouseService'; import { WriteBuffer } from 'common/input/WriteBuffer'; +import { CoreBrowserService } from 'browser/services/CoreBrowserService'; // Let it work inside Node.js for automated testing purposes. const document = (typeof window !== 'undefined') ? window.document : null; @@ -313,10 +314,6 @@ export class Terminal extends Disposable implements ITerminal, IDisposable, IInp } } - public get isFocused(): boolean { - return document.activeElement === this.textarea && document.hasFocus(); - } - private _setupOptionsListeners(): void { // TODO: These listeners should be owned by individual components this.optionsService.onOptionChange(key => { @@ -531,6 +528,9 @@ export class Terminal extends Disposable implements ITerminal, IDisposable, IInp this.register(addDisposableDomListener(this.textarea, 'blur', () => this._onTextAreaBlur())); this._helperContainer.appendChild(this.textarea); + const coreBrowserService = this._instantiationService.createInstance(CoreBrowserService, this.textarea); + this._instantiationService.setService(ICoreBrowserService, coreBrowserService); + this._charSizeService = this._instantiationService.createInstance(CharSizeService, this._document, this._helperContainer); this._instantiationService.setService(ICharSizeService, this._charSizeService); @@ -631,7 +631,7 @@ export class Terminal extends Disposable implements ITerminal, IDisposable, IInp private _createRenderer(): IRenderer { switch (this.options.rendererType) { - case 'canvas': return new Renderer(this._colorManager.colors, this, this._bufferService, this._charSizeService, this.optionsService, this._coreService); + case 'canvas': return new Renderer(this._colorManager.colors, this.screenElement, this.linkifier, this._bufferService, this._charSizeService, this.optionsService, this._coreService, this._coreBrowserService); case 'dom': return this._instantiationService.createInstance(DomRenderer, this._colorManager.colors, this.element, this.screenElement, this._viewportElement, this.linkifier); default: throw new Error(`Unrecognized rendererType "${this.options.rendererType}"`); } diff --git a/src/Types.d.ts b/src/Types.d.ts index 4f6ce40f3..2a922ae1c 100644 --- a/src/Types.d.ts +++ b/src/Types.d.ts @@ -155,7 +155,6 @@ export interface ITerminal extends IPublicTerminal, IElementAccessor, IBufferAcc browser: IBrowser; buffer: IBuffer; buffers: IBufferSet; - isFocused: boolean; viewport: IViewport; bracketedPasteMode: boolean; optionsService: IOptionsService; diff --git a/src/renderer/CursorRenderLayer.ts b/src/browser/renderer/CursorRenderLayer.ts similarity index 85% rename from src/renderer/CursorRenderLayer.ts rename to src/browser/renderer/CursorRenderLayer.ts index 0bfdd35b5..0ca1b97a8 100644 --- a/src/renderer/CursorRenderLayer.ts +++ b/src/browser/renderer/CursorRenderLayer.ts @@ -4,13 +4,13 @@ */ import { IRenderDimensions, IRequestRefreshRowsEvent } from 'browser/renderer/Types'; -import { BaseRenderLayer } from '../browser/renderer/BaseRenderLayer'; -import { ITerminal } from '../Types'; +import { BaseRenderLayer } from 'browser/renderer/BaseRenderLayer'; import { ICellData } from 'common/Types'; import { CellData } from 'common/buffer/CellData'; import { IColorSet } from 'browser/Types'; import { IBufferService, IOptionsService, ICoreService } from 'common/services/Services'; import { IEventEmitter } from 'common/EventEmitter'; +import { ICoreBrowserService } from 'browser/services/Services'; interface ICursorState { x: number; @@ -28,27 +28,27 @@ const BLINK_INTERVAL = 600; export class CursorRenderLayer extends BaseRenderLayer { private _state: ICursorState; private _cursorRenderers: {[key: string]: (x: number, y: number, cell: ICellData) => void}; - private _cursorBlinkStateManager: CursorBlinkStateManager; + private _cursorBlinkStateManager: CursorBlinkStateManager | undefined; private _cell: ICellData = new CellData(); constructor( container: HTMLElement, zIndex: number, colors: IColorSet, - private _terminal: ITerminal, rendererId: number, private _onRequestRefreshRowsEvent: IEventEmitter, readonly bufferService: IBufferService, readonly optionsService: IOptionsService, - private readonly _coreService: ICoreService + private readonly _coreService: ICoreService, + private readonly _coreBrowserService: ICoreBrowserService ) { super(container, 'cursor', zIndex, true, colors, rendererId, bufferService, optionsService); this._state = { - x: null, - y: null, - isFocused: null, - style: null, - width: null + x: 0, + y: 0, + isFocused: false, + style: '', + width: 0 }; this._cursorRenderers = { 'bar': this._renderBarCursor.bind(this), @@ -62,11 +62,11 @@ export class CursorRenderLayer extends BaseRenderLayer { super.resize(dim); // Resizing the canvas discards the contents of the canvas so clear state this._state = { - x: null, - y: null, - isFocused: null, - style: null, - width: null + x: 0, + y: 0, + isFocused: false, + style: '', + width: 0 }; } @@ -74,7 +74,7 @@ export class CursorRenderLayer extends BaseRenderLayer { this._clearCursor(); if (this._cursorBlinkStateManager) { this._cursorBlinkStateManager.dispose(); - this._cursorBlinkStateManager = null; + this._cursorBlinkStateManager = undefined; this.onOptionsChanged(); } } @@ -97,15 +97,13 @@ export class CursorRenderLayer extends BaseRenderLayer { public onOptionsChanged(): void { if (this._optionsService.options.cursorBlink) { if (!this._cursorBlinkStateManager) { - this._cursorBlinkStateManager = new CursorBlinkStateManager(this._terminal.isFocused, () => { + this._cursorBlinkStateManager = new CursorBlinkStateManager(this._coreBrowserService.isFocused, () => { this._render(true); }); } } else { - if (this._cursorBlinkStateManager) { - this._cursorBlinkStateManager.dispose(); - this._cursorBlinkStateManager = null; - } + this._cursorBlinkStateManager?.dispose(); + this._cursorBlinkStateManager = undefined; } // Request a refresh from the terminal as management of rendering is being // moved back to the terminal @@ -142,12 +140,12 @@ export class CursorRenderLayer extends BaseRenderLayer { return; } - this._bufferService.buffer.lines.get(cursorY).loadCell(this._bufferService.buffer.x, this._cell); + this._bufferService.buffer.lines.get(cursorY)!.loadCell(this._bufferService.buffer.x, this._cell); if (this._cell.content === undefined) { return; } - if (!this._terminal.isFocused) { + if (!this._coreBrowserService.isFocused) { this._clearCursor(); this._ctx.save(); this._ctx.fillStyle = this._colors.cursor.css; @@ -176,7 +174,7 @@ export class CursorRenderLayer extends BaseRenderLayer { // The cursor is already in the correct spot, don't redraw if (this._state.x === this._bufferService.buffer.x && this._state.y === viewportRelativeCursorY && - this._state.isFocused === this._terminal.isFocused && + this._state.isFocused === this._coreBrowserService.isFocused && this._state.style === this._optionsService.options.cursorStyle && this._state.width === this._cell.getWidth()) { return; @@ -199,11 +197,11 @@ export class CursorRenderLayer extends BaseRenderLayer { if (this._state) { this._clearCells(this._state.x, this._state.y, this._state.width, 1); this._state = { - x: null, - y: null, - isFocused: null, - style: null, - width: null + x: 0, + y: 0, + isFocused: false, + style: '', + width: 0 }; } } @@ -242,16 +240,16 @@ export class CursorRenderLayer extends BaseRenderLayer { class CursorBlinkStateManager { public isCursorVisible: boolean; - private _animationFrame: number; - private _blinkStartTimeout: number; - private _blinkInterval: number; + private _animationFrame: number | undefined; + private _blinkStartTimeout: number | undefined; + private _blinkInterval: number | undefined; /** * The time at which the animation frame was restarted, this is used on the * next render to restart the timers so they don't need to restart the timers * multiple times over a short period. */ - private _animationTimeRestarted: number; + private _animationTimeRestarted: number | undefined; constructor( isFocused: boolean, @@ -268,15 +266,15 @@ class CursorBlinkStateManager { public dispose(): void { if (this._blinkInterval) { window.clearInterval(this._blinkInterval); - this._blinkInterval = null; + this._blinkInterval = undefined; } if (this._blinkStartTimeout) { window.clearTimeout(this._blinkStartTimeout); - this._blinkStartTimeout = null; + this._blinkStartTimeout = undefined; } if (this._animationFrame) { window.cancelAnimationFrame(this._animationFrame); - this._animationFrame = null; + this._animationFrame = undefined; } } @@ -291,7 +289,7 @@ class CursorBlinkStateManager { if (!this._animationFrame) { this._animationFrame = window.requestAnimationFrame(() => { this._renderCallback(); - this._animationFrame = null; + this._animationFrame = undefined; }); } } @@ -311,7 +309,7 @@ class CursorBlinkStateManager { // started if (this._animationTimeRestarted) { const time = BLINK_INTERVAL - (Date.now() - this._animationTimeRestarted); - this._animationTimeRestarted = null; + this._animationTimeRestarted = undefined; if (time > 0) { this._restartInterval(time); return; @@ -322,7 +320,7 @@ class CursorBlinkStateManager { this.isCursorVisible = false; this._animationFrame = window.requestAnimationFrame(() => { this._renderCallback(); - this._animationFrame = null; + this._animationFrame = undefined; }); // Setup the blink interval @@ -332,7 +330,7 @@ class CursorBlinkStateManager { // calc time diff // Make restart interval do a setTimeout initially? const time = BLINK_INTERVAL - (Date.now() - this._animationTimeRestarted); - this._animationTimeRestarted = null; + this._animationTimeRestarted = undefined; this._restartInterval(time); return; } @@ -341,7 +339,7 @@ class CursorBlinkStateManager { this.isCursorVisible = !this.isCursorVisible; this._animationFrame = window.requestAnimationFrame(() => { this._renderCallback(); - this._animationFrame = null; + this._animationFrame = undefined; }); }, BLINK_INTERVAL); }, timeToStart); @@ -351,20 +349,20 @@ class CursorBlinkStateManager { this.isCursorVisible = true; if (this._blinkInterval) { window.clearInterval(this._blinkInterval); - this._blinkInterval = null; + this._blinkInterval = undefined; } if (this._blinkStartTimeout) { window.clearTimeout(this._blinkStartTimeout); - this._blinkStartTimeout = null; + this._blinkStartTimeout = undefined; } if (this._animationFrame) { window.cancelAnimationFrame(this._animationFrame); - this._animationFrame = null; + this._animationFrame = undefined; } } public resume(): void { - this._animationTimeRestarted = null; + this._animationTimeRestarted = undefined; this._restartInterval(); this.restartBlinkAnimation(); } diff --git a/src/browser/services/CoreBrowserService.ts b/src/browser/services/CoreBrowserService.ts new file mode 100644 index 000000000..e585f44ab --- /dev/null +++ b/src/browser/services/CoreBrowserService.ts @@ -0,0 +1,19 @@ +/** + * Copyright (c) 2019 The xterm.js authors. All rights reserved. + * @license MIT + */ + +import { ICoreBrowserService } from './Services'; + +export class CoreBrowserService implements ICoreBrowserService { + serviceBrand: any; + + constructor( + private _textarea: HTMLTextAreaElement + ) { + } + + public get isFocused(): boolean { + return document.activeElement === this._textarea && document.hasFocus(); + } +} diff --git a/src/browser/services/Services.ts b/src/browser/services/Services.ts index 2170a04e1..785fec34e 100644 --- a/src/browser/services/Services.ts +++ b/src/browser/services/Services.ts @@ -23,6 +23,13 @@ export interface ICharSizeService { measure(): void; } +export const ICoreBrowserService = createDecorator('CoreBrowserService'); +export interface ICoreBrowserService { + serviceBrand: any; + + readonly isFocused: boolean; +} + export const IMouseService = createDecorator('MouseService'); export interface IMouseService { serviceBrand: any; diff --git a/src/common/services/CoreService.ts b/src/common/services/CoreService.ts index a235e5390..11c3f3053 100644 --- a/src/common/services/CoreService.ts +++ b/src/common/services/CoreService.ts @@ -17,7 +17,6 @@ export class CoreService implements ICoreService { public isCursorInitialized: boolean = false; public isCursorHidden: boolean = false; - public isFocused: boolean = false; public decPrivateModes: IDecPrivateModes; private _onData = new EventEmitter(); diff --git a/src/common/services/Services.ts b/src/common/services/Services.ts index c067448d6..e4ff90d0f 100644 --- a/src/common/services/Services.ts +++ b/src/common/services/Services.ts @@ -64,7 +64,6 @@ export interface ICoreService { */ isCursorInitialized: boolean; isCursorHidden: boolean; - isFocused: boolean; readonly decPrivateModes: IDecPrivateModes; readonly onData: IEvent; diff --git a/src/renderer/Renderer.ts b/src/renderer/Renderer.ts index 28c4ce03a..f45fd4b5e 100644 --- a/src/renderer/Renderer.ts +++ b/src/renderer/Renderer.ts @@ -3,16 +3,15 @@ * @license MIT */ -import { TextRenderLayer } from '../browser/renderer/TextRenderLayer'; -import { SelectionRenderLayer } from '../browser/renderer/SelectionRenderLayer'; -import { CursorRenderLayer } from './CursorRenderLayer'; +import { TextRenderLayer } from 'browser/renderer/TextRenderLayer'; +import { SelectionRenderLayer } from 'browser/renderer/SelectionRenderLayer'; +import { CursorRenderLayer } from 'browser/renderer/CursorRenderLayer'; import { IRenderLayer, IRenderer, IRenderDimensions, CharacterJoinerHandler, ICharacterJoinerRegistry, IRequestRefreshRowsEvent } from 'browser/renderer/Types'; -import { ITerminal } from '../Types'; -import { LinkRenderLayer } from '../browser/renderer/LinkRenderLayer'; +import { LinkRenderLayer } from 'browser/renderer/LinkRenderLayer'; import { CharacterJoinerRegistry } from 'browser/renderer/CharacterJoinerRegistry'; import { Disposable } from 'common/Lifecycle'; -import { IColorSet } from 'browser/Types'; -import { ICharSizeService } from 'browser/services/Services'; +import { IColorSet, ILinkifier } from 'browser/Types'; +import { ICharSizeService, ICoreBrowserService } from 'browser/services/Services'; import { IBufferService, IOptionsService, ICoreService } from 'common/services/Services'; import { removeTerminalFromCache } from 'browser/renderer/atlas/CharAtlasCache'; import { EventEmitter, IEvent } from 'common/EventEmitter'; @@ -33,21 +32,23 @@ export class Renderer extends Disposable implements IRenderer { constructor( private _colors: IColorSet, - private readonly _terminal: ITerminal, + private readonly _screenElement: HTMLElement, + private readonly _linkifier: ILinkifier, private readonly _bufferService: IBufferService, private readonly _charSizeService: ICharSizeService, private readonly _optionsService: IOptionsService, - readonly coreService: ICoreService + readonly coreService: ICoreService, + readonly coreBrowserService: ICoreBrowserService ) { super(); const allowTransparency = this._optionsService.options.allowTransparency; this._characterJoinerRegistry = new CharacterJoinerRegistry(this._bufferService); this._renderLayers = [ - new TextRenderLayer(this._terminal.screenElement, 0, this._colors, this._characterJoinerRegistry, allowTransparency, this._id, this._bufferService, _optionsService), - new SelectionRenderLayer(this._terminal.screenElement, 1, this._colors, this._id, this._bufferService, _optionsService), - new LinkRenderLayer(this._terminal.screenElement, 2, this._colors, this._id, this._terminal.linkifier, this._bufferService, _optionsService), - new CursorRenderLayer(this._terminal.screenElement, 3, this._colors, this._terminal, this._id, this._onRequestRefreshRows, this._bufferService, _optionsService, coreService) + new TextRenderLayer(this._screenElement, 0, this._colors, this._characterJoinerRegistry, allowTransparency, this._id, this._bufferService, _optionsService), + new SelectionRenderLayer(this._screenElement, 1, this._colors, this._id, this._bufferService, _optionsService), + new LinkRenderLayer(this._screenElement, 2, this._colors, this._id, this._linkifier, this._bufferService, _optionsService), + new CursorRenderLayer(this._screenElement, 3, this._colors, this._id, this._onRequestRefreshRows, this._bufferService, _optionsService, coreService, coreBrowserService) ]; this.dimensions = { scaledCharWidth: null, @@ -101,8 +102,8 @@ export class Renderer extends Disposable implements IRenderer { this._renderLayers.forEach(l => l.resize(this.dimensions)); // Resize the screen - this._terminal.screenElement.style.width = `${this.dimensions.canvasWidth}px`; - this._terminal.screenElement.style.height = `${this.dimensions.canvasHeight}px`; + this._screenElement.style.width = `${this.dimensions.canvasWidth}px`; + this._screenElement.style.height = `${this.dimensions.canvasHeight}px`; } public onCharSizeChanged(): void { From 3f7238d9dca3e20794a212ec13ebdedcde3aea4e Mon Sep 17 00:00:00 2001 From: Daniel Imms Date: Thu, 7 Nov 2019 18:45:13 -0800 Subject: [PATCH 30/31] Move Renderer to browser --- src/Terminal.ts | 4 +-- src/{ => browser}/renderer/Renderer.ts | 34 +++++++++++++------------- 2 files changed, 19 insertions(+), 19 deletions(-) rename src/{ => browser}/renderer/Renderer.ts (92%) diff --git a/src/Terminal.ts b/src/Terminal.ts index f9adacc1d..3c589ffa9 100644 --- a/src/Terminal.ts +++ b/src/Terminal.ts @@ -28,7 +28,7 @@ import { Viewport } from 'browser/Viewport'; import { rightClickHandler, moveTextAreaUnderMouseCursor, handlePasteEvent, copyHandler, paste } from 'browser/Clipboard'; import { C0 } from 'common/data/EscapeSequences'; import { InputHandler } from './InputHandler'; -import { Renderer } from './renderer/Renderer'; +import { Renderer } from 'browser/renderer/Renderer'; import { Linkifier } from 'browser/Linkifier'; import { SelectionService } from 'browser/services/SelectionService'; import * as Browser from 'common/Platform'; @@ -631,7 +631,7 @@ export class Terminal extends Disposable implements ITerminal, IDisposable, IInp private _createRenderer(): IRenderer { switch (this.options.rendererType) { - case 'canvas': return new Renderer(this._colorManager.colors, this.screenElement, this.linkifier, this._bufferService, this._charSizeService, this.optionsService, this._coreService, this._coreBrowserService); + case 'canvas': return this._instantiationService.createInstance(Renderer, this._colorManager.colors, this.screenElement, this.linkifier); case 'dom': return this._instantiationService.createInstance(DomRenderer, this._colorManager.colors, this.element, this.screenElement, this._viewportElement, this.linkifier); default: throw new Error(`Unrecognized rendererType "${this.options.rendererType}"`); } diff --git a/src/renderer/Renderer.ts b/src/browser/renderer/Renderer.ts similarity index 92% rename from src/renderer/Renderer.ts rename to src/browser/renderer/Renderer.ts index f45fd4b5e..26b464cbd 100644 --- a/src/renderer/Renderer.ts +++ b/src/browser/renderer/Renderer.ts @@ -34,11 +34,11 @@ export class Renderer extends Disposable implements IRenderer { private _colors: IColorSet, private readonly _screenElement: HTMLElement, private readonly _linkifier: ILinkifier, - private readonly _bufferService: IBufferService, - private readonly _charSizeService: ICharSizeService, - private readonly _optionsService: IOptionsService, - readonly coreService: ICoreService, - readonly coreBrowserService: ICoreBrowserService + @IBufferService private readonly _bufferService: IBufferService, + @ICharSizeService private readonly _charSizeService: ICharSizeService, + @IOptionsService private readonly _optionsService: IOptionsService, + @ICoreService readonly coreService: ICoreService, + @ICoreBrowserService readonly coreBrowserService: ICoreBrowserService ) { super(); const allowTransparency = this._optionsService.options.allowTransparency; @@ -51,18 +51,18 @@ export class Renderer extends Disposable implements IRenderer { new CursorRenderLayer(this._screenElement, 3, this._colors, this._id, this._onRequestRefreshRows, this._bufferService, _optionsService, coreService, coreBrowserService) ]; this.dimensions = { - scaledCharWidth: null, - scaledCharHeight: null, - scaledCellWidth: null, - scaledCellHeight: null, - scaledCharLeft: null, - scaledCharTop: null, - scaledCanvasWidth: null, - scaledCanvasHeight: null, - canvasWidth: null, - canvasHeight: null, - actualCellWidth: null, - actualCellHeight: null + scaledCharWidth: 0, + scaledCharHeight: 0, + scaledCellWidth: 0, + scaledCellHeight: 0, + scaledCharLeft: 0, + scaledCharTop: 0, + scaledCanvasWidth: 0, + scaledCanvasHeight: 0, + canvasWidth: 0, + canvasHeight: 0, + actualCellWidth: 0, + actualCellHeight: 0 }; this._devicePixelRatio = window.devicePixelRatio; this._updateDimensions(); From 3bf149bbc569ecd9ef2825366bf30e58e70efe11 Mon Sep 17 00:00:00 2001 From: Daniel Imms Date: Thu, 7 Nov 2019 18:46:56 -0800 Subject: [PATCH 31/31] Fix webgl cursor --- addons/xterm-addon-webgl/src/renderLayer/CursorRenderLayer.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/addons/xterm-addon-webgl/src/renderLayer/CursorRenderLayer.ts b/addons/xterm-addon-webgl/src/renderLayer/CursorRenderLayer.ts index b018cf2b6..413f4fdd4 100644 --- a/addons/xterm-addon-webgl/src/renderLayer/CursorRenderLayer.ts +++ b/addons/xterm-addon-webgl/src/renderLayer/CursorRenderLayer.ts @@ -120,7 +120,7 @@ export class CursorRenderLayer extends BaseRenderLayer { private _render(terminal: Terminal, triggeredByAnimationFrame: boolean): void { // Don't draw the cursor if it's hidden // TODO: Need to expose API for this - if (!(terminal as any)._core.cursorState || (terminal as any)._core.cursorHidden) { + if (!(terminal as any)._core._coreService.isCursorInitialized || (terminal as any)._core._coreService.isCursorHidden) { this._clearCursor(); return; }