From 8c1c0aded8040cdfdcdf7532bd05e29519b16589 Mon Sep 17 00:00:00 2001 From: Jonathan Helmus Date: Wed, 15 Apr 2015 20:30:45 -0600 Subject: [PATCH 1/6] WIP: Support for IPython 3.0 --- ftplugin/python/vim_ipython.py | 31 ++++++++++++++++++------------- 1 file changed, 18 insertions(+), 13 deletions(-) diff --git a/ftplugin/python/vim_ipython.py b/ftplugin/python/vim_ipython.py index 202925c..b13303c 100644 --- a/ftplugin/python/vim_ipython.py +++ b/ftplugin/python/vim_ipython.py @@ -39,7 +39,7 @@ def flush(self):pass def vim_variable(name, default=None): exists = int(vim.eval("exists('%s')" % name)) return vim.eval(name) if exists else default - + def vim_regex_escape(x): for old, new in (("[", "\\["), ("]", "\\]"), (":", "\\:"), (".", "\."), ("*", "\\*")): x = x.replace(old, new) @@ -122,7 +122,7 @@ def km_from_string(s=''): except ImportError: # < 0.12, no find_connection_file pass - + global km, kc, send s = s.replace('--existing', '') @@ -183,7 +183,7 @@ def km_from_string(s=''): klass = sc.__class__ klass._oinfo_orig = klass.object_info klass.object_info = lambda s,x,y: s._oinfo_orig(x) - + #XXX: backwards compatibility for IPython < 1.0 if not hasattr(kc, 'iopub_channel'): kc.iopub_channel = kc.sub_channel @@ -399,14 +399,17 @@ def update_subchannel_msgs(debug=False, force=False): # TODO: alllow for distinguishing between stdout and stderr (using # custom syntax markers in the vim-ipython buffer perhaps), or by # also echoing the message to the status bar - s = strip_color_escapes(m['content']['data']) - elif header == 'pyout': + try: + s = strip_color_escapes(m['content']['data']) + except KeyError: # changed in IPython 3.0.0 + s = strip_color_escapes(m['content']['text']) + elif header == 'pyout' or header == 'execute_result': s = status_prompt_out % {'line': m['content']['execution_count']} s += m['content']['data']['text/plain'] elif header == 'display_data': # TODO: handle other display data types (HMTL? images?) s += m['content']['data']['text/plain'] - elif header == 'pyin': + elif header == 'pyin' or header == 'execute_input': # TODO: the next line allows us to resend a line to ipython if # %doctest_mode is on. In the future, IPython will send the # execution_count on subchannel, so this will need to be updated @@ -424,7 +427,7 @@ def update_subchannel_msgs(debug=False, force=False): s += c['ename'] + ":" + c['evalue'] if s.find('\n') == -1: - # somewhat ugly unicode workaround from + # somewhat ugly unicode workaround from # http://vim.1045645.n5.nabble.com/Limitations-of-vim-python-interface-with-respect-to-character-encodings-td1223881.html if isinstance(s,unicode): s=s.encode(vim_encoding) @@ -444,7 +447,7 @@ def update_subchannel_msgs(debug=False, force=False): if not startedin_vimipython: vim.command('normal! p') # go back to where you were return update_occured - + def get_child_msg(msg_id): # XXX: message handling should be split into its own process in the future while True: @@ -456,7 +459,7 @@ def get_child_msg(msg_id): #got a message, but not the one we were looking for echo('skipping a message on shell_channel','WarningMsg') return m - + def print_prompt(prompt,msg_id=None): """Print In[] or In[42] style messages""" global show_execution_count @@ -554,7 +557,6 @@ def set_pid(): global pid lines = '\n'.join(['import os', '_pid = os.getpid()']) msg_id = send(lines, silent=True, user_variables=['_pid']) - # wait to get message back from kernel try: child = get_child_msg(msg_id) @@ -565,6 +567,9 @@ def set_pid(): pid = int(child['content']['user_variables']['_pid']) except TypeError: # change in IPython 1.0.dev moved this out pid = int(child['content']['user_variables']['_pid']['data']['text/plain']) + except KeyError: # change in IPython 3.0+ + pid = int( + child['content']['user_expressions']['_pid']['data']['text/plain']) except KeyError: # change in IPython 1.0.dev moved this out echo("Could not get PID information, kernel not running Python?") return pid @@ -608,7 +613,7 @@ def dedent_run_this_line(): def dedent_run_these_lines(): run_these_lines(True) - + #def set_this_line(): # # not sure if there's a way to do this, since we have multiple clients # send("get_ipython().shell.set_next_input(\'%s\')" % vim.current.line.replace("\'","\\\'")) @@ -625,9 +630,9 @@ def toggle_reselect(): #def set_breakpoint(): # send("__IP.InteractiveTB.pdb.set_break('%s',%d)" % (vim.current.buffer.name, # vim.current.window.cursor[0])) -# print("set breakpoint in %s:%d"% (vim.current.buffer.name, +# print("set breakpoint in %s:%d"% (vim.current.buffer.name, # vim.current.window.cursor[0])) -# +# #def clear_breakpoint(): # send("__IP.InteractiveTB.pdb.clear_break('%s',%d)" % (vim.current.buffer.name, # vim.current.window.cursor[0])) From e5b32a6d96a8563e787baa7854cf6e5c8251e5a1 Mon Sep 17 00:00:00 2001 From: Jonathan Helmus Date: Fri, 8 May 2015 13:44:55 -0500 Subject: [PATCH 2/6] Add support for printing error from IPython 3 --- ftplugin/python/vim_ipython.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ftplugin/python/vim_ipython.py b/ftplugin/python/vim_ipython.py index b13303c..63fae74 100644 --- a/ftplugin/python/vim_ipython.py +++ b/ftplugin/python/vim_ipython.py @@ -421,7 +421,7 @@ def update_subchannel_msgs(debug=False, force=False): dots = '.' * len(prompt.rstrip()) dots += prompt[len(prompt.rstrip()):] s += m['content']['code'].rstrip().replace('\n', '\n' + dots) - elif header == 'pyerr': + elif header == 'pyerr' or header == 'error': c = m['content'] s = "\n".join(map(strip_color_escapes,c['traceback'])) s += c['ename'] + ":" + c['evalue'] From f64d22dc223b79221f280f49e7477838e5ea8fc7 Mon Sep 17 00:00:00 2001 From: Jonathan Helmus Date: Fri, 8 May 2015 14:44:11 -0500 Subject: [PATCH 3/6] IPython 3 completion The cursor position must be specified in IPython 3 as the kernel does the lexing. --- ftplugin/python/vim_ipython.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ftplugin/python/vim_ipython.py b/ftplugin/python/vim_ipython.py index 63fae74..621fa7f 100644 --- a/ftplugin/python/vim_ipython.py +++ b/ftplugin/python/vim_ipython.py @@ -300,7 +300,7 @@ def get_doc_buffer(level=0): vim.command('setlocal syntax=python') def ipy_complete(base, current_line, pos): - msg_id = kc.shell_channel.complete(base, current_line, pos) + msg_id = kc.shell_channel.complete(base, current_line, len(current_line)) try: m = get_child_msg(msg_id) matches = m['content']['matches'] From 30566620e8d8479fc5137ae28bf1779cc170bf65 Mon Sep 17 00:00:00 2001 From: Jonathan Helmus Date: Fri, 8 May 2015 15:20:14 -0500 Subject: [PATCH 4/6] Support object? functionality with IPython 3 --- ftplugin/python/vim_ipython.py | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/ftplugin/python/vim_ipython.py b/ftplugin/python/vim_ipython.py index 621fa7f..466c64d 100644 --- a/ftplugin/python/vim_ipython.py +++ b/ftplugin/python/vim_ipython.py @@ -247,6 +247,16 @@ def get_doc_msg(msg_id): if not content['found']: return b + # IPython 3.0+ the documentation message is encoding by the kernel + if 'data' in content: + try: + text = content['data']['text/plain'] + for line in text.split('\n'): + b.append(strip_color_escapes(line).rstrip()) + return b + except KeyError: # no text/plain key + return b + for field in ['type_name','base_class','string_form','namespace', 'file','length','definition','source','docstring']: c = content.get(field,None) From 015aae970741385cbc4a8adc1a191ac12b3d0dc7 Mon Sep 17 00:00:00 2001 From: Jonathan Helmus Date: Fri, 8 May 2015 15:49:15 -0500 Subject: [PATCH 5/6] Updated README.rst --- README.rst | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.rst b/README.rst index f4c8f3a..0e0dccc 100644 --- a/README.rst +++ b/README.rst @@ -4,7 +4,7 @@ vim-ipython A two-way integration between Vim and IPython. -IPython versions 0.11.x, 0.12.x, 0.13.x, 1.x and 2.x +IPython versions 0.11.x, 0.12.x, 0.13.x, 1.x, 2.x and 3.x * author: Paul Ivanov (http://pirsquared.org) * github: http://github.com/ivanov/vim-ipython @@ -293,6 +293,7 @@ pull request with your attribution. * @memeplex for fixing the identifier grabbing on e.g. non-PEP8 compliant code * @pydave for IPythonTerminate (sending SIGTERM using our hack) * @luispedro for IPythonNew +* @jjhelmus for IPython 3.x support. Similar Projects ---------------- From 64a435cbeda8aa6e5d64a2ca43c5e3e383fc5bdf Mon Sep 17 00:00:00 2001 From: Jonathan Helmus Date: Fri, 8 May 2015 17:07:08 -0500 Subject: [PATCH 6/6] BUG: Non-end of line completions in IPython 3.x Fixed issue where completions that occur not at the end of line where incorrectly completing at the end of the line. --- ftplugin/python/vim_ipython.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/ftplugin/python/vim_ipython.py b/ftplugin/python/vim_ipython.py index 466c64d..075c1bf 100644 --- a/ftplugin/python/vim_ipython.py +++ b/ftplugin/python/vim_ipython.py @@ -310,7 +310,10 @@ def get_doc_buffer(level=0): vim.command('setlocal syntax=python') def ipy_complete(base, current_line, pos): - msg_id = kc.shell_channel.complete(base, current_line, len(current_line)) + # pos is the location of the start of base, add the length + # to get the completion position + msg_id = kc.shell_channel.complete(base, current_line, + int(pos) + len(base) - 1) try: m = get_child_msg(msg_id) matches = m['content']['matches']