UNPKG

@cisstech/nge

Version:

NG Essentials is a collection of libraries for Angular developers.

1,203 lines 60.7 kB
import * as i0 from '@angular/core';
import { InjectionToken, Injectable, Optional, Inject, EventEmitter, Component, ViewChild, Output, Input, HostListener, ChangeDetectionStrategy, inject, ChangeDetectorRef, NgModule } from '@angular/core';
import { Subject, of, lastValueFrom, BehaviorSubject, firstValueFrom } from 'rxjs';
import * as i1 from '@cisstech/nge/services';
import * as i2 from '@angular/common';
import { CommonModule } from '@angular/common';
import { map } from 'rxjs/operators';
import * as i1$1 from '@angular/common/http';

/**
 * Monaco editor loader configuration token.
 */
const NGE_MONACO_CONFIG = new InjectionToken('NGE_MONACO_CONFIG');

const NGE_MONACO_CONTRIBUTION = new InjectionToken('NGE_MONACO_CONTRIBUTION');

/** monaco editor cdn url hosted at cdnjs. */
const MONACO_CDNJS_URL = 'https://cdnjs.cloudflare.com/ajax/libs/monaco-editor/0.52.0';
/** monaco editor cdn url hosted at jsdeliver. */
const MONACO_JS_DELIVER_URL = 'https://cdn.jsdelivr.net/npm/monaco-editor@0.52.0';
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const WINDOW = window;
/**
 * Loads monaco editor using AMD loader.
 */
class NgeMonacoLoaderService {
    constructor(config, contributions, resourceLoader) {
        this.config = config;
        this.contributions = contributions;
        this.resourceLoader = resourceLoader;
        this.monaco$ = new Subject();
        this.baseUrl = MONACO_CDNJS_URL;
        this.contributions = contributions || [];
    }
    async ngOnDestroy() {
        await this.deactivateContributions();
    }
    /**
     * Call the given `observer` function to extend monaco editor functionalities
     * once it will be available in `window.monaco`.
     *
     * The function will be called immediately if monaco api is already loaded.
     * @param observer observer object.
     * @returns A subscription object that should be unsubscribed later.
     */
    onLoadMonaco(observer) {
        if (typeof WINDOW.monaco === 'undefined') {
            return this.monaco$.asObservable().subscribe(observer);
        }
        return of(WINDOW.monaco).subscribe(observer);
    }
    /**
     * Loads monaco editor if it is not loaded.
     */
    loadAsync() {
        return (this.loadPromise ??
            (this.loadPromise = new Promise((resolve) => {
                (async () => {
                    // Try to fix the issues described here by loading monaco editor
                    // after all the other scripts.
                    // https://stackoverflow.com/a/33635881
                    // https://github.com/microsoft/monaco-editor/issues/662
                    // https://github.com/microsoft/monaco-editor/issues/1249
                    const interval = setInterval(() => {
                        if (document.readyState !== 'complete')
                            return;
                        clearInterval(interval);
                        setTimeout(async () => {
                            await this.resourceLoader.waitForPendings();
                            this.baseUrl = this.config?.assets || MONACO_CDNJS_URL;
                            if (this.baseUrl.endsWith('/')) {
                                this.baseUrl = this.baseUrl.slice(0, this.baseUrl.length - 1);
                            }
                            this.addWorkersIfCrossDomain();
                            if (!WINDOW.require) {
                                lastValueFrom(this.resourceLoader.loadAllAsync([['script', `${this.baseUrl}/min/vs/loader.js`]])).then(() => this.onLoad(resolve));
                            }
                            else {
                                this.onLoad(resolve);
                            }
                        }, 300);
                    });
                })();
            })));
    }
    onLoad(resolve) {
        WINDOW.require.config({
            paths: { vs: this.baseUrl + '/min/vs' },
        });
        const locale = this.config?.locale || '';
        if (locale !== 'en') {
            WINDOW.require.config({
                'vs/nls': {
                    availableLanguages: { '*': locale },
                },
            });
        }
        WINDOW.require(['vs/editor/editor.main'], async () => {
            await this.activateContributions();
            this.monaco$.next(monaco);
            resolve(monaco);
        });
    }
    addWorkersIfCrossDomain() {
        // https://github.com/microsoft/monaco-editor/blob/master/docs/integrate-amd-cross.md
        if (this.baseUrl.startsWith('http')) {
            const proxy = URL.createObjectURL(new Blob([
                `
                self.MonacoEnvironment = { baseUrl: '${this.baseUrl}/min' };
                importScripts('${this.baseUrl}/min/vs/base/worker/workerMain.js');
            `,
            ], { type: 'text/javascript' }));
            WINDOW.MonacoEnvironment = {
                baseUrl: this.baseUrl + '/min',
                getWorkerUrl: () => proxy,
                globalAPI: true,
            };
        }
    }
    async activateContributions() {
        await Promise.all(this.contributions.map((e) => e.activate()));
    }
    async deactivateContributions() {
        await Promise.all(this.contributions.map((e) => {
            if (e.deactivate) {
                return e.deactivate();
            }
            return Promise.resolve();
        }));
    }
    static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.1", ngImport: i0, type: NgeMonacoLoaderService, deps: [{ token: NGE_MONACO_CONFIG, optional: true }, { token: NGE_MONACO_CONTRIBUTION, optional: true }, { token: i1.ResourceLoaderService }], target: i0.ɵɵFactoryTarget.Injectable }); }
    static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.2.1", ngImport: i0, type: NgeMonacoLoaderService, providedIn: 'root' }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.1", ngImport: i0, type: NgeMonacoLoaderService, decorators: [{
            type: Injectable,
            args: [{ providedIn: 'root' }]
        }], ctorParameters: () => [{ type: undefined, decorators: [{
                    type: Optional
                }, {
                    type: Inject,
                    args: [NGE_MONACO_CONFIG]
                }] }, { type: undefined, decorators: [{
                    type: Optional
                }, {
                    type: Inject,
                    args: [NGE_MONACO_CONTRIBUTION]
                }] }, { type: i1.ResourceLoaderService }] });

class NgeMonacoDiffEditorComponent {
    constructor(loader, config) {
        this.loader = loader;
        this.config = config;
        this.ready = new EventEmitter();
        this.autoLayout = true;
        this.width = 0;
        this.height = 0;
    }
    onResizeWindow() {
        this.editor?.layout();
    }
    ngAfterViewInit() {
        this.loader.loadAsync().then(() => {
            this.createEditor();
        });
    }
    ngAfterViewChecked() {
        if (!this.autoLayout) {
            return;
        }
        const { offsetWidth, offsetHeight } = this.container.nativeElement;
        if (offsetWidth !== this.width || offsetHeight !== this.height) {
            this.width = offsetWidth;
            this.height = offsetHeight;
            this.editor?.layout();
        }
    }
    ngOnDestroy() {
        this.editor?.dispose();
    }
    createEditor() {
        this.editor = monaco.editor.createDiffEditor(this.container.nativeElement, {
            ...(this.config.options || {}),
            ...(this.options || {}),
        });
        this.ready.emit(this.editor);
    }
    static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.1", ngImport: i0, type: NgeMonacoDiffEditorComponent, deps: [{ token: NgeMonacoLoaderService }, { token: NGE_MONACO_CONFIG, optional: true }], target: i0.ɵɵFactoryTarget.Component }); }
    static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.1", type: NgeMonacoDiffEditorComponent, selector: "nge-monaco-diff-editor", inputs: { autoLayout: "autoLayout", options: "options" }, outputs: { ready: "ready" }, host: { listeners: { "window:resize": "onResizeWindow()" } }, viewQueries: [{ propertyName: "container", first: true, predicate: ["container"], descendants: true, static: true }], ngImport: i0, template: "<div class=\"nge-monaco-diff-editor-container\" #container></div>\n", styles: [":host{display:block;height:var(--editor-height, 100%);border:1px solid #F5F5F5;box-sizing:border-box}.nge-monaco-diff-editor-container{width:100%;height:100%}\n"] }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.1", ngImport: i0, type: NgeMonacoDiffEditorComponent, decorators: [{
            type: Component,
            args: [{ selector: 'nge-monaco-diff-editor', template: "<div class=\"nge-monaco-diff-editor-container\" #container></div>\n", styles: [":host{display:block;height:var(--editor-height, 100%);border:1px solid #F5F5F5;box-sizing:border-box}.nge-monaco-diff-editor-container{width:100%;height:100%}\n"] }]
        }], ctorParameters: () => [{ type: NgeMonacoLoaderService }, { type: undefined, decorators: [{
                    type: Optional
                }, {
                    type: Inject,
                    args: [NGE_MONACO_CONFIG]
                }] }], propDecorators: { container: [{
                type: ViewChild,
                args: ['container', { static: true }]
            }], ready: [{
                type: Output
            }], autoLayout: [{
                type: Input
            }], options: [{
                type: Input
            }], onResizeWindow: [{
                type: HostListener,
                args: ['window:resize']
            }] } });

class NgeMonacoPlaceholderComponent {
    static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.1", ngImport: i0, type: NgeMonacoPlaceholderComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
    static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.1", type: NgeMonacoPlaceholderComponent, selector: "nge-monaco-placeholder", ngImport: i0, template: "\n", styles: [":host{display:block;height:100%;width:100%;background:linear-gradient(90deg,#f0f0f0 25%,#e0e0e0,#f0f0f0 75%);background-size:200% 100%;animation:shimmer 1.5s infinite}@keyframes shimmer{0%{background-position:-200% 0}to{background-position:200% 0}}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.1", ngImport: i0, type: NgeMonacoPlaceholderComponent, decorators: [{
            type: Component,
            args: [{ selector: 'nge-monaco-placeholder', changeDetection: ChangeDetectionStrategy.OnPush, template: "\n", styles: [":host{display:block;height:100%;width:100%;background:linear-gradient(90deg,#f0f0f0 25%,#e0e0e0,#f0f0f0 75%);background-size:200% 100%;animation:shimmer 1.5s infinite}@keyframes shimmer{0%{background-position:-200% 0}to{background-position:200% 0}}\n"] }]
        }] });

class NgeMonacoEditorComponent {
    constructor(loader, config) {
        this.loader = loader;
        this.config = config;
        this.loading = true;
        this.ready = new EventEmitter();
        this.autoLayout = true;
        this.width = 0;
        this.height = 0;
    }
    ngAfterViewInit() {
        this.loader.loadAsync().then(() => {
            this.createEditor();
        });
    }
    ngAfterViewChecked() {
        if (!this.autoLayout) {
            return;
        }
        const { offsetWidth, offsetHeight } = this.container.nativeElement;
        if (offsetWidth !== this.width || offsetHeight !== this.height) {
            this.width = offsetWidth;
            this.height = offsetHeight;
            this.editor?.layout();
        }
    }
    ngOnDestroy() {
        this.editor?.dispose();
    }
    onResizeWindow() {
        this.editor?.layout();
    }
    createEditor() {
        this.editor = monaco.editor.create(this.container.nativeElement, {
            ...(this.config.options || {}),
            ...(this.options || {}),
        });
        this.loading = false;
        this.ready.emit(this.editor);
    }
    static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.1", ngImport: i0, type: NgeMonacoEditorComponent, deps: [{ token: NgeMonacoLoaderService }, { token: NGE_MONACO_CONFIG, optional: true }], target: i0.ɵɵFactoryTarget.Component }); }
    static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.1", type: NgeMonacoEditorComponent, selector: "nge-monaco-editor", inputs: { autoLayout: "autoLayout", options: "options" }, outputs: { ready: "ready" }, host: { listeners: { "window:resize": "onResizeWindow()" } }, viewQueries: [{ propertyName: "container", first: true, predicate: ["container"], descendants: true, static: true }], ngImport: i0, template: "<nge-monaco-placeholder *ngIf=\"loading\" />\n<div class=\"nge-monaco-editor-container\" #container></div>\n", styles: [":host{display:block;height:var(--editor-height, 100%);border:1px solid #f5f5f5;box-sizing:border-box}.nge-monaco-editor-container{width:100%;height:100%}\n"], dependencies: [{ kind: "directive", type: i2.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "component", type: NgeMonacoPlaceholderComponent, selector: "nge-monaco-placeholder" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.1", ngImport: i0, type: NgeMonacoEditorComponent, decorators: [{
            type: Component,
            args: [{ selector: 'nge-monaco-editor', changeDetection: ChangeDetectionStrategy.OnPush, template: "<nge-monaco-placeholder *ngIf=\"loading\" />\n<div class=\"nge-monaco-editor-container\" #container></div>\n", styles: [":host{display:block;height:var(--editor-height, 100%);border:1px solid #f5f5f5;box-sizing:border-box}.nge-monaco-editor-container{width:100%;height:100%}\n"] }]
        }], ctorParameters: () => [{ type: NgeMonacoLoaderService }, { type: undefined, decorators: [{
                    type: Optional
                }, {
                    type: Inject,
                    args: [NGE_MONACO_CONFIG]
                }] }], propDecorators: { container: [{
                type: ViewChild,
                args: ['container', { static: true }]
            }], ready: [{
                type: Output
            }], autoLayout: [{
                type: Input
            }], options: [{
                type: Input
            }], onResizeWindow: [{
                type: HostListener,
                args: ['window:resize']
            }] } });

class NgeMonacoThemeService {
    constructor(http, config) {
        this.http = http;
        this.config = config;
        this.themes = new BehaviorSubject([]);
        this.activeTheme = new BehaviorSubject(undefined);
    }
    /**
     * Gets the current active theme of monaco editor (undefined if monaco editor is not loaded).
     */
    get theme() {
        return this.activeTheme.value;
    }
    /**
     * Gets an observable that emit each time monaco editor theme change.
     *
     * Note: The observable emits first with the current theme
     * the first time `subscribe()` method is called.
     */
    get themeChanges() {
        return this.activeTheme.asObservable();
    }
    /**
     * Gets an observable that emit each time monaco editor theme list change.
     */
    get themesChanges() {
        return this.themes.asObservable().pipe(map((e) => e.slice()) // return a copy of the array
        );
    }
    async activate() {
        //this.decorateCreateEditorAPI()
        const node = document.createElement('div');
        const editor = monaco.editor.create(node);
        this.themeService = editor._themeService;
        setTimeout(() => editor.dispose());
        this.retrieveThemes();
        await this.setTheme(this.config?.theming?.default || 'vs');
        node.remove();
    }
    /**
     * Switches monaco editor theme.
     * @param themeName The new theme to use.
     *
     */
    async setTheme(themeName) {
        await this.defineTheme(themeName);
        monaco.editor.setTheme(themeName);
        this.activeTheme.next(this.themeService.getColorTheme());
    }
    /**
     * Gets the information about the given `themeName`
     * @param themeName The theme to get.
     * @returns A promise that resolves with the theme info.
     */
    async getTheme(themeName) {
        await this.defineTheme(themeName);
        return this.themeService._knownThemes.get(themeName);
    }
    /**
     * Defines a theme for the Monaco editor.
     * @remarks
     * - If the theme is already defined, this method does nothing.
     * @param themeName - The name of the theme to define.
     * @throws {ReferenceError} If the themeName argument is not provided.
     * @throws {Error} If the specified theme is missing.
     * @throws {Error} If HttpClientModule is missing in AppModule.
     * @returns A Promise that resolves when the theme is defined successfully.
     */
    async defineTheme(themeName) {
        if (!themeName) {
            throw new ReferenceError('Argument "themeName" is required');
        }
        const knownThemes = this.themeService._knownThemes;
        if (knownThemes.has(themeName)) {
            return;
        }
        const customThemePath = this.config?.theming?.themes?.find((e) => {
            return this.themeNameFromPath(e) === themeName;
        });
        if (!customThemePath) {
            throw new Error(`[nge-monaco] Missing theme "${themeName}"`);
        }
        if (!this.http) {
            throw new Error('[nge-monaco] Missing HttpClientModule in AppModule. See README for more information');
        }
        try {
            const theme = await firstValueFrom(this.http.get(customThemePath));
            monaco.editor.defineTheme(themeName, {
                base: theme.base,
                inherit: theme.inherit,
                rules: theme.rules,
                colors: theme.colors,
            });
        }
        catch (error) {
            console.error('[nge-monaco] Failed to load theme ' + customThemePath, error);
        }
    }
    retrieveThemes() {
        const themes = [];
        this.themeService._knownThemes.forEach((theme) => {
            themes.push(theme.themeName);
        });
        const customThemes = (this.config?.theming?.themes || []).map(this.themeNameFromPath.bind(this));
        this.themes.next(themes.concat(customThemes));
    }
    themeNameFromPath(path) {
        const name = path.split('/').pop();
        if (!name) {
            throw new Error(`[nge-monaco]: invalid theme path "${path}"`);
        }
        return name.replace('.json', '');
    }
    decorateCreateEditorAPI() {
        const createEditor = monaco.editor.create;
        monaco.editor.create = (element, options, override) => {
            const editor = createEditor.call(monaco.editor, element, options, override);
            const updateOptions = editor.updateOptions;
            editor.updateOptions = (newOptions) => {
                updateOptions.call(editor, newOptions);
                if (newOptions.theme) {
                    this.setTheme(newOptions.theme).catch(console.error);
                }
            };
            if (options?.theme) {
                this.setTheme(options.theme).catch(console.error);
            }
            return editor;
        };
    }
    static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.1", ngImport: i0, type: NgeMonacoThemeService, deps: [{ token: i1$1.HttpClient, optional: true }, { token: NGE_MONACO_CONFIG, optional: true }], target: i0.ɵɵFactoryTarget.Injectable }); }
    static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.2.1", ngImport: i0, type: NgeMonacoThemeService, providedIn: 'root' }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.1", ngImport: i0, type: NgeMonacoThemeService, decorators: [{
            type: Injectable,
            args: [{ providedIn: 'root' }]
        }], ctorParameters: () => [{ type: i1$1.HttpClient, decorators: [{
                    type: Optional
                }] }, { type: undefined, decorators: [{
                    type: Optional
                }, {
                    type: Inject,
                    args: [NGE_MONACO_CONFIG]
                }] }] });
/** List of all custom themes from of the library */
const NGE_MONACO_THEMES = [
    'active4d.json',
    'all-hallows-eve.json',
    'amy.json',
    'birds-of-paradise.json',
    'blackboard.json',
    'brilliance-black.json',
    'brilliance-dull.json',
    'chrome-devtools.json',
    'clouds-midnight.json',
    'clouds.json',
    'cobalt.json',
    'dawn.json',
    'dreamweaver.json',
    'eiffel.json',
    'espresso-libre.json',
    'github.json',
    'idle-fingers.json',
    'idle.json',
    'iplastic.json',
    'katzenmilch.json',
    'kuroir-theme.json',
    'kr-theme.json',
    'lazy.json',
    'magicwb-amiga.json',
    'merbivore-soft.json',
    'merbivore.json',
    'monokai-bright.json',
    'monokai.json',
    'monoindustrial.json',
    'night-owl.json',
    'nord.json',
    'oceanic-next.json',
    'one-dark-pro.json',
    'pastels-on-dark.json',
    'slush-and-poppies.json',
    'solarized-dark.json',
    'solarized-light.json',
    'space-cadet.json',
    'sunburst.json',
    'textmate.json',
    'tomorrow-night-blue.json',
    'tomorrow-night-bright.json',
    'tomorrow-night-eighties.json',
    'tomorrow-night.json',
    'tomorrow.json',
    'twilight.json',
    'upstream-sunburst.json',
    'vibrant-ink.json',
    'xcode.json',
    'zenburnesque.json',
];

class NgeMonacoColorizerService {
    constructor(loader, theming) {
        this.loader = loader;
        this.theming = theming;
    }
    async colorizeElement(options) {
        await this.loader.loadAsync();
        if (options.theme) {
            await this.theming.defineTheme(options.theme);
        }
        const { element } = options;
        element.innerHTML = this.escapeHtml(options.code || '');
        element.style.padding = '4px';
        element.style.display = 'block';
        const pre = element.parentElement;
        if (pre?.tagName === 'PRE') {
            if (!pre.classList.contains('monaco-editor')) {
                pre.classList.add('monaco-editor');
            }
            if (!pre.classList.contains('monaco-editor-background')) {
                pre.classList.add('monaco-editor-background');
            }
        }
        element.className = '';
        const languages = monaco.languages.getLanguages();
        const language = languages.find((e) => {
            return e.id === options.language || e.aliases?.find((a) => a === options.language);
        })?.id;
        await monaco.editor.colorizeElement(element, {
            mimeType: language || 'plaintext',
            theme: options.theme || this.theming.theme?.themeName || 'vs',
        });
        this.highlightLines(options);
        this.showLineNumbers(options);
        this.addFileTab(options);
    }
    escapeHtml(input) {
        // eslint-disable-next-line @typescript-eslint/no-explicit-any
        const map = {
            '<': '&lt;',
            '>': '&gt;',
        };
        return input.replace(/[<>]/g, (tag) => map[tag] || tag);
    }
    highlightLines(options) {
        if (!options.highlights) {
            return;
        }
        const { element } = options;
        const linesToHighlight = this.lineNumbersFromString(options.highlights.toString());
        let newLine = true;
        let lineNumber = 1;
        element.childNodes.forEach((e) => {
            const node = e;
            if (newLine) {
                const div = document.createElement('div');
                div.style.height = '18px';
                if (linesToHighlight.includes(lineNumber)) {
                    div.classList.add('rangeHighlight');
                    div.classList.add('selected-text');
                }
                element.insertBefore(div, node);
                element.removeChild(node);
                div.appendChild(node);
                newLine = false;
            }
            else if (node.tagName === 'BR') {
                lineNumber++;
                newLine = true;
            }
        });
        Array.from(element.getElementsByTagName('br')).forEach((node) => node.remove());
    }
    showLineNumbers(options) {
        if (!options.lines) {
            return;
        }
        const { element } = options;
        const lines = this.lineNumbersFromString(options.lines.toString());
        const length = (options.code || '').split('\n').length;
        if (lines.length === 1) {
            for (let i = lines[0] + 1; i <= length; i++) {
                lines.push(i);
            }
        }
        const side = ['<div style="padding:0  12px; text-align: right;">'];
        for (let i = 0; i < length; i++) {
            let num = '';
            if (lines.includes(i + 1)) {
                num = '' + (i + 1);
            }
            side.push(`<div class="line-numbers" style="height: 18px">${num}</div>`);
        }
        side.push('</div>');
        element.style.display = 'flex';
        element.innerHTML = `
            ${side.join('')}
            <div style="flex: 1;">${element.innerHTML}</div>
        `;
    }
    lineNumbersFromString(input) {
        const tokens = (input || '').trim().split(' ');
        const lines = [];
        for (const token of tokens) {
            if (token.includes('-')) {
                const range = token.split('-');
                const start = Number.parseInt(range[0], 10);
                const end = Number.parseInt(range[1], 10);
                if (start && end) {
                    for (let i = start; i <= end; i++) {
                        if (!lines.includes(i)) {
                            lines.push(i);
                        }
                    }
                }
            }
            else {
                const n = Number.parseInt(token, 10);
                if (n) {
                    lines.push(n);
                }
            }
        }
        return lines;
    }
    addFileTab(options) {
        const { element, code, filename } = options;
        const container = element.parentElement;
        // Force remove padding from pre element
        if (container) {
            container.style.padding = '0';
            container.style.margin = '0';
            container.style.width = '100%';
        }
        // Create tab container that takes full width
        const tabContainer = document.createElement('div');
        tabContainer.style.display = 'flex';
        tabContainer.style.justifyContent = 'space-between';
        tabContainer.style.alignItems = 'center';
        tabContainer.style.padding = '8px 16px';
        tabContainer.style.borderBottom = '1px solid var(--vscode-dropdown-border, #e8e8e8)';
        tabContainer.style.backgroundColor = 'var(--vscode-editor-background, #fafafa)';
        tabContainer.style.fontSize = '14px';
        tabContainer.style.width = '100%';
        tabContainer.style.boxSizing = 'border-box';
        tabContainer.style.fontFamily = 'var(--monaco-monospace-font, "SF Mono", Monaco, Menlo, Consolas, "Ubuntu Mono", monospace)';
        // Add filename on left side
        const filenameSpan = document.createElement('span');
        filenameSpan.textContent = filename || '';
        filenameSpan.style.overflow = 'hidden';
        filenameSpan.style.textOverflow = 'ellipsis';
        filenameSpan.style.whiteSpace = 'nowrap';
        filenameSpan.style.fontWeight = '500';
        filenameSpan.style.color = 'var(--vscode-editor-foreground, rgba(0, 0, 0, 0.85))';
        filenameSpan.title = filename || '';
        // Add file actions container (right side)
        const fileActions = document.createElement('div');
        fileActions.className = 'file-actions';
        fileActions.style.display = 'flex';
        fileActions.style.gap = '4px';
        // Create copy button with icon
        const copyButton = document.createElement('button');
        copyButton.style.border = 'none';
        copyButton.style.background = 'none';
        copyButton.style.cursor = 'pointer';
        copyButton.style.color = 'var(--vscode-editor-foreground, rgba(0, 0, 0, 0.85))';
        copyButton.style.display = 'flex';
        copyButton.style.alignItems = 'center';
        copyButton.style.justifyContent = 'center';
        copyButton.style.width = '32px';
        copyButton.style.height = '32px';
        copyButton.style.padding = '0';
        copyButton.style.borderRadius = '4px';
        copyButton.style.transition = 'all 0.3s';
        copyButton.title = 'Copy code to clipboard';
        // Hover effect
        copyButton.addEventListener('mouseover', () => {
            copyButton.style.color = '#1890ff';
            copyButton.style.backgroundColor = 'rgba(0, 0, 0, 0.04)';
        });
        copyButton.addEventListener('mouseout', () => {
            copyButton.style.color = 'var(--vscode-editor-foreground, rgba(0, 0, 0, 0.85))';
            copyButton.style.backgroundColor = 'transparent';
        });
        // Copy functionality
        copyButton.addEventListener('click', async (event) => {
            // Prevent default action and event bubbling
            event.preventDefault();
            event.stopPropagation();
            try {
                await navigator.clipboard.writeText(code || '');
                // Show feedback
                copyButton.innerHTML = `<svg viewBox="0 0 24 24" width="16" height="16" stroke="currentColor" stroke-width="2" fill="none" stroke-linecap="round" stroke-linejoin="round"><path d="M9 16.17L4.83 12l-1.42 1.41L9 19 21 7l-1.41-1.41z"></path></svg>`;
                copyButton.style.color = '#52c41a';
                setTimeout(() => {
                    // Use requestAnimationFrame to ensure smooth transition
                    requestAnimationFrame(() => {
                        copyButton.innerHTML = copySvg;
                        copyButton.style.color = 'var(--vscode-editor-foreground, rgba(0, 0, 0, 0.85))';
                    });
                }, 2000);
            }
            catch (err) {
                console.error('Failed to copy code:', err);
            }
            // Return false to ensure no further action
            return false;
        });
        // Create download button with icon
        const downloadButton = document.createElement('button');
        downloadButton.style.border = 'none';
        downloadButton.style.background = 'none';
        downloadButton.style.cursor = 'pointer';
        downloadButton.style.color = 'var(--vscode-editor-foreground, rgba(0, 0, 0, 0.85))';
        downloadButton.style.display = 'flex';
        downloadButton.style.alignItems = 'center';
        downloadButton.style.justifyContent = 'center';
        downloadButton.style.width = '32px';
        downloadButton.style.height = '32px';
        downloadButton.style.padding = '0';
        downloadButton.style.borderRadius = '4px';
        downloadButton.style.transition = 'all 0.3s';
        downloadButton.title = 'Download code as file';
        // Hover effect
        downloadButton.addEventListener('mouseover', () => {
            downloadButton.style.color = '#1890ff';
            downloadButton.style.backgroundColor = 'rgba(0, 0, 0, 0.04)';
        });
        downloadButton.addEventListener('mouseout', () => {
            downloadButton.style.color = 'var(--vscode-editor-foreground, rgba(0, 0, 0, 0.85))';
            downloadButton.style.backgroundColor = 'transparent';
        });
        // Download functionality
        downloadButton.addEventListener('click', (event) => {
            // Prevent default action and event bubbling
            event.preventDefault();
            event.stopPropagation();
            // Save original content
            const originalInnerHTML = downloadButton.innerHTML;
            try {
                const blob = new Blob([code || ''], { type: 'text/plain' });
                const url = URL.createObjectURL(blob);
                const a = document.createElement('a');
                a.href = url;
                a.download = filename || 'code.txt';
                a.style.display = 'none';
                a.setAttribute('data-no-scroll', 'true'); // Mark as no-scroll
                // Execute download
                document.body.appendChild(a);
                a.click();
                document.body.removeChild(a);
                // Show success feedback similar to copy button
                downloadButton.innerHTML = `<svg viewBox="0 0 24 24" width="16" height="16" stroke="currentColor" stroke-width="2" fill="none" stroke-linecap="round" stroke-linejoin="round"><path d="M9 16.17L4.83 12l-1.42 1.41L9 19 21 7l-1.41-1.41z"></path></svg>`;
                downloadButton.style.color = '#52c41a';
                // Reset button after timeout
                setTimeout(() => {
                    // Use requestAnimationFrame for smoother transition
                    requestAnimationFrame(() => {
                        downloadButton.innerHTML = downloadSvg;
                        downloadButton.style.color = 'var(--vscode-editor-foreground, rgba(0, 0, 0, 0.85))';
                        URL.revokeObjectURL(url); // Clean up URL object
                    });
                }, 2000);
            }
            catch (err) {
                console.error('Failed to download code:', err);
                downloadButton.innerHTML = originalInnerHTML;
            }
            // Return false to ensure no further action
            return false;
        });
        // Copy icon SVG
        const copySvg = `<svg viewBox="0 0 24 24" width="16" height="16" stroke="currentColor" stroke-width="2" fill="none" stroke-linecap="round" stroke-linejoin="round"><rect x="9" y="9" width="13" height="13" rx="2" ry="2"></rect><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"></path></svg>`;
        // Download icon SVG
        const downloadSvg = `<svg viewBox="0 0 24 24" width="16" height="16" stroke="currentColor" stroke-width="2" fill="none" stroke-linecap="round" stroke-linejoin="round"><path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"></path><polyline points="7 10 12 15 17 10"></polyline><line x1="12" y1="15" x2="12" y2="3"></line></svg>`;
        copyButton.innerHTML = copySvg;
        downloadButton.innerHTML = downloadSvg;
        // Add buttons to actions container
        fileActions.appendChild(copyButton);
        fileActions.appendChild(downloadButton);
        // Build the tab
        tabContainer.appendChild(filenameSpan);
        tabContainer.appendChild(fileActions);
        // Insert tab before the editor content
        if (container) {
            container.insertBefore(tabContainer, element);
            // Add some styling to the container for better appearance
            container.style.border = '1px solid #e8e8e8';
            container.style.borderRadius = '2px';
            container.style.overflow = 'hidden';
            container.style.marginBottom = '16px';
            container.style.padding = '0';
            // Add inner padding to code content
            element.style.padding = '16px';
        }
        else {
            // If no container, wrap the element with one
            const wrapper = document.createElement('div');
            wrapper.style.border = '1px solid #e8e8e8';
            wrapper.style.borderRadius = '2px';
            wrapper.style.overflow = 'hidden';
            wrapper.style.marginBottom = '16px';
            wrapper.style.padding = '0';
            wrapper.style.width = '100%';
            const parent = element.parentElement;
            if (parent) {
                parent.insertBefore(wrapper, element);
                wrapper.appendChild(tabContainer);
                wrapper.appendChild(element);
                // Add inner padding to code content
                element.style.padding = '16px';
            }
        }
    }
    static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.1", ngImport: i0, type: NgeMonacoColorizerService, deps: [{ token: NgeMonacoLoaderService }, { token: NgeMonacoThemeService }], target: i0.ɵɵFactoryTarget.Injectable }); }
    static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.2.1", ngImport: i0, type: NgeMonacoColorizerService, providedIn: 'root' }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.1", ngImport: i0, type: NgeMonacoColorizerService, decorators: [{
            type: Injectable,
            args: [{ providedIn: 'root' }]
        }], ctorParameters: () => [{ type: NgeMonacoLoaderService }, { type: NgeMonacoThemeService }] });

class NgeMonacoViewerComponent {
    constructor() {
        this.colorizer = inject(NgeMonacoColorizerService);
        this.changeDetectorRef = inject(ChangeDetectorRef);
        this.subscriptions = [];
        this.loading = true;
    }
    ngOnChanges() {
        const code = this.transclusion.nativeElement.textContent?.trim() || this.code || '';
        this.colorize(code);
    }
    ngOnDestroy() {
        this.editor?.dispose();
        this.observer?.disconnect();
        this.subscriptions.forEach((s) => s.unsubscribe());
    }
    async colorize(code) {
        try {
            await this.colorizer.colorizeElement({
                code: code || '',
                theme: this.theme,
                lines: this.lines,
                language: this.language,
                highlights: this.highlights,
                filename: this.filename,
                element: this.container.nativeElement,
            });
        }
        finally {
            this.loading = false;
            this.changeDetectorRef.markForCheck();
        }
    }
    static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.1", ngImport: i0, type: NgeMonacoViewerComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
    static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.1", type: NgeMonacoViewerComponent, selector: "nge-monaco-viewer", inputs: { code: "code", lines: "lines", theme: "theme", language: "language", highlights: "highlights", filename: "filename" }, viewQueries: [{ propertyName: "container", first: true, predicate: ["container"], descendants: true, static: true }, { propertyName: "transclusion", first: true, predicate: ["transclusion"], descendants: true, static: true }], usesOnChanges: true, ngImport: i0, template: "<nge-monaco-placeholder *ngIf=\"loading\" />\n\n<pre class=\"monaco-editor monaco-editor-background\">\n  <code #container></code>\n</pre>\n\n<div #transclusion style=\"display: none;\">\n  <ng-content></ng-content>\n</div>\n\n", styles: ["pre{margin:.5em 0;overflow:auto;border:1px solid #f2f2f2}nge-monaco-placeholder{max-height:200px}\n"], dependencies: [{ kind: "directive", type: i2.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "component", type: NgeMonacoPlaceholderComponent, selector: "nge-monaco-placeholder" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.1", ngImport: i0, type: NgeMonacoViewerComponent, decorators: [{
            type: Component,
            args: [{ selector: 'nge-monaco-viewer', changeDetection: ChangeDetectionStrategy.OnPush, template: "<nge-monaco-placeholder *ngIf=\"loading\" />\n\n<pre class=\"monaco-editor monaco-editor-background\">\n  <code #container></code>\n</pre>\n\n<div #transclusion style=\"display: none;\">\n  <ng-content></ng-content>\n</div>\n\n", styles: ["pre{margin:.5em 0;overflow:auto;border:1px solid #f2f2f2}nge-monaco-placeholder{max-height:200px}\n"] }]
        }], propDecorators: { container: [{
                type: ViewChild,
                args: ['container', { static: true }]
            }], transclusion: [{
                type: ViewChild,
                args: ['transclusion', { static: true }]
            }], code: [{
                type: Input
            }], lines: [{
                type: Input
            }], theme: [{
                type: Input
            }], language: [{
                type: Input
            }], highlights: [{
                type: Input
            }], filename: [{
                type: Input
            }] } });

// ACTIONS
/** Toggle High Contrast Theme */
const ACTION_TOGGLE_HIGH_CONTRAST = 'editor.action.toggleHighContrast';
/** Set Selection Anchor */
const ACTION_SET_SELECTION_ANCHOR = 'editor.action.setSelectionAnchor';
/** Move Selected Text Left */
const ACTION_MOVE_CARRET_LEFT = 'editor.action.moveCarretLeftAction';
/** Move Selected Text Right */
const ACTION_MOVE_CARRET_RIGHT = 'editor.action.moveCarretRightAction';
/** Transpose Letters */
const ACTION_TRANSPOSE_LETTERS = 'editor.action.transposeLetters';
/** Copy With Syntax Highlighting */
const ACTION_CLIPBOARD_COPY_WITH_SYNTAX_HIGHLIGHTING = 'editor.action.clipboardCopyWithSyntaxHighlightingAction';
/** Toggle Line Comment */
const ACTION_COMMENT_LINE = 'editor.action.commentLine';
/** Add Line Comment */
const ACTION_ADD_COMMENT_LINE = 'editor.action.addCommentLine';
/** Remove Line Comment */
const ACTION_REMOVE_COMMENT_LINE = 'editor.action.removeCommentLine';
/** Toggle Block Comment */
const ACTION_BLOCK_COMMENT = 'editor.action.blockComment';
/** Show Editor Context Menu */
const ACTION_SHOW_CONTEXT_MENU = 'editor.action.showContextMenu';
/** Cursor Undo */
const ACTION_CURSOR_UNDO = 'cursorUndo';
/** Cursor Redo */
const ACTION_CURSOR_REDO = 'cursorRedo';
/** Editor Font Zoom In */
const ACTION_FONT_ZOOM_IN = 'editor.action.fontZoomIn';
/** Editor Font Zoom Out */
const ACTION_FONT_ZOOM_OUT = 'editor.action.fontZoomOut';
/** Editor Font Zoom Reset */
const ACTION_FONT_ZOOM_RESET = 'editor.action.fontZoomReset';
/** Convert Indentation to Spaces */
const ACTION_INDENTATION_TO_SPACES = 'editor.action.indentationToSpaces';
/** Convert Indentation to Tabs */
const ACTION_INDENTATION_TO_TABS = 'editor.action.indentationToTabs';
/** Indent Using Tabs */
const ACTION_INDENT_USING_TABS = 'editor.action.indentUsingTabs';
/** Indent Using Spaces */
const ACTION_INDENT_USING_SPACES = 'editor.action.indentUsingSpaces';
/** Detect Indentation from Content */
const ACTION_DETECT_INDENTATION = 'editor.action.detectIndentation';
/** Reindent Lines */
const ACTION_REINDENTLINES = 'editor.action.reindentlines';
/** Reindent Selected Lines */
const ACTION_REINDENTSELECTEDLINES = 'editor.action.reindentselectedlines';
/** Copy Line Up */
const ACTION_COPY_LINES_UP = 'editor.action.copyLinesUpAction';
/** Copy Line Down */
const ACTION_COPY_LINES_DOWN = 'editor.action.copyLinesDownAction';
/** Duplicate Selection */
const ACTION_DUPLICATE_SELECTION = 'editor.action.duplicateSelection';
/** Move Line Up */
const ACTION_MOVE_LINES_UP = 'editor.action.moveLinesUpAction';
/** Move Line Down */
const ACTION_MOVE_LINES_DOWN = 'editor.action.moveLinesDownAction';
/** Sort Lines Ascending */
const ACTION_SORT_LINES_ASCENDING = 'editor.action.sortLinesAscending';
/** Sort Lines Descending */
const ACTION_SORT_LINES_DESCENDING = 'editor.action.sortLinesDescending';
/** Trim Trailing Whitespace */
const ACTION_TRIM_TRAILING_WHITESPACE = 'editor.action.trimTrailingWhitespace';
/** Delete Line */
const ACTION_DELETE_LINES = 'editor.action.deleteLines';
/** Indent Line */
const ACTION_INDENT_LINES = 'editor.action.indentLines';
/** Outdent Line */
const ACTION_OUTDENT_LINES = 'editor.action.outdentLines';
/** Insert Line Above */
const ACTION_INSERT_LINE_BEFORE = 'editor.action.insertLineBefore';
/** Insert Line Below */
const ACTION_INSERT_LINE_AFTER = 'editor.action.insertLineAfter';
/** Delete All Left */
const ACTION_DELETE_ALL_LEFT = 'deleteAllLeft';
/** Delete All Right */
const ACTION_DELETE_ALL_RIGHT = 'deleteAllRight';
/** Join Lines */
const ACTION_JOIN_LINES = 'editor.action.joinLines';
/** Transpose characters around the cursor */
const ACTION_TRANSPOSE = 'editor.action.transpose';
/** Transform to Uppercase */
const ACTION_TRANSFORM_TO_UPPERCASE = 'editor.action.transformToUppercase';
/** Transform to Lowercase */
const ACTION_TRANSFORM_TO_LOWERCASE = 'editor.action.transformToLowercase';
/** Transform to Title Case */
const ACTION_TRANSFORM_TO_TITLECASE = 'editor.action.transformToTitlecase';
/** Expand Selection */
const ACTION_SMART_SELECT_EXPAND = 'editor.action.smartSelect.expand';
/** Shrink Selection */
const ACTION_SMART_SELECT_SHRINK = 'editor.action.smartSelect.shrink';
/** Developer: Force Retokenize */
const ACTION_FORCE_RETOKENIZE = 'editor.action.forceRetokenize';
/** Toggle Tab Key Moves Focus */
const ACTION_TOGGLE_TAB_FOCUS_MODE = 'editor.action.toggleTabFocusMode';
/** Command Palette */
const ACTION_QUICK_COMMAND = 'editor.action.quickCommand';
/** Replace with Previous Value */
const ACTION_IN_PLACE_REPLACE_UP = 'editor.action.inPlaceReplace.up';
/** Replace with Next Value */
const ACTION_IN_PLACE_REPLACE_DOWN = 'editor.action.inPlaceReplace.down';
/** Go to Line/Column... */
const ACTION_GOTO_LINE = 'editor.action.gotoLine';
/** Select to Bracket */
const ACTION_SELECT_TO_BRACKET = 'editor.action.selectToBracket';
/** Go to Bracket */
const ACTION_JUMP_TO_BRACKET = 'editor.action.jumpToBracket';
/** Find */
const ACTION_FIND = 'actions.find';
/** Find With Selection */
const ACTION_FIND_WITH_SELECTION = 'actions.findWithSelection';
/** Find Next */
const ACTION_NEXT_MATCH_FIND = 'editor.action.nextMatchFindAction';
/** Find Previous */
const ACTION_PREVIOUS_MATCH_FIND = 'editor.action.previousMatchFindAction';
/** Find Next Selection */
const ACTION_NEXT_SELECTION_MATCH_FIND = 'editor.action.nextSelectionMatchFindAction';
/** Find Previous Selection */
const ACTION_PREVIOUS_SELECTION_MATCH_FIND = 'editor.action.previousSelectionMatchFindAction';
/** Replace */
const ACTION_START_FIND_REPLACE = 'editor.action.startFindReplaceAction';
/** Unfold */
const ACTION_EDITOR_UNFOLD = 'editor.unfold';
/** Unfold Recursively */
const ACTION_EDITOR_UNFOLD_RECURSIVELY = 'editor.unfoldRecursively';
/** Fold */
const ACTION_EDITOR_FOLD = 'editor.fold';
/** Fold Recursively */
const ACTION_EDITOR_FOLD_RECURSIVELY = 'editor.foldRecursively';
/** Fold All */
const ACTION_EDITOR_FOLD_ALL = 'editor.foldAll';
/** Unfold All */
const ACTION_EDITOR_UNFOLD_ALL = 'editor.unfoldAll';
/** Fold All Block Comments */
const ACTION_EDITOR_FOLD_ALL_BLOCK_COMMENTS = 'editor.foldAllBlockComments';
/** Fold All Regions */
const ACTION_EDITOR_FOLD_ALL_MARKER_REGIONS = 'editor.foldAllMarkerRegions';
/** Unfold All Regions */
const ACTION_EDITOR_UNFOLD_ALL_MARKER_REGIONS = 'editor.unfoldAllMarkerRegions';
/** Toggle Fold */
const ACTION_EDITOR_TOGGLE_FOLD = 'editor.toggleFold';
/** Fold Level 1 */
const ACTION_EDITOR_FOLD_LEVEL1 = 'editor.foldLevel1';
/** Fold Level 2 */
const ACTION_EDITOR_FOLD_LEVEL2 = 'editor.foldLevel2';
/** Fold Level 3 */
const ACTION_EDITOR_FOLD_LEVEL3 = 'editor.foldLevel3';
/** Fold Level 4 */
const ACTION_EDITOR_FOLD_LEVEL4 = 'editor.foldLevel4';
/** Fold Level 5 */
const ACTION_EDITOR_FOLD_LEVEL5 = 'editor.foldLevel5';
/** Fold Level 6 */
const ACTION_EDITOR_FOLD_LEVEL6 = 'editor.foldLevel6';
/** Fold Level 7 */
const ACTION_EDITOR_FOLD_LEVEL7 = 'editor.foldLevel7';
/** Open Link */
const ACTION_OPEN_LINK = 'editor.action.openLink';
/** Trigger Symbol Highlight */
const ACTION_WORD_HIGHLIGHT_TRIGGER = 'editor.action.wordHighlight.trigger';
/** Show Accessibility Help */
const ACTION_SHOW_ACCESSIBILITY_HELP = 'editor.action.showAccessibilityHelp';
/** Developer: Inspect Tokens */
const ACTION_INSPECT_TOKENS = 'editor.action.inspectTokens';
/** Go to Next Problem (Error, Warning, Info) */
const ACTION_MARKER_NEXT = 'editor.action.marker.next';
/** Go to Previous Problem (Error, Warning, Info) */
const ACTION_MARKER_PREV = 'editor.action.marker.prev';
/** Go to Next Problem in Files (Error, Warning, Info) */
const ACTION_MARKER_NEXT_IN_FILES = 'editor.action.marker.nextInFiles';
/** Go to Previous Problem in Files (Error, Warning, Info) */
const ACTION_MARKER_PREV_IN_FILES = 'editor.action.marker.prevInFiles';
/** Show Hover */
const ACTION_SHOW_HOVER = 'editor.action.showHover';
/** Show Definition Preview Hover */
const ACTION_SHOW_DEFINITION_PREVIEW_HOVER = 'editor.action.showDefinitionPreviewHover';
/** Add Cursor Above */
const ACTION_INSERT_CURSOR_ABOVE = 'editor.action.insertCursorAbove';
/** Add Cursor Below */
const ACTION_INSERT_CURSOR_BELOW = 'editor.action.insertCursorBelow';
/** Add Cursors to Line Ends */
const ACTION_INSERT_CURSOR_AT_END_OF_EACH_LINE_SELECTED = 'editor.action.insertCursorAtEndOfEachLineSelected';
/** Add Selection To Next Find Match */
const ACTION_ADD_SELECTION_TO_NEXT_FIND_MATCH = 'editor.action.addSelectionToNextFindMatch';
/** Add Selection To Previous Find Match */
const ACTION_ADD_SELECTION_TO_PREVIOUS_FIND_MATCH = 'editor.action.addSelectionToPreviousFindMatch';
/** Move Last Selection To Next Find Match */
const ACTION_MOVE_SELECTION_TO_NEXT_FIND_MATCH = 'editor.action.moveSelectionToNextFindMatch';
/** Move Last Selection To Previous Find Match */
const ACTION_MOVE_SELECTION_TO_PREVIOUS_FIND_MATCH = 'editor.action.moveSelectionToPreviousFindMatch';
/** Select All Occurrences of Find Match */
const ACTION_SELECT_HIGHLIGHTS = 'editor.action.selectHighlights';
/** Add Cursors To Bottom */
const ACTION_ADD_CURSORS_TO_BOTTOM = 'editor.action.addCursorsToBottom';
/** Add Cursors To Top */
const ACTION_ADD_CURSORS_TO_TOP = 'editor.action.addCursorsToTop';
/** Trigger Suggest */
const ACTION_TRIGGER_SUGGEST = 'editor.action.triggerSuggest';
// https://github.com/microsoft/vscode/tree/master/src/vs/editor/contrib
const COLOR_DETECTOR_CONTRIB = 'editor.contrib.colorDetector';
const CONTEXT_MENU_CONTRIB = 'editor.contrib.contextmenu';
const CURSOR_UNDO_REDO_CONTROLLER_CONTRIB = 'editor.contrib.cursorUndoRedoController';
const DRAG_AND_DROP_CONTRIB = 'editor.contrib.dragAndDrop';
const AUTO_FORMAT_CONTRIB = 'editor.contrib.autoFormat';
const FORMAT_ON_PAST_CONTRIB = 'editor.contrib.formatOnPaste';
const SMART_SELECT_CONTRIB = 'editor.contrib.smartSelectController';
const IPAD_SHOW_KEYBOARD_CONTRIB = 'editor.contrib.iPadShowKeyboard';
const BRACKET_MATCHING_CONTROLLER_CONTRIB = 'editor.contrib.bracketMatchingController';
const CODE_LENS_CONTRIB = 'css.editor.codeLens';
const FIND_CONTROLLE_CONTRIB = 'editor.contrib.findController';
const FOLDING_CONTRIB = 'editor.contrib.folding';
const IN_PLACE_REPLACE_CONTROLLER_CONTRIB = 'editor.contrib.inPlaceReplaceController';
const LINK_DETECTOR_CONTRIB = 'editor.linkDetector';
const MESSAGE_CONTROLLER_CONTRIB = 'editor.contrib.messageController';
const QUICK_FIX_CONTROLLER_CONTRIB = 'editor.contrib.quickFixController';
const MULTI_CURSOR_CONTROLLER_CONTRIB = 'editor.contrib.multiCursorController';
const SELECTION_HIGHLIGHTER_CONTRIB = 'editor.contrib.selectionHighlighter';
const PARAMETER_HINTS_CONTRIB = 'editor.controller.parameterHints';
const REFERENCE_CONTROLLER_CONTRIB = 'editor.contrib.referenceController';
const RENAME_CONTROLLER_CONTRIB = 'editor.contrib.renameController';
const WORD_HIGHLIGHTER_CONTRIB = 'editor.contrib.wordHighlighter';
const ACCESSIBILIY_HELP_CONTROLLER_CONTRIB = 'editor.contrib.accessibilityHelpController';
const INSPECT_TOKENS_CONTRIB = 'editor.contrib.inspectTokens';
const QUICK_OPEN_CONTROLLER_CONTRIB = 'editor.controller.quickOpenController';
const GOTO_DEFINITION_CONTRIB = 'editor.contrib.gotodefinitionatposition';
const REFERENCES_CONTROLLER_CONTRIB = 'editor.contrib.referencesController';
const MARKER_CONTROLLER_CONTRIB = 'editor.contrib.markerController';
const HOVER_CONTRIB = 'editor.contrib.hover';
const SNIPPET_CONTROLLER_CONTRIB = 'snippetController2';
const SUGGEST_CONTROLLER_CONTRIB = 'editor.contrib.suggestController';

/**
 * When a user type a composition key like ^ or \` the editor
 * enter in composition mode, then after the user type any key the editor leave
 * this composition mode an duplicate the character pressed by the user.
 *
 * This bug occurs only on some browsers like firefox and calling this method will prevent this behavior
 * by removing any extra character added by the editor between 2 calls
 * of `onDidCompositionStart` and `onDidCompositionEnd`
 */
class PreventSymbolDuplication {
    activate() {
        this.disposable = monaco.editor.onDidCreateEditor((e) => {
            this.preventSymbolDuplicationOnCompositionEnd(e);
        });
    }
    deactivate() {
        this.disposable?.dispose();
    }
    preventSymbolDuplicationOnCompositionEnd(editor) {
        const positions = [];
        let disposables = [];
        disposables.push(editor.onDidCompositionStart(() => {
            const position = editor.getPosition();
            if (position) {
                positions.push(position);
            }
        }));
        disposables.push(editor.onDidCompositionEnd(() => {
            setTimeout(() => {
                if (!positions.length) {
                    return;
                }
                const before = positions[0];
                const after = editor.getPosition();
                if (!after) {
                    return;
                }
                positions.splice(0, 1);
                const diff = after.column - before.column;
                if (diff > 1) {
                    // unfocus the editor to leave composition
                    // mode because when the user type ` the editor
                    // leave the composition mode and begin another one
                    ;
                    document.activeElement?.blur();
                    // focus the editor to let the user continue to edit the content
                    // of the editor
                    editor.focus();
                    const r = new monaco.Range(after.lineNumber, after.column - (diff - 1), after.lineNumber, after.column);
                    editor.executeEdits('api', [{ range: r, text: '', forceMoveMarkers: false }]);
                }
            });
        }));
        disposables.push(editor.onDidDispose(() => {
            disposables.forEach((e) => e.dispose());
            disposables = [];
        }));
    }
}

class NgeMonacoModule {
    static forRoot(config) {
        return {
            ngModule: NgeMonacoModule,
            providers: [
                { provide: NGE_MONACO_CONFIG, useValue: config },
                {
                    provide: NGE_MONACO_CONTRIBUTION,
                    multi: true,
                    useExisting: NgeMonacoThemeService,
                },
                {
                    provide: NGE_MONACO_CONTRIBUTION,
                    multi: true,
                    useClass: PreventSymbolDuplication,
                },
            ],
        };
    }
    static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.1", ngImport: i0, type: NgeMonacoModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); }
    static { this.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "18.2.1", ngImport: i0, type: NgeMonacoModule, declarations: [NgeMonacoEditorComponent,
            NgeMonacoDiffEditorComponent,
            NgeMonacoViewerComponent,
            NgeMonacoPlaceholderComponent], imports: [CommonModule], exports: [NgeMonacoEditorComponent, NgeMonacoDiffEditorComponent, NgeMonacoViewerComponent] }); }
    static { this.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "18.2.1", ngImport: i0, type: NgeMonacoModule, imports: [CommonModule] }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.1", ngImport: i0, type: NgeMonacoModule, decorators: [{
            type: NgModule,
            args: [{
                    imports: [CommonModule],
                    exports: [NgeMonacoEditorComponent, NgeMonacoDiffEditorComponent, NgeMonacoViewerComponent],
                    declarations: [
                        NgeMonacoEditorComponent,
                        NgeMonacoDiffEditorComponent,
                        NgeMonacoViewerComponent,
                        NgeMonacoPlaceholderComponent,
                    ],
                }]
        }] });

/// <reference types="monaco-editor/monaco" />

/**
 * Generated bundle index. Do not edit.
 */

export { ACCESSIBILIY_HELP_CONTROLLER_CONTRIB, ACTION_ADD_COMMENT_LINE, ACTION_ADD_CURSORS_TO_BOTTOM, ACTION_ADD_CURSORS_TO_TOP, ACTION_ADD_SELECTION_TO_NEXT_FIND_MATCH, ACTION_ADD_SELECTION_TO_PREVIOUS_FIND_MATCH, ACTION_BLOCK_COMMENT, ACTION_CLIPBOARD_COPY_WITH_SYNTAX_HIGHLIGHTING, ACTION_COMMENT_LINE, ACTION_COPY_LINES_DOWN, ACTION_COPY_LINES_UP, ACTION_CURSOR_REDO, ACTION_CURSOR_UNDO, ACTION_DELETE_ALL_LEFT, ACTION_DELETE_ALL_RIGHT, ACTION_DELETE_LINES, ACTION_DETECT_INDENTATION, ACTION_DUPLICATE_SELECTION, ACTION_EDITOR_FOLD, ACTION_EDITOR_FOLD_ALL, ACTION_EDITOR_FOLD_ALL_BLOCK_COMMENTS, ACTION_EDITOR_FOLD_ALL_MARKER_REGIONS, ACTION_EDITOR_FOLD_LEVEL1, ACTION_EDITOR_FOLD_LEVEL2, ACTION_EDITOR_FOLD_LEVEL3, ACTION_EDITOR_FOLD_LEVEL4, ACTION_EDITOR_FOLD_LEVEL5, ACTION_EDITOR_FOLD_LEVEL6, ACTION_EDITOR_FOLD_LEVEL7, ACTION_EDITOR_FOLD_RECURSIVELY, ACTION_EDITOR_TOGGLE_FOLD, ACTION_EDITOR_UNFOLD, ACTION_EDITOR_UNFOLD_ALL, ACTION_EDITOR_UNFOLD_ALL_MARKER_REGIONS, ACTION_EDITOR_UNFOLD_RECURSIVELY, ACTION_FIND, ACTION_FIND_WITH_SELECTION, ACTION_FONT_ZOOM_IN, ACTION_FONT_ZOOM_OUT, ACTION_FONT_ZOOM_RESET, ACTION_FORCE_RETOKENIZE, ACTION_GOTO_LINE, ACTION_INDENTATION_TO_SPACES, ACTION_INDENTATION_TO_TABS, ACTION_INDENT_LINES, ACTION_INDENT_USING_SPACES, ACTION_INDENT_USING_TABS, ACTION_INSERT_CURSOR_ABOVE, ACTION_INSERT_CURSOR_AT_END_OF_EACH_LINE_SELECTED, ACTION_INSERT_CURSOR_BELOW, ACTION_INSERT_LINE_AFTER, ACTION_INSERT_LINE_BEFORE, ACTION_INSPECT_TOKENS, ACTION_IN_PLACE_REPLACE_DOWN, ACTION_IN_PLACE_REPLACE_UP, ACTION_JOIN_LINES, ACTION_JUMP_TO_BRACKET, ACTION_MARKER_NEXT, ACTION_MARKER_NEXT_IN_FILES, ACTION_MARKER_PREV, ACTION_MARKER_PREV_IN_FILES, ACTION_MOVE_CARRET_LEFT, ACTION_MOVE_CARRET_RIGHT, ACTION_MOVE_LINES_DOWN, ACTION_MOVE_LINES_UP, ACTION_MOVE_SELECTION_TO_NEXT_FIND_MATCH, ACTION_MOVE_SELECTION_TO_PREVIOUS_FIND_MATCH, ACTION_NEXT_MATCH_FIND, ACTION_NEXT_SELECTION_MATCH_FIND, ACTION_OPEN_LINK, ACTION_OUTDENT_LINES, ACTION_PREVIOUS_MATCH_FIND, ACTION_PREVIOUS_SELECTION_MATCH_FIND, ACTION_QUICK_COMMAND, ACTION_REINDENTLINES, ACTION_REINDENTSELECTEDLINES, ACTION_REMOVE_COMMENT_LINE, ACTION_SELECT_HIGHLIGHTS, ACTION_SELECT_TO_BRACKET, ACTION_SET_SELECTION_ANCHOR, ACTION_SHOW_ACCESSIBILITY_HELP, ACTION_SHOW_CONTEXT_MENU, ACTION_SHOW_DEFINITION_PREVIEW_HOVER, ACTION_SHOW_HOVER, ACTION_SMART_SELECT_EXPAND, ACTION_SMART_SELECT_SHRINK, ACTION_SORT_LINES_ASCENDING, ACTION_SORT_LINES_DESCENDING, ACTION_START_FIND_REPLACE, ACTION_TOGGLE_HIGH_CONTRAST, ACTION_TOGGLE_TAB_FOCUS_MODE, ACTION_TRANSFORM_TO_LOWERCASE, ACTION_TRANSFORM_TO_TITLECASE, ACTION_TRANSFORM_TO_UPPERCASE, ACTION_TRANSPOSE, ACTION_TRANSPOSE_LETTERS, ACTION_TRIGGER_SUGGEST, ACTION_TRIM_TRAILING_WHITESPACE, ACTION_WORD_HIGHLIGHT_TRIGGER, AUTO_FORMAT_CONTRIB, BRACKET_MATCHING_CONTROLLER_CONTRIB, CODE_LENS_CONTRIB, COLOR_DETECTOR_CONTRIB, CONTEXT_MENU_CONTRIB, CURSOR_UNDO_REDO_CONTROLLER_CONTRIB, DRAG_AND_DROP_CONTRIB, FIND_CONTROLLE_CONTRIB, FOLDING_CONTRIB, FORMAT_ON_PAST_CONTRIB, GOTO_DEFINITION_CONTRIB, HOVER_CONTRIB, INSPECT_TOKENS_CONTRIB, IN_PLACE_REPLACE_CONTROLLER_CONTRIB, IPAD_SHOW_KEYBOARD_CONTRIB, LINK_DETECTOR_CONTRIB, MARKER_CONTROLLER_CONTRIB, MESSAGE_CONTROLLER_CONTRIB, MONACO_CDNJS_URL, MONACO_JS_DELIVER_URL, MULTI_CURSOR_CONTROLLER_CONTRIB, NGE_MONACO_CONTRIBUTION, NGE_MONACO_THEMES, NgeMonacoColorizerService, NgeMonacoDiffEditorComponent, NgeMonacoEditorComponent, NgeMonacoLoaderService, NgeMonacoModule, NgeMonacoThemeService, NgeMonacoViewerComponent, PARAMETER_HINTS_CONTRIB, QUICK_FIX_CONTROLLER_CONTRIB, QUICK_OPEN_CONTROLLER_CONTRIB, REFERENCES_CONTROLLER_CONTRIB, REFERENCE_CONTROLLER_CONTRIB, RENAME_CONTROLLER_CONTRIB, SELECTION_HIGHLIGHTER_CONTRIB, SMART_SELECT_CONTRIB, SNIPPET_CONTROLLER_CONTRIB, SUGGEST_CONTROLLER_CONTRIB, WORD_HIGHLIGHTER_CONTRIB };
//# sourceMappingURL=cisstech-nge-monaco.mjs.map