diff --git a/IPython/html/static/services/kernels/js/kernel.js b/IPython/html/static/services/kernels/js/kernel.js
index b867fc1..783655c 100644
--- a/IPython/html/static/services/kernels/js/kernel.js
+++ b/IPython/html/static/services/kernels/js/kernel.js
@@ -1,9 +1,5 @@
-//----------------------------------------------------------------------------
-// Copyright (C) 2008-2011 The IPython Development Team
-//
-// Distributed under the terms of the BSD License. The full license is in
-// the file COPYING, distributed as part of this software.
-//----------------------------------------------------------------------------
+// Copyright (c) IPython Development Team.
+// Distributed under the terms of the Modified BSD License.
//============================================================================
// Kernel
@@ -49,6 +45,9 @@ var IPython = (function (IPython) {
this.init_iopub_handlers();
this.comm_manager = new IPython.CommManager(this);
this.widget_manager = new IPython.WidgetManager(this.comm_manager);
+
+ this.last_msg_id = null;
+ this.last_msg_callbacks = {};
};
@@ -429,7 +428,11 @@ var IPython = (function (IPython) {
Kernel.prototype.get_callbacks_for_msg = function (msg_id) {
// get callbacks for a specific message
- return this._msg_callbacks[msg_id];
+ if (msg_id == this.last_msg_id) {
+ return this.last_msg_callbacks;
+ } else {
+ return this._msg_callbacks[msg_id];
+ }
};
@@ -439,6 +442,26 @@ var IPython = (function (IPython) {
}
};
+ Kernel.prototype._finish_shell = function (msg_id) {
+ var callbacks = this._msg_callbacks[msg_id];
+ if (callbacks !== undefined) {
+ callbacks.shell_done = true;
+ if (callbacks.iopub_done) {
+ this.clear_callbacks_for_msg(msg_id);
+ }
+ }
+ };
+
+ Kernel.prototype._finish_iopub = function (msg_id) {
+ var callbacks = this._msg_callbacks[msg_id];
+ if (callbacks !== undefined) {
+ callbacks.iopub_done = true;
+ if (!callbacks.shell_done) {
+ this.clear_callbacks_for_msg(msg_id);
+ }
+ }
+ };
+
/* Set callbacks for a particular message.
* Callbacks should be a struct of the following form:
* shell : {
@@ -447,13 +470,17 @@ var IPython = (function (IPython) {
*/
Kernel.prototype.set_callbacks_for_msg = function (msg_id, callbacks) {
+ this.last_msg_id = msg_id;
if (callbacks) {
// shallow-copy mapping, because we will modify it at the top level
- var cbcopy = this._msg_callbacks[msg_id] = {};
+ var cbcopy = this._msg_callbacks[msg_id] = this.last_msg_callbacks = {};
cbcopy.shell = callbacks.shell;
cbcopy.iopub = callbacks.iopub;
cbcopy.input = callbacks.input;
- this._msg_callbacks[msg_id] = cbcopy;
+ cbcopy.shell_done = (!callbacks.shell);
+ cbcopy.iopub_done = (!callbacks.iopub);
+ } else {
+ this.last_msg_callbacks = {};
}
};
@@ -470,12 +497,8 @@ var IPython = (function (IPython) {
}
var shell_callbacks = callbacks.shell;
- // clear callbacks on shell
- delete callbacks.shell;
- delete callbacks.input;
- if (!callbacks.iopub) {
- this.clear_callbacks_for_msg(parent_id);
- }
+ // signal that shell callbacks are done
+ this._finish_shell(parent_id);
if (shell_callbacks.reply !== undefined) {
shell_callbacks.reply(reply);
@@ -516,14 +539,11 @@ var IPython = (function (IPython) {
if (execution_state === 'busy') {
$([IPython.events]).trigger('status_busy.Kernel', {kernel: this});
} else if (execution_state === 'idle') {
- // clear callbacks on idle, there can be no more
- if (callbacks !== undefined) {
- delete callbacks.iopub;
- delete callbacks.input;
- if (!callbacks.shell) {
- this.clear_callbacks_for_msg(parent_id);
- }
- }
+ // signal that iopub callbacks are (probably) done
+ // async output may still arrive,
+ // but only for the most recent request
+ this._finish_iopub(parent_id);
+
// trigger status_idle event
$([IPython.events]).trigger('status_idle.Kernel', {kernel: this});
} else if (execution_state === 'restarting') {