@theia/core
Version:
Theia is a cloud & desktop IDE framework implemented in TypeScript.
121 lines (106 loc) • 4.7 kB
text/typescript
// *****************************************************************************
// Copyright (C) 2022 TypeFox and others.
//
// This program and the accompanying materials are made available under the
// terms of the Eclipse Public License v. 2.0 which is available at
// http://www.eclipse.org/legal/epl-2.0.
//
// This Source Code may also be made available under the following Secondary
// Licenses when the conditions for such availability set forth in the Eclipse
// Public License v. 2.0 are satisfied: GNU General Public License, version 2
// with the GNU Classpath Exception which is available at
// https://www.gnu.org/software/classpath/license.html.
//
// SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0
// *****************************************************************************
import { inject, injectable, named, postConstruct } from 'inversify';
import { escapeRegExpCharacters } from '../../common/strings';
import { Emitter, Event } from '../../common/event';
import { CorePreferences } from '../core-preferences';
import { FrontendApplicationConfigProvider } from '../frontend-application-config-provider';
import { ContributionProvider } from '../../common';
export const WindowTitleContribution = Symbol('WindowTitleAddOnContribution');
export interface WindowTitleContribution {
enhanceTitle(title: string, parts: Map<string, string | undefined>): string;
}
export const InitialWindowTitleParts = {
activeEditorShort: undefined,
activeEditorMedium: undefined,
activeEditorLong: undefined,
activeFolderShort: undefined,
activeFolderMedium: undefined,
activeFolderLong: undefined,
folderName: undefined,
folderPath: undefined,
rootName: undefined,
rootPath: undefined,
appName: FrontendApplicationConfigProvider.get().applicationName,
remoteName: undefined,
dirty: undefined,
developmentHost: undefined
};
export class WindowTitleService {
protected readonly preferences: CorePreferences;
protected readonly titleContributions: ContributionProvider<WindowTitleContribution>;
protected _title = '';
protected titleTemplate?: string;
protected onDidChangeTitleEmitter = new Emitter<string>();
protected titleParts = new Map<string, string | undefined>(Object.entries(InitialWindowTitleParts));
protected separator = ' - ';
protected init(): void {
this.titleTemplate = this.preferences['window.title'];
this.separator = this.preferences['window.titleSeparator'];
this.updateTitle();
this.preferences.onPreferenceChanged(e => {
if (e.preferenceName === 'window.title') {
this.titleTemplate = e.newValue;
this.updateTitle();
} else if (e.preferenceName === 'window.titleSeparator') {
this.separator = e.newValue;
this.updateTitle();
}
});
}
get onDidChangeTitle(): Event<string> {
return this.onDidChangeTitleEmitter.event;
}
get title(): string {
return this._title;
}
update(parts: Record<string, string | undefined>): void {
for (const [key, value] of Object.entries(parts)) {
this.titleParts.set(key, value);
}
this.updateTitle();
}
protected updateTitle(): void {
if (!this.titleTemplate) {
this._title = '';
} else {
let title = this.titleTemplate;
for (const [key, value] of this.titleParts.entries()) {
if (key !== 'developmentHost') {
const label = `$\{${key}\}`;
const regex = new RegExp(escapeRegExpCharacters(label), 'g');
title = title.replace(regex, value ?? '');
}
}
const separatedTitle = title.split('${separator}').filter(e => e.trim().length > 0);
this._title = separatedTitle.join(this.separator);
const contributions = this.titleContributions.getContributions();
for (const contribution of contributions) {
this._title = contribution.enhanceTitle(this.title, this.titleParts);
}
}
const developmentHost = this.titleParts.get('developmentHost');
if (developmentHost) {
this._title = developmentHost + this.separator + this._title;
}
document.title = this._title || FrontendApplicationConfigProvider.get().applicationName;
this.onDidChangeTitleEmitter.fire(this._title);
}
}