From 44d102dded9ff59249a5adb4bd6e0a801f93c83f Mon Sep 17 00:00:00 2001 From: Jacob Date: Sat, 16 Mar 2013 00:02:02 +0000 Subject: [PATCH 1/4] Adds command for jumping to location of last error. --- ftplugin/python/ipy.vim | 23 +++++++++++++++++++++++ plugin/ipy.vim | 12 ++++++++++++ 2 files changed, 35 insertions(+) create mode 100644 plugin/ipy.vim diff --git a/ftplugin/python/ipy.vim b/ftplugin/python/ipy.vim index a0c689b..e8975b8 100644 --- a/ftplugin/python/ipy.vim +++ b/ftplugin/python/ipy.vim @@ -369,6 +369,13 @@ 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 get_pyout_msg(msg_id): + while True: + m = km.sub_channel.get_msg(timeout=1) + if m['msg_type'] == 'pyout' and m['parent_header']['msg_id'] == msg_id: + break + return m def print_prompt(prompt,msg_id=None): """Print In[] or In[42] style messages""" @@ -384,6 +391,14 @@ def print_prompt(prompt,msg_id=None): else: echo("In[]: %s" % prompt) +def read_output(msg_id): + try: + child = get_pyout_msg(msg_id) + data = child['content']['data']['text/plain'] + return data + except Empty: + return None + def with_subchannel(f,*args): "conditionally monitor subchannel" def f_with_update(*args): @@ -410,6 +425,11 @@ def run_command(cmd): msg_id = send(cmd) print_prompt(cmd, msg_id) +def run_command_and_read(cmd): + msg_id = send(cmd) + data = read_output(msg_id) + return data + @with_subchannel def run_these_lines(): r = vim.current.range @@ -572,6 +592,9 @@ if g:ipy_perform_mappings != 0 map d :py get_doc_buffer() map s :py if update_subchannel_msgs(force=True): echo("vim-ipython shell updated",'Operator') map :python toggle_reselect() + + nmap e :call IPythonTraceback() + "map :python send('%pdb') "map :python set_breakpoint() "map :python clear_breakpoint() diff --git a/plugin/ipy.vim b/plugin/ipy.vim new file mode 100644 index 0000000..2653e83 --- /dev/null +++ b/plugin/ipy.vim @@ -0,0 +1,12 @@ +function! IPythonTraceback() +python << EOF +command = """ +import sys +import traceback +path, line = traceback.extract_tb(sys.last_traceback)[-1][0:2] +'edit +%d %s' % (line, path) +""" +reply = get_output(command) +vim.command(reply[1:-1]) +EOF +endfunction From 941e0962e1f10b70afcbb2c0fa9e5b378eed5537 Mon Sep 17 00:00:00 2001 From: Jacob Date: Sat, 16 Mar 2013 00:13:42 +0000 Subject: [PATCH 2/4] fixes bad function name --- plugin/ipy.vim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugin/ipy.vim b/plugin/ipy.vim index 2653e83..969caba 100644 --- a/plugin/ipy.vim +++ b/plugin/ipy.vim @@ -6,7 +6,7 @@ import traceback path, line = traceback.extract_tb(sys.last_traceback)[-1][0:2] 'edit +%d %s' % (line, path) """ -reply = get_output(command) +reply = run_command_and_read(command) vim.command(reply[1:-1]) EOF endfunction From ef88cc05a478b90a086a3f098cf7c2fe15c616d5 Mon Sep 17 00:00:00 2001 From: Benjamin van der Burgh Date: Fri, 4 Mar 2016 16:32:45 +0100 Subject: [PATCH 3/4] Utilize Jupyter for instantiating a kernel connection in IPython >= 4 --- ftplugin/python/vim_ipython.py | 43 +++++++++++++++++++++++----------- 1 file changed, 29 insertions(+), 14 deletions(-) diff --git a/ftplugin/python/vim_ipython.py b/ftplugin/python/vim_ipython.py index 0a4ed08..1308efd 100644 --- a/ftplugin/python/vim_ipython.py +++ b/ftplugin/python/vim_ipython.py @@ -93,7 +93,10 @@ def new_ipy(s=''): new_ipy() """ - from IPython.kernel import KernelManager + try: + from jupyter_client.manager import KernelManager + except ImportError: + from IPython.kernel import KernelManager km = KernelManager() km.start_kernel() return km_from_string(km.connection_file) @@ -107,21 +110,28 @@ def km_from_string(s=''): import IPython except ImportError: raise ImportError("Could not find IPython. " + _install_instructions) - from IPython.config.loader import KeyValueConfigLoader try: - from IPython.kernel import ( - KernelManager, - find_connection_file, - ) + from traitlets.config.loader import KeyValueConfigLoader + except ImportError: + from IPython.config.loader import KeyValueConfigLoader + try: + from jupyter_client.manager import KernelManager + from jupyter_client.connect import find_connection_file except ImportError: - # IPython < 1.0 - from IPython.zmq.blockingkernelmanager import BlockingKernelManager as KernelManager - from IPython.zmq.kernelapp import kernel_aliases try: - from IPython.lib.kernel import find_connection_file + from IPython.kernel import ( + KernelManager, + find_connection_file, + ) except ImportError: - # < 0.12, no find_connection_file - pass + # IPython < 1.0 + from IPython.zmq.blockingkernelmanager import BlockingKernelManager as KernelManager + from IPython.zmq.kernelapp import kernel_aliases + try: + from IPython.lib.kernel import find_connection_file + except ImportError: + # < 0.12, no find_connection_file + pass global km, kc, send @@ -147,8 +157,13 @@ def km_from_string(s=''): echo(":IPython " + s + " failed", "Info") echo("^-- failed '" + s + "' not found", "Error") return - km = KernelManager(connection_file = fullpath) - km.load_connection_file() + if IPython.version_info[0] >= 4: + km = KernelManager() + km.connection_file = find_connection_file() + km.load_connection_file() + else: + km = KernelManager(connection_file = fullpath) + km.load_connection_file() else: if s == '': echo(":IPython 0.11 requires the full connection string") From 359083728a73f1b8143f6b0f6c1ba2cd1b9eb7c8 Mon Sep 17 00:00:00 2001 From: Benjamin van der Burgh Date: Mon, 5 Feb 2018 12:26:21 +0100 Subject: [PATCH 4/4] Revert "Add support for debugging" This reverts commit 6887b2561c92092a6e6ee3ed68345416a7e8de18, reversing changes made to ef88cc05a478b90a086a3f098cf7c2fe15c616d5. --- ftplugin/python/ipy.vim | 511 ---------------------------------------- plugin/ipy.vim | 12 - 2 files changed, 523 deletions(-) delete mode 100644 plugin/ipy.vim diff --git a/ftplugin/python/ipy.vim b/ftplugin/python/ipy.vim index 98ad361..8c7011b 100644 --- a/ftplugin/python/ipy.vim +++ b/ftplugin/python/ipy.vim @@ -48,499 +48,6 @@ vim_ipython_path = vim.eval("expand(':h')") sys.path.append(vim_ipython_path) from vim_ipython import * -# get around unicode problems when interfacing with vim -vim_encoding=vim.eval('&encoding') or 'utf-8' - -try: - sys.stdout.flush -except AttributeError: - # IPython complains if stderr and stdout don't have flush - # this is fixed in newer version of Vim - class WithFlush(object): - def __init__(self,noflush): - self.write=noflush.write - self.writelines=noflush.writelines - def flush(self):pass - sys.stdout = WithFlush(sys.stdout) - sys.stderr = WithFlush(sys.stderr) - - - -ip = '127.0.0.1' -try: - km -except NameError: - km = None -try: - pid -except NameError: - pid = None - -def km_from_string(s=''): - """create kernel manager from IPKernelApp string - such as '--shell=47378 --iopub=39859 --stdin=36778 --hb=52668' for IPython 0.11 - or just 'kernel-12345.json' for IPython 0.12 - """ - from os.path import join as pjoin - from IPython.zmq.blockingkernelmanager import BlockingKernelManager, Empty - from IPython.config.loader import KeyValueConfigLoader - from IPython.zmq.kernelapp import kernel_aliases - global km,send,Empty - - s = s.replace('--existing', '') - if 'connection_file' in BlockingKernelManager.class_trait_names(): - from IPython.lib.kernel import find_connection_file - # 0.12 uses files instead of a collection of ports - # include default IPython search path - # filefind also allows for absolute paths, in which case the search - # is ignored - try: - # XXX: the following approach will be brittle, depending on what - # connection strings will end up looking like in the future, and - # whether or not they are allowed to have spaces. I'll have to sync - # up with the IPython team to address these issues -pi - if '--profile' in s: - k,p = s.split('--profile') - k = k.lstrip().rstrip() # kernel part of the string - p = p.lstrip().rstrip() # profile part of the string - fullpath = find_connection_file(k,p) - else: - fullpath = find_connection_file(s.lstrip().rstrip()) - except IOError,e: - echo(":IPython " + s + " failed", "Info") - echo("^-- failed '" + s + "' not found", "Error") - return - km = BlockingKernelManager(connection_file = fullpath) - km.load_connection_file() - else: - if s == '': - echo(":IPython 0.11 requires the full connection string") - return - loader = KeyValueConfigLoader(s.split(), aliases=kernel_aliases) - cfg = loader.load_config()['KernelApp'] - try: - km = BlockingKernelManager( - shell_address=(ip, cfg['shell_port']), - sub_address=(ip, cfg['iopub_port']), - stdin_address=(ip, cfg['stdin_port']), - hb_address=(ip, cfg['hb_port'])) - except KeyError,e: - echo(":IPython " +s + " failed", "Info") - echo("^-- failed --"+e.message.replace('_port','')+" not specified", "Error") - return - km.start_channels() - send = km.shell_channel.execute - - # now that we're connect to an ipython kernel, activate completion - # machinery, but do so only for the local buffer if the user added the - # following line the vimrc: - # let g:ipy_completefunc = 'local' - vim.command(""" - if g:ipy_completefunc == 'global' - set completefunc=CompleteIPython - elseif g:ipy_completefunc == 'local' - setl completefunc=CompleteIPython - endif - """) - # also activate GUI doc balloons if in gvim - vim.command(""" - if has('balloon_eval') - set bexpr=IPythonBalloonExpr() - set ballooneval - endif - """) - set_pid() - return km - -def echo(arg,style="Question"): - try: - vim.command("echohl %s" % style) - vim.command("echom \"%s\"" % arg.replace('\"','\\\"')) - vim.command("echohl None") - except vim.error: - print "-- %s" % arg - -def disconnect(): - "disconnect kernel manager" - # XXX: make a prompt here if this km owns the kernel - pass - -def get_doc(word): - if km is None: - return ["Not connected to IPython, cannot query: %s" % word] - msg_id = km.shell_channel.object_info(word) - doc = get_doc_msg(msg_id) - # get around unicode problems when interfacing with vim - return [d.encode(vim_encoding) for d in doc] - -import re -# from http://serverfault.com/questions/71285/in-centos-4-4-how-can-i-strip-escape-sequences-from-a-text-file -strip = re.compile('\x1B\[([0-9]{1,2}(;[0-9]{1,2})?)?[m|K]') -def strip_color_escapes(s): - return strip.sub('',s) - -def get_doc_msg(msg_id): - n = 13 # longest field name (empirically) - b=[] - try: - content = get_child_msg(msg_id)['content'] - except Empty: - # timeout occurred - return ["no reply from IPython kernel"] - - if not content['found']: - return b - - for field in ['type_name','base_class','string_form','namespace', - 'file','length','definition','source','docstring']: - c = content.get(field,None) - if c: - if field in ['definition']: - c = strip_color_escapes(c).rstrip() - s = field.replace('_',' ').title()+':' - s = s.ljust(n) - if c.find('\n')==-1: - b.append(s+c) - else: - b.append(s) - b.extend(c.splitlines()) - return b - -def get_doc_buffer(level=0): - # empty string in case vim.eval return None - word = vim.eval('expand("")') or '' - doc = get_doc(word) - if len(doc) ==0: - echo(repr(word)+" not found","Error") - return - # documentation buffer name is same as the query made to ipython - vim.command('new '+word) - vim.command('setlocal modifiable noro') - # doc window quick quit keys: 'q' and 'escape' - vim.command('map q :q') - # Known issue: to enable the use of arrow keys inside the terminal when - # viewing the documentation, comment out the next line - vim.command('map :q') - # and uncomment this line (which will work if you have a timoutlen set) - #vim.command('map :q') - b = vim.current.buffer - b[:] = None - b[:] = doc - vim.command('setlocal nomodified bufhidden=wipe') - #vim.command('setlocal previewwindow nomodifiable nomodified ro') - #vim.command('set previewheight=%d'%len(b))# go to previous window - vim.command('resize %d'%len(b)) - #vim.command('pcl') - #vim.command('pedit doc') - #vim.command('normal ') # go to previous window - # use the ReST formatting that ships with stock vim - vim.command('setlocal syntax=rst') - -def vim_ipython_is_open(): - """ - Helper function to let us know if the vim-ipython shell is currently - visible - """ - for w in vim.windows: - if w.buffer.name is not None and w.buffer.name.endswith("vim-ipython"): - return True - return False - -def update_subchannel_msgs(debug=False, force=False): - """ - Grab any pending messages and place them inside the vim-ipython shell. - This function will do nothing if the vim-ipython shell is not visible, - unless force=True argument is passed. - """ - if km is None or (not vim_ipython_is_open() and not force): - return False - msgs = km.sub_channel.get_msgs() - if debug: - #try: - # vim.command("b debug_msgs") - #except vim.error: - # vim.command("new debug_msgs") - #finally: - db = vim.current.buffer - else: - db = [] - b = vim.current.buffer - startedin_vimipython = vim.eval('@%')=='vim-ipython' - if not startedin_vimipython: - # switch to preview window - vim.command( - "try" - "|silent! wincmd P" - "|catch /^Vim\%((\a\+)\)\=:E441/" - "|silent pedit +set\ ma vim-ipython" - "|silent! wincmd P" - "|endtry") - # if the current window is called 'vim-ipython' - if vim.eval('@%')=='vim-ipython': - # set the preview window height to the current height - vim.command("set pvh=" + vim.eval('winheight(0)')) - else: - # close preview window, it was something other than 'vim-ipython' - vim.command("pcl") - vim.command("silent pedit +set\ ma vim-ipython") - vim.command("wincmd P") #switch to preview window - # subchannel window quick quit key 'q' - vim.command('map q :q') - vim.command("set bufhidden=hide buftype=nofile ft=python") - # make shift-enter and control-enter in insert mode behave same as in ipython notebook - # shift-enter send the current line, control-enter send the line - # but keeps it around for further editing. - vim.command("imap dd:python run_command('''\"''')i") - # pkddA: paste, go up one line which is blank after run_command, - # delete it, and then back to insert mode - vim.command("imap dd:python run_command('''\"''')pkddA") - # ctrl-C gets sent to the IPython process as a signal on POSIX - vim.command("map  :IPythonInterrupt") - - #syntax highlighting for python prompt - # QtConsole In[] is blue, but I prefer the oldschool green - # since it makes the vim-ipython 'shell' look like the holidays! - #vim.command("hi Blue ctermfg=Blue guifg=Blue") - vim.command("hi Green ctermfg=Green guifg=Green") - vim.command("hi Red ctermfg=Red guifg=Red") - vim.command("syn keyword Green 'In\ []:'") - vim.command("syn match Green /^In \[[0-9]*\]\:/") - vim.command("syn match Red /^Out\[[0-9]*\]\:/") - b = vim.current.buffer - update_occured = False - for m in msgs: - #db.append(str(m).splitlines()) - s = '' - if 'msg_type' not in m['header']: - # debug information - #echo('skipping a message on sub_channel','WarningMsg') - #echo(str(m)) - continue - elif m['header']['msg_type'] == 'status': - continue - elif m['header']['msg_type'] == 'stream': - s = strip_color_escapes(m['content']['data']) - elif m['header']['msg_type'] == 'pyout': - s = "Out[%d]: " % m['content']['execution_count'] - s += m['content']['data']['text/plain'] - elif m['header']['msg_type'] == 'pyin': - # 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 - # once that happens - if 'execution_count' in m['content']: - s = "\nIn [%d]: "% m['content']['execution_count'] - else: - s = "\nIn [00]: " - s += m['content']['code'].strip() - elif m['header']['msg_type'] == 'pyerr': - c = m['content'] - s = "\n".join(map(strip_color_escapes,c['traceback'])) - s += c['ename'] + ":" + c['evalue'] - if s.find('\n') == -1: - # 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) - b.append(s) - else: - try: - b.append(s.splitlines()) - except: - b.append([l.encode(vim_encoding) for l in s.splitlines()]) - update_occured = True - # make a newline so we can just start typing there - if b[-1] != '': - b.append(['']) - vim.command('normal G') # go to the end of the file - 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: - # get_msg will raise with Empty exception if no messages arrive in 1 second - m= km.shell_channel.get_msg(timeout=1) - if m['parent_header']['msg_id'] == msg_id: - break - else: - #got a message, but not the one we were looking for - echo('skipping a message on shell_channel','WarningMsg') - return m - -def get_pyout_msg(msg_id): - while True: - m = km.sub_channel.get_msg(timeout=1) - if m['msg_type'] == 'pyout' and m['parent_header']['msg_id'] == msg_id: - break - return m - -def print_prompt(prompt,msg_id=None): - """Print In[] or In[42] style messages""" - global show_execution_count - if show_execution_count and msg_id: - # wait to get message back from kernel - try: - child = get_child_msg(msg_id) - count = child['content']['execution_count'] - echo("In[%d]: %s" %(count,prompt)) - except Empty: - echo("In[]: %s (no reply from IPython kernel)" % prompt) - else: - echo("In[]: %s" % prompt) - -def read_output(msg_id): - try: - child = get_pyout_msg(msg_id) - data = child['content']['data']['text/plain'] - return data - except Empty: - return None - -def with_subchannel(f,*args): - "conditionally monitor subchannel" - def f_with_update(*args): - try: - f(*args) - if monitor_subchannel: - update_subchannel_msgs() - except AttributeError: #if km is None - echo("not connected to IPython", 'Error') - return f_with_update - -@with_subchannel -def run_this_file(): - msg_id = send('run %s %s' % (run_flags, repr(vim.current.buffer.name),)) - print_prompt("In[]: run %s %s" % (run_flags, repr(vim.current.buffer.name)),msg_id) - -@with_subchannel -def run_this_line(): - msg_id = send(vim.current.line) - print_prompt(vim.current.line, msg_id) - -@with_subchannel -def run_command(cmd): - msg_id = send(cmd) - print_prompt(cmd, msg_id) - -def run_command_and_read(cmd): - msg_id = send(cmd) - data = read_output(msg_id) - return data - -@with_subchannel -def run_these_lines(): - r = vim.current.range - lines = "\n".join(vim.current.buffer[r.start:r.end+1]) - msg_id = send(lines) - #alternative way of doing this in more recent versions of ipython - #but %paste only works on the local machine - #vim.command("\"*yy") - #send("'%paste')") - #reselect the previously highlighted block - vim.command("normal gv") - if not reselect: - vim.command("normal ") - - #vim lines start with 1 - #print "lines %d-%d sent to ipython"% (r.start+1,r.end+1) - prompt = "lines %d-%d "% (r.start+1,r.end+1) - print_prompt(prompt,msg_id) - - -def set_pid(): - """ - Explicitly ask the ipython kernel for its pid - """ - global km, 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) - except Empty: - echo("no reply from IPython kernel") - return - - pid = int(child['content']['user_variables']['_pid']) - return pid - - -def interrupt_kernel_hack(): - """ - Sends the interrupt signal to the remote kernel. This side steps the - (non-functional) ipython interrupt mechanisms. - Only works on posix. - """ - global pid - import signal - import os - if pid is None: - # Avoid errors if we couldn't get pid originally, - # by trying to obtain it now - pid = set_pid() - - if pid is None: - echo("cannot get kernel PID, Ctrl-C will not be supported") - return - echo("KeyboardInterrupt (sent to ipython: pid " + - "%i with signal %i)" % (pid, signal.SIGINT),"Operator") - try: - os.kill(pid, signal.SIGINT) - except OSError: - echo("unable to kill pid %d" % pid) - pid = None - -def dedent_run_this_line(): - vim.command("left") - run_this_line() - vim.command("silent undo") - -def dedent_run_these_lines(): - r = vim.current.range - shiftwidth = vim.eval('&shiftwidth') - count = int(vim.eval('indent(%d+1)/%s' % (r.start,shiftwidth))) - if count > 0: - vim.command("'<,'>" + "<"*count) - run_these_lines() - if count > 0: - vim.command("silent undo") - -#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("\'","\\\'")) -# #print "line \'%s\' set at ipython prompt"% vim.current.line -# echo("line \'%s\' set at ipython prompt"% vim.current.line,'Statement') - - -def toggle_reselect(): - global reselect - reselect=not reselect - print "F9 will%sreselect lines after sending to ipython"% (reselect and " " or " not ") - -#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, -# 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])) -# print "clearing breakpoint in %s:%d" % (vim.current.buffer.name, -# vim.current.window.cursor[0]) -# -#def clear_all_breakpoints(): -# send("__IP.InteractiveTB.pdb.clear_all_breaks()"); -# print "clearing all breakpoints" -# -#def run_this_file_pdb(): -# send(' __IP.InteractiveTB.pdb.run(\'execfile("%s")\')' % (vim.current.buffer.name,)) -# #send('run -d %s' % (vim.current.buffer.name,)) -# echo("In[]: run -d %s (using pdb)" % vim.current.buffer.name) - EOF fun! toggle_send_on_save() @@ -618,24 +125,6 @@ if g:ipy_perform_mappings != 0 imap (IPython-RunLines) imap (IPython-RunFile) map (IPython-ToggleSendOnSave) - map :python run_this_file() - map :python run_this_line() - map :python run_these_lines() - map d :py get_doc_buffer() - map s :py if update_subchannel_msgs(force=True): echo("vim-ipython shell updated",'Operator') - map :python toggle_reselect() - - nmap e :call IPythonTraceback() - - "map :python send('%pdb') - "map :python set_breakpoint() - "map :python clear_breakpoint() - "map :python run_this_file_pdb() - "map :python clear_all_breaks() - imap - imap - imap - map :call toggle_send_on_save() "" Example of how to quickly clear the current plot with a keystroke "map (IPython-PlotClearCurrent) "" Example of how to quickly close all figures with a keystroke diff --git a/plugin/ipy.vim b/plugin/ipy.vim deleted file mode 100644 index 969caba..0000000 --- a/plugin/ipy.vim +++ /dev/null @@ -1,12 +0,0 @@ -function! IPythonTraceback() -python << EOF -command = """ -import sys -import traceback -path, line = traceback.extract_tb(sys.last_traceback)[-1][0:2] -'edit +%d %s' % (line, path) -""" -reply = run_command_and_read(command) -vim.command(reply[1:-1]) -EOF -endfunction