Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
Avatar for KuCalc : devops.
Download
50654 views
1
//----------------------------------------------------------------------------
2
// Copyright (C) 2008-2011 The IPython Development Team
3
//
4
// Distributed under the terms of the BSD License. The full license is in
5
// the file COPYING, distributed as part of this software.
6
//----------------------------------------------------------------------------
7
8
//============================================================================
9
// CodeCell
10
//============================================================================
11
/**
12
* An extendable module that provide base functionnality to create cell for notebook.
13
* @module IPython
14
* @namespace IPython
15
* @submodule CodeCell
16
*/
17
18
19
/* local util for codemirror */
20
var posEq = function(a, b) {return a.line == b.line && a.ch == b.ch;};
21
22
/**
23
*
24
* function to delete until previous non blanking space character
25
* or first multiple of 4 tabstop.
26
* @private
27
*/
28
CodeMirror.commands.delSpaceToPrevTabStop = function(cm){
29
var from = cm.getCursor(true), to = cm.getCursor(false), sel = !posEq(from, to);
30
if (!posEq(from, to)) { cm.replaceRange("", from, to); return; }
31
var cur = cm.getCursor(), line = cm.getLine(cur.line);
32
var tabsize = cm.getOption('tabSize');
33
var chToPrevTabStop = cur.ch-(Math.ceil(cur.ch/tabsize)-1)*tabsize;
34
from = {ch:cur.ch-chToPrevTabStop,line:cur.line};
35
var select = cm.getRange(from,cur);
36
if( select.match(/^\ +$/) !== null){
37
cm.replaceRange("",from,cur);
38
} else {
39
cm.deleteH(-1,"char");
40
}
41
};
42
43
44
var IPython = (function (IPython) {
45
"use strict";
46
47
var utils = IPython.utils;
48
var keycodes = IPython.keyboard.keycodes;
49
50
/**
51
* A Cell conceived to write code.
52
*
53
* The kernel doesn't have to be set at creation time, in that case
54
* it will be null and set_kernel has to be called later.
55
* @class CodeCell
56
* @extends IPython.Cell
57
*
58
* @constructor
59
* @param {Object|null} kernel
60
* @param {object|undefined} [options]
61
* @param [options.cm_config] {object} config to pass to CodeMirror
62
*/
63
var CodeCell = function (kernel, options) {
64
this.kernel = kernel || null;
65
this.collapsed = false;
66
67
// create all attributed in constructor function
68
// even if null for V8 VM optimisation
69
this.input_prompt_number = null;
70
this.celltoolbar = null;
71
this.output_area = null;
72
this.last_msg_id = null;
73
this.completer = null;
74
75
76
var cm_overwrite_options = {
77
onKeyEvent: $.proxy(this.handle_keyevent,this)
78
};
79
80
options = this.mergeopt(CodeCell, options, {cm_config:cm_overwrite_options});
81
82
IPython.Cell.apply(this,[options]);
83
84
// Attributes we want to override in this subclass.
85
this.cell_type = "code";
86
87
var that = this;
88
this.element.focusout(
89
function() { that.auto_highlight(); }
90
);
91
};
92
93
CodeCell.options_default = {
94
cm_config : {
95
extraKeys: {
96
"Tab" : "indentMore",
97
"Shift-Tab" : "indentLess",
98
"Backspace" : "delSpaceToPrevTabStop",
99
"Cmd-/" : "toggleComment",
100
"Ctrl-/" : "toggleComment"
101
},
102
mode: 'ipython',
103
theme: 'ipython',
104
matchBrackets: true,
105
// don't auto-close strings because of CodeMirror #2385
106
autoCloseBrackets: "()[]{}"
107
}
108
};
109
110
CodeCell.msg_cells = {};
111
112
CodeCell.prototype = new IPython.Cell();
113
114
/**
115
* @method auto_highlight
116
*/
117
CodeCell.prototype.auto_highlight = function () {
118
this._auto_highlight(IPython.config.cell_magic_highlight);
119
};
120
121
/** @method create_element */
122
CodeCell.prototype.create_element = function () {
123
IPython.Cell.prototype.create_element.apply(this, arguments);
124
125
var cell = $('<div></div>').addClass('cell border-box-sizing code_cell');
126
cell.attr('tabindex','2');
127
128
var input = $('<div></div>').addClass('input');
129
var prompt = $('<div/>').addClass('prompt input_prompt');
130
var inner_cell = $('<div/>').addClass('inner_cell');
131
this.celltoolbar = new IPython.CellToolbar(this);
132
inner_cell.append(this.celltoolbar.element);
133
var input_area = $('<div/>').addClass('input_area');
134
this.code_mirror = CodeMirror(input_area.get(0), this.cm_config);
135
$(this.code_mirror.getInputField()).attr("spellcheck", "false");
136
inner_cell.append(input_area);
137
input.append(prompt).append(inner_cell);
138
139
var widget_area = $('<div/>')
140
.addClass('widget-area')
141
.hide();
142
this.widget_area = widget_area;
143
var widget_prompt = $('<div/>')
144
.addClass('prompt')
145
.appendTo(widget_area);
146
var widget_subarea = $('<div/>')
147
.addClass('widget-subarea')
148
.appendTo(widget_area);
149
this.widget_subarea = widget_subarea;
150
var widget_clear_buton = $('<button />')
151
.addClass('close')
152
.html('&times;')
153
.click(function() {
154
widget_area.slideUp('', function(){ widget_subarea.html(''); });
155
})
156
.appendTo(widget_prompt);
157
158
var output = $('<div></div>');
159
cell.append(input).append(widget_area).append(output);
160
this.element = cell;
161
this.output_area = new IPython.OutputArea(output, true);
162
this.completer = new IPython.Completer(this);
163
};
164
165
/** @method bind_events */
166
CodeCell.prototype.bind_events = function () {
167
IPython.Cell.prototype.bind_events.apply(this);
168
var that = this;
169
170
this.element.focusout(
171
function() { that.auto_highlight(); }
172
);
173
};
174
175
176
/**
177
* This method gets called in CodeMirror's onKeyDown/onKeyPress
178
* handlers and is used to provide custom key handling. Its return
179
* value is used to determine if CodeMirror should ignore the event:
180
* true = ignore, false = don't ignore.
181
* @method handle_codemirror_keyevent
182
*/
183
CodeCell.prototype.handle_codemirror_keyevent = function (editor, event) {
184
185
var that = this;
186
// whatever key is pressed, first, cancel the tooltip request before
187
// they are sent, and remove tooltip if any, except for tab again
188
var tooltip_closed = null;
189
if (event.type === 'keydown' && event.which != keycodes.tab ) {
190
tooltip_closed = IPython.tooltip.remove_and_cancel_tooltip();
191
}
192
193
var cur = editor.getCursor();
194
if (event.keyCode === keycodes.enter){
195
this.auto_highlight();
196
}
197
198
if (event.which === keycodes.down && event.type === 'keypress' && IPython.tooltip.time_before_tooltip >= 0) {
199
// triger on keypress (!) otherwise inconsistent event.which depending on plateform
200
// browser and keyboard layout !
201
// Pressing '(' , request tooltip, don't forget to reappend it
202
// The second argument says to hide the tooltip if the docstring
203
// is actually empty
204
IPython.tooltip.pending(that, true);
205
} else if ( tooltip_closed && event.which === keycodes.esc && event.type === 'keydown') {
206
// If tooltip is active, cancel it. The call to
207
// remove_and_cancel_tooltip above doesn't pass, force=true.
208
// Because of this it won't actually close the tooltip
209
// if it is in sticky mode. Thus, we have to check again if it is open
210
// and close it with force=true.
211
if (!IPython.tooltip._hidden) {
212
IPython.tooltip.remove_and_cancel_tooltip(true);
213
}
214
// If we closed the tooltip, don't let CM or the global handlers
215
// handle this event.
216
event.stop();
217
return true;
218
} else if (event.keyCode === keycodes.tab && event.type === 'keydown' && event.shiftKey) {
219
if (editor.somethingSelected()){
220
var anchor = editor.getCursor("anchor");
221
var head = editor.getCursor("head");
222
if( anchor.line != head.line){
223
return false;
224
}
225
}
226
IPython.tooltip.request(that);
227
event.stop();
228
return true;
229
} else if (event.keyCode === keycodes.tab && event.type == 'keydown') {
230
// Tab completion.
231
IPython.tooltip.remove_and_cancel_tooltip();
232
if (editor.somethingSelected()) {
233
return false;
234
}
235
var pre_cursor = editor.getRange({line:cur.line,ch:0},cur);
236
if (pre_cursor.trim() === "") {
237
// Don't autocomplete if the part of the line before the cursor
238
// is empty. In this case, let CodeMirror handle indentation.
239
return false;
240
} else {
241
event.stop();
242
this.completer.startCompletion();
243
return true;
244
}
245
}
246
247
// keyboard event wasn't one of those unique to code cells, let's see
248
// if it's one of the generic ones (i.e. check edit mode shortcuts)
249
return IPython.Cell.prototype.handle_codemirror_keyevent.apply(this, [editor, event]);
250
};
251
252
// Kernel related calls.
253
254
CodeCell.prototype.set_kernel = function (kernel) {
255
this.kernel = kernel;
256
};
257
258
/**
259
* Execute current code cell to the kernel
260
* @method execute
261
*/
262
CodeCell.prototype.execute = function () {
263
this.output_area.clear_output();
264
265
// Clear widget area
266
this.widget_subarea.html('');
267
this.widget_subarea.height('');
268
this.widget_area.height('');
269
this.widget_area.hide();
270
271
this.set_input_prompt('*');
272
this.element.addClass("running");
273
if (this.last_msg_id) {
274
this.kernel.clear_callbacks_for_msg(this.last_msg_id);
275
}
276
var callbacks = this.get_callbacks();
277
278
var old_msg_id = this.last_msg_id;
279
this.last_msg_id = this.kernel.execute(this.get_text(), callbacks, {silent: false, store_history: true});
280
if (old_msg_id) {
281
delete CodeCell.msg_cells[old_msg_id];
282
}
283
CodeCell.msg_cells[this.last_msg_id] = this;
284
};
285
286
/**
287
* Construct the default callbacks for
288
* @method get_callbacks
289
*/
290
CodeCell.prototype.get_callbacks = function () {
291
return {
292
shell : {
293
reply : $.proxy(this._handle_execute_reply, this),
294
payload : {
295
set_next_input : $.proxy(this._handle_set_next_input, this),
296
page : $.proxy(this._open_with_pager, this)
297
}
298
},
299
iopub : {
300
output : $.proxy(this.output_area.handle_output, this.output_area),
301
clear_output : $.proxy(this.output_area.handle_clear_output, this.output_area),
302
},
303
input : $.proxy(this._handle_input_request, this)
304
};
305
};
306
307
CodeCell.prototype._open_with_pager = function (payload) {
308
$([IPython.events]).trigger('open_with_text.Pager', payload);
309
};
310
311
/**
312
* @method _handle_execute_reply
313
* @private
314
*/
315
CodeCell.prototype._handle_execute_reply = function (msg) {
316
this.set_input_prompt(msg.content.execution_count);
317
this.element.removeClass("running");
318
$([IPython.events]).trigger('set_dirty.Notebook', {value: true});
319
};
320
321
/**
322
* @method _handle_set_next_input
323
* @private
324
*/
325
CodeCell.prototype._handle_set_next_input = function (payload) {
326
var data = {'cell': this, 'text': payload.text};
327
$([IPython.events]).trigger('set_next_input.Notebook', data);
328
};
329
330
/**
331
* @method _handle_input_request
332
* @private
333
*/
334
CodeCell.prototype._handle_input_request = function (msg) {
335
this.output_area.append_raw_input(msg);
336
};
337
338
339
// Basic cell manipulation.
340
341
CodeCell.prototype.select = function () {
342
var cont = IPython.Cell.prototype.select.apply(this);
343
if (cont) {
344
this.code_mirror.refresh();
345
this.auto_highlight();
346
}
347
return cont;
348
};
349
350
CodeCell.prototype.render = function () {
351
var cont = IPython.Cell.prototype.render.apply(this);
352
// Always execute, even if we are already in the rendered state
353
return cont;
354
};
355
356
CodeCell.prototype.unrender = function () {
357
// CodeCell is always rendered
358
return false;
359
};
360
361
CodeCell.prototype.select_all = function () {
362
var start = {line: 0, ch: 0};
363
var nlines = this.code_mirror.lineCount();
364
var last_line = this.code_mirror.getLine(nlines-1);
365
var end = {line: nlines-1, ch: last_line.length};
366
this.code_mirror.setSelection(start, end);
367
};
368
369
370
CodeCell.prototype.collapse_output = function () {
371
this.collapsed = true;
372
this.output_area.collapse();
373
};
374
375
376
CodeCell.prototype.expand_output = function () {
377
this.collapsed = false;
378
this.output_area.expand();
379
this.output_area.unscroll_area();
380
};
381
382
CodeCell.prototype.scroll_output = function () {
383
this.output_area.expand();
384
this.output_area.scroll_if_long();
385
};
386
387
CodeCell.prototype.toggle_output = function () {
388
this.collapsed = Boolean(1 - this.collapsed);
389
this.output_area.toggle_output();
390
};
391
392
CodeCell.prototype.toggle_output_scroll = function () {
393
this.output_area.toggle_scroll();
394
};
395
396
397
CodeCell.input_prompt_classical = function (prompt_value, lines_number) {
398
var ns;
399
if (prompt_value === undefined) {
400
ns = "&nbsp;";
401
} else {
402
ns = encodeURIComponent(prompt_value);
403
}
404
return 'In&nbsp;[' + ns + ']:';
405
};
406
407
CodeCell.input_prompt_continuation = function (prompt_value, lines_number) {
408
var html = [CodeCell.input_prompt_classical(prompt_value, lines_number)];
409
for(var i=1; i < lines_number; i++) {
410
html.push(['...:']);
411
}
412
return html.join('<br/>');
413
};
414
415
CodeCell.input_prompt_function = CodeCell.input_prompt_classical;
416
417
418
CodeCell.prototype.set_input_prompt = function (number) {
419
var nline = 1;
420
if (this.code_mirror !== undefined) {
421
nline = this.code_mirror.lineCount();
422
}
423
this.input_prompt_number = number;
424
var prompt_html = CodeCell.input_prompt_function(this.input_prompt_number, nline);
425
// This HTML call is okay because the user contents are escaped.
426
this.element.find('div.input_prompt').html(prompt_html);
427
};
428
429
430
CodeCell.prototype.clear_input = function () {
431
this.code_mirror.setValue('');
432
};
433
434
435
CodeCell.prototype.get_text = function () {
436
return this.code_mirror.getValue();
437
};
438
439
440
CodeCell.prototype.set_text = function (code) {
441
return this.code_mirror.setValue(code);
442
};
443
444
445
CodeCell.prototype.clear_output = function (wait) {
446
this.output_area.clear_output(wait);
447
this.set_input_prompt();
448
};
449
450
451
// JSON serialization
452
453
CodeCell.prototype.fromJSON = function (data) {
454
IPython.Cell.prototype.fromJSON.apply(this, arguments);
455
if (data.cell_type === 'code') {
456
if (data.input !== undefined) {
457
this.set_text(data.input);
458
// make this value the starting point, so that we can only undo
459
// to this state, instead of a blank cell
460
this.code_mirror.clearHistory();
461
this.auto_highlight();
462
}
463
if (data.prompt_number !== undefined) {
464
this.set_input_prompt(data.prompt_number);
465
} else {
466
this.set_input_prompt();
467
}
468
this.output_area.trusted = data.trusted || false;
469
this.output_area.fromJSON(data.outputs);
470
if (data.collapsed !== undefined) {
471
if (data.collapsed) {
472
this.collapse_output();
473
} else {
474
this.expand_output();
475
}
476
}
477
}
478
};
479
480
481
CodeCell.prototype.toJSON = function () {
482
var data = IPython.Cell.prototype.toJSON.apply(this);
483
data.input = this.get_text();
484
// is finite protect against undefined and '*' value
485
if (isFinite(this.input_prompt_number)) {
486
data.prompt_number = this.input_prompt_number;
487
}
488
var outputs = this.output_area.toJSON();
489
data.outputs = outputs;
490
data.language = 'python';
491
data.trusted = this.output_area.trusted;
492
data.collapsed = this.collapsed;
493
return data;
494
};
495
496
/**
497
* handle cell level logic when a cell is unselected
498
* @method unselect
499
* @return is the action being taken
500
*/
501
CodeCell.prototype.unselect = function () {
502
var cont = IPython.Cell.prototype.unselect.apply(this);
503
if (cont) {
504
// When a code cell is usnelected, make sure that the corresponding
505
// tooltip and completer to that cell is closed.
506
IPython.tooltip.remove_and_cancel_tooltip(true);
507
if (this.completer !== null) {
508
this.completer.close();
509
}
510
}
511
return cont;
512
};
513
514
IPython.CodeCell = CodeCell;
515
516
return IPython;
517
}(IPython));
518
519