Files
jupyter_contrib_nbextensions/nbextensions/usability/breakpoints.js
T
2015-09-01 13:03:39 +02:00

233 lines
7.2 KiB
JavaScript

// Breakpoints extension - allow execute of notebook cells until a breakpoint
// is encountered. If a breakpoint is set at the currently selected cell,
// run cell anyway, allowing to step through the notebook
"using strict";
var cellstate_extension = (function() {
var breakpointKey = { "Alt-B" : function(){toggle_breakpoint();} };
function setMarker() {
var marker = document.createElement("div");
marker.style.color = "#822";
marker.innerHTML = "●";
return marker;
}
/**
* Concatenate associative array objects
*
* Source: http://stackoverflow.com/questions/2454295/javascript-concatenate-properties-from-multiple-objects-associative-array
*/
function collect() {
var ret = {};
var len = arguments.length;
for (var i=0; i<len; i++) {
for (p in arguments[i]) {
if (arguments[i].hasOwnProperty(p)) {
ret[p] = arguments[i][p];
}
}
}
return ret;
}
/**
* Toggle breakpoint marker on/off
*
* @param {Object} current codecell
* @param {Boolean} turn breakpoint on/off
*/
function makeMarker(cell,val) {
if (cell.metadata.run_control == undefined){
cell.metadata.run_control = {};
}
if (val == undefined) { val = false; }
cell.metadata.run_control.breakpoint = val;
cell.code_mirror.setGutterMarker(0, "breakpoints", val ? setMarker(): null);
};
/**
* Clear all breakpoints in notebook
*
*/
function clear_breakpoints() {
var cells = IPython.notebook.get_cells();
for(var i in cells){
var cell = cells[i];
if ((cell instanceof IPython.CodeCell)) {
if (cell.metadata.run_control == undefined){cell.metadata.run_control = {}} {
makeMarker(cell,false);
}
}
}
};
/**
* Run code cells from current cell until next breakpoint
*
*/
function run_breakpoint() {
var start = IPython.notebook.get_selected_index();
var end = IPython.notebook.ncells()
for (var i=start; i<end; i++) {
IPython.notebook.select(i);
var cell = IPython.notebook.get_selected_cell();
if ((cell instanceof IPython.CodeCell)) {
if (cell.metadata.run_control != undefined) {
if (cell.metadata.run_control.breakpoint == true && i > start) {
break;
}
}
IPython.notebook.execute_cell({add_new:false});
}
}
};
/**
* Toggle breakpoint in current cell
*
*/
function toggle_breakpoint() {
var cell = IPython.notebook.get_selected_cell();
if ((cell instanceof IPython.CodeCell)) {
var val;
if (cell.metadata.run_control == undefined){
val = true;
} else {
val = !cell.metadata.run_control.breakpoint;
}
makeMarker(cell,val);
}
};
/**
* Add run control buttons to toolbar
*
*/
IPython.toolbar.add_buttons_group([
{
id : 'run_c',
label : 'Run current cell',
icon : 'fa-step-forward',
callback : function () {
IPython.notebook.execute_cell();
}
},
{
id : 'run_ca',
label : 'Run from top to current cell',
icon : 'fa-fast-forward',
callback : function () {
IPython.notebook.execute_cells_above();
}
},
{
id : 'run_cb',
label : 'Run from current cell to end',
icon : 'fa-forward',
callback : function () {
IPython.notebook.execute_cells_below();
}
},
{
id : 'run_a',
label : 'Run All',
icon : 'fa-play',
callback : function () {
IPython.notebook.execute_all_cells();
}
},
{
id : 'interrupt_b',
label : 'Interrupt',
icon : 'fa-stop',
callback : function () {
IPython.notebook.kernel.interrupt();
}
},
{
id : 'run_until_break',
label : 'Run until next breakpoint',
icon : 'fa-play-circle',
callback : run_breakpoint
},
{
id : 'set_breakpoint',
label : 'Toggle Breakpoint',
icon : 'fa-bullseye',
callback : toggle_breakpoint
},
{
id : 'clear_all_breakpoints',
label : 'Clear all Breakpoints',
icon : 'fa-remove',
callback : clear_breakpoints
}
]);
/**
* Register newly created cell TODO: needed here ??
*
* @param {Object} event
* @param {Object} nbcell notebook cell
*/
create_cell = function (event,nbcell,nbindex) {
var cell = nbcell.cell;
if ((cell instanceof IPython.CodeCell)) {
cell.code_mirror.on("gutterClick", changeEvent);
var gutters = cell.code_mirror.getOption('gutters');
cell.code_mirror.setOption('gutters', [gutters, "breakpoints" ]);
var keys = cell.code_mirror.getOption('extraKeys');
cell.code_mirror.setOption('extraKeys', collect(keys, breakpointKey ));
makeMarker(cell,false,0);
}
};
/**
* Register newly created cell TODO: needed here ??
*
* @param {Object} event
* @param {Object} nbcell notebook cell
*/
function changeEvent(cm,n) {
var val;
var cell = IPython.notebook.get_selected_cell();
if (cell.code_mirror != cm) {
console.log("other cell");
var cells = IPython.notebook.get_cells();
for(var i in cells){
var cell = cells[i];
if (cell.code_mirror == cm ) { break; }
}
}
if (cell.metadata.run_control == undefined){
val = true;
} else {
val = !cell.metadata.run_control.breakpoint;
}
makeMarker(cell,val);
}
var cells = IPython.notebook.get_cells();
for(var i in cells){
var cell = cells[i];
if ((cell instanceof IPython.CodeCell)) {
cell.code_mirror.on("gutterClick", changeEvent);
var gutters = cell.code_mirror.getOption('gutters');
cell.code_mirror.setOption('gutters', [gutters, "breakpoints" ]);
var keys = cell.code_mirror.getOption('extraKeys');
cell.code_mirror.setOption('extraKeys', collect(keys, breakpointKey ));
if (cell.metadata.run_control != undefined) {
makeMarker(cell,cell.metadata.run_control.breakpoint);
}
}
};
$([IPython.events]).on('create.Cell',create_cell);
})();