Merge remote-tracking branch 'upstream/master' into mono_cursor_offset

This commit is contained in:
mcelrath 2012-06-22 21:22:43 -07:00
commit 5a070dcd1a
15 changed files with 167 additions and 46 deletions

View File

@ -193,7 +193,7 @@ class MultiKernelManager(LoggingConfigurable):
def create_shell_stream(self, kernel_id):
ip = self.get_kernel_ip(kernel_id)
ports = self.get_kernel_ports(kernel_id)
shell_stream = self.create_connected_stream(ip, ports['shell_port'], zmq.XREQ)
shell_stream = self.create_connected_stream(ip, ports['shell_port'], zmq.DEALER)
return shell_stream
def create_hb_stream(self, kernel_id):

View File

@ -228,6 +228,7 @@ class NotebookManager(LoggingConfigurable):
os.unlink(old_pypath)
self.mapping[notebook_id] = new_name
self.rev_mapping[new_name] = notebook_id
del self.rev_mapping[old_name]
def delete_notebook(self, notebook_id):
"""Delete notebook by notebook_id."""

View File

@ -39,6 +39,10 @@ span#notebook_name {
padding: 2px 1.6em;
}
.ui-menu .ui-menu-item a.ui-state-focus {
margin: 0;
}
.ui-menu hr {
margin: 0.3em 0;
}
@ -281,7 +285,7 @@ div.text_cell_render {
.completions {
position: absolute;
z-index: 10;
overflow: auto;
overflow: hidden;
border: 1px solid grey;
}
@ -291,6 +295,7 @@ div.text_cell_render {
border: none;
padding: 0px;
margin: 0px;
overflow: auto;
font-family: monospace;
}

View File

@ -61,11 +61,11 @@ var IPython = (function (IPython) {
// handlers and is used to provide custom key handling. Its return
// value is used to determine if CodeMirror should ignore the event:
// true = ignore, false = don't ignore.
if (this.read_only){
return false;
}
var that = this;
// whatever key is pressed, first, cancel the tooltip request before
// they are sent, and remove tooltip if any, except for tab again
@ -90,7 +90,7 @@ var IPython = (function (IPython) {
event.stop();
return false;
} else {
return true;
return true;
};
} else if (event.which === key.ESC) {
IPython.tooltip.remove_and_cancel_tooltip(true);
@ -102,7 +102,7 @@ var IPython = (function (IPython) {
event.stop();
return false;
} else {
return true;
return true;
};
} else if (event.keyCode === key.TAB && event.type == 'keydown') {
// Tab completion.
@ -267,6 +267,9 @@ var IPython = (function (IPython) {
if (data.cell_type === 'code') {
if (data.input !== undefined) {
this.set_text(data.input);
// make this value the starting point, so that we can only undo
// to this state, instead of a blank cell
this.code_mirror.clearHistory();
}
if (data.prompt_number !== undefined) {
this.set_input_prompt(data.prompt_number);

View File

@ -8,17 +8,41 @@ var IPython = (function (IPython) {
// easyier key mapping
var key = IPython.utils.keycodes;
function prepend_n_prc(str, n) {
for( var i =0 ; i< n ; i++)
{ str = '%'+str }
return str;
}
function _existing_completion(item, completion_array){
for( var c in completion_array ) {
if(completion_array[c].substr(-item.length) == item)
{ return true; }
}
return false;
}
// what is the common start of all completions
function shared_start(B) {
function shared_start(B, drop_prct) {
if (B.length == 1) {
return B[0];
}
var A = new Array();
var common;
var min_lead_prct = 10;
for (var i = 0; i < B.length; i++) {
A.push(B[i].str);
var str = B[i].str;
var localmin = 0;
if(drop_prct == true){
while ( str.substr(0, 1) == '%') {
localmin = localmin+1;
str = str.substring(1);
}
}
min_lead_prct = Math.min(min_lead_prct, localmin);
A.push(str);
}
if (A.length > 1) {
var tem1, tem2, s;
A = A.slice(0).sort();
@ -29,10 +53,10 @@ var IPython = (function (IPython) {
tem1 = tem1.substring(0, --s);
}
if (tem1 == "" || tem2.indexOf(tem1) != 0) {
return null;
return prepend_n_prc('', min_lead_prct);
}
return {
str: tem1,
str: prepend_n_prc(tem1, min_lead_prct),
type: "computed",
from: B[0].from,
to: B[0].to
@ -116,12 +140,19 @@ var IPython = (function (IPython) {
var cur = this.editor.getCursor();
var results = CodeMirror.contextHint(this.editor);
var filterd_results = Array();
//remove results from context completion
//that are already in kernel completion
for(var elm in results) {
if(_existing_completion(results[elm]['str'], matches) == false)
{ filterd_results.push(results[elm]); }
}
// append the introspection result, in order, at at the beginning of
// the table and compute the replacement range from current cursor
// positon and matched_text length.
for (var i = matches.length - 1; i >= 0; --i) {
results.unshift({
filterd_results.unshift({
str: matches[i],
type: "introspection",
from: {
@ -136,7 +167,7 @@ var IPython = (function (IPython) {
}
// one the 2 sources results have been merge, deal with it
this.raw_result = results;
this.raw_result = filterd_results;
// if empty result return
if (!this.raw_result || !this.raw_result.length) return;
@ -244,7 +275,7 @@ var IPython = (function (IPython) {
//Check that shared start is not null which can append with prefixed completion
// like %pylab , pylab have no shred start, and ff will result in py<tab><tab>
// to erase py
var sh = shared_start(this.raw_result);
var sh = shared_start(this.raw_result, true);
if (sh) {
this.insert(sh);
}

View File

@ -98,8 +98,9 @@ var IPython = (function (IPython) {
" or if the url does not look right, there could be an error in the" +
" server's configuration.";
} else {
msg = "Websocket connection closed unexpectedly." +
" The kernel will no longer be responsive.";
IPython.notification_widget.set_message('Reconnecting Websockets', 1000);
this.start_channels();
return;
}
var dialog = $('<div/>');
dialog.html(msg);

View File

@ -28,7 +28,7 @@ var IPython = (function (IPython) {
this.control_key_active = false;
this.notebook_id = null;
this.notebook_name = null;
this.notebook_name_blacklist_re = /[\/\\]/;
this.notebook_name_blacklist_re = /[\/\\:]/;
this.nbformat = 3 // Increment this when changing the nbformat
this.style();
this.create_elements();
@ -602,6 +602,9 @@ var IPython = (function (IPython) {
text = '';
}
target_cell.set_text(text);
// make this value the starting point, so that we can only undo
// to this state, instead of a blank cell
target_cell.code_mirror.clearHistory();
source_element.remove();
this.dirty = true;
};
@ -623,6 +626,9 @@ var IPython = (function (IPython) {
// The edit must come before the set_text.
target_cell.edit();
target_cell.set_text(text);
// make this value the starting point, so that we can only undo
// to this state, instead of a blank cell
target_cell.code_mirror.clearHistory();
source_element.remove();
this.dirty = true;
};
@ -645,6 +651,9 @@ var IPython = (function (IPython) {
// The edit must come before the set_text.
target_cell.edit();
target_cell.set_text(text);
// make this value the starting point, so that we can only undo
// to this state, instead of a blank cell
target_cell.code_mirror.clearHistory();
source_element.remove();
this.dirty = true;
};
@ -667,6 +676,9 @@ var IPython = (function (IPython) {
// The edit must come before the set_text.
target_cell.edit();
target_cell.set_text(text);
// make this value the starting point, so that we can only undo
// to this state, instead of a blank cell
target_cell.code_mirror.clearHistory();
source_element.remove();
this.dirty = true;
};
@ -693,6 +705,9 @@ var IPython = (function (IPython) {
target_cell.set_level(level);
target_cell.edit();
target_cell.set_text(text);
// make this value the starting point, so that we can only undo
// to this state, instead of a blank cell
target_cell.code_mirror.clearHistory();
source_element.remove();
this.dirty = true;
};

View File

@ -85,10 +85,10 @@ var IPython = (function (IPython) {
that.set_message("Saving notebook",500);
});
$([IPython.events]).on('notebook_saved.Notebook', function () {
that.set_message("Notebook saved",500);
that.set_message("Notebook saved",2000);
});
$([IPython.events]).on('notebook_save_failed.Notebook', function () {
that.set_message("Notebook save failed",500);
that.set_message("Notebook save failed",2000);
});
};

View File

@ -181,11 +181,7 @@ var IPython = (function (IPython) {
if (json.stream == undefined){
json.stream = 'stdout';
}
if (!utils.fixConsole(json.text)){
// fixConsole gives nothing (empty string, \r, etc.)
// so don't append any elements, which might add undesirable space
return;
}
var text = json.text;
var subclass = "output_"+json.stream;
if (this.outputs.length > 0){
// have at least one output to consider
@ -194,15 +190,23 @@ var IPython = (function (IPython) {
// latest output was in the same stream,
// so append directly into its pre tag
// escape ANSI & HTML specials:
var text = utils.fixConsole(json.text);
this.element.find('div.'+subclass).last().find('pre').append(text);
var pre = this.element.find('div.'+subclass).last().find('pre');
var html = utils.fixCarriageReturn(
pre.html() + utils.fixConsole(text));
pre.html(html);
return;
}
}
if (!text.replace("\r", "")) {
// text is nothing (empty string, \r, etc.)
// so don't append any elements, which might add undesirable space
return;
}
// If we got here, attach a new div
var toinsert = this.create_output_area();
this.append_text(json.text, toinsert, "output_stream "+subclass);
this.append_text(text, toinsert, "output_stream "+subclass);
this.element.append(toinsert);
};
@ -260,6 +264,7 @@ var IPython = (function (IPython) {
var toinsert = $("<div/>").addClass("box-flex1 output_subarea output_text");
// escape ANSI & HTML specials in plaintext:
data = utils.fixConsole(data);
data = utils.fixCarriageReturn(data);
if (extra_class){
toinsert.addClass(extra_class);
}
@ -277,14 +282,22 @@ var IPython = (function (IPython) {
OutputArea.prototype.append_png = function (png, element) {
var toinsert = $("<div/>").addClass("box-flex1 output_subarea output_png");
toinsert.append($("<img/>").attr('src','data:image/png;base64,'+png));
var img = $("<img/>").attr('src','data:image/png;base64,'+png);
img.load(function () {
$(this).resizable({'aspectRatio': true, 'autoHide': true})
});
toinsert.append(img);
element.append(toinsert);
};
OutputArea.prototype.append_jpeg = function (jpeg, element) {
var toinsert = $("<div/>").addClass("box-flex1 output_subarea output_jpeg");
toinsert.append($("<img/>").attr('src','data:image/jpeg;base64,'+jpeg));
var img = $("<img/>").attr('src','data:image/jpeg;base64,'+jpeg);
img.load(function () {
$(this).resizable({'aspectRatio': true, 'autoHide': true})
});
toinsert.append(img);
element.append(toinsert);
};
@ -328,7 +341,7 @@ var IPython = (function (IPython) {
OutputArea.prototype.clear_output_callback = function (stdout, stderr, other) {
var output_div = this.element;
if (stdout && stderr && other){
// clear all, no need for logic
output_div.html("");
@ -347,7 +360,7 @@ var IPython = (function (IPython) {
if (other) {
output_div.find("div.output_subarea").not("div.output_stderr").not("div.output_stdout").parent().remove();
}
// remove cleared outputs from JSON list:
for (var i = this.outputs.length - 1; i >= 0; i--) {
var out = this.outputs[i];

View File

@ -117,7 +117,7 @@ var IPython = (function (IPython) {
Pager.prototype.append_text = function (text) {
var toinsert = $("<div/>").addClass("output_area output_stream");
toinsert.append($('<pre/>').html(utils.fixConsole(text)));
toinsert.append($('<pre/>').html(utils.fixCarriageReturn(utils.fixConsole(text))));
this.pager_element.append(toinsert);
};

View File

@ -52,7 +52,7 @@ var IPython = (function (IPython) {
that.update_document_title();
});
$([IPython.events]).on('notebook_save_failed.Notebook', function () {
that.set_save_status('');
that.set_save_status('Last Save Failed!');
});
};
@ -83,7 +83,7 @@ var IPython = (function (IPython) {
$(this).find('h3').html(
"Invalid notebook name. Notebook names must "+
"have 1 or more characters and can contain any characters " +
"except / and \\. Please enter a new notebook name:"
"except :/\\. Please enter a new notebook name:"
);
} else {
IPython.notebook.set_notebook_name(new_name);

View File

@ -158,6 +158,9 @@ var IPython = (function (IPython) {
if (data.cell_type === this.cell_type) {
if (data.source !== undefined) {
this.set_text(data.source);
// make this value the starting point, so that we can only undo
// to this state, instead of a blank cell
this.code_mirror.clearHistory();
this.set_rendered(data.rendered || '');
this.rendered = false;
this.render();

View File

@ -43,11 +43,11 @@ IPython.utils = (function (IPython) {
ansi_colormap = {
"30":"ansiblack", "31":"ansired",
"32":"ansigreen", "33":"ansiyellow",
"34":"ansiblue", "35":"ansipurple","36":"ansicyan",
"34":"ansiblue", "35":"ansipurple","36":"ansicyan",
"37":"ansigrey", "01":"ansibold"
};
// Transform ANI color escape codes into HTML <span> tags with css
// Transform ANSI color escape codes into HTML <span> tags with css
// classes listed in the above ansi_colormap object. The actual color used
// are set in the css file.
function fixConsole(txt) {
@ -57,8 +57,6 @@ IPython.utils = (function (IPython) {
var cmds = [];
var opener = "";
var closer = "";
// \r does nothing, so shouldn't be included
txt = txt.replace('\r', '');
while (re.test(txt)) {
var cmds = txt.match(re)[1].split(";");
closer = opened?"</span>":"";
@ -74,6 +72,16 @@ IPython.utils = (function (IPython) {
return txt;
}
// Remove chunks that should be overridden by the effect of
// carriage return characters
function fixCarriageReturn(txt) {
tmp = txt;
do {
txt = tmp;
tmp = txt.replace(/^.*\r(?!\n)/gm, '');
} while (tmp.length < txt.length);
return txt;
}
grow = function(element) {
// Grow the cell by hand. This is used upon reloading from JSON, when the
@ -118,12 +126,24 @@ IPython.utils = (function (IPython) {
DOWN : 40,
};
points_to_pixels = function (points) {
// A reasonably good way of converting between points and pixels.
var test = $('<div style="display: none; width: 10000pt; padding:0; border:0;"></div>');
$(body).append(test);
var pixel_per_point = test.width()/10000;
test.remove();
return Math.floor(points*pixel_per_point);
}
return {
uuid : uuid,
fixConsole : fixConsole,
keycodes : keycodes,
grow : grow,
fixCarriageReturn : fixCarriageReturn,
points_to_pixels : points_to_pixels
};
}(IPython));

View File

@ -26,6 +26,7 @@ itself from the command line. There are two ways of running this script:
#-----------------------------------------------------------------------------
# Stdlib
import glob
import os
import os.path as path
import signal
@ -148,16 +149,18 @@ have = {}
have['curses'] = test_for('_curses')
have['matplotlib'] = test_for('matplotlib')
have['numpy'] = test_for('numpy')
have['pexpect'] = test_for('IPython.external.pexpect')
have['pymongo'] = test_for('pymongo')
have['pygments'] = test_for('pygments')
have['wx'] = test_for('wx')
have['wx.aui'] = test_for('wx.aui')
have['qt'] = test_for('IPython.external.qt')
have['rpy2'] = test_for('rpy2')
have['sqlite3'] = test_for('sqlite3')
have['cython'] = test_for('Cython')
have['oct2py'] = test_for('oct2py')
have['tornado'] = test_for('tornado.version_info', (2,1,0), callback=None)
have['wx'] = test_for('wx')
have['wx.aui'] = test_for('wx.aui')
if os.name == 'nt':
min_zmq = (2,1,7)
@ -234,6 +237,11 @@ def make_exclude():
exclusions.append(ipjoin('core', 'history'))
if not have['wx']:
exclusions.append(ipjoin('lib', 'inputhookwx'))
# FIXME: temporarily disable autoreload tests, as they can produce
# spurious failures in subsequent tests (cythonmagic).
exclusions.append(ipjoin('extensions', 'autoreload'))
exclusions.append(ipjoin('extensions', 'tests', 'test_autoreload'))
# We do this unconditionally, so that the test suite doesn't import
# gtk, changing the default encoding and masking some unicode bugs.
@ -277,9 +285,17 @@ def make_exclude():
exclusions.extend([ipjoin('extensions', 'cythonmagic')])
exclusions.extend([ipjoin('extensions', 'tests', 'test_cythonmagic')])
if not have['oct2py']:
exclusions.extend([ipjoin('extensions', 'octavemagic')])
exclusions.extend([ipjoin('extensions', 'tests', 'test_octavemagic')])
if not have['tornado']:
exclusions.append(ipjoin('frontend', 'html'))
if not have['rpy2'] or not have['numpy']:
exclusions.append(ipjoin('extensions', 'rmagic'))
exclusions.append(ipjoin('extensions', 'tests', 'test_rmagic'))
# This is needed for the reg-exp to match on win32 in the ipdoctest plugin.
if sys.platform == 'win32':
exclusions = [s.replace('\\','\\\\') for s in exclusions]
@ -287,8 +303,11 @@ def make_exclude():
# check for any exclusions that don't seem to exist:
parent, _ = os.path.split(get_ipython_package_dir())
for exclusion in exclusions:
if exclusion.endswith(('deathrow', 'quarantine')):
# ignore deathrow/quarantine, which exist in dev, but not install
continue
fullpath = pjoin(parent, exclusion)
if not os.path.exists(fullpath) and not os.path.exists(fullpath + '.py'):
if not os.path.exists(fullpath) and not glob.glob(fullpath + '.*'):
warn("Excluding nonexistent file: %r\n" % exclusion)
return exclusions

View File

@ -20,7 +20,7 @@ from subprocess import Popen, PIPE
import nose.tools as nt
from IPython.testing import decorators as dec
from IPython.utils.io import Tee
from IPython.utils.io import Tee, capture_output
from IPython.utils.py3compat import doctest_refactor_print
#-----------------------------------------------------------------------------
@ -73,3 +73,13 @@ def test_io_init():
# __class__ is a reference to the class object in Python 3, so we can't
# just test for string equality.
assert 'IPython.utils.io.IOStream' in classname, classname
def test_capture_output():
"""capture_output() context works"""
with capture_output() as io:
print 'hi, stdout'
print >> sys.stderr, 'hi, stderr'
nt.assert_equals(io.stdout, 'hi, stdout\n')
nt.assert_equals(io.stderr, 'hi, stderr\n')