Skip to content

Commit

Permalink
Improve widget specific status bar handling
Browse files Browse the repository at this point in the history
  • Loading branch information
msujew committed Oct 1, 2024
1 parent 363865f commit d08794b
Show file tree
Hide file tree
Showing 14 changed files with 234 additions and 132 deletions.
5 changes: 5 additions & 0 deletions packages/core/src/browser/frontend-application-module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,7 @@ import { bindTreePreferences } from './tree';
import { OpenWithService } from './open-with-service';
import { ViewColumnService } from './shell/view-column-service';
import { DomInputUndoRedoHandler, UndoRedoHandler, UndoRedoHandlerService } from './undo-redo-handler';
import { WidgetStatusBarContribution, WidgetStatusBarService } from './widget-status-bar-service';

export { bindResourceProvider, bindMessageService, bindPreferenceService };

Expand Down Expand Up @@ -471,4 +472,8 @@ export const frontendApplicationModule = new ContainerModule((bind, _unbind, _is
bindContributionProvider(bind, UndoRedoHandler);
bind(DomInputUndoRedoHandler).toSelf().inSingletonScope();
bind(UndoRedoHandler).toService(DomInputUndoRedoHandler);

bind(WidgetStatusBarService).toSelf().inSingletonScope();
bind(FrontendApplicationContribution).toService(WidgetStatusBarService);
bindContributionProvider(bind, WidgetStatusBarContribution);
});
1 change: 1 addition & 0 deletions packages/core/src/browser/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,3 +48,4 @@ export * from './styling-service';
export * from './hover-service';
export * from './saveable-service';
export * from './undo-redo-handler';
export * from './widget-status-bar-service';
84 changes: 84 additions & 0 deletions packages/core/src/browser/widget-status-bar-service.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
// *****************************************************************************
// Copyright (C) 2024 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 } from 'inversify';
import { Widget } from './widgets';
import { StatusBar } from './status-bar';
import { FrontendApplicationContribution } from './frontend-application-contribution';
import { ContributionProvider } from '../common';
import { FrontendApplication } from './frontend-application';

export const WidgetStatusBarContribution = Symbol('WidgetStatusBarContribution');

export interface WidgetStatusBarContribution<T extends Widget> {
canHandle(widget: Widget): widget is T;
activate(statusBar: StatusBar, widget: T): void;
deactivate(statusBar: StatusBar): void;
}

/**
* Creates an empty {@link WidgetStatusBarContribution} that does nothing.
* Useful for widgets that are not handled by any other contribution, for example:
* * Settings widget
* * Welcome widget
* * Webview widget
*
* @param prototype Prototype to identify the kind of the widget.
* @returns An empty {@link WidgetStatusBarContribution}.
*/
export function noopWidgetStatusBarContribution(prototype: Function): WidgetStatusBarContribution<Widget> {
return {
canHandle(widget: Widget): widget is Widget {
return widget instanceof prototype;
},
activate: () => { },
deactivate: () => { }
};
}

@injectable()
export class WidgetStatusBarService implements FrontendApplicationContribution {

@inject(ContributionProvider) @named(WidgetStatusBarContribution)
protected readonly contributionProvider: ContributionProvider<WidgetStatusBarContribution<Widget>>;

@inject(StatusBar)
protected readonly statusBar: StatusBar;

onStart(app: FrontendApplication): void {
app.shell.onDidChangeCurrentWidget(event => {
if (event.newValue) {
this.show(event.newValue);
}
});
}

protected show(widget: Widget): void {
const contributions = this.contributionProvider.getContributions();
// If any contribution can handle the widget, activate it
// If none can, keep everything as is
if (contributions.some(contribution => contribution.canHandle(widget))) {
for (const contribution of contributions) {
// Deactivate all contributions
contribution.deactivate(this.statusBar);
if (contribution.canHandle(widget)) {
// Selectively re-activate them
contribution.activate(this.statusBar, widget);
}
}
}
}
}
59 changes: 33 additions & 26 deletions packages/editor/src/browser/editor-contribution.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,9 @@ import { injectable, inject, optional } from '@theia/core/shared/inversify';
import { StatusBarAlignment, StatusBar } from '@theia/core/lib/browser/status-bar/status-bar';
import {
FrontendApplicationContribution, DiffUris, DockLayout,
QuickInputService, KeybindingRegistry, KeybindingContribution, SHELL_TABBAR_CONTEXT_SPLIT, ApplicationShell
QuickInputService, KeybindingRegistry, KeybindingContribution, SHELL_TABBAR_CONTEXT_SPLIT, ApplicationShell,
WidgetStatusBarContribution,
Widget
} from '@theia/core/lib/browser';
import { ContextKeyService } from '@theia/core/lib/browser/context-key-service';
import { CommandHandler, DisposableCollection, MenuContribution, MenuModelRegistry } from '@theia/core';
Expand All @@ -33,9 +35,9 @@ import { EditorWidget } from './editor-widget';
import { EditorLanguageStatusService } from './language-status/editor-language-status-service';

@injectable()
export class EditorContribution implements FrontendApplicationContribution, CommandContribution, KeybindingContribution, MenuContribution {
export class EditorContribution implements FrontendApplicationContribution,
CommandContribution, KeybindingContribution, MenuContribution, WidgetStatusBarContribution<EditorWidget> {

@inject(StatusBar) protected readonly statusBar: StatusBar;
@inject(EditorManager) protected readonly editorManager: EditorManager;
@inject(EditorLanguageStatusService) protected readonly languageStatusService: EditorLanguageStatusService;
@inject(ApplicationShell) protected readonly shell: ApplicationShell;
Expand All @@ -48,9 +50,6 @@ export class EditorContribution implements FrontendApplicationContribution, Comm

onStart(): void {
this.initEditorContextKeys();

this.updateStatusBar();
this.editorManager.onCurrentEditorChanged(() => this.updateStatusBar());
}

protected initEditorContextKeys(): void {
Expand All @@ -72,33 +71,41 @@ export class EditorContribution implements FrontendApplicationContribution, Comm
}

protected readonly toDisposeOnCurrentEditorChanged = new DisposableCollection();
protected updateStatusBar(): void {

canHandle(widget: Widget): widget is EditorWidget {
return widget instanceof EditorWidget;
}

activate(statusBar: StatusBar, widget: EditorWidget): void {
this.toDisposeOnCurrentEditorChanged.dispose();
const editor = widget.editor;
this.updateLanguageStatus(statusBar, editor);
this.updateEncodingStatus(statusBar, editor);
this.setCursorPositionStatus(statusBar, editor);
this.toDisposeOnCurrentEditorChanged.pushAll([
editor.onLanguageChanged(() => this.updateLanguageStatus(statusBar, editor)),
editor.onEncodingChanged(() => this.updateEncodingStatus(statusBar, editor)),
editor.onCursorPositionChanged(() => this.setCursorPositionStatus(statusBar, editor))
]);
}

const widget = this.editorManager.currentEditor;
const editor = widget && widget.editor;
this.updateLanguageStatus(editor);
this.updateEncodingStatus(editor);
this.setCursorPositionStatus(editor);
if (editor) {
this.toDisposeOnCurrentEditorChanged.pushAll([
editor.onLanguageChanged(() => this.updateLanguageStatus(editor)),
editor.onEncodingChanged(() => this.updateEncodingStatus(editor)),
editor.onCursorPositionChanged(() => this.setCursorPositionStatus(editor))
]);
}
deactivate(statusBar: StatusBar): void {
this.toDisposeOnCurrentEditorChanged.dispose();
this.updateLanguageStatus(statusBar, undefined);
this.updateEncodingStatus(statusBar, undefined);
this.setCursorPositionStatus(statusBar, undefined);
}

protected updateLanguageStatus(editor: TextEditor | undefined): void {
protected updateLanguageStatus(statusBar: StatusBar, editor: TextEditor | undefined): void {
this.languageStatusService.updateLanguageStatus(editor);
}

protected updateEncodingStatus(editor: TextEditor | undefined): void {
protected updateEncodingStatus(statusBar: StatusBar, editor: TextEditor | undefined): void {
if (!editor) {
this.statusBar.removeElement('editor-status-encoding');
statusBar.removeElement('editor-status-encoding');
return;
}
this.statusBar.setElement('editor-status-encoding', {
statusBar.setElement('editor-status-encoding', {
text: SUPPORTED_ENCODINGS[editor.getEncoding()].labelShort,
alignment: StatusBarAlignment.RIGHT,
priority: 10,
Expand All @@ -107,13 +114,13 @@ export class EditorContribution implements FrontendApplicationContribution, Comm
});
}

protected setCursorPositionStatus(editor: TextEditor | undefined): void {
protected setCursorPositionStatus(statusBar: StatusBar, editor: TextEditor | undefined): void {
if (!editor) {
this.statusBar.removeElement('editor-status-cursor-position');
statusBar.removeElement('editor-status-cursor-position');
return;
}
const { cursor } = editor;
this.statusBar.setElement('editor-status-cursor-position', {
statusBar.setElement('editor-status-cursor-position', {
text: nls.localizeByDefault('Ln {0}, Col {1}', cursor.line + 1, editor.getVisibleColumn(cursor)),
alignment: StatusBarAlignment.RIGHT,
priority: 100,
Expand Down
11 changes: 8 additions & 3 deletions packages/editor/src/browser/editor-frontend-module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ import '../../src/browser/language-status/editor-language-status.css';

import { ContainerModule } from '@theia/core/shared/inversify';
import { CommandContribution, MenuContribution } from '@theia/core/lib/common';
import { OpenHandler, WidgetFactory, FrontendApplicationContribution, KeybindingContribution } from '@theia/core/lib/browser';
import { OpenHandler, WidgetFactory, FrontendApplicationContribution, KeybindingContribution, WidgetStatusBarContribution } from '@theia/core/lib/browser';
import { VariableContribution } from '@theia/variable-resolver/lib/browser';
import { EditorManager, EditorAccess, ActiveEditorAccess, CurrentEditorAccess } from './editor-manager';
import { EditorContribution } from './editor-contribution';
Expand Down Expand Up @@ -59,7 +59,6 @@ export default new ContainerModule(bind => {
bind(KeybindingContribution).toService(EditorKeybindingContribution);

bind(EditorContribution).toSelf().inSingletonScope();
bind(FrontendApplicationContribution).toService(EditorContribution);
bind(EditorLanguageStatusService).toSelf().inSingletonScope();

bind(EditorLineNumberContribution).toSelf().inSingletonScope();
Expand All @@ -73,7 +72,13 @@ export default new ContainerModule(bind => {

bind(VariableContribution).to(EditorVariableContribution).inSingletonScope();

[CommandContribution, KeybindingContribution, MenuContribution].forEach(serviceIdentifier => {
[
FrontendApplicationContribution,
WidgetStatusBarContribution,
CommandContribution,
KeybindingContribution,
MenuContribution
].forEach(serviceIdentifier => {
bind(serviceIdentifier).toService(EditorContribution);
});
bind(QuickEditorService).toSelf().inSingletonScope();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,14 @@
import { GettingStartedContribution } from './getting-started-contribution';
import { ContainerModule, interfaces } from '@theia/core/shared/inversify';
import { GettingStartedWidget } from './getting-started-widget';
import { WidgetFactory, FrontendApplicationContribution, bindViewContribution } from '@theia/core/lib/browser';
import { WidgetFactory, FrontendApplicationContribution, bindViewContribution, noopWidgetStatusBarContribution, WidgetStatusBarContribution } from '@theia/core/lib/browser';
import { bindGettingStartedPreferences } from './getting-started-preferences';
import '../../src/browser/style/index.css';

export default new ContainerModule((bind: interfaces.Bind) => {
bindViewContribution(bind, GettingStartedContribution);
bind(FrontendApplicationContribution).toService(GettingStartedContribution);
bind(WidgetStatusBarContribution).toConstantValue(noopWidgetStatusBarContribution(GettingStartedWidget));
bind(GettingStartedWidget).toSelf();
bind(WidgetFactory).toDynamicValue(context => ({
id: GettingStartedWidget.ID,
Expand Down
3 changes: 2 additions & 1 deletion packages/keymaps/src/browser/keymaps-frontend-module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ import { KeymapsFrontendContribution } from './keymaps-frontend-contribution';
import { CommandContribution, MenuContribution } from '@theia/core/lib/common';
import { KeybindingContribution } from '@theia/core/lib/browser/keybinding';
import { TabBarToolbarContribution } from '@theia/core/lib/browser/shell/tab-bar-toolbar';
import { WidgetFactory } from '@theia/core/lib/browser';
import { noopWidgetStatusBarContribution, WidgetFactory, WidgetStatusBarContribution } from '@theia/core/lib/browser';
import { KeybindingWidget } from './keybindings-widget';
import { KeybindingSchemaUpdater } from './keybinding-schema-updater';
import { JsonSchemaContribution } from '@theia/core/lib/browser/json-schema-store';
Expand All @@ -41,4 +41,5 @@ export default new ContainerModule(bind => {
})).inSingletonScope();
bind(KeybindingSchemaUpdater).toSelf().inSingletonScope();
bind(JsonSchemaContribution).toService(KeybindingSchemaUpdater);
bind(WidgetStatusBarContribution).toConstantValue(noopWidgetStatusBarContribution(KeybindingWidget));
});
5 changes: 3 additions & 2 deletions packages/monaco/src/browser/monaco-frontend-module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,8 @@ import {
FrontendApplicationContribution, KeybindingContribution,
PreferenceService, PreferenceSchemaProvider, createPreferenceProxy,
PreferenceScope, PreferenceChange, OVERRIDE_PROPERTY_PATTERN, QuickInputService, StylingParticipant, WebSocketConnectionProvider,
UndoRedoHandler
UndoRedoHandler,
WidgetStatusBarContribution
} from '@theia/core/lib/browser';
import { TextEditorProvider, DiffNavigatorProvider, TextEditor } from '@theia/editor/lib/browser';
import { MonacoEditorProvider, MonacoEditorFactory } from './monaco-editor-provider';
Expand Down Expand Up @@ -135,7 +136,7 @@ export default new ContainerModule((bind, unbind, isBound, rebind) => {
bind(FrontendApplicationContribution).toService(MonacoFormattingConflictsContribution);

bind(MonacoStatusBarContribution).toSelf().inSingletonScope();
bind(FrontendApplicationContribution).toService(MonacoStatusBarContribution);
bind(WidgetStatusBarContribution).toService(MonacoStatusBarContribution);

bind(MonacoCommandRegistry).toSelf().inSingletonScope();
bind(MonacoEditorCommandHandlers).toSelf().inSingletonScope();
Expand Down
Loading

0 comments on commit d08794b

Please sign in to comment.