mirror of
https://github.com/compiler-explorer/compiler-explorer.git
synced 2025-12-27 09:23:52 -05:00
Enforce max-statement/line & further unify UI
This commit is contained in:
@@ -8,8 +8,8 @@
|
||||
},
|
||||
"rules": {
|
||||
"eqeqeq": ["error", "smart"],
|
||||
"max-statements": ["warn", 50],
|
||||
"max-len": ["warn", 120, { "ignoreRegExpLiterals": true }],
|
||||
"max-statements": ["error", 50],
|
||||
"max-len": ["error", 120, { "ignoreRegExpLiterals": true }],
|
||||
"eol-last": ["error", "always"],
|
||||
"semi": ["error", "always"],
|
||||
"indent": ["error", 4, { "SwitchCase": 1 }],
|
||||
|
||||
10
app.js
10
app.js
@@ -241,7 +241,9 @@ function ClientOptionsHandler(fileSources) {
|
||||
}), 'name');
|
||||
|
||||
const supportsBinary = compilerPropsAT(languages, res => !!res, 'supportsBinary', true);
|
||||
const supportsExecutePerLanguage = compilerPropsAT(languages, (res, lang) => supportsBinary[lang.id] && !!res, 'supportsExecute', true);
|
||||
const supportsExecutePerLanguage = compilerPropsAT(languages, (res, lang) => {
|
||||
return supportsBinary[lang.id] && !!res;
|
||||
}, 'supportsExecute', true);
|
||||
const supportsExecute = Object.values(supportsExecutePerLanguage).some((value) => value);
|
||||
|
||||
const libs = {};
|
||||
@@ -303,7 +305,8 @@ function ClientOptionsHandler(fileSources) {
|
||||
doCache: doCache
|
||||
};
|
||||
this.setCompilers = compilers => {
|
||||
const blacklistedKeys = ['exe', 'versionFlag', 'versionRe', 'compilerType', 'demangler', 'objdumper', 'postProcess'];
|
||||
const blacklistedKeys = ['exe', 'versionFlag', 'versionRe', 'compilerType', 'demangler', 'objdumper',
|
||||
'postProcess'];
|
||||
const copiedCompilers = JSON.parse(JSON.stringify(compilers));
|
||||
_.each(options.compilers, (compiler, compilersKey) => {
|
||||
_.each(compiler, (_, propKey) => {
|
||||
@@ -649,7 +652,8 @@ Promise.all([findCompilers(), aws.initConfig(awsProps)])
|
||||
}));
|
||||
webServer.use(express.static(staticDir));
|
||||
} else {
|
||||
//assume that anything not dev is just production this gives sane defaults for anyone who isn't messing with this
|
||||
/* Assume that anything not dev is just production.
|
||||
* This gives sane defaults for anyone who isn't messing with this */
|
||||
logger.info(" serving static files from '" + staticDir + "'");
|
||||
webServer.use(express.static(staticDir, {maxAge: staticMaxAgeSecs * 1000}));
|
||||
}
|
||||
|
||||
@@ -269,7 +269,9 @@ class BaseCompiler {
|
||||
const outputFilebase = "output";
|
||||
const outputFilename = this.getOutputFilename(dirPath, outputFilebase);
|
||||
|
||||
options = _.compact(this.prepareArguments(options, filters, backendOptions, inputFilename, outputFilename));
|
||||
options = _.compact(
|
||||
this.prepareArguments(options, filters, backendOptions, inputFilename, outputFilename)
|
||||
);
|
||||
|
||||
const execOptions = this.getDefaultExecOptions();
|
||||
|
||||
|
||||
@@ -46,7 +46,9 @@ function execute(command, args, options) {
|
||||
// AP: Run Windows-volume executables in winTmp. Otherwise, run in tmpDir (which may be undefined).
|
||||
// https://nodejs.org/api/child_process.html#child_process_child_process_spawn_command_args_options
|
||||
const child = child_process.spawn(command, args, {
|
||||
cwd: options.customCwd ? options.customCwd : (command.startsWith("/mnt") && process.env.wsl) ? process.env.winTmp : process.env.tmpDir,
|
||||
cwd: options.customCwd ? options.customCwd : (
|
||||
(command.startsWith("/mnt") && process.env.wsl) ? process.env.winTmp : process.env.tmpDir
|
||||
),
|
||||
env: env,
|
||||
detached: process.platform === 'linux'
|
||||
});
|
||||
|
||||
@@ -125,7 +125,9 @@ class CompileHandler {
|
||||
_.each(this.compilersById, compilerInLang => {
|
||||
if (response === undefined) {
|
||||
_.each(compilerInLang, compiler => {
|
||||
if (response === undefined && (compiler.compiler.id === compilerId || compiler.compiler.alias === compilerId)) {
|
||||
if (response === undefined &&
|
||||
(compiler.compiler.id === compilerId || compiler.compiler.alias === compilerId)) {
|
||||
|
||||
response = compiler;
|
||||
}
|
||||
});
|
||||
@@ -195,7 +197,8 @@ class CompileHandler {
|
||||
const {source, options, backendOptions, filters} = this.parseRequest(req, compiler);
|
||||
const remote = compiler.getRemote();
|
||||
if (remote) {
|
||||
req.url = req.originalUrl; // Undo any routing that was done to get here (i.e. /api/* path has been removed)
|
||||
// Undo any routing that was done to get here (i.e. /api/* path has been removed)
|
||||
req.url = req.originalUrl;
|
||||
this.proxy.web(req, res, {target: remote}, e => {
|
||||
logger.error("Proxy error: ", e);
|
||||
next(e);
|
||||
|
||||
@@ -77,9 +77,7 @@ class PascalDemangler {
|
||||
|
||||
demangle(text) {
|
||||
if (!text.endsWith(':')) return false;
|
||||
if (this.shouldIgnoreSymbol(text)) {
|
||||
return false;
|
||||
}
|
||||
if (this.shouldIgnoreSymbol(text)) return false;
|
||||
|
||||
text = text.substr(0, text.length - 1);
|
||||
|
||||
@@ -91,13 +89,12 @@ class PascalDemangler {
|
||||
}
|
||||
}
|
||||
|
||||
let unmangledGlobalVar;
|
||||
if (text.startsWith("U_$OUTPUT_$$_")) {
|
||||
unmangledGlobalVar = text.substr(13).toLowerCase();
|
||||
let unmangledGlobalVar = text.substr(13).toLowerCase();
|
||||
this.symbolStore.Add(text, unmangledGlobalVar);
|
||||
return unmangledGlobalVar;
|
||||
} else if (text.startsWith("U_OUTPUT_")) {
|
||||
unmangledGlobalVar = text.substr(9).toLowerCase();
|
||||
let unmangledGlobalVar = text.substr(9).toLowerCase();
|
||||
this.symbolStore.Add(text, unmangledGlobalVar);
|
||||
return unmangledGlobalVar;
|
||||
}
|
||||
|
||||
@@ -8,8 +8,8 @@
|
||||
},
|
||||
"rules": {
|
||||
"eqeqeq": ["error", "smart"],
|
||||
"max-statements": ["warn", 50],
|
||||
"max-len": ["warn", 120, { "ignoreRegExpLiterals": true }],
|
||||
"max-statements": ["error", 50],
|
||||
"max-len": ["error", 120, { "ignoreRegExpLiterals": true }],
|
||||
"strict": ["error", "safe"],
|
||||
"eol-last": ["error", "always"],
|
||||
"semi": ["error", "always"],
|
||||
|
||||
@@ -131,6 +131,16 @@ Ast.prototype.onCompilerClose = function (id) {
|
||||
};
|
||||
|
||||
Ast.prototype.updateState = function () {
|
||||
this.container.setState(this.currentState());
|
||||
};
|
||||
|
||||
Ast.prototype.currentState = function () {
|
||||
var state = {
|
||||
id: this._compilerid,
|
||||
editorid: this._editorid
|
||||
};
|
||||
this.fontScale.addState(state);
|
||||
return state;
|
||||
};
|
||||
|
||||
Ast.prototype.onCompilerClose = function (id) {
|
||||
|
||||
@@ -93,28 +93,15 @@ function Cfg(hub, container, state) {
|
||||
}
|
||||
};
|
||||
|
||||
this.toggles = new Toggles(this.domRoot.find('.options'), state.options);
|
||||
|
||||
this.cfgVisualiser = new vis.Network(this.domRoot.find('.graph-placeholder')[0],
|
||||
this.defaultCfgOutput, this.networkOpts);
|
||||
|
||||
this.cfgVisualiser.on('dragEnd', _.bind(this.saveState, this));
|
||||
this.cfgVisualiser.on('zoom', _.bind(this.saveState, this));
|
||||
|
||||
this.toggleNavigationButton = this.domRoot.find('.toggle-navigation');
|
||||
this.toggleNavigationButton.on('click', _.bind(function () {
|
||||
this.networkOpts.interaction.navigationButtons = this.toggleNavigationButton.hasClass('active');
|
||||
this.cfgVisualiser.setOptions(this.networkOpts);
|
||||
}, this));
|
||||
this.togglePhysicsButton = this.domRoot.find('.toggle-physics');
|
||||
this.togglePhysicsButton.on('click', _.bind(function () {
|
||||
this.networkOpts.physics.enabled = this.togglePhysicsButton.hasClass('active');
|
||||
// change only physics.enabled option to preserve current node locations
|
||||
this.cfgVisualiser.setOptions({
|
||||
physics: {enabled: this.networkOpts.physics.enabled}
|
||||
});
|
||||
}, this));
|
||||
this.initButtons(state);
|
||||
|
||||
this.initCallbacks();
|
||||
this.compilerId = state.id;
|
||||
this._editorid = state.editorid;
|
||||
this._binaryFilter = false;
|
||||
@@ -137,24 +124,13 @@ function Cfg(hub, container, state) {
|
||||
}
|
||||
}, this));
|
||||
|
||||
this.eventHub.on('compilerClose', this.onCompilerClose, this);
|
||||
this.eventHub.on('compileResult', this.onCompileResult, this);
|
||||
this.eventHub.on('compiler', this.onCompiler, this);
|
||||
this.eventHub.on('filtersChange', this.onFiltersChange, this);
|
||||
|
||||
this.container.on('destroy', this.close, this);
|
||||
this.container.on('resize', this.resize, this);
|
||||
this.container.on('shown', this.resize, this);
|
||||
this.eventHub.emit('cfgViewOpened', this.compilerId);
|
||||
this.eventHub.emit('requestFilters', this.compilerId);
|
||||
this.eventHub.emit('requestCompiler', this.compilerId);
|
||||
|
||||
this.initCallbacks();
|
||||
this.adaptStructure = function (names) {
|
||||
return _.map(names, function (name) {
|
||||
return {name: name};
|
||||
});
|
||||
};
|
||||
|
||||
this.updateButtons();
|
||||
this.setTitle();
|
||||
}
|
||||
|
||||
@@ -203,6 +179,57 @@ Cfg.prototype.onFiltersChange = function (id, filters) {
|
||||
}
|
||||
};
|
||||
|
||||
Cfg.prototype.initButtons = function (state) {
|
||||
this.toggles = new Toggles(this.domRoot.find('.options'), state.options);
|
||||
|
||||
this.toggleNavigationButton = this.domRoot.find('.toggle-navigation');
|
||||
this.toggleNavigationTitle = this.toggleNavigationButton.prop('title');
|
||||
|
||||
this.togglePhysicsButton = this.domRoot.find('.toggle-physics');
|
||||
this.togglePhysicsTitle = this.togglePhysicsButton.prop('title');
|
||||
};
|
||||
|
||||
Cfg.prototype.initCallbacks = function () {
|
||||
this.eventHub.on('compilerClose', this.onCompilerClose, this);
|
||||
this.eventHub.on('compileResult', this.onCompileResult, this);
|
||||
this.eventHub.on('compiler', this.onCompiler, this);
|
||||
this.eventHub.on('filtersChange', this.onFiltersChange, this);
|
||||
|
||||
this.container.on('destroy', this.close, this);
|
||||
this.container.on('resize', this.resize, this);
|
||||
this.container.on('shown', this.resize, this);
|
||||
this.eventHub.emit('cfgViewOpened', this.compilerId);
|
||||
this.eventHub.emit('requestFilters', this.compilerId);
|
||||
this.eventHub.emit('requestCompiler', this.compilerId);
|
||||
|
||||
this.togglePhysicsButton.on('click', _.bind(function () {
|
||||
this.networkOpts.physics.enabled = this.togglePhysicsButton.hasClass('active');
|
||||
// change only physics.enabled option to preserve current node locations
|
||||
this.cfgVisualiser.setOptions({
|
||||
physics: {enabled: this.networkOpts.physics.enabled}
|
||||
});
|
||||
}, this));
|
||||
|
||||
this.toggleNavigationButton.on('click', _.bind(function () {
|
||||
this.networkOpts.interaction.navigationButtons = this.toggleNavigationButton.hasClass('active');
|
||||
this.cfgVisualiser.setOptions({interaction: {
|
||||
navigationButtons: this.networkOpts.interaction.navigationButtons}
|
||||
});
|
||||
}, this));
|
||||
this.toggles.on('change', _.bind(function () {
|
||||
this.updateButtons();
|
||||
this.saveState();
|
||||
}, this));
|
||||
};
|
||||
|
||||
Cfg.prototype.updateButtons = function () {
|
||||
var formatButtonTitle = function (button, title) {
|
||||
button.prop('title', '[' + (button.hasClass('active') ? 'ON' : 'OFF') + '] ' + title);
|
||||
};
|
||||
formatButtonTitle(this.togglePhysicsButton, this.togglePhysicsTitle);
|
||||
formatButtonTitle(this.toggleNavigationButton, this.toggleNavigationTitle);
|
||||
};
|
||||
|
||||
Cfg.prototype.resize = function () {
|
||||
if (this.cfgVisualiser.canvas) {
|
||||
var height = this.domRoot.height() - this.domRoot.find('.top-bar').outerHeight(true);
|
||||
@@ -212,7 +239,8 @@ Cfg.prototype.resize = function () {
|
||||
};
|
||||
|
||||
Cfg.prototype.setTitle = function () {
|
||||
this.container.setTitle(this._compilerName + ' Graph Viewer (Editor #' + this._editorid + ', Compiler #' + this.compilerId + ')');
|
||||
this.container.setTitle(
|
||||
this._compilerName + ' Graph Viewer (Editor #' + this._editorid + ', Compiler #' + this.compilerId + ')');
|
||||
};
|
||||
|
||||
Cfg.prototype.assignLevels = function (data) {
|
||||
|
||||
@@ -68,6 +68,7 @@ var languages = options.languages;
|
||||
|
||||
function Compiler(hub, container, state) {
|
||||
this.container = container;
|
||||
this.hub = hub;
|
||||
this.eventHub = hub.createEventHub();
|
||||
this.compilerService = hub.compilerService;
|
||||
this.domRoot = container.getElement();
|
||||
@@ -75,31 +76,12 @@ function Compiler(hub, container, state) {
|
||||
this.id = state.id || hub.nextCompilerId();
|
||||
this.sourceEditorId = state.source || 1;
|
||||
this.settings = JSON.parse(local.get('settings', '{}'));
|
||||
// If we don't have a language, but a compiler, find the corresponding language.
|
||||
this.currentLangId = state.lang;
|
||||
if (!this.currentLangId && state.compiler) {
|
||||
this.currentLangId = this.langOfCompiler(state.compiler);
|
||||
}
|
||||
if (!this.currentLangId && languages[this.settings.defaultLanguage]) {
|
||||
this.currentLangId = languages[this.settings.defaultLanguage].id;
|
||||
}
|
||||
if (!this.currentLangId) {
|
||||
this.currentLangId = _.keys(languages)[0];
|
||||
}
|
||||
this.originalCompilerId = state.compiler;
|
||||
if (state.compiler)
|
||||
this.compiler = this.findCompiler(this.currentLangId, state.compiler);
|
||||
else
|
||||
this.compiler = this.findCompiler(this.currentLangId, options.defaultCompiler[this.currentLangId]);
|
||||
if (!this.compiler) {
|
||||
var compilers = this.compilerService.compilersByLang[this.currentLangId];
|
||||
if (compilers) this.compiler = _.values(compilers)[0];
|
||||
}
|
||||
this.initLang(state);
|
||||
this.initCompiler(state);
|
||||
this.infoByLang = {};
|
||||
this.deferCompiles = hub.deferred;
|
||||
this.needsCompile = false;
|
||||
this.options = state.options || options.compileOptions[this.currentLangId];
|
||||
this.filters = new Toggles(this.domRoot.find('.filters'), patchOldFilters(state.filters));
|
||||
this.source = '';
|
||||
this.assembly = [];
|
||||
this.colours = [];
|
||||
@@ -113,18 +95,7 @@ function Compiler(hub, container, state) {
|
||||
this.prevDecorations = [];
|
||||
this.alertSystem = new Alert();
|
||||
|
||||
this.initButtons();
|
||||
this.initLibraries(state);
|
||||
|
||||
this.linkedFadeTimeoutId = -1;
|
||||
this.getGroupsInUse = function () {
|
||||
var currentLangCompilers = _.map(this.getCurrentLangCompilers(), _.identity, this);
|
||||
return _.map(_.uniq(currentLangCompilers, false, function (compiler) {
|
||||
return compiler.group;
|
||||
}), function (compiler) {
|
||||
return {value: compiler.group, label: compiler.groupName || compiler.group};
|
||||
});
|
||||
};
|
||||
|
||||
this.domRoot.find('.compiler-picker').selectize({
|
||||
sortField: 'name',
|
||||
@@ -133,7 +104,7 @@ function Compiler(hub, container, state) {
|
||||
searchField: ['name'],
|
||||
optgroupField: 'group',
|
||||
optgroups: this.getGroupsInUse(),
|
||||
options: _.map(this.getCurrentLangCompilers(), _.identity, this),
|
||||
options: _.map(this.getCurrentLangCompilers(), _.identity),
|
||||
items: this.compiler ? [this.compiler.id] : []
|
||||
}).on('change', _.bind(function (e) {
|
||||
var val = $(e.target).val();
|
||||
@@ -146,15 +117,6 @@ function Compiler(hub, container, state) {
|
||||
this.onCompilerChange(val);
|
||||
}
|
||||
}, this));
|
||||
var optionsChange = _.debounce(_.bind(function (e) {
|
||||
this.onOptionsChange($(e.target).val());
|
||||
}, this), 800);
|
||||
this.optionsField
|
||||
.val(this.options)
|
||||
.on('change', optionsChange)
|
||||
.on('keyup', optionsChange);
|
||||
|
||||
this.filterExecuteButton.toggle(options.supportsExecute);
|
||||
|
||||
this.outputEditor = monaco.editor.create(this.domRoot.find('.monaco-placeholder')[0], {
|
||||
scrollBeyondLastLine: false,
|
||||
@@ -168,6 +130,181 @@ function Compiler(hub, container, state) {
|
||||
},
|
||||
lineNumbersMinChars: options.embedded ? 1 : 5
|
||||
});
|
||||
|
||||
this.initButtons(state);
|
||||
this.initLibraries(state);
|
||||
|
||||
this.initEditorActions();
|
||||
|
||||
this.mouseMoveThrottledFunction = _.throttle(_.bind(this.onMouseMove, this), 250);
|
||||
|
||||
this.initCallbacks();
|
||||
// Handle initial settings
|
||||
this.onSettingsChange(this.settings);
|
||||
this.sendCompiler();
|
||||
this.updateCompilerInfo();
|
||||
this.updateButtons();
|
||||
this.updateLibsDropdown();
|
||||
this.saveState();
|
||||
}
|
||||
|
||||
Compiler.prototype.clearEditorsLinkedLines = function () {
|
||||
this.eventHub.emit('editorSetDecoration', this.sourceEditorId, -1, false);
|
||||
};
|
||||
|
||||
Compiler.prototype.getGroupsInUse = function () {
|
||||
var currentLangCompilers = _.map(this.getCurrentLangCompilers(), _.identity);
|
||||
return _.map(_.uniq(currentLangCompilers, false, function (compiler) {
|
||||
return compiler.group;
|
||||
}), function (compiler) {
|
||||
return {value: compiler.group, label: compiler.groupName || compiler.group};
|
||||
});
|
||||
};
|
||||
|
||||
Compiler.prototype.close = function () {
|
||||
this.eventHub.unsubscribe();
|
||||
this.eventHub.emit('compilerClose', this.id);
|
||||
this.outputEditor.dispose();
|
||||
};
|
||||
|
||||
Compiler.prototype.initPanerButtons = function () {
|
||||
var outputConfig = _.bind(function () {
|
||||
return Components.getOutput(this.id, this.sourceEditorId);
|
||||
}, this);
|
||||
|
||||
this.container.layoutManager.createDragSource(this.outputBtn, outputConfig);
|
||||
this.outputBtn.click(_.bind(function () {
|
||||
var insertPoint = this.hub.findParentRowOrColumn(this.container) ||
|
||||
this.container.layoutManager.root.contentItems[0];
|
||||
insertPoint.addChild(outputConfig);
|
||||
}, this));
|
||||
|
||||
var cloneComponent = _.bind(function () {
|
||||
return {
|
||||
type: 'component',
|
||||
componentName: 'compiler',
|
||||
componentState: this.currentState()
|
||||
};
|
||||
}, this);
|
||||
var createOptView = _.bind(function () {
|
||||
return Components.getOptViewWith(this.id, this.source, this.lastResult.optOutput, this.getCompilerName(),
|
||||
this.sourceEditorId);
|
||||
}, this);
|
||||
|
||||
var createAstView = _.bind(function () {
|
||||
return Components.getAstViewWith(this.id, this.source, this.lastResult.astOutput, this.getCompilerName(),
|
||||
this.sourceEditorId);
|
||||
}, this);
|
||||
|
||||
var createGccDumpView = _.bind(function () {
|
||||
return Components.getGccDumpViewWith(this.id, this.getCompilerName(), this.sourceEditorId,
|
||||
this.lastResult.gccDumpOutput);
|
||||
}, this);
|
||||
|
||||
var createCfgView = _.bind(function () {
|
||||
return Components.getCfgViewWith(this.id, this.sourceEditorId);
|
||||
}, this);
|
||||
|
||||
var panerDropdown = this.domRoot.find('.pane-dropdown');
|
||||
var togglePannerAdder = function () {
|
||||
panerDropdown.dropdown('toggle');
|
||||
};
|
||||
|
||||
this.container.layoutManager
|
||||
.createDragSource(this.domRoot.find('.btn.add-compiler'), cloneComponent)
|
||||
._dragListener.on('dragStart', togglePannerAdder);
|
||||
|
||||
this.domRoot.find('.btn.add-compiler').click(_.bind(function () {
|
||||
var insertPoint = this.hub.findParentRowOrColumn(this.container) ||
|
||||
this.container.layoutManager.root.contentItems[0];
|
||||
insertPoint.addChild(cloneComponent);
|
||||
}, this));
|
||||
|
||||
this.container.layoutManager
|
||||
.createDragSource(this.optButton, createOptView)
|
||||
._dragListener.on('dragStart', togglePannerAdder);
|
||||
|
||||
this.optButton.click(_.bind(function () {
|
||||
var insertPoint = this.hub.findParentRowOrColumn(this.container) ||
|
||||
this.container.layoutManager.root.contentItems[0];
|
||||
insertPoint.addChild(createOptView);
|
||||
}, this));
|
||||
|
||||
this.container.layoutManager
|
||||
.createDragSource(this.astButton, createAstView)
|
||||
._dragListener.on('dragStart', togglePannerAdder);
|
||||
|
||||
this.astButton.click(_.bind(function () {
|
||||
var insertPoint = this.hub.findParentRowOrColumn(this.container) ||
|
||||
this.container.layoutManager.root.contentItems[0];
|
||||
insertPoint.addChild(createAstView);
|
||||
}, this));
|
||||
|
||||
this.container.layoutManager
|
||||
.createDragSource(this.gccDumpButton, createGccDumpView)
|
||||
._dragListener.on('dragStart', togglePannerAdder);
|
||||
|
||||
this.gccDumpButton.click(_.bind(function () {
|
||||
var insertPoint = this.hub.findParentRowOrColumn(this.container) ||
|
||||
this.container.layoutManager.root.contentItems[0];
|
||||
insertPoint.addChild(createGccDumpView);
|
||||
}, this));
|
||||
|
||||
this.container.layoutManager
|
||||
.createDragSource(this.cfgButton, createCfgView)
|
||||
._dragListener.on('dragStart', togglePannerAdder);
|
||||
|
||||
this.cfgButton.click(_.bind(function () {
|
||||
var insertPoint = this.hub.findParentRowOrColumn(this.container) ||
|
||||
this.container.layoutManager.root.contentItems[0];
|
||||
insertPoint.addChild(createCfgView);
|
||||
}, this));
|
||||
};
|
||||
|
||||
Compiler.prototype.undefer = function () {
|
||||
this.deferCompiles = false;
|
||||
if (this.needsCompile) this.compile();
|
||||
};
|
||||
|
||||
// TODO: need to call resize if either .top-bar or .bottom-bar resizes, which needs some work.
|
||||
// Issue manifests if you make a window where one compiler is small enough that the buttons spill onto two lines:
|
||||
// reload the page and the bottom-bar is off the bottom until you scroll a tiny bit.
|
||||
Compiler.prototype.resize = function () {
|
||||
var topBarHeight = this.domRoot.find('.top-bar').outerHeight(true);
|
||||
var bottomBarHeight = this.domRoot.find('.bottom-bar').outerHeight(true);
|
||||
this.outputEditor.layout({
|
||||
width: this.domRoot.width(),
|
||||
height: this.domRoot.height() - topBarHeight - bottomBarHeight
|
||||
});
|
||||
};
|
||||
|
||||
Compiler.prototype.initLang = function (state) {
|
||||
// If we don't have a language, but a compiler, find the corresponding language.
|
||||
this.currentLangId = state.lang;
|
||||
if (!this.currentLangId && state.compiler) {
|
||||
this.currentLangId = this.langOfCompiler(state.compiler);
|
||||
}
|
||||
if (!this.currentLangId && languages[this.settings.defaultLanguage]) {
|
||||
this.currentLangId = languages[this.settings.defaultLanguage].id;
|
||||
}
|
||||
if (!this.currentLangId) {
|
||||
this.currentLangId = _.keys(languages)[0];
|
||||
}
|
||||
};
|
||||
|
||||
Compiler.prototype.initCompiler = function (state) {
|
||||
this.originalCompilerId = state.compiler;
|
||||
if (state.compiler)
|
||||
this.compiler = this.findCompiler(this.currentLangId, state.compiler);
|
||||
else
|
||||
this.compiler = this.findCompiler(this.currentLangId, options.defaultCompiler[this.currentLangId]);
|
||||
if (!this.compiler) {
|
||||
var compilers = this.compilerService.compilersByLang[this.currentLangId];
|
||||
if (compilers) this.compiler = _.values(compilers)[0];
|
||||
}
|
||||
};
|
||||
|
||||
Compiler.prototype.initEditorActions = function () {
|
||||
this.outputEditor.addAction({
|
||||
id: 'viewsource',
|
||||
label: 'Scroll to source',
|
||||
@@ -210,183 +347,6 @@ function Compiler(hub, container, state) {
|
||||
}, this)
|
||||
});
|
||||
|
||||
var clearEditorsLinkedLines = _.bind(function () {
|
||||
this.eventHub.emit('editorSetDecoration', this.sourceEditorId, -1, false);
|
||||
}, this);
|
||||
|
||||
this.outputEditor.onMouseMove(_.bind(function (e) {
|
||||
this.mouseMoveThrottledFunction(e);
|
||||
if (this.linkedFadeTimeoutId !== -1) {
|
||||
clearTimeout(this.linkedFadeTimeoutId);
|
||||
this.linkedFadeTimeoutId = -1;
|
||||
}
|
||||
}, this));
|
||||
|
||||
this.mouseMoveThrottledFunction = _.throttle(_.bind(this.onMouseMove, this), 250);
|
||||
|
||||
this.outputEditor.onMouseLeave(_.bind(function () {
|
||||
this.linkedFadeTimeoutId = setTimeout(_.bind(function () {
|
||||
clearEditorsLinkedLines();
|
||||
this.linkedFadeTimeoutId = -1;
|
||||
}, this), 5000);
|
||||
}, this));
|
||||
|
||||
this.fontScale = new FontScale(this.domRoot, state, this.outputEditor);
|
||||
this.fontScale.on('change', _.bind(function () {
|
||||
this.saveState();
|
||||
}, this));
|
||||
|
||||
this.filters.on('change', _.bind(this.onFilterChange, this));
|
||||
|
||||
this.initCallbacks();
|
||||
|
||||
this.onSettingsChange(this.settings);
|
||||
this.sendCompiler();
|
||||
this.updateCompilerInfo();
|
||||
this.updateButtons();
|
||||
|
||||
var outputConfig = _.bind(function () {
|
||||
return Components.getOutput(this.id, this.sourceEditorId);
|
||||
}, this);
|
||||
|
||||
this.container.layoutManager.createDragSource(this.outputBtn, outputConfig);
|
||||
this.outputBtn.click(_.bind(function () {
|
||||
var insertPoint = hub.findParentRowOrColumn(this.container) ||
|
||||
this.container.layoutManager.root.contentItems[0];
|
||||
insertPoint.addChild(outputConfig);
|
||||
}, this));
|
||||
|
||||
var cloneComponent = _.bind(function () {
|
||||
return {
|
||||
type: 'component',
|
||||
componentName: 'compiler',
|
||||
componentState: this.currentState()
|
||||
};
|
||||
}, this);
|
||||
|
||||
var createOptView = _.bind(function () {
|
||||
return Components.getOptViewWith(this.id, this.source, this.lastResult.optOutput, this.getCompilerName(),
|
||||
this.sourceEditorId);
|
||||
}, this);
|
||||
|
||||
var createAstView = _.bind(function () {
|
||||
return Components.getAstViewWith(this.id, this.source, this.lastResult.astOutput, this.getCompilerName(),
|
||||
this.sourceEditorId);
|
||||
}, this);
|
||||
|
||||
var createGccDumpView = _.bind(function () {
|
||||
return Components.getGccDumpViewWith(this.id, this.getCompilerName(), this.sourceEditorId,
|
||||
this.lastResult.gccDumpOutput);
|
||||
}, this);
|
||||
|
||||
var createCfgView = _.bind(function () {
|
||||
return Components.getCfgViewWith(this.id, this.sourceEditorId);
|
||||
}, this);
|
||||
|
||||
var panerDropdown = this.domRoot.find('.pane-dropdown');
|
||||
var togglePannerAdder = function () {
|
||||
panerDropdown.dropdown('toggle');
|
||||
};
|
||||
|
||||
this.container.layoutManager
|
||||
.createDragSource(this.domRoot.find('.btn.add-compiler'), cloneComponent)
|
||||
._dragListener.on('dragStart', togglePannerAdder);
|
||||
|
||||
this.domRoot.find('.btn.add-compiler').click(_.bind(function () {
|
||||
var insertPoint = hub.findParentRowOrColumn(this.container) ||
|
||||
this.container.layoutManager.root.contentItems[0];
|
||||
insertPoint.addChild(cloneComponent);
|
||||
}, this));
|
||||
|
||||
this.container.layoutManager
|
||||
.createDragSource(this.optButton, createOptView)
|
||||
._dragListener.on('dragStart', togglePannerAdder);
|
||||
|
||||
this.optButton.click(_.bind(function () {
|
||||
var insertPoint = hub.findParentRowOrColumn(this.container) ||
|
||||
this.container.layoutManager.root.contentItems[0];
|
||||
insertPoint.addChild(createOptView);
|
||||
}, this));
|
||||
|
||||
this.container.layoutManager
|
||||
.createDragSource(this.astButton, createAstView)
|
||||
._dragListener.on('dragStart', togglePannerAdder);
|
||||
|
||||
this.astButton.click(_.bind(function () {
|
||||
var insertPoint = hub.findParentRowOrColumn(this.container) ||
|
||||
this.container.layoutManager.root.contentItems[0];
|
||||
insertPoint.addChild(createAstView);
|
||||
}, this));
|
||||
|
||||
this.container.layoutManager
|
||||
.createDragSource(this.gccDumpButton, createGccDumpView)
|
||||
._dragListener.on('dragStart', togglePannerAdder);
|
||||
|
||||
this.gccDumpButton.click(_.bind(function () {
|
||||
var insertPoint = hub.findParentRowOrColumn(this.container) ||
|
||||
this.container.layoutManager.root.contentItems[0];
|
||||
insertPoint.addChild(createGccDumpView);
|
||||
}, this));
|
||||
|
||||
this.container.layoutManager
|
||||
.createDragSource(this.cfgButton, createCfgView)
|
||||
._dragListener.on('dragStart', togglePannerAdder);
|
||||
|
||||
this.cfgButton.click(_.bind(function () {
|
||||
var insertPoint = hub.findParentRowOrColumn(this.container) ||
|
||||
this.container.layoutManager.root.contentItems[0];
|
||||
insertPoint.addChild(createCfgView);
|
||||
}, this));
|
||||
|
||||
this.updateLibsDropdown();
|
||||
|
||||
this.compileClearCache.on('click', _.bind(function () {
|
||||
this.compilerService.cache.reset();
|
||||
this.compile();
|
||||
}, this));
|
||||
|
||||
// Dismiss the popover on escape.
|
||||
$(document).on('keyup.editable', _.bind(function (e) {
|
||||
if (e.which === 27) {
|
||||
this.libsButton.popover('hide');
|
||||
}
|
||||
}, this));
|
||||
|
||||
// Dismiss on any click that isn't either in the opening element, inside
|
||||
// the popover or on any alert
|
||||
$(document).on('click', _.bind(function (e) {
|
||||
var elem = this.libsButton;
|
||||
var target = $(e.target);
|
||||
if (!target.is(elem) && elem.has(target).length === 0 && target.closest('.popover').length === 0) {
|
||||
elem.popover('hide');
|
||||
}
|
||||
}, this));
|
||||
|
||||
this.eventHub.on('initialised', this.undefer, this);
|
||||
this.saveState();
|
||||
}
|
||||
|
||||
Compiler.prototype.close = function () {
|
||||
this.eventHub.unsubscribe();
|
||||
this.eventHub.emit('compilerClose', this.id);
|
||||
this.outputEditor.dispose();
|
||||
};
|
||||
|
||||
Compiler.prototype.undefer = function () {
|
||||
this.deferCompiles = false;
|
||||
if (this.needsCompile) this.compile();
|
||||
};
|
||||
|
||||
// TODO: need to call resize if either .top-bar or .bottom-bar resizes, which needs some work.
|
||||
// Issue manifests if you make a window where one compiler is small enough that the buttons spill onto two lines:
|
||||
// reload the page and the bottom-bar is off the bottom until you scroll a tiny bit.
|
||||
Compiler.prototype.resize = function () {
|
||||
var topBarHeight = this.domRoot.find('.top-bar').outerHeight(true);
|
||||
var bottomBarHeight = this.domRoot.find('.bottom-bar').outerHeight(true);
|
||||
this.outputEditor.layout({
|
||||
width: this.domRoot.width(),
|
||||
height: this.domRoot.height() - topBarHeight - bottomBarHeight
|
||||
});
|
||||
};
|
||||
|
||||
// Gets the filters that will actually be used (accounting for issues with binary
|
||||
@@ -490,11 +450,11 @@ Compiler.prototype.getBinaryForLine = function (line) {
|
||||
|
||||
// TODO: use ContentWidgets? OverlayWidgets?
|
||||
// Use highlight providers? hover providers? highlight providers?
|
||||
Compiler.prototype.setAssembly = function (assembly) {
|
||||
this.assembly = assembly;
|
||||
Compiler.prototype.setAssembly = function (asm) {
|
||||
this.assembly = asm;
|
||||
if (!this.outputEditor || !this.outputEditor.getModel()) return;
|
||||
var currentTopLine = this.outputEditor.getCompletelyVisibleLinesRangeInViewport().startLineNumber;
|
||||
this.outputEditor.getModel().setValue(assembly.length ? _.pluck(assembly, 'text').join('\n') : "<No assembly generated>");
|
||||
this.outputEditor.getModel().setValue(asm.length ? _.pluck(asm, 'text').join('\n') : "<No assembly generated>");
|
||||
this.outputEditor.revealLine(currentTopLine);
|
||||
var addrToAddrDiv = {};
|
||||
var decorations = [];
|
||||
@@ -725,7 +685,10 @@ Compiler.prototype.onCfgViewClosed = function (id) {
|
||||
}
|
||||
};
|
||||
|
||||
Compiler.prototype.initButtons = function () {
|
||||
Compiler.prototype.initButtons = function (state) {
|
||||
this.filters = new Toggles(this.domRoot.find('.filters'), patchOldFilters(state.filters));
|
||||
this.fontScale = new FontScale(this.domRoot, state, this.outputEditor);
|
||||
|
||||
this.optButton = this.domRoot.find('.btn.view-optimization');
|
||||
this.astButton = this.domRoot.find('.btn.view-ast');
|
||||
this.gccDumpButton = this.domRoot.find('.btn.view-gccdump');
|
||||
@@ -770,6 +733,10 @@ Compiler.prototype.initButtons = function () {
|
||||
this.filterDemangleTitle = this.filterDemangleButton.prop('title');
|
||||
|
||||
this.noBinaryFiltersButtons = this.domRoot.find('.nonbinary');
|
||||
this.filterExecuteButton.toggle(options.supportsExecute);
|
||||
this.optionsField.val(this.options);
|
||||
|
||||
this.initPanerButtons();
|
||||
};
|
||||
|
||||
Compiler.prototype.initLibraries = function (state) {
|
||||
@@ -796,7 +763,8 @@ Compiler.prototype.updateButtons = function () {
|
||||
// We can support intel output if the compiler supports it, or if we're compiling
|
||||
// to binary (as we can disassemble it however we like).
|
||||
var formatFilterTitle = function (button, title) {
|
||||
button.prop('title', '[' + (button.hasClass('active') ? 'ON' : 'OFF') + '] ' + title + (button.prop('disabled') ? ' [LOCKED]' : ''));
|
||||
button.prop('title', '[' + (button.hasClass('active') ? 'ON' : 'OFF') + '] ' + title +
|
||||
(button.prop('disabled') ? ' [LOCKED]' : ''));
|
||||
};
|
||||
var isIntelFilterDisabled = !this.compiler.supportsIntel && !filters.binary;
|
||||
this.filterIntelButton.prop('disabled', isIntelFilterDisabled);
|
||||
@@ -844,8 +812,10 @@ Compiler.prototype.updateButtons = function () {
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
Compiler.prototype.initCallbacks = function () {
|
||||
this.filters.on('change', _.bind(this.onFilterChange, this));
|
||||
this.fontScale.on('change', _.bind(this.saveState, this));
|
||||
|
||||
this.container.on('destroy', this.close, this);
|
||||
this.container.on('resize', this.resize, this);
|
||||
this.container.on('shown', this.resize, this);
|
||||
@@ -887,6 +857,46 @@ Compiler.prototype.initCallbacks = function () {
|
||||
}
|
||||
}, this);
|
||||
this.eventHub.on('languageChange', this.onLanguageChange, this);
|
||||
|
||||
var optionsChange = _.debounce(_.bind(function (e) {
|
||||
this.onOptionsChange($(e.target).val());
|
||||
}, this), 800);
|
||||
|
||||
this.optionsField
|
||||
.on('change', optionsChange)
|
||||
.on('keyup', optionsChange);
|
||||
|
||||
this.outputEditor.onMouseLeave(_.bind(function () {
|
||||
this.linkedFadeTimeoutId = setTimeout(_.bind(function () {
|
||||
this.clearEditorsLinkedLines();
|
||||
this.linkedFadeTimeoutId = -1;
|
||||
}, this), 5000);
|
||||
}, this));
|
||||
|
||||
|
||||
this.compileClearCache.on('click', _.bind(function () {
|
||||
this.compilerService.cache.reset();
|
||||
this.compile();
|
||||
}, this));
|
||||
|
||||
// Dismiss the popover on escape.
|
||||
$(document).on('keyup.editable', _.bind(function (e) {
|
||||
if (e.which === 27) {
|
||||
this.libsButton.popover('hide');
|
||||
}
|
||||
}, this));
|
||||
|
||||
// Dismiss on any click that isn't either in the opening element, inside
|
||||
// the popover or on any alert
|
||||
$(document).on('click', _.bind(function (e) {
|
||||
var elem = this.libsButton;
|
||||
var target = $(e.target);
|
||||
if (!target.is(elem) && elem.has(target).length === 0 && target.closest('.popover').length === 0) {
|
||||
elem.popover('hide');
|
||||
}
|
||||
}, this));
|
||||
|
||||
this.eventHub.on('initialised', this.undefer, this);
|
||||
};
|
||||
|
||||
Compiler.prototype.onOptionsChange = function (options) {
|
||||
@@ -1065,8 +1075,7 @@ function getNumericToolTip(value) {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
var getAsmInfo = function (opcode) {
|
||||
function getAsmInfo(opcode) {
|
||||
var cacheName = 'asm/' + opcode;
|
||||
var cached = OpcodeCache.get(cacheName);
|
||||
if (cached) {
|
||||
@@ -1088,7 +1097,7 @@ var getAsmInfo = function (opcode) {
|
||||
cache: true
|
||||
});
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
Compiler.prototype.onMouseMove = function (e) {
|
||||
if (e === null || e.target === null || e.target.position === null) return;
|
||||
@@ -1096,22 +1105,27 @@ Compiler.prototype.onMouseMove = function (e) {
|
||||
var hoverAsm = this.assembly[e.target.position.lineNumber - 1];
|
||||
if (hoverAsm) {
|
||||
// We check that we actually have something to show at this point!
|
||||
this.eventHub.emit('editorSetDecoration', this.sourceEditorId, hoverAsm.source && !hoverAsm.source.file ? hoverAsm.source.line : -1, false);
|
||||
this.eventHub.emit('editorSetDecoration', this.sourceEditorId, hoverAsm.source && !hoverAsm.source.file ?
|
||||
hoverAsm.source.line : -1, false);
|
||||
}
|
||||
}
|
||||
var currentWord = this.outputEditor.getModel().getWordAtPosition(e.target.position);
|
||||
if (currentWord && currentWord.word) {
|
||||
var word = currentWord.word;
|
||||
currentWord.range = new monaco.Range(e.target.position.lineNumber, currentWord.startColumn, e.target.position.lineNumber, currentWord.endColumn);
|
||||
// Avoid throwing an exception if somehow (How?) we have a non existent lineNumber. c.f. https://sentry.io/matt-godbolt/compiler-explorer/issues/285270358/
|
||||
var startColumn = currentWord.startColumn;
|
||||
// Avoid throwing an exception if somehow (How?) we have a non existent lineNumber.
|
||||
// c.f. https://sentry.io/matt-godbolt/compiler-explorer/issues/285270358/
|
||||
if (e.target.position.lineNumber < this.outputEditor.getModel().getLineCount()) {
|
||||
// Hacky workaround to check for negative numbers. c.f. https://github.com/mattgodbolt/compiler-explorer/issues/434
|
||||
// Hacky workaround to check for negative numbers.
|
||||
// c.f. https://github.com/mattgodbolt/compiler-explorer/issues/434
|
||||
var lineContent = this.outputEditor.getModel().getLineContent(e.target.position.lineNumber);
|
||||
if (lineContent[currentWord.startColumn - 2] === '-') {
|
||||
word = '-' + word;
|
||||
currentWord.range.startColumn -= 1;
|
||||
startColumn -= 1;
|
||||
}
|
||||
}
|
||||
currentWord.range = new monaco.Range(e.target.position.lineNumber, Math.max(startColumn, 1),
|
||||
e.target.position.lineNumber, currentWord.endColumn);
|
||||
var numericToolTip = getNumericToolTip(word);
|
||||
if (numericToolTip) {
|
||||
this.decorations.numericToolTip = {
|
||||
@@ -1376,4 +1390,3 @@ Compiler.prototype.onOutputClosed = function (compilerId) {
|
||||
module.exports = {
|
||||
Compiler: Compiler
|
||||
};
|
||||
|
||||
|
||||
@@ -105,6 +105,7 @@ function Diff(hub, container, state) {
|
||||
this.eventHub.on('compileResult', this.onCompileResult, this);
|
||||
this.eventHub.on('compiler', this.onCompiler, this);
|
||||
this.eventHub.on('compilerClose', this.onCompilerClose, this);
|
||||
this.eventHub.on('settingsChange', this.onSettingsChange, this);
|
||||
this.eventHub.on('themeChange', this.onThemeChange, this);
|
||||
this.container.on('destroy', function () {
|
||||
this.eventHub.unsubscribe();
|
||||
@@ -117,6 +118,7 @@ function Diff(hub, container, state) {
|
||||
this.eventHub.emit('resendCompilation', this.rhs.id);
|
||||
this.eventHub.emit('findCompilers');
|
||||
this.eventHub.emit('requestTheme');
|
||||
this.eventHub.emit('requestSettings');
|
||||
|
||||
this.updateCompilerNames();
|
||||
this.updateCompilers();
|
||||
@@ -216,6 +218,14 @@ Diff.prototype.onThemeChange = function (newTheme) {
|
||||
this.outputEditor.updateOptions({theme: newTheme.monaco});
|
||||
};
|
||||
|
||||
Diff.prototype.onSettingsChange = function (newSettings) {
|
||||
this.outputEditor.updateOptions({
|
||||
minimap: {
|
||||
enabled: newSettings.showMinimap
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
module.exports = {
|
||||
Diff: Diff,
|
||||
getComponent: function (lhs, rhs) {
|
||||
|
||||
405
static/editor.js
405
static/editor.js
@@ -50,6 +50,7 @@ function Editor(hub, state, container) {
|
||||
this.container = container;
|
||||
this.domRoot = container.getElement();
|
||||
this.domRoot.html($('#codeEditor').html());
|
||||
this.hub = hub;
|
||||
this.eventHub = hub.createEventHub();
|
||||
// Should probably be its own function somewhere
|
||||
this.settings = JSON.parse(local.get('settings', '{}'));
|
||||
@@ -67,23 +68,10 @@ function Editor(hub, state, container) {
|
||||
|
||||
this.editorSourceByLang = {};
|
||||
this.alertSystem = new Alert();
|
||||
this.languageBtn = this.domRoot.find('.change-language');
|
||||
var langKeys = _.keys(languages);
|
||||
// Ensure that the btn is disabled if we don't have nothing to select
|
||||
// Note that is might be disabled for other reasons beforehand
|
||||
if (langKeys.length <= 1) {
|
||||
this.languageBtn.prop("disabled", true);
|
||||
}
|
||||
this.currentLanguage = languages[langKeys[0]];
|
||||
this.waitingForLanguage = state.source && !state.lang;
|
||||
if (languages[this.settings.defaultLanguage]) {
|
||||
this.currentLanguage = languages[this.settings.defaultLanguage];
|
||||
}
|
||||
if (languages[state.lang]) {
|
||||
this.currentLanguage = languages[state.lang];
|
||||
} else if (this.settings.newEditorLastLang && languages[hub.lastOpenedLangId]) {
|
||||
this.currentLanguage = languages[hub.lastOpenedLangId];
|
||||
}
|
||||
|
||||
this.langKeys = _.keys(languages);
|
||||
this.initLanguage(state);
|
||||
|
||||
var root = this.domRoot.find(".monaco-placeholder");
|
||||
var legacyReadOnly = state.options && !!state.options.readOnly;
|
||||
this.editor = monaco.editor.create(root[0], {
|
||||
@@ -117,6 +105,210 @@ function Editor(hub, state, container) {
|
||||
foldAction.run();
|
||||
}
|
||||
|
||||
this.initEditorActions();
|
||||
this.initButtons(state);
|
||||
this.initCallbacks();
|
||||
|
||||
var usableLanguages = _.filter(languages, function (language) {
|
||||
return hub.compilerService.compilersByLang[language.id];
|
||||
});
|
||||
|
||||
this.languageBtn.selectize({
|
||||
sortField: 'name',
|
||||
valueField: 'id',
|
||||
labelField: 'name',
|
||||
searchField: ['name'],
|
||||
options: _.map(usableLanguages, _.identity),
|
||||
items: [this.currentLanguage.id]
|
||||
}).on('change', _.bind(function (e) {
|
||||
this.onLanguageChange($(e.target).val());
|
||||
}, this));
|
||||
this.selectize = this.languageBtn[0].selectize;
|
||||
// We suppress posting changes until the user has stopped typing by:
|
||||
// * Using _.debounce() to run emitChange on any key event or change
|
||||
// only after a delay.
|
||||
// * Only actually triggering a change if the document text has changed from
|
||||
// the previous emitted.
|
||||
this.lastChangeEmitted = null;
|
||||
this.onSettingsChange(this.settings);
|
||||
// this.editor.on("keydown", _.bind(function () {
|
||||
// // Not strictly a change; but this suppresses changes until some time
|
||||
// // after the last key down (be it an actual change or a just a cursor
|
||||
// // movement etc).
|
||||
// this.debouncedEmitChange();
|
||||
// }, this));
|
||||
|
||||
this.updateTitle();
|
||||
this.updateState();
|
||||
}
|
||||
|
||||
// If compilerId is undefined, every compiler will be pinged
|
||||
Editor.prototype.maybeEmitChange = function (force, compilerId) {
|
||||
var source = this.getSource();
|
||||
if (!force && source === this.lastChangeEmitted) return;
|
||||
this.lastChangeEmitted = source;
|
||||
this.eventHub.emit('editorChange', this.id, this.lastChangeEmitted, this.currentLanguage.id, compilerId);
|
||||
};
|
||||
|
||||
Editor.prototype.updateState = function () {
|
||||
var state = {
|
||||
id: this.id,
|
||||
source: this.getSource(),
|
||||
lang: this.currentLanguage.id
|
||||
};
|
||||
this.fontScale.addState(state);
|
||||
this.container.setState(state);
|
||||
};
|
||||
|
||||
Editor.prototype.setSource = function (newSource) {
|
||||
this.editor.getModel().setValue(newSource);
|
||||
};
|
||||
|
||||
Editor.prototype.getSource = function () {
|
||||
return this.editor.getModel().getValue();
|
||||
};
|
||||
|
||||
Editor.prototype.initLanguage = function (state) {
|
||||
this.currentLanguage = languages[this.langKeys[0]];
|
||||
this.waitingForLanguage = state.source && !state.lang;
|
||||
if (languages[this.settings.defaultLanguage]) {
|
||||
this.currentLanguage = languages[this.settings.defaultLanguage];
|
||||
}
|
||||
if (languages[state.lang]) {
|
||||
this.currentLanguage = languages[state.lang];
|
||||
} else if (this.settings.newEditorLastLang && languages[this.hub.lastOpenedLangId]) {
|
||||
this.currentLanguage = languages[this.hub.lastOpenedLangId];
|
||||
}
|
||||
};
|
||||
|
||||
Editor.prototype.initCallbacks = function () {
|
||||
this.fontScale.on('change', _.bind(this.updateState, this));
|
||||
|
||||
this.container.on('resize', this.resize, this);
|
||||
this.container.on('shown', this.resize, this);
|
||||
this.container.on('open', _.bind(function () {
|
||||
this.eventHub.emit('editorOpen', this.id);
|
||||
}, this));
|
||||
this.container.on('destroy', this.close, this);
|
||||
this.container.layoutManager.on('initialised', function () {
|
||||
// Once initialized, let everyone know what text we have.
|
||||
this.maybeEmitChange();
|
||||
}, this);
|
||||
|
||||
this.eventHub.on('compilerOpen', this.onCompilerOpen, this);
|
||||
this.eventHub.on('compilerClose', this.onCompilerClose, this);
|
||||
this.eventHub.on('compiling', this.onCompiling, this);
|
||||
this.eventHub.on('compileResult', this.onCompileResponse, this);
|
||||
this.eventHub.on('selectLine', this.onSelectLine, this);
|
||||
this.eventHub.on('editorSetDecoration', this.onEditorSetDecoration, this);
|
||||
this.eventHub.on('settingsChange', this.onSettingsChange, this);
|
||||
this.eventHub.on('conformanceViewOpen', this.onConformanceViewOpen, this);
|
||||
this.eventHub.on('conformanceViewClose', this.onConformanceViewClose, this);
|
||||
this.eventHub.on('resize', this.resize, this);
|
||||
|
||||
this.editor.getModel().onDidChangeContent(_.bind(function () {
|
||||
this.debouncedEmitChange();
|
||||
this.updateState();
|
||||
}, this));
|
||||
|
||||
this.editor.onMouseLeave(_.bind(function () {
|
||||
this.fadeTimeoutId = setTimeout(_.bind(function () {
|
||||
this.clearCompilerLinkedLines();
|
||||
this.fadeTimeoutId = -1;
|
||||
}, this), 5000);
|
||||
}, this));
|
||||
|
||||
this.mouseMoveThrottledFunction = _.throttle(_.bind(function (e) {
|
||||
if (e !== null && e.target !== null && this.settings.hoverShowSource && e.target.position !== null) {
|
||||
this.tryCompilerLinkLine(e.target.position.lineNumber, false);
|
||||
}
|
||||
}, this), 250);
|
||||
|
||||
this.editor.onMouseMove(_.bind(function (e) {
|
||||
this.mouseMoveThrottledFunction(e);
|
||||
// This can't be throttled or we can clear a timeout where we're already outside
|
||||
if (this.fadeTimeoutId !== -1) {
|
||||
clearTimeout(this.fadeTimeoutId);
|
||||
this.fadeTimeoutId = -1;
|
||||
}
|
||||
}, this));
|
||||
|
||||
this.eventHub.on('initialised', this.maybeEmitChange, this);
|
||||
};
|
||||
|
||||
Editor.prototype.initButtons = function (state) {
|
||||
this.fontScale = new FontScale(this.domRoot, state, this.editor);
|
||||
this.languageBtn = this.domRoot.find('.change-language');
|
||||
// Ensure that the buttonn is disabled if we don't have nothing to select
|
||||
// Note that is might be disabled for other reasons beforehand
|
||||
if (this.langKeys.length <= 1) {
|
||||
this.languageBtn.prop("disabled", true);
|
||||
}
|
||||
var addCompilerButton = this.domRoot.find('.btn.add-compiler');
|
||||
var paneAdderDropdown = this.domRoot.find('.add-pane');
|
||||
|
||||
var togglePaneAdder = function () {
|
||||
paneAdderDropdown.dropdown('toggle');
|
||||
};
|
||||
|
||||
|
||||
// NB a new compilerConfig needs to be created every time; else the state is shared
|
||||
// between all compilers created this way. That leads to some nasty-to-find state
|
||||
// bugs e.g. https://github.com/mattgodbolt/compiler-explorer/issues/225
|
||||
var getCompilerConfig = _.bind(function () {
|
||||
return Components.getCompiler(this.id, this.currentLanguage.id);
|
||||
}, this);
|
||||
|
||||
var getConformanceConfig = _.bind(function () {
|
||||
return Components.getConformanceView(this.id, this.getSource());
|
||||
}, this);
|
||||
|
||||
this.container.layoutManager
|
||||
.createDragSource(addCompilerButton, getCompilerConfig)
|
||||
._dragListener.on('dragStart', togglePaneAdder);
|
||||
|
||||
addCompilerButton.click(_.bind(function () {
|
||||
var insertPoint = this.hub.findParentRowOrColumn(this.container) ||
|
||||
this.container.layoutManager.root.contentItems[0];
|
||||
insertPoint.addChild(getCompilerConfig);
|
||||
}, this));
|
||||
|
||||
this.conformanceViewerButton = this.domRoot.find('.btn.conformance');
|
||||
|
||||
this.container.layoutManager
|
||||
.createDragSource(this.conformanceViewerButton, getConformanceConfig)
|
||||
._dragListener.on('dragStart', togglePaneAdder);
|
||||
this.conformanceViewerButton.click(_.bind(function () {
|
||||
var insertPoint = this.hub.findParentRowOrColumn(this.container) ||
|
||||
this.container.layoutManager.root.contentItems[0];
|
||||
insertPoint.addChild(getConformanceConfig);
|
||||
}, this));
|
||||
};
|
||||
|
||||
Editor.prototype.changeLanguage = function (newLang) {
|
||||
this.selectize.setValue(newLang);
|
||||
};
|
||||
|
||||
Editor.prototype.clearCompilerLinkedLines = function () {
|
||||
_.each(this.asmByCompiler, _.bind(function (asms, compilerId) {
|
||||
this.eventHub.emit('compilerSetDecorations', compilerId, -1, false);
|
||||
}, this));
|
||||
};
|
||||
|
||||
Editor.prototype.tryCompilerLinkLine = function (thisLineNumber, reveal) {
|
||||
_.each(this.asmByCompiler, _.bind(function (asms, compilerId) {
|
||||
var targetLines = [];
|
||||
_.each(asms, function (asmLine, i) {
|
||||
if (asmLine.source && asmLine.source.file === null &&
|
||||
asmLine.source.line === thisLineNumber) {
|
||||
targetLines.push(i + 1);
|
||||
}
|
||||
});
|
||||
this.eventHub.emit('compilerSetDecorations', compilerId, targetLines, reveal);
|
||||
}, this));
|
||||
};
|
||||
|
||||
Editor.prototype.initEditorActions = function () {
|
||||
this.editor.addAction({
|
||||
id: 'compile',
|
||||
label: 'Compile',
|
||||
@@ -167,185 +359,14 @@ function Editor(hub, state, container) {
|
||||
contextMenuGroupId: 'navigation',
|
||||
contextMenuOrder: 1.5,
|
||||
run: function (ed) {
|
||||
tryCompilerLinkLine(ed.getPosition().lineNumber, true);
|
||||
this.tryCompilerLinkLine(ed.getPosition().lineNumber, true);
|
||||
}
|
||||
});
|
||||
|
||||
var tryCompilerLinkLine = _.bind(function (thisLineNumber, reveal) {
|
||||
_.each(this.asmByCompiler, _.bind(function (asms, compilerId) {
|
||||
var targetLines = [];
|
||||
_.each(asms, function (asmLine, i) {
|
||||
if (asmLine.source && asmLine.source.file === null &&
|
||||
asmLine.source.line === thisLineNumber) {
|
||||
targetLines.push(i + 1);
|
||||
}
|
||||
});
|
||||
this.eventHub.emit('compilerSetDecorations', compilerId, targetLines, reveal);
|
||||
}, this));
|
||||
}, this);
|
||||
|
||||
var clearCompilerLinkedLines = _.bind(function () {
|
||||
_.each(this.asmByCompiler, _.bind(function (asms, compilerId) {
|
||||
this.eventHub.emit('compilerSetDecorations', compilerId, -1, false);
|
||||
}, this));
|
||||
}, this);
|
||||
|
||||
this.editor.onMouseLeave(_.bind(function () {
|
||||
this.fadeTimeoutId = setTimeout(_.bind(function () {
|
||||
clearCompilerLinkedLines();
|
||||
this.fadeTimeoutId = -1;
|
||||
}, this), 5000);
|
||||
}, this));
|
||||
|
||||
this.mouseMoveThrottledFunction = _.throttle(_.bind(function (e) {
|
||||
if (e !== null && e.target !== null && this.settings.hoverShowSource && e.target.position !== null) {
|
||||
tryCompilerLinkLine(e.target.position.lineNumber, false);
|
||||
}
|
||||
}, this), 250);
|
||||
|
||||
this.editor.onMouseMove(_.bind(function (e) {
|
||||
this.mouseMoveThrottledFunction(e);
|
||||
// This can't be throttled or we can clear a timeout where we're already outside
|
||||
if (this.fadeTimeoutId !== -1) {
|
||||
clearTimeout(this.fadeTimeoutId);
|
||||
this.fadeTimeoutId = -1;
|
||||
}
|
||||
}, this));
|
||||
|
||||
this.updateEditorLayout = _.bind(function () {
|
||||
var topBarHeight = this.domRoot.find(".top-bar").outerHeight(true) || 0;
|
||||
this.editor.layout({width: this.domRoot.width(), height: this.domRoot.height() - topBarHeight});
|
||||
}, this);
|
||||
|
||||
this.fontScale = new FontScale(this.domRoot, state, this.editor);
|
||||
this.fontScale.on('change', _.bind(this.updateState, this));
|
||||
|
||||
var usableLanguages = _.filter(languages, function (language) {
|
||||
return hub.compilerService.compilersByLang[language.id];
|
||||
});
|
||||
|
||||
this.languageBtn.selectize({
|
||||
sortField: 'name',
|
||||
valueField: 'id',
|
||||
labelField: 'name',
|
||||
searchField: ['name'],
|
||||
options: _.map(usableLanguages, _.identity),
|
||||
items: [this.currentLanguage.id]
|
||||
}).on('change', _.bind(function (e) {
|
||||
this.onLanguageChange($(e.target).val());
|
||||
}, this));
|
||||
this.changeLanguage = function (newLang) {
|
||||
this.languageBtn[0].selectize.setValue(newLang);
|
||||
};
|
||||
|
||||
// We suppress posting changes until the user has stopped typing by:
|
||||
// * Using _.debounce() to run emitChange on any key event or change
|
||||
// only after a delay.
|
||||
// * Only actually triggering a change if the document text has changed from
|
||||
// the previous emitted.
|
||||
this.lastChangeEmitted = null;
|
||||
this.onSettingsChange(this.settings);
|
||||
this.editor.getModel().onDidChangeContent(_.bind(function () {
|
||||
this.debouncedEmitChange();
|
||||
this.updateState();
|
||||
}, this));
|
||||
// this.editor.on("keydown", _.bind(function () {
|
||||
// // Not strictly a change; but this suppresses changes until some time
|
||||
// // after the last key down (be it an actual change or a just a cursor
|
||||
// // movement etc).
|
||||
// this.debouncedEmitChange();
|
||||
// }, this));
|
||||
|
||||
container.on('resize', this.updateEditorLayout);
|
||||
container.on('shown', this.updateEditorLayout);
|
||||
container.on('open', _.bind(function () {
|
||||
this.eventHub.emit('editorOpen', this.id);
|
||||
}, this));
|
||||
container.on('destroy', this.close, this);
|
||||
this.container.layoutManager.on('initialised', function () {
|
||||
// Once initialized, let everyone know what text we have.
|
||||
this.maybeEmitChange();
|
||||
}, this);
|
||||
|
||||
this.eventHub.on('compilerOpen', this.onCompilerOpen, this);
|
||||
this.eventHub.on('compilerClose', this.onCompilerClose, this);
|
||||
this.eventHub.on('compiling', this.onCompiling, this);
|
||||
this.eventHub.on('compileResult', this.onCompileResponse, this);
|
||||
this.eventHub.on('selectLine', this.onSelectLine, this);
|
||||
this.eventHub.on('editorSetDecoration', this.onEditorSetDecoration, this);
|
||||
this.eventHub.on('settingsChange', this.onSettingsChange, this);
|
||||
this.eventHub.on('conformanceViewOpen', this.onConformanceViewOpen, this);
|
||||
this.eventHub.on('conformanceViewClose', this.onConformanceViewClose, this);
|
||||
this.eventHub.on('resize', this.updateEditorLayout, this);
|
||||
|
||||
// NB a new compilerConfig needs to be created every time; else the state is shared
|
||||
// between all compilers created this way. That leads to some nasty-to-find state
|
||||
// bugs e.g. https://github.com/mattgodbolt/compiler-explorer/issues/225
|
||||
var compilerConfig = _.bind(function () {
|
||||
return Components.getCompiler(this.id, this.currentLanguage.id);
|
||||
}, this);
|
||||
|
||||
var addCompilerButton = this.domRoot.find('.btn.add-compiler');
|
||||
var paneAdderDropdown = this.domRoot.find('.add-pane');
|
||||
|
||||
var togglePaneAdder = function () {
|
||||
paneAdderDropdown.dropdown('toggle');
|
||||
};
|
||||
|
||||
this.container.layoutManager
|
||||
.createDragSource(addCompilerButton, compilerConfig)
|
||||
._dragListener.on('dragStart', togglePaneAdder);
|
||||
|
||||
addCompilerButton.click(_.bind(function () {
|
||||
var insertPoint = hub.findParentRowOrColumn(this.container) ||
|
||||
this.container.layoutManager.root.contentItems[0];
|
||||
insertPoint.addChild(compilerConfig);
|
||||
}, this));
|
||||
|
||||
|
||||
var conformanceConfig = _.bind(function () {
|
||||
return Components.getConformanceView(this.id, this.getSource());
|
||||
}, this);
|
||||
|
||||
this.conformanceViewerButton = this.domRoot.find('.btn.conformance');
|
||||
|
||||
this.container.layoutManager
|
||||
.createDragSource(this.conformanceViewerButton, conformanceConfig)
|
||||
._dragListener.on('dragStart', togglePaneAdder);
|
||||
this.conformanceViewerButton.click(_.bind(function () {
|
||||
var insertPoint = hub.findParentRowOrColumn(this.container) ||
|
||||
this.container.layoutManager.root.contentItems[0];
|
||||
insertPoint.addChild(conformanceConfig);
|
||||
}, this));
|
||||
this.updateTitle();
|
||||
this.eventHub.on('initialised', this.maybeEmitChange, this);
|
||||
this.updateState();
|
||||
}
|
||||
|
||||
// If compilerId is undefined, every compiler will be pinged
|
||||
Editor.prototype.maybeEmitChange = function (force, compilerId) {
|
||||
var source = this.getSource();
|
||||
if (!force && source === this.lastChangeEmitted) return;
|
||||
this.lastChangeEmitted = source;
|
||||
this.eventHub.emit('editorChange', this.id, this.lastChangeEmitted, this.currentLanguage.id, compilerId);
|
||||
};
|
||||
|
||||
Editor.prototype.updateState = function () {
|
||||
var state = {
|
||||
id: this.id,
|
||||
source: this.getSource(),
|
||||
lang: this.currentLanguage.id
|
||||
};
|
||||
this.fontScale.addState(state);
|
||||
this.container.setState(state);
|
||||
};
|
||||
|
||||
Editor.prototype.setSource = function (newSource) {
|
||||
this.editor.getModel().setValue(newSource);
|
||||
};
|
||||
|
||||
Editor.prototype.getSource = function () {
|
||||
return this.editor.getModel().getValue();
|
||||
Editor.prototype.resize = function () {
|
||||
var topBarHeight = this.domRoot.find(".top-bar").outerHeight(true) || 0;
|
||||
this.editor.layout({width: this.domRoot.width(), height: this.domRoot.height() - topBarHeight});
|
||||
};
|
||||
|
||||
Editor.prototype.onSettingsChange = function (newSettings) {
|
||||
|
||||
@@ -79,15 +79,6 @@ function Opt(hub, container, state) {
|
||||
this.eventHub.emit("optViewOpened", this._compilerid);
|
||||
}
|
||||
|
||||
// TODO: de-dupe with compiler etc
|
||||
Opt.prototype.resize = function () {
|
||||
var topBarHeight = this.domRoot.find(".top-bar").outerHeight(true);
|
||||
this.optEditor.layout({
|
||||
width: this.domRoot.width(),
|
||||
height: this.domRoot.height() - topBarHeight
|
||||
});
|
||||
};
|
||||
|
||||
Opt.prototype.onEditorChange = function (id, source) {
|
||||
if (this._editorid === id) {
|
||||
this.code = source;
|
||||
@@ -103,8 +94,10 @@ Opt.prototype.onCompileResult = function (id, compiler, result, lang) {
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
Opt.prototype.setTitle = function () {
|
||||
this.container.setTitle(this._compilerName + " Opt Viewer (Editor #" + this._editorid + ", Compiler #" + this._compilerid + ")");
|
||||
this.container.setTitle(
|
||||
this._compilerName + " Opt Viewer (Editor #" + this._editorid + ", Compiler #" + this._compilerid + ")");
|
||||
};
|
||||
|
||||
Opt.prototype.getDisplayableOpt = function (optResult) {
|
||||
@@ -161,7 +154,6 @@ Opt.prototype.onCompiler = function (id, compiler, options, editorid) {
|
||||
}
|
||||
};
|
||||
|
||||
// TODO: de-dupe with compiler etc
|
||||
Opt.prototype.resize = function () {
|
||||
var topBarHeight = this.domRoot.find(".top-bar").outerHeight(true);
|
||||
this.optEditor.layout({
|
||||
@@ -170,22 +162,17 @@ Opt.prototype.resize = function () {
|
||||
});
|
||||
};
|
||||
|
||||
Opt.prototype.onEditorChange = function (id, source) {
|
||||
if (this._editorid === id) {
|
||||
this.code = source;
|
||||
this.optEditor.setValue(source);
|
||||
}
|
||||
};
|
||||
|
||||
Opt.prototype.setTitle = function () {
|
||||
this.container.setTitle(this._compilerName + " Opt Viewer (Editor #" + this._editorid + ", Compiler #" + this._compilerid + ")");
|
||||
};
|
||||
|
||||
Opt.prototype.getDisplayableOpt = function (optResult) {
|
||||
return "**" + optResult.optType + "** - " + optResult.displayString;
|
||||
};
|
||||
|
||||
Opt.prototype.updateState = function () {
|
||||
this.container.setState(this.currentState());
|
||||
};
|
||||
|
||||
Opt.prototype.currentState = function () {
|
||||
var state = {
|
||||
id: this._compilerid,
|
||||
editorid: this._editorid
|
||||
};
|
||||
this.fontScale.addState(state);
|
||||
return state;
|
||||
};
|
||||
|
||||
Opt.prototype.close = function () {
|
||||
|
||||
@@ -148,7 +148,9 @@ function setupSettings(root, settings, onChange, langId) {
|
||||
var isStoredUsable = false;
|
||||
colourSchemeSelect.empty();
|
||||
_.each(colour.schemes, function (scheme) {
|
||||
if (!scheme.themes || scheme.themes.length === 0 || scheme.themes.indexOf(newTheme) !== -1 || scheme.themes.indexOf('all') !== -1) {
|
||||
if (!scheme.themes || scheme.themes.length === 0 || scheme.themes.indexOf(newTheme) !== -1 ||
|
||||
scheme.themes.indexOf('all') !== -1) {
|
||||
|
||||
colourSchemeSelect.append($('<option value="' + scheme.name + '">' + scheme.desc + "</option>"));
|
||||
if (newThemeStoredScheme === scheme.name) {
|
||||
isStoredUsable = true;
|
||||
@@ -159,7 +161,8 @@ function setupSettings(root, settings, onChange, langId) {
|
||||
colourSchemeSelect.val(isStoredUsable ? newThemeStoredScheme : colourSchemeSelect.first().val());
|
||||
} else {
|
||||
// This should never happen. In case it does, lets use the default one
|
||||
colourSchemeSelect.append($('<option value="' + colour.schemes[0].name + '">' + colour.schemes[0].desc + "</option>"));
|
||||
colourSchemeSelect.append(
|
||||
$('<option value="' + colour.schemes[0].name + '">' + colour.schemes[0].desc + "</option>"));
|
||||
colourSchemeSelect.val(colourSchemeSelect.first().val());
|
||||
}
|
||||
colourSchemeSelect.trigger('change');
|
||||
|
||||
Reference in New Issue
Block a user