@theia/terminal 1.77.0-next.84 → 1.77.0-next.88

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -2,11 +2,21 @@ import { ITheme } from 'xterm';
2
2
  import { ColorRegistry } from '@theia/core/lib/browser/color-registry';
3
3
  import { ThemeService } from '@theia/core/lib/browser/theming';
4
4
  import { ThemeChangeEvent } from '@theia/core/lib/common/theme';
5
- import { Event } from '@theia/core';
5
+ import { Emitter, Event } from '@theia/core';
6
6
  export declare class TerminalThemeService {
7
7
  protected readonly colorRegistry: ColorRegistry;
8
8
  protected readonly themeService: ThemeService;
9
+ protected readonly onDidChangeEmitter: Emitter<ThemeChangeEvent>;
10
+ protected appliedTheme: string | undefined;
11
+ /**
12
+ * Fires when the color theme changes, and when a change in the `ColorRegistry` changes the terminal colors.
13
+ */
9
14
  get onDidChange(): Event<ThemeChangeEvent>;
15
+ /**
16
+ * Subscribes on first use rather than at construction, so that the theme listener runs after the one that applies
17
+ * a new theme to Monaco, whose color registry the terminal colors are read from.
18
+ */
19
+ protected listenForChanges(): void;
10
20
  get theme(): ITheme;
11
21
  }
12
22
  //# sourceMappingURL=terminal-theme-service.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"terminal-theme-service.d.ts","sourceRoot":"","sources":["../../src/browser/terminal-theme-service.ts"],"names":[],"mappings":"AAgBA,OAAO,EAAE,MAAM,EAAE,MAAM,OAAO,CAAC;AAE/B,OAAO,EAAE,aAAa,EAAE,MAAM,wCAAwC,CAAC;AACvE,OAAO,EAAE,YAAY,EAAE,MAAM,iCAAiC,CAAC;AAC/D,OAAO,EAAE,gBAAgB,EAAE,MAAM,8BAA8B,CAAC;AAChE,OAAO,EAAE,KAAK,EAAE,MAAM,aAAa,CAAC;AAGpC,qBACa,oBAAoB;IAEN,SAAS,CAAC,QAAQ,CAAC,aAAa,EAAE,aAAa,CAAC;IACjD,SAAS,CAAC,QAAQ,CAAC,YAAY,EAAE,YAAY,CAAC;IAEpE,IAAI,WAAW,IAAI,KAAK,CAAC,gBAAgB,CAAC,CAEzC;IAED,IAAI,KAAK,IAAI,MAAM,CA0BlB;CAEJ"}
1
+ {"version":3,"file":"terminal-theme-service.d.ts","sourceRoot":"","sources":["../../src/browser/terminal-theme-service.ts"],"names":[],"mappings":"AAgBA,OAAO,EAAE,MAAM,EAAE,MAAM,OAAO,CAAC;AAE/B,OAAO,EAAE,aAAa,EAAE,MAAM,wCAAwC,CAAC;AACvE,OAAO,EAAE,YAAY,EAAE,MAAM,iCAAiC,CAAC;AAC/D,OAAO,EAAE,gBAAgB,EAAE,MAAM,8BAA8B,CAAC;AAChE,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,aAAa,CAAC;AAG7C,qBACa,oBAAoB;IAEN,SAAS,CAAC,QAAQ,CAAC,aAAa,EAAE,aAAa,CAAC;IACjD,SAAS,CAAC,QAAQ,CAAC,YAAY,EAAE,YAAY,CAAC;IAEpE,SAAS,CAAC,QAAQ,CAAC,kBAAkB,4BAAmC;IACxE,SAAS,CAAC,YAAY,EAAE,MAAM,GAAG,SAAS,CAAC;IAE3C;;OAEG;IACH,IAAI,WAAW,IAAI,KAAK,CAAC,gBAAgB,CAAC,CAGzC;IAED;;;OAGG;IACH,SAAS,CAAC,gBAAgB,IAAI,IAAI;IAoBlC,IAAI,KAAK,IAAI,MAAM,CA0BlB;CAEJ"}
@@ -20,10 +20,41 @@ const tslib_1 = require("tslib");
20
20
  const inversify_1 = require("@theia/core/shared/inversify");
21
21
  const color_registry_1 = require("@theia/core/lib/browser/color-registry");
22
22
  const theming_1 = require("@theia/core/lib/browser/theming");
23
+ const core_1 = require("@theia/core");
23
24
  const terminal_preferences_1 = require("../common/terminal-preferences");
24
25
  let TerminalThemeService = class TerminalThemeService {
26
+ constructor() {
27
+ this.onDidChangeEmitter = new core_1.Emitter();
28
+ }
29
+ /**
30
+ * Fires when the color theme changes, and when a change in the `ColorRegistry` changes the terminal colors.
31
+ */
25
32
  get onDidChange() {
26
- return this.themeService.onDidColorThemeChange;
33
+ this.listenForChanges();
34
+ return this.onDidChangeEmitter.event;
35
+ }
36
+ /**
37
+ * Subscribes on first use rather than at construction, so that the theme listener runs after the one that applies
38
+ * a new theme to Monaco, whose color registry the terminal colors are read from.
39
+ */
40
+ listenForChanges() {
41
+ if (this.appliedTheme !== undefined) {
42
+ return;
43
+ }
44
+ this.appliedTheme = JSON.stringify(this.theme);
45
+ this.themeService.onDidColorThemeChange(event => {
46
+ this.appliedTheme = JSON.stringify(this.theme);
47
+ this.onDidChangeEmitter.fire(event);
48
+ });
49
+ // The registry fires on every register() call and assigning the xterm theme repaints the whole terminal,
50
+ // so only fire when the resolved terminal colors change.
51
+ this.colorRegistry.onDidChange(() => {
52
+ const theme = JSON.stringify(this.theme);
53
+ if (theme !== this.appliedTheme) {
54
+ this.appliedTheme = theme;
55
+ this.onDidChangeEmitter.fire({ newTheme: this.themeService.getCurrentTheme() });
56
+ }
57
+ });
27
58
  }
28
59
  get theme() {
29
60
  const foregroundColor = this.colorRegistry.getCurrentColor('terminal.foreground');
@@ -1 +1 @@
1
- {"version":3,"file":"terminal-theme-service.js","sourceRoot":"","sources":["../../src/browser/terminal-theme-service.ts"],"names":[],"mappings":";AAAA,gFAAgF;AAChF,yCAAyC;AACzC,EAAE;AACF,2EAA2E;AAC3E,mEAAmE;AACnE,wCAAwC;AACxC,EAAE;AACF,4EAA4E;AAC5E,8EAA8E;AAC9E,6EAA6E;AAC7E,yDAAyD;AACzD,uDAAuD;AACvD,EAAE;AACF,gFAAgF;AAChF,gFAAgF;;;;AAGhF,4DAAkE;AAClE,2EAAuE;AACvE,6DAA+D;AAG/D,yEAAsE;AAG/D,IAAM,oBAAoB,GAA1B,MAAM,oBAAoB;IAK7B,IAAI,WAAW;QACX,OAAO,IAAI,CAAC,YAAY,CAAC,qBAAqB,CAAC;IACnD,CAAC;IAED,IAAI,KAAK;QACL,MAAM,eAAe,GAAG,IAAI,CAAC,aAAa,CAAC,eAAe,CAAC,qBAAqB,CAAC,CAAC;QAClF,MAAM,eAAe,GAAG,IAAI,CAAC,aAAa,CAAC,eAAe,CAAC,qBAAqB,CAAC,IAAI,IAAI,CAAC,aAAa,CAAC,eAAe,CAAC,kBAAkB,CAAC,CAAC;QAC5I,MAAM,WAAW,GAAG,IAAI,CAAC,aAAa,CAAC,eAAe,CAAC,2BAA2B,CAAC,IAAI,eAAe,CAAC;QACvG,MAAM,iBAAiB,GAAG,IAAI,CAAC,aAAa,CAAC,eAAe,CAAC,2BAA2B,CAAC,IAAI,eAAe,CAAC;QAC7G,MAAM,wBAAwB,GAAG,IAAI,CAAC,aAAa,CAAC,eAAe,CAAC,8BAA8B,CAAC,CAAC;QACpG,MAAM,2BAA2B,GAAG,IAAI,CAAC,aAAa,CAAC,eAAe,CAAC,sCAAsC,CAAC,CAAC;QAC/G,MAAM,wBAAwB,GAAG,IAAI,CAAC,aAAa,CAAC,eAAe,CAAC,8BAA8B,CAAC,CAAC;QAEpG,MAAM,KAAK,GAAW;YAClB,UAAU,EAAE,eAAe;YAC3B,UAAU,EAAE,eAAe;YAC3B,MAAM,EAAE,WAAW;YACnB,YAAY,EAAE,iBAAiB;YAC/B,mBAAmB,EAAE,wBAAwB;YAC7C,2BAA2B,EAAE,2BAA2B;YACxD,mBAAmB,EAAE,wBAAwB;SAChD,CAAC;QACF,wCAAwC;QACxC,KAAK,MAAM,EAAE,IAAI,2CAAoB,EAAE,CAAC;YACpC,MAAM,OAAO,GAAG,EAAE,CAAC,SAAS,CAAC,EAAE,CAAC,CAAC;YACjC,MAAM,SAAS,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,WAAW,EAAE,GAAG,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;YACrE,8DAA8D;YAC7D,KAAa,CAAC,SAAS,CAAC,GAAG,IAAI,CAAC,aAAa,CAAC,eAAe,CAAC,EAAE,CAAC,CAAC;QACvE,CAAC;QACD,OAAO,KAAK,CAAC;IACjB,CAAC;CAEJ,CAAA;AArCY,oDAAoB;AAEa;IAAzC,IAAA,kBAAM,EAAC,8BAAa,CAAC;sCAAmC,8BAAa;2DAAC;AAC9B;IAAxC,IAAA,kBAAM,EAAC,sBAAY,CAAC;sCAAkC,sBAAY;0DAAC;+BAH3D,oBAAoB;IADhC,IAAA,sBAAU,GAAE;GACA,oBAAoB,CAqChC"}
1
+ {"version":3,"file":"terminal-theme-service.js","sourceRoot":"","sources":["../../src/browser/terminal-theme-service.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=terminal-theme-service.spec.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"terminal-theme-service.spec.d.ts","sourceRoot":"","sources":["../../src/browser/terminal-theme-service.spec.ts"],"names":[],"mappings":""}
@@ -0,0 +1,113 @@
1
+ "use strict";
2
+ // *****************************************************************************
3
+ // Copyright (C) 2026 CodeSignal and others.
4
+ //
5
+ // This program and the accompanying materials are made available under the
6
+ // terms of the Eclipse Public License v. 2.0 which is available at
7
+ // http://www.eclipse.org/legal/epl-2.0.
8
+ //
9
+ // This Source Code may also be made available under the following Secondary
10
+ // Licenses when the conditions for such availability set forth in the Eclipse
11
+ // Public License v. 2.0 are satisfied: GNU General Public License, version 2
12
+ // with the GNU Classpath Exception which is available at
13
+ // https://www.gnu.org/software/classpath/license.html.
14
+ //
15
+ // SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0
16
+ // *****************************************************************************
17
+ Object.defineProperty(exports, "__esModule", { value: true });
18
+ const tslib_1 = require("tslib");
19
+ const jsdom_1 = require("@theia/core/lib/browser/test/jsdom");
20
+ let disableJSDOM = (0, jsdom_1.enableJSDOM)();
21
+ const chai_1 = require("chai");
22
+ const inversify_1 = require("@theia/core/shared/inversify");
23
+ const core_1 = require("@theia/core");
24
+ const color_registry_1 = require("@theia/core/lib/browser/color-registry");
25
+ const theming_1 = require("@theia/core/lib/browser/theming");
26
+ const terminal_theme_service_1 = require("./terminal-theme-service");
27
+ disableJSDOM();
28
+ class TestColorRegistry extends color_registry_1.ColorRegistry {
29
+ constructor() {
30
+ super(...arguments);
31
+ this.colors = new Map();
32
+ }
33
+ getCurrentColor(id) {
34
+ return this.colors.get(id);
35
+ }
36
+ set(id, value) {
37
+ this.colors.set(id, value);
38
+ this.fireDidChange();
39
+ }
40
+ touch() {
41
+ this.fireDidChange();
42
+ }
43
+ }
44
+ let SubclassWithPostConstruct = class SubclassWithPostConstruct extends terminal_theme_service_1.TerminalThemeService {
45
+ setup() { }
46
+ };
47
+ tslib_1.__decorate([
48
+ (0, inversify_1.postConstruct)(),
49
+ tslib_1.__metadata("design:type", Function),
50
+ tslib_1.__metadata("design:paramtypes", []),
51
+ tslib_1.__metadata("design:returntype", void 0)
52
+ ], SubclassWithPostConstruct.prototype, "setup", null);
53
+ SubclassWithPostConstruct = tslib_1.__decorate([
54
+ (0, inversify_1.injectable)()
55
+ ], SubclassWithPostConstruct);
56
+ const DARK = { id: 'dark', type: 'dark', label: 'Dark' };
57
+ describe('TerminalThemeService', () => {
58
+ let colors;
59
+ let themeChange;
60
+ let service;
61
+ let changes;
62
+ before(() => disableJSDOM = (0, jsdom_1.enableJSDOM)());
63
+ after(() => disableJSDOM());
64
+ function create(serviceClass) {
65
+ colors = new TestColorRegistry();
66
+ themeChange = new core_1.Emitter();
67
+ const themeService = { onDidColorThemeChange: themeChange.event, getCurrentTheme: () => DARK };
68
+ const container = new inversify_1.Container();
69
+ container.bind(color_registry_1.ColorRegistry).toConstantValue(colors);
70
+ container.bind(theming_1.ThemeService).toConstantValue(themeService);
71
+ container.bind(terminal_theme_service_1.TerminalThemeService).to(serviceClass).inSingletonScope();
72
+ const created = container.get(terminal_theme_service_1.TerminalThemeService);
73
+ changes = [];
74
+ created.onDidChange(event => changes.push(event));
75
+ return created;
76
+ }
77
+ beforeEach(() => service = create(terminal_theme_service_1.TerminalThemeService));
78
+ it('should report a terminal color that changes in the color registry', () => {
79
+ colors.set('terminal.selectionForeground', '#ff0000');
80
+ (0, chai_1.expect)(changes).to.have.lengthOf(1);
81
+ (0, chai_1.expect)(service.theme.selectionForeground).to.equal('#ff0000');
82
+ });
83
+ it('should not report color registry changes that leave the terminal colors as they are', () => {
84
+ colors.set('editor.background', '#000000');
85
+ colors.touch();
86
+ (0, chai_1.expect)(changes).to.be.empty;
87
+ });
88
+ it('should report color theme changes', () => {
89
+ const event = { newTheme: DARK };
90
+ themeChange.fire(event);
91
+ (0, chai_1.expect)(changes).to.deep.equal([event]);
92
+ });
93
+ it('should report each change once to each of several listeners', () => {
94
+ const second = [];
95
+ service.onDidChange(event => second.push(event));
96
+ colors.set('terminal.selectionForeground', '#ff0000');
97
+ themeChange.fire({ newTheme: DARK });
98
+ (0, chai_1.expect)([changes.length, second.length]).to.deep.equal([2, 2]);
99
+ });
100
+ it('should report changes for a subclass with its own post-construct method', () => {
101
+ service = create(SubclassWithPostConstruct);
102
+ themeChange.fire({ newTheme: DARK });
103
+ colors.set('terminal.selectionForeground', '#ff0000');
104
+ (0, chai_1.expect)(changes).to.have.lengthOf(2);
105
+ });
106
+ it('should not report a color registry change that a color theme change already applied', () => {
107
+ colors.colors.set('terminal.background', '#111111');
108
+ themeChange.fire({ newTheme: DARK });
109
+ colors.touch();
110
+ (0, chai_1.expect)(changes).to.have.lengthOf(1);
111
+ });
112
+ });
113
+ //# sourceMappingURL=terminal-theme-service.spec.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"terminal-theme-service.spec.js","sourceRoot":"","sources":["../../src/browser/terminal-theme-service.spec.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,15 +1,15 @@
1
1
  {
2
2
  "name": "@theia/terminal",
3
- "version": "1.77.0-next.84+28288b6e7",
3
+ "version": "1.77.0-next.88+99b9e381a",
4
4
  "description": "Theia - Terminal Extension",
5
5
  "dependencies": {
6
- "@theia/core": "1.77.0-next.84+28288b6e7",
7
- "@theia/editor": "1.77.0-next.84+28288b6e7",
8
- "@theia/file-search": "1.77.0-next.84+28288b6e7",
9
- "@theia/filesystem": "1.77.0-next.84+28288b6e7",
10
- "@theia/process": "1.77.0-next.84+28288b6e7",
11
- "@theia/variable-resolver": "1.77.0-next.84+28288b6e7",
12
- "@theia/workspace": "1.77.0-next.84+28288b6e7",
6
+ "@theia/core": "1.77.0-next.88+99b9e381a",
7
+ "@theia/editor": "1.77.0-next.88+99b9e381a",
8
+ "@theia/file-search": "1.77.0-next.88+99b9e381a",
9
+ "@theia/filesystem": "1.77.0-next.88+99b9e381a",
10
+ "@theia/process": "1.77.0-next.88+99b9e381a",
11
+ "@theia/variable-resolver": "1.77.0-next.88+99b9e381a",
12
+ "@theia/workspace": "1.77.0-next.88+99b9e381a",
13
13
  "tslib": "^2.8.1",
14
14
  "xterm": "^5.3.0",
15
15
  "xterm-addon-fit": "^0.8.0",
@@ -59,5 +59,5 @@
59
59
  "nyc": {
60
60
  "extends": "../../configs/nyc.json"
61
61
  },
62
- "gitHead": "28288b6e714db6a4941d4aee74680ea6a6ceaff9"
62
+ "gitHead": "99b9e381abb93101610d188372fb8a9023ea80bd"
63
63
  }
@@ -0,0 +1,128 @@
1
+ // *****************************************************************************
2
+ // Copyright (C) 2026 CodeSignal and others.
3
+ //
4
+ // This program and the accompanying materials are made available under the
5
+ // terms of the Eclipse Public License v. 2.0 which is available at
6
+ // http://www.eclipse.org/legal/epl-2.0.
7
+ //
8
+ // This Source Code may also be made available under the following Secondary
9
+ // Licenses when the conditions for such availability set forth in the Eclipse
10
+ // Public License v. 2.0 are satisfied: GNU General Public License, version 2
11
+ // with the GNU Classpath Exception which is available at
12
+ // https://www.gnu.org/software/classpath/license.html.
13
+ //
14
+ // SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0
15
+ // *****************************************************************************
16
+
17
+ import { enableJSDOM } from '@theia/core/lib/browser/test/jsdom';
18
+ let disableJSDOM = enableJSDOM();
19
+
20
+ import { expect } from 'chai';
21
+ import { Container, injectable, postConstruct } from '@theia/core/shared/inversify';
22
+ import { Emitter } from '@theia/core';
23
+ import { ColorRegistry } from '@theia/core/lib/browser/color-registry';
24
+ import { ThemeService } from '@theia/core/lib/browser/theming';
25
+ import { Theme, ThemeChangeEvent } from '@theia/core/lib/common/theme';
26
+ import { TerminalThemeService } from './terminal-theme-service';
27
+
28
+ disableJSDOM();
29
+
30
+ class TestColorRegistry extends ColorRegistry {
31
+ readonly colors = new Map<string, string>();
32
+
33
+ override getCurrentColor(id: string): string | undefined {
34
+ return this.colors.get(id);
35
+ }
36
+
37
+ set(id: string, value: string): void {
38
+ this.colors.set(id, value);
39
+ this.fireDidChange();
40
+ }
41
+
42
+ touch(): void {
43
+ this.fireDidChange();
44
+ }
45
+ }
46
+
47
+ @injectable()
48
+ class SubclassWithPostConstruct extends TerminalThemeService {
49
+ @postConstruct()
50
+ protected setup(): void { }
51
+ }
52
+
53
+ const DARK: Theme = { id: 'dark', type: 'dark', label: 'Dark' };
54
+
55
+ describe('TerminalThemeService', () => {
56
+
57
+ let colors: TestColorRegistry;
58
+ let themeChange: Emitter<ThemeChangeEvent>;
59
+ let service: TerminalThemeService;
60
+ let changes: ThemeChangeEvent[];
61
+
62
+ before(() => disableJSDOM = enableJSDOM());
63
+ after(() => disableJSDOM());
64
+
65
+ function create(serviceClass: typeof TerminalThemeService): TerminalThemeService {
66
+ colors = new TestColorRegistry();
67
+ themeChange = new Emitter<ThemeChangeEvent>();
68
+ const themeService = { onDidColorThemeChange: themeChange.event, getCurrentTheme: () => DARK } as unknown as ThemeService;
69
+ const container = new Container();
70
+ container.bind(ColorRegistry).toConstantValue(colors);
71
+ container.bind(ThemeService).toConstantValue(themeService);
72
+ container.bind(TerminalThemeService).to(serviceClass).inSingletonScope();
73
+ const created = container.get(TerminalThemeService);
74
+ changes = [];
75
+ created.onDidChange(event => changes.push(event));
76
+ return created;
77
+ }
78
+
79
+ beforeEach(() => service = create(TerminalThemeService));
80
+
81
+ it('should report a terminal color that changes in the color registry', () => {
82
+ colors.set('terminal.selectionForeground', '#ff0000');
83
+
84
+ expect(changes).to.have.lengthOf(1);
85
+ expect(service.theme.selectionForeground).to.equal('#ff0000');
86
+ });
87
+
88
+ it('should not report color registry changes that leave the terminal colors as they are', () => {
89
+ colors.set('editor.background', '#000000');
90
+ colors.touch();
91
+
92
+ expect(changes).to.be.empty;
93
+ });
94
+
95
+ it('should report color theme changes', () => {
96
+ const event = { newTheme: DARK };
97
+ themeChange.fire(event);
98
+
99
+ expect(changes).to.deep.equal([event]);
100
+ });
101
+
102
+ it('should report each change once to each of several listeners', () => {
103
+ const second: ThemeChangeEvent[] = [];
104
+ service.onDidChange(event => second.push(event));
105
+
106
+ colors.set('terminal.selectionForeground', '#ff0000');
107
+ themeChange.fire({ newTheme: DARK });
108
+
109
+ expect([changes.length, second.length]).to.deep.equal([2, 2]);
110
+ });
111
+
112
+ it('should report changes for a subclass with its own post-construct method', () => {
113
+ service = create(SubclassWithPostConstruct);
114
+
115
+ themeChange.fire({ newTheme: DARK });
116
+ colors.set('terminal.selectionForeground', '#ff0000');
117
+
118
+ expect(changes).to.have.lengthOf(2);
119
+ });
120
+
121
+ it('should not report a color registry change that a color theme change already applied', () => {
122
+ colors.colors.set('terminal.background', '#111111');
123
+ themeChange.fire({ newTheme: DARK });
124
+ colors.touch();
125
+
126
+ expect(changes).to.have.lengthOf(1);
127
+ });
128
+ });
@@ -19,7 +19,7 @@ import { injectable, inject } from '@theia/core/shared/inversify';
19
19
  import { ColorRegistry } from '@theia/core/lib/browser/color-registry';
20
20
  import { ThemeService } from '@theia/core/lib/browser/theming';
21
21
  import { ThemeChangeEvent } from '@theia/core/lib/common/theme';
22
- import { Event } from '@theia/core';
22
+ import { Emitter, Event } from '@theia/core';
23
23
  import { terminalAnsiColorMap } from '../common/terminal-preferences';
24
24
 
25
25
  @injectable()
@@ -28,8 +28,39 @@ export class TerminalThemeService {
28
28
  @inject(ColorRegistry) protected readonly colorRegistry: ColorRegistry;
29
29
  @inject(ThemeService) protected readonly themeService: ThemeService;
30
30
 
31
+ protected readonly onDidChangeEmitter = new Emitter<ThemeChangeEvent>();
32
+ protected appliedTheme: string | undefined;
33
+
34
+ /**
35
+ * Fires when the color theme changes, and when a change in the `ColorRegistry` changes the terminal colors.
36
+ */
31
37
  get onDidChange(): Event<ThemeChangeEvent> {
32
- return this.themeService.onDidColorThemeChange;
38
+ this.listenForChanges();
39
+ return this.onDidChangeEmitter.event;
40
+ }
41
+
42
+ /**
43
+ * Subscribes on first use rather than at construction, so that the theme listener runs after the one that applies
44
+ * a new theme to Monaco, whose color registry the terminal colors are read from.
45
+ */
46
+ protected listenForChanges(): void {
47
+ if (this.appliedTheme !== undefined) {
48
+ return;
49
+ }
50
+ this.appliedTheme = JSON.stringify(this.theme);
51
+ this.themeService.onDidColorThemeChange(event => {
52
+ this.appliedTheme = JSON.stringify(this.theme);
53
+ this.onDidChangeEmitter.fire(event);
54
+ });
55
+ // The registry fires on every register() call and assigning the xterm theme repaints the whole terminal,
56
+ // so only fire when the resolved terminal colors change.
57
+ this.colorRegistry.onDidChange(() => {
58
+ const theme = JSON.stringify(this.theme);
59
+ if (theme !== this.appliedTheme) {
60
+ this.appliedTheme = theme;
61
+ this.onDidChangeEmitter.fire({ newTheme: this.themeService.getCurrentTheme() });
62
+ }
63
+ });
33
64
  }
34
65
 
35
66
  get theme(): ITheme {