|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
define([ |
|
'base/js/namespace', |
|
'jquery', |
|
'require', |
|
'base/js/events', |
|
'services/config', |
|
'notebook/js/codecell', |
|
'codemirror/lib/codemirror', |
|
'codemirror/addon/fold/foldcode', |
|
'codemirror/addon/fold/foldgutter', |
|
'codemirror/addon/fold/brace-fold', |
|
'codemirror/addon/fold/indent-fold' |
|
], function (Jupyter, $, requirejs, events, configmod, codecell, CodeMirror) { |
|
"use strict"; |
|
|
|
|
|
var params = { |
|
codefolding_hotkey : 'Alt-f', |
|
init_delay : 1000 |
|
}; |
|
|
|
|
|
var update_params = function (config_data) { |
|
for (var key in params) { |
|
if (config_data.hasOwnProperty(key)) { |
|
params[key] = config_data[key]; |
|
} |
|
} |
|
}; |
|
|
|
var on_config_loaded = function () { |
|
if (Jupyter.notebook !== undefined) { |
|
|
|
var prefix = 'auto'; |
|
var name = 'toggle-codefolding'; |
|
var action = { |
|
icon: 'fa-comment-o', |
|
help : 'Toggle codefolding', |
|
help_index : 'ec', |
|
id : 'toggle_codefolding', |
|
handler : toggleFolding |
|
}; |
|
var action_full_name = Jupyter.keyboard_manager.actions.register(action, name, prefix); |
|
|
|
|
|
var edit_mode_shortcuts = {}; |
|
edit_mode_shortcuts[params.codefolding_hotkey] = action_full_name; |
|
|
|
|
|
Jupyter.notebook.keyboard_manager.edit_shortcuts.add_shortcuts(edit_mode_shortcuts); |
|
Jupyter.notebook.keyboard_manager.command_shortcuts.add_shortcuts(edit_mode_shortcuts); |
|
} |
|
else { |
|
|
|
var extraKeys = Jupyter.editor.codemirror.getOption('extraKeys'); |
|
extraKeys[params.codefolding_hotkey] = toggleFolding; |
|
CodeMirror.normalizeKeyMap(extraKeys); |
|
console.log('[codefolding] binding hotkey', params.codefolding_hotkey); |
|
Jupyter.editor.codemirror.setOption('extraKeys', extraKeys); |
|
} |
|
}; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
function toggleFolding () { |
|
var cm; |
|
var pos = {line: 0, ch: 0, xRel: 0}; |
|
if (Jupyter.notebook !== undefined) { |
|
cm = Jupyter.notebook.get_selected_cell().code_mirror; |
|
if (Jupyter.notebook.mode === 'edit') { |
|
pos = cm.getCursor(); |
|
} |
|
} |
|
else { |
|
cm = Jupyter.editor.codemirror; |
|
pos = cm.getCursor(); |
|
} |
|
var opts = cm.state.foldGutter.options; |
|
cm.foldCode(pos, opts.rangeFinder); |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
function updateMetadata (cm) { |
|
var list = cm.getAllMarks(); |
|
var lines = []; |
|
for (var i = 0; i < list.length; i++) { |
|
if (list[i].__isFold) { |
|
var range = list[i].find(); |
|
lines.push(range.from.line); |
|
} |
|
} |
|
|
|
var cell = Jupyter.notebook.get_selected_cell(); |
|
if (cell.code_mirror !== cm) { |
|
var cells = Jupyter.notebook.get_cells(); |
|
var ncells = Jupyter.notebook.ncells(); |
|
for (var k = 0; k < ncells; k++) { |
|
var _cell = cells[k]; |
|
if (_cell.code_mirror === cm ) { cell = _cell; break; } |
|
} |
|
} |
|
cell.metadata.code_folding = lines; |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
function activate_cm_folding (cm) { |
|
var gutters = cm.getOption('gutters').slice(); |
|
if ( $.inArray("CodeMirror-foldgutter", gutters) < 0) { |
|
gutters.push('CodeMirror-foldgutter'); |
|
cm.setOption('gutters', gutters); |
|
} |
|
|
|
|
|
var opts = true; |
|
if (Jupyter.notebook) { |
|
opts = { |
|
rangeFinder: new CodeMirror.fold.combine( |
|
CodeMirror.fold.firstline, |
|
CodeMirror.fold.magic, |
|
CodeMirror.fold.blockcomment, |
|
cm.getMode().fold === 'indent' ? CodeMirror.fold.indent : CodeMirror.fold.brace |
|
) |
|
}; |
|
} |
|
cm.setOption('foldGutter', opts); |
|
} |
|
|
|
|
|
|
|
|
|
|
|
var restoreFolding = function (cell) { |
|
if (cell.metadata.code_folding === undefined || !(cell instanceof codecell.CodeCell)) { |
|
return; |
|
} |
|
|
|
var lines = cell.metadata.code_folding.slice().sort(); |
|
for (var idx = lines.length - 1; idx >= 0; idx--) { |
|
var line = lines[idx]; |
|
var opts = cell.code_mirror.state.foldGutter.options; |
|
var linetext = cell.code_mirror.getLine(line); |
|
if (linetext !== undefined) { |
|
cell.code_mirror.foldCode(CodeMirror.Pos(line, 0), opts.rangeFinder); |
|
} |
|
else { |
|
|
|
cell.metadata.code_folding = lines.slice(0, idx); |
|
} |
|
cell.code_mirror.refresh(); |
|
} |
|
}; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
var createCell = function (event, nbcell) { |
|
var cell = nbcell.cell; |
|
if ((cell instanceof codecell.CodeCell)) { |
|
activate_cm_folding(cell.code_mirror); |
|
cell.code_mirror.on('fold', updateMetadata); |
|
cell.code_mirror.on('unfold', updateMetadata); |
|
|
|
|
|
setTimeout(function () { restoreFolding(cell); }, 500); |
|
} |
|
}; |
|
|
|
|
|
|
|
|
|
|
|
var initExistingCells = function () { |
|
var cells = Jupyter.notebook.get_cells(); |
|
var ncells = Jupyter.notebook.ncells(); |
|
for (var i = 0; i < ncells; i++) { |
|
var cell = cells[i]; |
|
if ((cell instanceof codecell.CodeCell)) { |
|
activate_cm_folding(cell.code_mirror); |
|
|
|
restoreFolding(cell); |
|
cell.code_mirror.on('fold', updateMetadata); |
|
cell.code_mirror.on('unfold', updateMetadata); |
|
} |
|
} |
|
events.on('create.Cell', createCell); |
|
}; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
var load_css = function (name) { |
|
var link = document.createElement("link"); |
|
link.type = "text/css"; |
|
link.rel = "stylesheet"; |
|
link.href = requirejs.toUrl(name, 'css'); |
|
document.getElementsByTagName("head")[0].appendChild(link); |
|
}; |
|
|
|
|
|
|
|
|
|
|
|
var load_extension = function () { |
|
|
|
var conf_sect; |
|
if (Jupyter.notebook) { |
|
|
|
conf_sect = Jupyter.notebook.config; |
|
} |
|
else if (Jupyter.editor) { |
|
|
|
conf_sect = new configmod.ConfigSection('notebook', {base_url: Jupyter.editor.base_url}); |
|
conf_sect.load(); |
|
} |
|
else { |
|
|
|
return; |
|
} |
|
|
|
load_css('codemirror/addon/fold/foldgutter.css'); |
|
|
|
load_css( './foldgutter.css'); |
|
|
|
conf_sect.loaded |
|
.then(function () { update_params(conf_sect.data); }) |
|
.then(on_config_loaded); |
|
|
|
if (Jupyter.notebook) { |
|
|
|
requirejs(['./firstline-fold', './magic-fold', './blockcomment-fold'], function () { |
|
if (Jupyter.notebook._fully_loaded) { |
|
setTimeout(function () { |
|
console.log('Codefolding: Wait for', params.init_delay, 'ms'); |
|
initExistingCells(); |
|
}, params.init_delay); |
|
} |
|
else { |
|
events.one('notebook_loaded.Notebook', initExistingCells); |
|
} |
|
}); |
|
} |
|
else { |
|
activate_cm_folding(Jupyter.editor.codemirror); |
|
setTimeout(function () { |
|
console.log('Codefolding: Wait for', params.init_delay, 'ms'); |
|
Jupyter.editor.codemirror.refresh(); |
|
}, params.init_delay); |
|
} |
|
}; |
|
|
|
return {load_ipython_extension : load_extension}; |
|
}); |
|
|