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