##// END OF EJS Templates
Initial reply handling implemented along with css fixes.
Brian Granger -
Show More
@@ -33,7 +33,7 b' class KernelManager(object):'
33 33 def start_kernel(self, kernel_id):
34 34 if kernel_id in self._kernels:
35 35 raise DuplicateKernelError("Kernel already exists: %s" % kernel_id)
36 (process, shell_port, iopub_port, stdin_port, hb_port) = launch_kernel()
36 (process, shell_port, iopub_port, stdin_port, hb_port) = launch_kernel(pylab='inline')
37 37 d = dict(
38 38 process = process,
39 39 stdin_port = stdin_port,
@@ -80,15 +80,17 b' class ZMQStreamHandler(websocket.WebSocketHandler, BaseKernelHandler):'
80 80 self.zmq_stream.on_recv(self._on_zmq_reply)
81 81
82 82 def on_message(self, msg):
83 logging.info("Message received: %r" % msg)
83 logging.info("Message received: %r, %r" % (msg, self.__class__))
84 logging.info(self.zmq_stream)
84 85 self.zmq_stream.send_unicode(msg)
85 86
86 87 def on_close(self):
87 88 self.zmq_stream.close()
88 89
89 def _on_zmq_reply(self, msg):
90 logging.info("Message reply: %r" % msg)
91 self.write_message(msg)
90 def _on_zmq_reply(self, msg_list):
91 for msg in msg_list:
92 logging.info("Message reply: %r" % msg)
93 self.write_message(msg)
92 94
93 95
94 96 class IOPubStreamHandler(ZMQStreamHandler):
@@ -33,6 +33,7 b' class SessionManager(object):'
33 33 session_id = str(uuid.uuid4())
34 34 ports = self.kernel_manager.get_kernel_ports(self.kernel_id)
35 35 iopub_stream = self.create_connected_stream(ports['iopub_port'], zmq.SUB)
36 iopub_stream.socket.setsockopt(zmq.SUBSCRIBE, b'')
36 37 shell_stream = self.create_connected_stream(ports['shell_port'], zmq.XREQ)
37 38 self._sessions[session_id] = dict(
38 39 iopub_stream = iopub_stream,
@@ -54,7 +55,7 b' class SessionManager(object):'
54 55 def create_connected_stream(self, port, socket_type):
55 56 sock = self.context.socket(socket_type)
56 57 addr = "tcp://%s:%i" % (self.kernel_manager.ip, port)
57 logging.info("Connecting to: %s" % addr)
58 logging.info("Connecting to: %s, %r" % (addr, socket_type))
58 59 sock.connect(addr)
59 60 return ZMQStream(sock)
60 61
@@ -1,24 +1,77 b''
1 html, body, div, span, applet, object, iframe,
1 /**
2 * HTML5 ✰ Boilerplate
3 *
4 * style.css contains a reset, font normalization and some base styles.
5 *
6 * Credit is left where credit is due.
7 * Much inspiration was taken from these projects:
8 * - yui.yahooapis.com/2.8.1/build/base/base.css
9 * - camendesign.com/design/
10 * - praegnanz.de/weblog/htmlcssjs-kickstart
11 */
12
13
14 /**
15 * html5doctor.com Reset Stylesheet (Eric Meyer's Reset Reloaded + HTML5 baseline)
16 * v1.6.1 2010-09-17 | Authors: Eric Meyer & Richard Clark
17 * html5doctor.com/html-5-reset-stylesheet/
18 */
19
20 html, body, div, span, object, iframe,
2 21 h1, h2, h3, h4, h5, h6, p, blockquote, pre,
3 a, abbr, acronym, address, big, cite, code,
4 del, dfn, em, img, ins, kbd, q, s, samp,
5 small, strike, strong, sub, sup, tt, var,
6 b, u, i, center,
7 dl, dt, dd, ol, ul, li,
22 abbr, address, cite, code, del, dfn, em, img, ins, kbd, q, samp,
23 small, strong, sub, sup, var, b, i, dl, dt, dd, ol, ul, li,
8 24 fieldset, form, label, legend,
9 25 table, caption, tbody, tfoot, thead, tr, th, td,
10 article, aside, canvas, details, embed,
11 figure, figcaption, footer, header, hgroup,
12 menu, nav, output, ruby, section, summary,
26 article, aside, canvas, details, figcaption, figure,
27 footer, header, hgroup, menu, nav, section, summary,
13 28 time, mark, audio, video {
14 margin: 0;
15 padding: 0;
16 border: 0;
17 font-size: 100%;
18 font: inherit;
19 vertical-align: baseline;
29 margin: 0;
30 padding: 0;
31 border: 0;
32 font-size: 100%;
33 font: inherit;
34 vertical-align: baseline;
35 }
36
37 article, aside, details, figcaption, figure,
38 footer, header, hgroup, menu, nav, section {
39 display: block;
20 40 }
21 41
42 blockquote, q { quotes: none; }
43
44 blockquote:before, blockquote:after,
45 q:before, q:after { content: ""; content: none; }
46
47 ins { background-color: #ff9; color: #000; text-decoration: none; }
48
49 mark { background-color: #ff9; color: #000; font-style: italic; font-weight: bold; }
50
51 del { text-decoration: line-through; }
52
53 abbr[title], dfn[title] { border-bottom: 1px dotted; cursor: help; }
54
55 table { border-collapse: collapse; border-spacing: 0; }
56
57 hr { display: block; height: 1px; border: 0; border-top: 1px solid #ccc; margin: 1em 0; padding: 0; }
58
59 input, select { vertical-align: middle; }
60
61
62 /**
63 * Font normalization inspired by YUI Library's fonts.css: developer.yahoo.com/yui/
64 */
65
66 body { font:13px/1.231 sans-serif; *font-size:small; } /* Hack retained to preserve specificity */
67 select, input, textarea, button { font:99% sans-serif; }
68
69 /* Normalize monospace sizing:
70 en.wikipedia.org/wiki/MediaWiki_talk:Common.css/Archive_11#Teletype_style_fix_for_Chrome */
71 pre, code, kbd, samp { font-family: monospace, sans-serif; }
72
73
74
22 75 body {
23 76 background-color: white;
24 77 }
@@ -37,45 +90,33 b' div#toolbar {'
37 90 border-bottom-width: 2px;
38 91 border-bottom-style: solid;
39 92 border-bottom-color: black;
40 padding: 5px;
93 padding: 5px;
41 94 }
42 95
43 #main_toolbar {
44 }
45 96
46 #main_toolbar button {
97 /*#main_toolbar button {
47 98 font-size: 0.9em;
48 }
99 }*/
49 100
50 101 div.notebook {
51 width: 760px;
102 width: 790px;
52 103 height: 100%;
53 104 margin-left: auto;
54 105 margin-right: auto;
55 106 padding-top: 5px;
56 107 padding-bottom: 5px;
57 108 background-color: white;
58
59 /* Uncomment this block for help in debugging the padding and margins
60 /* border-left-width: 1px;
61 border-left-style: solid;
62 border-left-color: black;
63 border-right-width: 1px;
64 border-right-style: solid;
65 border-right-color: black;
66 border-bottom-width: 1px;
67 border-bottom-style: solid;
68 border-bottom-color: black;*/
69 109 }
70 110
71 111 div.cell {
72 112 width: 740px;
73 margin: 5px 5px 5px 5px;
113 margin: 5px auto 5px 5px;
74 114 padding: 5px;
75 font-size: 11pt;
76 115 position: relative;
116 display: table;
77 117 }
78 118
119
79 120 div.code_cell {
80 121 background-color: white;
81 122 }
@@ -83,16 +124,18 b' div.code_cell {'
83 124 div.prompt {
84 125 vertical-align: top;
85 126 display: table-cell;
86 width: 85px;
87 min-width 80px !important;
127 width: 80px;
128 padding: 0px;
129 margin: 0px;
88 130 font-family: Menlo, "Courier New", Courier, mono;
89 131 font-weight: normal;
90 132 font-style: normal;
91 133 }
92 134
93 135 div.input {
94 display: table;
95 height: auto;
136 display: table-row;
137 padding: 0px;
138 margin: 0px;
96 139 }
97 140
98 141 div.input_prompt {
@@ -106,19 +149,21 b' textarea.input_area {'
106 149 font-size: inherit;
107 150 border-style: none;
108 151 display: table-cell;
109 margin: 0;
110 padding: 0;
152 padding: 0px;
153 margin: 0px;
111 154 overflow: auto;
112 155 font-weight: normal;
113 156 font-style: normal;
114 width: 665px;
157 width: 650px;
115 158 outline: none;
116 159 resize: none;
117 160 }
118 161
119 162
120 163 div.output {
121 display: table;
164 display: table-row;
165 padding: 0px;
166 margin: 0px;
122 167 }
123 168
124 169 div.output_prompt {
@@ -128,11 +173,10 b' div.output_prompt {'
128 173 div.output_area {
129 174 text-align: left;
130 175 font-family: Menlo, "Courier New", Courier, mono;
131 font-size: inherit;
132 margin: 0;
133 padding: 0;
176 padding: 0px;
177 margin: 0px;
134 178 display: table-cell;
135 width: 665px;
179 width: 650px;
136 180 }
137 181
138 182 div.text_cell {
@@ -2,6 +2,67 b' var IPYTHON = {};'
2 2
3 3
4 4 //============================================================================
5 // Utilities
6 //============================================================================
7
8
9 var uuid = function () {
10 // http://www.ietf.org/rfc/rfc4122.txt
11 var s = [];
12 var hexDigits = "0123456789ABCDEF";
13 for (var i = 0; i < 32; i++) {
14 s[i] = hexDigits.substr(Math.floor(Math.random() * 0x10), 1);
15 }
16 s[12] = "4"; // bits 12-15 of the time_hi_and_version field to 0010
17 s[16] = hexDigits.substr((s[16] & 0x3) | 0x8, 1); // bits 6-7 of the clock_seq_hi_and_reserved to 01
18
19 var uuid = s.join("");
20 return uuid;
21 };
22
23
24 //Fix raw text to parse correctly in crazy XML
25 function xmlencode(string) {
26 return string.replace(/\&/g,'&'+'amp;')
27 .replace(/</g,'&'+'lt;')
28 .replace(/>/g,'&'+'gt;')
29 .replace(/\'/g,'&'+'apos;')
30 .replace(/\"/g,'&'+'quot;')
31 .replace(/`/g,'&'+'#96;')
32 }
33
34 //Map from terminal commands to CSS classes
35 attrib = {
36 "30":"cblack", "31":"cred",
37 "32":"cgreen", "33":"cyellow",
38 "34":"cblue", "36":"ccyan",
39 "37":"cwhite", "01":"cbold"}
40
41 //Fixes escaped console commands, IE colors. Turns them into HTML
42 function fixConsole(txt) {
43 txt = xmlencode(txt)
44 var re = /\033\[([\d;]*?)m/
45 var opened = false
46 var cmds = []
47 var opener = ""
48 var closer = ""
49
50 while (re.test(txt)) {
51 var cmds = txt.match(re)[1].split(";")
52 closer = opened?"</span>":""
53 opened = cmds.length > 1 || cmds[0] != 0
54 var rep = []
55 for (var i in cmds)
56 if (typeof(attrib[cmds[i]]) != "undefined")
57 rep.push(attrib[cmds[i]])
58 opener = rep.length > 0?"<span class=\""+rep.join(" ")+"\">":""
59 txt = txt.replace(re, closer + opener)
60 }
61 if (opened) txt += "</span>"
62 return txt.trim()
63 }
64
65 //============================================================================
5 66 // Notebook
6 67 //============================================================================
7 68
@@ -11,14 +72,18 b' var Notebook = function (selector) {'
11 72 this.element.scroll();
12 73 this.element.data("notebook", this);
13 74 this.next_prompt_number = 1;
75 this.next_kernel_number = 0;
76 this.kernel = null;
77 this.msg_cell_map = {};
14 78 this.bind_events();
79 this.start_kernel();
15 80 };
16 81
17 82
18 83 Notebook.prototype.bind_events = function () {
19 84 var that = this;
20 85 $(document).keydown(function (event) {
21 console.log(event);
86 // console.log(event);
22 87 if (event.which == 38 && event.shiftKey) {
23 88 event.preventDefault();
24 89 that.select_prev();
@@ -27,9 +92,27 b' Notebook.prototype.bind_events = function () {'
27 92 that.select_next();
28 93 } else if (event.which == 13 && event.shiftKey) {
29 94 // The focus is not quite working here.
95 var cell = that.selected_cell();
96 var cell_index = that.find_cell_index(cell);
97 if (cell instanceof CodeCell) {
98 event.preventDefault();
99 cell.clear_output();
100 var msg_id = that.kernel.execute(cell.get_code());
101 that.msg_cell_map[msg_id] = cell.cell_id;
102 if (cell_index === (that.ncells()-1)) {
103 that.insert_code_cell_after();
104 } else {
105 that.select(cell_index+1);
106 };
107 }
108 } else if (event.which == 9) {
30 109 event.preventDefault();
31 that.insert_code_cell_after();
32 }
110 var cell = that.selected_cell();
111 if (cell instanceof CodeCell) {
112 var ta = cell.element.find("textarea.input_area");
113 ta.val(ta.val() + " ");
114 };
115 };
33 116 });
34 117 };
35 118
@@ -112,6 +195,19 b' Notebook.prototype.selected_index = function () {'
112 195 };
113 196
114 197
198 Notebook.prototype.cell_for_msg = function (msg_id) {
199 var cell_id = this.msg_cell_map[msg_id];
200 var result = null;
201 this.cell_elements().filter(function (index) {
202 cell = $(this).data("cell");
203 if (cell.cell_id === cell_id) {
204 result = cell;
205 };
206 });
207 return result;
208 };
209
210
115 211 Notebook.prototype.selected_cell = function () {
116 212 return this.cell_elements().eq(this.selected_index()).data("cell");
117 213 }
@@ -301,13 +397,63 b' Notebook.prototype.code_to_text = function (index) {'
301 397 Notebook.prototype.collapse = function (index) {
302 398 var i = this.index_or_selected(index);
303 399 this.cells()[i].collapse();
304 }
400 };
305 401
306 402
307 403 Notebook.prototype.expand = function (index) {
308 404 var i = this.index_or_selected(index);
309 405 this.cells()[i].expand();
310 }
406 };
407
408
409 // Kernel related things
410
411 Notebook.prototype.start_kernel = function () {
412 this.kernel = new Kernel("kernel" + this.next_kernel_number);
413 this.next_kernel_number = this.next_kernel_number + 1;
414 this.kernel.start_kernel(this._kernel_started, this);
415 };
416
417
418 Notebook.prototype._kernel_started = function () {
419 console.log("Kernel started: ", this.kernel.kernel_id);
420 this.kernel.start_session(this._session_started, this);
421 };
422
423
424 Notebook.prototype._session_started = function () {
425 console.log("Session started: ", this.kernel.session_id);
426 var that = this;
427
428 this.kernel.shell_channel.onmessage = function (e) {
429 reply = $.parseJSON(e.data);
430 console.log(reply);
431 var msg_type = reply.msg_type;
432 var cell = that.cell_for_msg(reply.parent_header.msg_id);
433 if (msg_type === "execute_reply") {
434 cell.set_prompt(reply.content.execution_count);
435 };
436 };
437
438 this.kernel.iopub_channel.onmessage = function (e) {
439 reply = $.parseJSON(e.data);
440 console.log(reply);
441 var msg_type = reply.msg_type;
442 var cell = that.cell_for_msg(reply.parent_header.msg_id);
443 if (msg_type === "stream") {
444 cell.expand();
445 cell.append_stream(reply.content.data + "\n");
446 } else if (msg_type === "pyout" || msg_type === "display_data") {
447 cell.expand();
448 cell.append_display_data(reply.content.data);
449 };
450 };
451 };
452
453
454 Notebook.prototype._handle_execute_reply = function (reply, cell) {
455 cell.set_prompt(reply.content.execution_count);
456 };
311 457
312 458
313 459 //============================================================================
@@ -324,6 +470,7 b' var Cell = function (notebook) {'
324 470 this.element.data("cell", this);
325 471 this.bind_events();
326 472 }
473 this.cell_id = uuid();
327 474 };
328 475
329 476
@@ -394,9 +541,41 b' CodeCell.prototype.create_element = function () {'
394 541 ).append(
395 542 $('<div/>').addClass('output_area')
396 543 );
397 output.hide();
398 544 cell.append(input).append(output);
399 545 this.element = cell;
546 this.collapse()
547 };
548
549
550 CodeCell.prototype.append_stream = function (data) {
551 var data_list = data.split("\n");
552 console.log(data_list);
553 if (data_list.length > 0) {
554 for (var i=0; i<data_list.length; i++) {
555 console.log(i, data_list[i]);
556 var toinsert = fixConsole(data_list[i]);
557 this.element.find("div.output_area").append($("<p>").append(toinsert));
558 };
559 }
560 };
561
562
563 CodeCell.prototype.append_display_data = function (data) {
564 if (data["image/svg+xml"] !== undefined) {
565 this.append_svg(data["image/svg+xml"]);
566 } else if (data["text/plain"] !== undefined) {
567 console.log(data["text/plain"]);
568 this.append_stream(data["text/plain"]);
569 };
570 };
571
572 CodeCell.prototype.append_svg = function (svg) {
573 this.element.find("div.output_area").append(svg);
574 };
575
576
577 CodeCell.prototype.clear_output = function () {
578 this.element.find("div.output_area").html("");
400 579 };
401 580
402 581
@@ -429,6 +608,10 b' CodeCell.prototype.set_output_prompt = function (number) {'
429 608 };
430 609
431 610
611 CodeCell.prototype.get_code = function () {
612 return this.element.find("textarea.input_area").val();
613 };
614
432 615 //============================================================================
433 616 // TextCell
434 617 //============================================================================
@@ -508,34 +691,71 b' TextCell.prototype.config_mathjax = function () {'
508 691 //============================================================================
509 692
510 693
511 var KernelManager = function () {
512 this.kernelid = null;
513 this.baseurl = "/kernels";
694 var Kernel = function (kernel_id) {
695 this.kernel_id = kernel_id;
696 this.base_url = "/kernels";
697 this.kernel_url = this.base_url + "/" + this.kernel_id
698 this.session_id = null;
699 };
700
701
702 Kernel.prototype.get_msg = function (msg_type, content) {
703 var msg = {
704 header : {
705 msg_id : uuid(),
706 username : "bgranger",
707 session: this.session_id
708 },
709 msg_type : msg_type,
710 content : content,
711 parent_header : {}
712 };
713 return msg;
714 }
715
716 Kernel.prototype.start_kernel = function (callback, context) {
717 $.post(this.kernel_url, function () {
718 callback.call(context);
719 });
514 720 };
515 721
516 722
517 KernelManager.prototype.create_kernel = function () {
723 Kernel.prototype.start_session = function (callback, context) {
518 724 var that = this;
519 $.post(this.baseurl, function (data) {
520 that.kernelid = data;
521 }, 'json');
725 $.post(this.kernel_url + "/sessions",
726 function (session_id) {
727 that._handle_start_session(session_id, callback, context);
728 },
729 'json');
522 730 }
523 731
524 732
525 KernelManager.prototype.execute = function (code, callback) {
526 var msg = {
527 header : {msg_id : 0, username : "bgranger", session: 0},
528 msg_type : "execute_request",
529 content : {code : code}
733 Kernel.prototype._handle_start_session = function (session_id, callback, context) {
734 this.session_id = session_id;
735 this.session_url = this.kernel_url + "/sessions/" + this.session_id;
736 this._start_channels();
737 callback.call(context);
738 };
739
740
741 Kernel.prototype._start_channels = function () {
742 var ws_url = "ws://127.0.0.1:8888" + this.session_url;
743 this.shell_channel = new WebSocket(ws_url + "/shell");
744 this.iopub_channel = new WebSocket(ws_url + "/iopub");
745 }
746
747
748 Kernel.prototype.execute = function (code) {
749 var content = {
750 code : code,
751 silent : false,
752 user_variables : [],
753 user_expressions : {}
530 754 };
531 var settings = {
532 data : JSON.stringify(msg),
533 processData : false,
534 contentType : "application/json",
535 success : callback,
536 type : "POST"
537 }
538 var url = this.baseurl + "/" + this.kernelid + "/" + ""
755 var msg = this.get_msg("execute_request", content);
756
757 this.shell_channel.send(JSON.stringify(msg));
758 return msg.header.msg_id;
539 759 }
540 760
541 761
@@ -579,4 +799,8 b' $(document).ready(function () {'
579 799 $("#sort").buttonset();
580 800 $("#sort_cells").click(function () {IPYTHON.notebook.sort_cells();});
581 801
802 $("#toggle").buttonset();
803 $("#collapse").click(function () {IPYTHON.notebook.collapse();});
804 $("#expand").click(function () {IPYTHON.notebook.expand();});
805
582 806 }); No newline at end of file
@@ -67,6 +67,10 b''
67 67 <span id="sort">
68 68 <button id="sort_cells">Sort</button>
69 69 </span>
70 <span id="toggle">
71 <button id="collapse">Collapse</button>
72 <button id="expand">Expand</button>
73 </span>
70 74 </span>
71 75 </div>
72 76
@@ -46,7 +46,6 b' from session import Session, Message'
46 46 from zmqshell import ZMQInteractiveShell
47 47
48 48
49
50 49 #-----------------------------------------------------------------------------
51 50 # Main kernel class
52 51 #-----------------------------------------------------------------------------
General Comments 0
You need to be logged in to leave comments. Login now