|
define([ |
|
'module', |
|
'jquery', |
|
'base/js/namespace', |
|
'base/js/keyboard', |
|
'notebook/js/cell', |
|
'notebook/js/codecell', |
|
'notebook/js/completer', |
|
], function ( |
|
module, |
|
$, |
|
Jupyter, |
|
keyboard, |
|
cell, |
|
codecell, |
|
completer |
|
) { |
|
'use strict'; |
|
|
|
var Cell = cell.Cell; |
|
var CodeCell = codecell.CodeCell; |
|
var Completer = completer.Completer; |
|
|
|
var log_prefix = '[' + module.id + ']'; |
|
|
|
|
|
var config = { |
|
enable_at_start: true, |
|
exclude_regexp: ':', |
|
include_regexp: '', |
|
tooltip_regexp: '\\(', |
|
hint_delay: 20, |
|
hint_inside_comments: false, |
|
}; |
|
|
|
var do_hinting; |
|
|
|
|
|
var specials = [ |
|
keyboard.keycodes.enter, |
|
keyboard.keycodes.esc, |
|
keyboard.keycodes.backspace, |
|
keyboard.keycodes.tab, |
|
keyboard.keycodes.up, |
|
keyboard.keycodes.down, |
|
keyboard.keycodes.left, |
|
keyboard.keycodes.right, |
|
keyboard.keycodes.shift, |
|
keyboard.keycodes.ctrl, |
|
keyboard.keycodes.alt, |
|
keyboard.keycodes.meta, |
|
keyboard.keycodes.capslock, |
|
keyboard.keycodes.space, |
|
keyboard.keycodes.pageup, |
|
keyboard.keycodes.pagedown, |
|
keyboard.keycodes.end, |
|
keyboard.keycodes.home, |
|
keyboard.keycodes.insert, |
|
keyboard.keycodes.delete, |
|
keyboard.keycodes.numlock, |
|
keyboard.keycodes.f1, |
|
keyboard.keycodes.f2, |
|
keyboard.keycodes.f3, |
|
keyboard.keycodes.f4, |
|
keyboard.keycodes.f5, |
|
keyboard.keycodes.f6, |
|
keyboard.keycodes.f7, |
|
keyboard.keycodes.f8, |
|
keyboard.keycodes.f9, |
|
keyboard.keycodes.f10, |
|
keyboard.keycodes.f11, |
|
keyboard.keycodes.f12, |
|
keyboard.keycodes.f13, |
|
keyboard.keycodes.f14, |
|
keyboard.keycodes.f15 |
|
]; |
|
|
|
|
|
|
|
|
|
|
|
|
|
function only_modifier_event (event) { |
|
var key = keyboard.inv_keycodes[event.which]; |
|
return ( |
|
(event.altKey || event.ctrlKey || event.metaKey || event.shiftKey) && |
|
(key === 'alt'|| key === 'ctrl'|| key === 'meta'|| key === 'shift') |
|
); |
|
} |
|
|
|
function patch_cell_keyevent () { |
|
console.log(log_prefix, 'patching Cell.prototype.handle_codemirror_keyevent'); |
|
var orig_handle_codemirror_keyevent = Cell.prototype.handle_codemirror_keyevent; |
|
Cell.prototype.handle_codemirror_keyevent = function (editor, event) { |
|
if (do_hinting && (this instanceof CodeCell) && !only_modifier_event(event)) { |
|
|
|
this.tooltip.remove_and_cancel_tooltip(); |
|
|
|
if ( !editor.somethingSelected() && |
|
editor.getSelections().length <= 1 && |
|
!this.completer.visible && |
|
specials.indexOf(event.keyCode) == -1) { |
|
var cell = this; |
|
|
|
|
|
setTimeout(function () { |
|
var cur = editor.getCursor(); |
|
var pre_cursor = editor.getRange({ |
|
line: cur.line, |
|
ch: cur.ch - 1 |
|
}, cur); |
|
if ( pre_cursor !== '' && |
|
(config.hint_inside_comments || editor.getTokenAt(cur).type !== "comment") && |
|
(config.include_regexp.test(pre_cursor) || config.tooltip_regexp.test(pre_cursor)) && |
|
!config.exclude_regexp.test(pre_cursor) ) { |
|
if (config.tooltip_regexp.test(pre_cursor)) { |
|
cell.tooltip.request(cell); |
|
} |
|
else { |
|
cell.completer.startCompletion(); |
|
cell.completer.autopick = false; |
|
} |
|
} |
|
}, config.hint_delay); |
|
} |
|
} |
|
return orig_handle_codemirror_keyevent.apply(this, arguments); |
|
}; |
|
} |
|
|
|
function set_hinterland_state (new_state) { |
|
do_hinting = new_state; |
|
$('.hinterland-toggle > .fa') |
|
.toggleClass('fa-check', do_hinting); |
|
console.log(log_prefix, 'continuous hinting', do_hinting ? 'on' : 'off'); |
|
} |
|
|
|
function toggle_hinterland () { |
|
set_hinterland_state(!do_hinting); |
|
} |
|
|
|
function add_menu_item () { |
|
if ($('#help_menu').find('.hinterland_toggle').length > 0) { |
|
return; |
|
} |
|
var menu_item = $('<li/>') |
|
.insertAfter('#keyboard_shortcuts'); |
|
var menu_link = $('<a/>') |
|
.text('Continuous hints') |
|
.addClass('hinterland-toggle') |
|
.attr('title', 'Provide continuous code hints') |
|
.on('click', toggle_hinterland) |
|
.appendTo(menu_item); |
|
$('<i/>') |
|
.addClass('fa menu-icon pull-right') |
|
.prependTo(menu_link); |
|
} |
|
|
|
function load_notebook_extension () { |
|
|
|
Jupyter.notebook.config.loaded.then(function on_success () { |
|
$.extend(true, config, Jupyter.notebook.config.data.hinterland); |
|
|
|
|
|
if (config.include_regexp === '') { |
|
config.include_regexp = Completer.reinvoke_re; |
|
} |
|
|
|
|
|
var regexp_names = ['exclude_regexp', 'include_regexp', 'tooltip_regexp']; |
|
for (var ii=0; ii < regexp_names.length; ii++) { |
|
if (config[regexp_names[ii]] === '') { |
|
continue; |
|
} |
|
try { |
|
config[regexp_names[ii]] = new RegExp(config[regexp_names[ii]]); |
|
} |
|
catch (err) { |
|
console.warn(log_prefix, 'error parsing', regexp_names[ii] + ':', err); |
|
} |
|
} |
|
}, function on_error (err) { |
|
console.warn(log_prefix, 'error loading config:', err); |
|
}).then(function on_success () { |
|
patch_cell_keyevent(); |
|
add_menu_item(); |
|
set_hinterland_state(config.enable_at_start); |
|
}); |
|
} |
|
|
|
return { |
|
load_ipython_extension : load_notebook_extension |
|
}; |
|
}); |
|
|