mirror of
https://github.com/compiler-explorer/compiler-explorer.git
synced 2025-12-27 12:54:00 -05:00
- Removes `rootDirs` so all imports will be relative in the frontend - Updates (and unifies) imports to be `../types/...` etc instead of relying on "types" being in the rootDir for the frontend. - Fixes one type that was being picked up from `lib` in the frontend. - Adds a precommit hook to check in future Paves the way to writing _unit_ tests for the frontend for the subset of the frontend code we can import from `node` (which might be a lot of it!)
168 lines
6.2 KiB
TypeScript
168 lines
6.2 KiB
TypeScript
// Copyright (c) 2022, Tom Ritter and Compiler Explorer Authors
|
|
// All rights reserved.
|
|
//
|
|
// Redistribution and use in source and binary forms, with or without
|
|
// modification, are permitted provided that the following conditions are met:
|
|
//
|
|
// * Redistributions of source code must retain the above copyright notice,
|
|
// this list of conditions and the following disclaimer.
|
|
// * Redistributions in binary form must reproduce the above copyright
|
|
// notice, this list of conditions and the following disclaimer in the
|
|
// documentation and/or other materials provided with the distribution.
|
|
//
|
|
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
|
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
|
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
|
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
|
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
|
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
|
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
|
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
|
// POSSIBILITY OF SUCH DAMAGE.
|
|
|
|
import {Container} from 'golden-layout';
|
|
import $ from 'jquery';
|
|
import * as monaco from 'monaco-editor';
|
|
import _ from 'underscore';
|
|
import {CompilationResult} from '../../types/compilation/compilation.interfaces.js';
|
|
import {CompilerInfo} from '../../types/compiler.interfaces.js';
|
|
import {Hub} from '../hub.js';
|
|
import * as monacoConfig from '../monaco-config.js';
|
|
import {Settings, SiteSettings} from '../settings.js';
|
|
import {FlagsViewState} from './flags-view.interfaces.js';
|
|
import {MonacoPaneState} from './pane.interfaces.js';
|
|
import {MonacoPane} from './pane.js';
|
|
|
|
export class Flags extends MonacoPane<monaco.editor.IStandaloneCodeEditor, FlagsViewState> {
|
|
debouncedEmitChange: (e: boolean) => void = () => {};
|
|
cursorSelectionThrottledFunction: ((e: any) => void) & _.Cancelable;
|
|
lastChangeEmitted: string;
|
|
constructor(hub: Hub, container: Container, state: FlagsViewState & MonacoPaneState) {
|
|
super(hub, container, state);
|
|
|
|
let value = '';
|
|
if (state.compilerFlags) {
|
|
value = state.compilerFlags.replace(/ /g, '\n');
|
|
}
|
|
this.editor.setValue(value);
|
|
|
|
this.onSettingsChange(Settings.getStoredSettings());
|
|
this.eventHub.emit('flagsViewOpened', this.compilerInfo.compilerId);
|
|
}
|
|
|
|
override getInitialHTML() {
|
|
return $('#flags').html();
|
|
}
|
|
|
|
override createEditor(editorRoot: HTMLElement) {
|
|
this.editor = monaco.editor.create(
|
|
editorRoot,
|
|
monacoConfig.extendConfig({
|
|
language: 'plaintext',
|
|
readOnly: false,
|
|
glyphMargin: true,
|
|
}),
|
|
);
|
|
}
|
|
|
|
override getPrintName() {
|
|
return '<Unimplemented>';
|
|
}
|
|
|
|
override sendPrintData() {
|
|
// nop
|
|
}
|
|
|
|
override registerCallbacks() {
|
|
this.eventHub.emit('requestSettings');
|
|
this.eventHub.emit('findCompilers');
|
|
|
|
this.container.layoutManager.on('initialised', () => {
|
|
// Once initialized, let everyone know what text we have.
|
|
this.maybeEmitChange(false);
|
|
});
|
|
this.eventHub.on('initialised', () => this.maybeEmitChange(false), this);
|
|
|
|
this.editor.getModel()?.onDidChangeContent(() => {
|
|
this.debouncedEmitChange(false);
|
|
this.updateState();
|
|
});
|
|
|
|
this.cursorSelectionThrottledFunction = _.throttle(this.onDidChangeCursorSelection.bind(this), 500);
|
|
this.editor.onDidChangeCursorSelection(e => {
|
|
this.cursorSelectionThrottledFunction(e);
|
|
});
|
|
}
|
|
|
|
override getDefaultPaneName() {
|
|
return 'Detailed Compiler Flags';
|
|
}
|
|
|
|
override onCompiler(
|
|
compilerId: number,
|
|
compiler: CompilerInfo | null,
|
|
options: string,
|
|
editorId: number,
|
|
treeId: number,
|
|
) {
|
|
if (compilerId === this.compilerInfo.compilerId) {
|
|
this.compilerInfo.compilerName = compiler ? compiler.name : '';
|
|
this.compilerInfo.editorId = editorId;
|
|
this.compilerInfo.treeId = treeId;
|
|
this.updateTitle();
|
|
}
|
|
}
|
|
|
|
override onCompileResult(compilerId: number, compiler: CompilerInfo, result: CompilationResult) {}
|
|
|
|
override close() {
|
|
this.eventHub.unsubscribe();
|
|
this.eventHub.emit('flagsViewClosed', this.compilerInfo.compilerId, this.getOptions());
|
|
this.editor.dispose();
|
|
}
|
|
|
|
override onCompilerClose(compilerId: number) {
|
|
if (compilerId === this.compilerInfo.compilerId) {
|
|
// We can't immediately close as an outer loop somewhere in GoldenLayout is iterating over
|
|
// the hierarchy. We can't modify while it's being iterated over.
|
|
this.close();
|
|
_.defer(() => {
|
|
this.container.close();
|
|
});
|
|
}
|
|
}
|
|
|
|
override onSettingsChange(newSettings: SiteSettings) {
|
|
super.onSettingsChange(newSettings);
|
|
this.debouncedEmitChange = _.debounce(this.maybeEmitChange.bind(this), newSettings.delayAfterChange);
|
|
}
|
|
|
|
getOptions() {
|
|
const lines = this.editor.getModel()?.getValue();
|
|
return lines ? lines.replace(/\n/g, ' ') : ''; // TODO
|
|
}
|
|
|
|
override getCurrentState() {
|
|
const parent = super.getCurrentState();
|
|
const state = {
|
|
compilerFlags: this.getOptions(),
|
|
...parent,
|
|
};
|
|
// FIXME: need some way to have this return S & MonacoPaneState
|
|
// or maybe have an abstract function in pane.ts returning S
|
|
// that pane.ts can then merge. will require reworking pane.ts'
|
|
// interface a bit either way
|
|
return state as MonacoPaneState;
|
|
}
|
|
|
|
maybeEmitChange(force: boolean) {
|
|
const options = this.getOptions();
|
|
if (!force && options === this.lastChangeEmitted) return;
|
|
|
|
this.lastChangeEmitted = options;
|
|
this.eventHub.emit('compilerFlagsChange', this.compilerInfo.compilerId, this.lastChangeEmitted);
|
|
}
|
|
}
|