UNPKG

@theia/monaco

Version:
286 lines (233 loc) • 10.8 kB
// ***************************************************************************** // Copyright (C) 2024 1C-Soft LLC 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 { Position, Range } from '@theia/core/shared/vscode-languageserver-protocol'; import { DisposableCollection } from '@theia/core'; import { MonacoEditor } from './monaco-editor'; import * as monaco from '@theia/monaco-editor-core'; import { PeekViewWidget, IPeekViewOptions, IPeekViewStyles } from '@theia/monaco-editor-core/esm/vs/editor/contrib/peekView/browser/peekView'; import { ICodeEditor } from '@theia/monaco-editor-core/esm/vs/editor/browser/editorBrowser'; import { ActionBar } from '@theia/monaco-editor-core/esm/vs/base/browser/ui/actionbar/actionbar'; import { Action } from '@theia/monaco-editor-core/esm/vs/base/common/actions'; import { StandaloneServices } from '@theia/monaco-editor-core/esm/vs/editor/standalone/browser/standaloneServices'; import { IInstantiationService } from '@theia/monaco-editor-core/esm/vs/platform/instantiation/common/instantiation'; import { IThemeService } from '@theia/monaco-editor-core/esm/vs/platform/theme/common/themeService'; import { Color } from '@theia/monaco-editor-core/esm/vs/base/common/color'; export { peekViewBorder, peekViewTitleBackground, peekViewTitleForeground, peekViewTitleInfoForeground } from '@theia/monaco-editor-core/esm/vs/editor/contrib/peekView/browser/peekView'; export namespace MonacoEditorPeekViewWidget { export interface Styles { frameColor?: string; arrowColor?: string; headerBackgroundColor?: string; primaryHeadingColor?: string; secondaryHeadingColor?: string; } export interface Options { showFrame?: boolean; showArrow?: boolean; frameWidth?: number; className?: string; isAccessible?: boolean; isResizeable?: boolean; keepEditorSelection?: boolean; allowUnlimitedHeight?: boolean; ordinal?: number; showInHiddenAreas?: boolean; supportOnTitleClick?: boolean; } export interface Action { readonly id: string; label: string; tooltip: string; class: string | undefined; enabled: boolean; checked?: boolean; run(...args: unknown[]): unknown; } export interface ActionOptions { icon?: boolean; label?: boolean; keybinding?: string; index?: number; } } export class MonacoEditorPeekViewWidget { protected readonly toDispose = new DisposableCollection(); readonly onDidClose = this.toDispose.onDispose; private readonly themeService = StandaloneServices.get(IThemeService); private readonly delegate; constructor( readonly editor: MonacoEditor, options: MonacoEditorPeekViewWidget.Options = {}, protected styles: MonacoEditorPeekViewWidget.Styles = {} ) { const that = this; this.toDispose.push(this.delegate = new class extends PeekViewWidget { get actionBar(): ActionBar | undefined { return this._actionbarWidget; } fillContainer(container: HTMLElement): void { super._fillContainer(container); } protected override _fillContainer(container: HTMLElement): void { that.fillContainer(container); } fillHead(container: HTMLElement, noCloseAction?: boolean): void { super._fillHead(container, noCloseAction); } protected override _fillHead(container: HTMLElement, noCloseAction?: boolean): void { that.fillHead(container, noCloseAction); } fillBody(container: HTMLElement): void { // super._fillBody is an abstract method } protected override _fillBody(container: HTMLElement): void { that.fillBody(container); }; doLayoutHead(heightInPixel: number, widthInPixel: number): void { super._doLayoutHead(heightInPixel, widthInPixel); } protected override _doLayoutHead(heightInPixel: number, widthInPixel: number): void { that.doLayoutHead(heightInPixel, widthInPixel); } doLayoutBody(heightInPixel: number, widthInPixel: number): void { super._doLayoutBody(heightInPixel, widthInPixel); } protected override _doLayoutBody(heightInPixel: number, widthInPixel: number): void { that.doLayoutBody(heightInPixel, widthInPixel); } onWidth(widthInPixel: number): void { super._onWidth(widthInPixel); } protected override _onWidth(widthInPixel: number): void { that.onWidth(widthInPixel); } doRevealRange(range: monaco.Range, isLastLine: boolean): void { super.revealRange(range, isLastLine); } protected override revealRange(range: monaco.Range, isLastLine: boolean): void { that.doRevealRange(that.editor['m2p'].asRange(range), isLastLine); } getBodyElement(): HTMLDivElement | undefined { return this._bodyElement; } setBodyElement(element: HTMLDivElement | undefined): void { this._bodyElement = element; } getHeadElement(): HTMLDivElement | undefined { return this._headElement; } setHeadElement(element: HTMLDivElement | undefined): void { this._headElement = element; } override setCssClass(className: string, classToReplace?: string | undefined): void { super.setCssClass(className, classToReplace); } }( editor.getControl() as unknown as ICodeEditor, Object.assign(<IPeekViewOptions>{}, options, this.convertStyles(styles)), StandaloneServices.get(IInstantiationService) )); this.toDispose.push(this.themeService.onDidColorThemeChange(() => this.style(this.styles))); } dispose(): void { this.toDispose.dispose(); } create(): void { this.delegate.create(); } setTitle(primaryHeading: string, secondaryHeading?: string): void { this.delegate.setTitle(primaryHeading, secondaryHeading); } style(styles: MonacoEditorPeekViewWidget.Styles): void { this.delegate.style(this.convertStyles(this.styles = styles)); } show(rangeOrPos: Range | Position, heightInLines: number): void { this.delegate.show(this.convertRangeOrPosition(rangeOrPos), heightInLines); } hide(): void { this.delegate.hide(); } clearActions(): void { this.delegate.actionBar?.clear(); } addAction(id: string, label: string, cssClass: string | undefined, enabled: boolean, actionCallback: (arg: unknown) => unknown, options?: MonacoEditorPeekViewWidget.ActionOptions): MonacoEditorPeekViewWidget.Action { options = cssClass ? { icon: true, label: false, ...options } : { icon: false, label: true, ...options }; const { actionBar } = this.delegate; if (!actionBar) { throw new Error('Action bar has not been created.'); } const action = new Action(id, label, cssClass, enabled, actionCallback); actionBar.push(action, options); return action; } protected fillContainer(container: HTMLElement): void { this.delegate.fillContainer(container); } protected fillHead(container: HTMLElement, noCloseAction?: boolean): void { this.delegate.fillHead(container, noCloseAction); } protected fillBody(container: HTMLElement): void { this.delegate.fillBody(container); } protected doLayoutHead(heightInPixel: number, widthInPixel: number): void { this.delegate.doLayoutHead(heightInPixel, widthInPixel); } protected doLayoutBody(heightInPixel: number, widthInPixel: number): void { this.delegate.doLayoutBody(heightInPixel, widthInPixel); } protected onWidth(widthInPixel: number): void { this.delegate.onWidth(widthInPixel); } protected doRevealRange(range: Range, isLastLine: boolean): void { this.delegate.doRevealRange(this.editor['p2m'].asRange(range), isLastLine); } protected get bodyElement(): HTMLDivElement | undefined { return this.delegate.getBodyElement(); } protected set bodyElement(element: HTMLDivElement | undefined) { this.delegate.setBodyElement(element); } protected get headElement(): HTMLDivElement | undefined { return this.delegate.getHeadElement(); } protected set headElement(element: HTMLDivElement | undefined) { this.delegate.setHeadElement(element); } protected setCssClass(className: string, classToReplace?: string | undefined): void { this.delegate.setCssClass(className, classToReplace); } private convertStyles(styles: MonacoEditorPeekViewWidget.Styles): IPeekViewStyles { return { frameColor: this.convertColor(styles.frameColor), arrowColor: this.convertColor(styles.arrowColor), headerBackgroundColor: this.convertColor(styles.headerBackgroundColor), primaryHeadingColor: this.convertColor(styles.primaryHeadingColor), secondaryHeadingColor: this.convertColor(styles.secondaryHeadingColor), }; } private convertColor(color?: string): Color | undefined { if (color === undefined) { return undefined; } return this.themeService.getColorTheme().getColor(color) || Color.fromHex(color); } private convertRangeOrPosition(arg: Range | Position): monaco.Range | monaco.Position { const p2m = this.editor['p2m']; return Range.is(arg) ? p2m.asRange(arg) : p2m.asPosition(arg); } }