Skip to content
This repository

updated vim-ipython (pending) #1120

Closed
wants to merge 1 commit into from

2 participants

Paul Ivanov Fernando Perez
Paul Ivanov
Collaborator

Just wanted to place this in the queue to make sure that an updated version goes into 0.12

I wanted to add this but not have it merged until 0.12 RCs are being cut, but in case I don't get to it again, this version is a big improvement over what ships with ipython currently.

Fernando Perez
Owner

Does this need any further updates, or should we just merge it as-is? I think we're about ready to cut the first RC in a day or two.

Fernando Perez
Owner

@ivanov: last call... Do you want us to wait on this one for further updates, or should we go ahead and merge? I'd like to get to the RC pretty soon...

Paul Ivanov
Collaborator

sorry, I've been a bit occupied - please merge as is

Fernando Perez
Owner

Was it you taking the pic or holding the sign?

Paul Ivanov ivanov closed this pull request from a commit December 07, 2011
Paul Ivanov updated vim-ipython
Various small updates to vim integration.

Closes #1120, rebased to avoid unnecessary recursive merge.
633cbe1
Paul Ivanov ivanov closed this in 633cbe1 December 13, 2011
Fernando Perez
Owner

OK, merged and pushed. Thanks!

Paul Ivanov
Collaborator

It was me holding the sign - I know it's not PEP-8 compliant - I'll pylint and pyflakes and otherwise PEP8-proof my future political activity.

Fernando Perez
Owner

Otherwise we won't commit! :)

Fernando Perez fperez referenced this pull request from a commit January 10, 2012
Commit has since been removed from the repository and is no longer available.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Showing 1 unique commit by 1 author.

Dec 07, 2011
Paul Ivanov updated vim-ipython
ivanov/vim-ipython 3b62ca3
2ffa8c9
This page is out of date. Refresh to see the latest.
142  docs/examples/vim/README.rst
Source Rendered
@@ -4,11 +4,10 @@ vim-ipython
4 4
 
5 5
 A two-way integration between Vim and IPython 0.11+
6 6
 
7  
-author: Paul Ivanov (http://pirsquared.org)
8  
-
9  
-github: http://github.com/ivanov/vim-ipython
10  
-
11  
-demo: http://pirsquared.org/vim-ipython/
  7
+* author: Paul Ivanov (http://pirsquared.org)
  8
+* github: http://github.com/ivanov/vim-ipython
  9
+* demos: http://pirsquared.org/vim-ipython/
  10
+* blogpost: http://pirsquared.org/blog/2011/07/28/vim-ipython/
12 11
 
13 12
 Using this plugin, you can send lines or whole files for IPython to
14 13
 execute, and also get back object introspection and word completions in
@@ -16,30 +15,46 @@ Vim, like what you get with: ``object?<enter>`` and ``object.<tab>`` in
16 15
 IPython.
17 16
 
18 17
 The big change from previous versions of ``ipy.vim`` is that it no longer
19  
-requires the brittle ipy_vimserver.py instantiation, and since it uses
20  
-just vim and python, it is platform independent (i.e. should work even
21  
-on windows, unlike the previous \*nix only solution)
  18
+requires the old brittle ``ipy_vimserver.py`` instantiation, and since
  19
+it uses just vim and python, it is platform independent (i.e. should work
  20
+even on windows, unlike the previous \*nix only solution). The requirements
  21
+are IPython 0.11+ with zeromq capabilities, vim compiled with +python.
22 22
 
  23
+If you can launch ``ipython qtconsole`` or ``ipython kernel``, and
  24
+``:echo has('python')`` returns 1 in vim, you should be good to go.
23 25
 
24 26
 -----------------
25 27
 Quickstart Guide:
26 28
 -----------------
27  
-Start ``ipython qtconsole`` and copy the connection string.
  29
+Start ``ipython qtconsole`` [*]_ and copy the connection string.
28 30
 Source ``ipy.vim`` file, which provides new IPython command::
29 31
 
30  
-  :source ipy.vim  
  32
+  :source ipy.vim
31 33
   (or copy it to ~/.vim/ftplugin/python to load automatically)
32 34
 
33  
-  :IPythonClipboard   
  35
+  :IPythonClipboard
34 36
   (or :IPythonXSelection if you're using X11 without having to copy)
35 37
 
36  
-The :IPython command allows you to put the full string, e.g.::
  38
+The :IPython command allows you to put the full connection string. For IPython
  39
+0.11, it would look like this::
37 40
 
38 41
   :IPython --existing --shell=41882 --iopub=43286 --stdin=34987 --hb=36697
39 42
 
  43
+and for IPython 0.12, like this::
  44
+
  45
+  :IPython --existing kernel-85997.json
  46
+
40 47
 The ``:IPythonClipboard`` command just uses the ``+`` register to get the
41 48
 connection string, whereas ``:IPythonXSelection`` uses the ``*`` register
42 49
 
  50
+.. [*] Though the demos above use ``qtconsole``, it is not required
  51
+    for this workflow, it's just that it was the easiest way to show how to
  52
+    make use of the new functionality in 0.11 release. In the current git
  53
+    trunk of IPython, you can use ``ipython kernel`` to create a kernel and
  54
+    get the connection string to use for any frontend (including vim-ipython).
  55
+    If you are still using 0.11, you can launch a regular kernel using
  56
+    ``python -c "from IPython.zmq.ipkernel import main; main()"``
  57
+
43 58
 ------------------------
44 59
 Sending lines to IPython
45 60
 ------------------------
@@ -50,10 +65,12 @@ Now type out a line and send it to IPython using ``<Ctrl-S>`` from Command mode:
50 65
 You should see a notification message confirming the line was sent, along
51 66
 with the input number for the line, like so ``In[1]: import os``.
52 67
 
53  
-``<Ctrl-S>`` also works from insert mode, but doesn't show notification
  68
+``<Ctrl-S>`` also works from insert mode, but doesn't show notification,
  69
+unless ``monitor_subchannel`` is set to ``True`` (see `vim-ipython 'shell'`_,
  70
+below)
54 71
 
55  
-It also works blockwise in Visual Mode. Strip the leading double quotes and
56  
-send these lines using ``<Ctrl-S>``::
  72
+It also works blockwise in Visual Mode. Select and send these lines using
  73
+``<Ctrl-S>``::
57 74
 
58 75
   import this,math # secret decoder ring
59 76
   a,b,c,d,e,f,g,h,i = range(1,10)
@@ -65,7 +82,7 @@ send these lines using ``<Ctrl-S>``::
65 82
   '%d'*len(code)%code == str(int(math.pi*1e5))
66 83
 
67 84
 Then, go to the qtconsole and run this line::
68  
-  
  85
+
69 86
   print secret_decoder(_i,_)
70 87
 
71 88
 You can also send whole files to IPython's ``%run`` magic using ``<F5>``.
@@ -86,22 +103,87 @@ IPython's tab-completion Functionality
86 103
 vim-ipython activates a 'completefunc' that queries IPython.
87 104
 A completefunc is activated using ``Ctrl-X Ctrl-U`` in Insert Mode (vim
88 105
 default). You can combine this functionality with SuperTab to get tab
89  
-completion 
  106
+completion.
90 107
 
91  
----------------
92  
-Current issues:
93  
----------------
94  
-For now, vim-ipython only connects to an ipython session in progress.
  108
+-------------------
  109
+vim-ipython 'shell'
  110
+-------------------
  111
+**NEW since IPython 0.11**!
  112
+
  113
+By monitoring km.sub_channel, we can recreate what messages were sent to
  114
+IPython, and what IPython sends back in response.
  115
+
  116
+``monitor_subchannel`` is a parameter that sets whether this 'shell' should
  117
+updated on every sent command (default: True).
  118
+
  119
+If at any later time you wish to bring this shell up, including if you've set
  120
+``monitor_subchannel=False``, hit ``<leader>s``.
95 121
 
96  
-ipy.vim takes a while to load, I'll eventually move the python code to its
97  
-own file and do a lazy import (only when the IPython command is called)
  122
+-------
  123
+Options
  124
+-------
  125
+You can change these at the top of the ipy.vim::
98 126
 
99  
-The ipdb integration is not yet re-implemented.
  127
+  reselect = False            # reselect lines after sending from Visual mode
  128
+  show_execution_count = True # wait to get numbers for In[43]: feedback?
  129
+  monitor_subchannel = True   # update vim-ipython 'shell' on every send?
  130
+  run_flags= "-i"             # flags to for IPython's run magic when using <F5>
100 131
 
101  
-Need to add more message handling for sub_channel messages from IPython
102  
-(i.e. notification of changes which were not sent from vim).
  132
+**Disabling default mappings**
  133
+In your own ``.vimrc``, if you don't like the mappings provided by default,
  134
+you can define a variable ``let g:ipy_perform_mappings=0`` which will prevent
  135
+vim-ipython from defining any of the default mappings.
103 136
 
104  
-------
105  
-Thanks
106  
-------
107  
-@MinRK for guiding me through the IPython kernel manager protocol.
  137
+---------------
  138
+Current issues:
  139
+---------------
  140
+- For now, vim-ipython only connects to an ipython session in progress.
  141
+- The ipdb integration is not yet re-implemented.
  142
+- If you're running inside ``screen``, read about the ``<CTRL-S>`` issue `here
  143
+  <http://munkymorgy.blogspot.com/2008/07/screen-ctrl-s-bug.html>`_, and add
  144
+  this line to your ``.bashrc`` to fix it::
  145
+
  146
+    stty stop undef # to unmap ctrl-s
  147
+
  148
+- In vim, if you're getting ``ImportError: No module named
  149
+  IPython.zmq.blockingkernelmanager`` but are able to import it in regular
  150
+  python, **either**
  151
+
  152
+  1. your ``sys.path`` in vim differs from the ``sys.path`` in regular python.
  153
+     Try running these two lines, and comparing their output files::
  154
+
  155
+      $ vim -c 'py import vim, sys; vim.current.buffer.append(sys.path)' -c ':wq vim_syspath'
  156
+      $ python -c "import sys; f=file('python_syspath','w'); f.write('\n'.join(sys.path)); f.close()"
  157
+
  158
+  **or**
  159
+
  160
+  2. your vim is compiled against a different python than you are launching. See
  161
+     if there's a difference between ::
  162
+
  163
+      $ vim -c ':py import os; print os.__file__' -c ':q'
  164
+      $ python -c ':py import os; print os.__file__'
  165
+
  166
+- For vim inside a terminal, using the arrow keys won't work inside a
  167
+  documentation buffer, because the mapping for ``<Esc>`` overlaps with
  168
+  ``^[OA`` and so on, and we use ``<Esc>`` as a quick way of closing the
  169
+  documentation preview window. If you want go without this quick close
  170
+  functionality and want to use the arrow keys instead, look for instructions
  171
+  starting with "Known issue: to enable the use of arrow keys..." in the
  172
+  ``get_doc_buffer`` function.
  173
+
  174
+- @fholgado's update to ``minibufexpl.vim`` that is up on GitHub will always
  175
+  put the cursor in the minibuf after sending a command when
  176
+  ``monitor_subchannel`` is set. This is a bug in minibufexpl.vim and the workaround
  177
+  is described in vim-ipython issue #7.
  178
+
  179
+----------------------------
  180
+Thanks and Bug Participation
  181
+----------------------------
  182
+* @MinRK for guiding me through the IPython kernel manager protocol.
  183
+* @nakamuray and @tcheneau for reporting and providing a fix for when vim is compiled without a gui (#1)
  184
+* @unpingco for reporting Windows bugs (#3,#4)
  185
+* @simon-b for terminal vim arrow key issue (#5)
  186
+* @jorgesca and @kwgoodman for shell (#6)
  187
+* @zeekay for easily allowing custom mappings (#9)
  188
+* @minrk for support of connection_file-based IPython connection (#13)
  189
+* @jorgesca for reporting the lack of profile handling capability (#14)
408  docs/examples/vim/ipy.vim
@@ -17,10 +17,17 @@
17 17
 "
18 18
 " written by Paul Ivanov (http://pirsquared.org)
19 19
 python << EOF
20  
-import time
  20
+reselect = False            # reselect lines after sending from Visual mode
  21
+show_execution_count = True # wait to get numbers for In[43]: feedback?
  22
+monitor_subchannel = True   # update vim-ipython 'shell' on every send?
  23
+run_flags= "-i"             # flags to for IPython's run magic when using <F5>
  24
+
21 25
 import vim
22 26
 import sys
23 27
 
  28
+# get around unicode problems when interfacing with vim
  29
+vim_encoding=vim.eval('&encoding') or 'utf-8'
  30
+
24 31
 try:
25 32
     sys.stdout.flush
26 33
 except AttributeError:
@@ -34,10 +41,6 @@ except AttributeError:
34 41
     sys.stdout = WithFlush(sys.stdout)
35 42
     sys.stderr = WithFlush(sys.stderr)
36 43
 
37  
-from IPython.zmq.blockingkernelmanager import BlockingKernelManager
38  
-
39  
-from IPython.config.loader import KeyValueConfigLoader
40  
-from IPython.zmq.kernelapp import kernel_aliases
41 44
 
42 45
 
43 46
 ip = '127.0.0.1'
@@ -46,34 +49,62 @@ try:
46 49
 except NameError:
47 50
     km = None
48 51
 
49  
-def km_from_string(s):
  52
+def km_from_string(s=''):
50 53
     """create kernel manager from IPKernelApp string
51  
-    such as '--shell=47378 --iopub=39859 --stdin=36778 --hb=52668'
  54
+    such as '--shell=47378 --iopub=39859 --stdin=36778 --hb=52668' for IPython 0.11
  55
+    or just 'kernel-12345.json' for IPython 0.12
52 56
     """
53  
-    global km,send
54  
-    # vim interface currently only deals with existing kernels
55  
-    s = s.replace('--existing','')
56  
-    loader = KeyValueConfigLoader(s.split(), aliases=kernel_aliases)
57  
-    cfg = loader.load_config()['KernelApp']
58  
-    try:
59  
-        km = BlockingKernelManager(
60  
-            shell_address=(ip, cfg['shell_port']),
61  
-            sub_address=(ip, cfg['iopub_port']),
62  
-            stdin_address=(ip, cfg['stdin_port']),
63  
-            hb_address=(ip, cfg['hb_port']))
64  
-    except KeyError,e:
65  
-        echo(":IPython " +s + " failed", "Info")
66  
-        echo("^-- failed --"+e.message.replace('_port','')+" not specified", "Error")
67  
-        return
  57
+    from os.path import join as pjoin
  58
+    from IPython.zmq.blockingkernelmanager import BlockingKernelManager, Empty
  59
+    from IPython.config.loader import KeyValueConfigLoader
  60
+    from IPython.zmq.kernelapp import kernel_aliases
  61
+    global km,send,Empty
  62
+
  63
+    s = s.replace('--existing', '')
  64
+    if 'connection_file' in BlockingKernelManager.class_trait_names():
  65
+        from IPython.lib.kernel import find_connection_file
  66
+        # 0.12 uses files instead of a collection of ports
  67
+        # include default IPython search path
  68
+        # filefind also allows for absolute paths, in which case the search
  69
+        # is ignored
  70
+        try:
  71
+            # XXX: the following approach will be brittle, depending on what
  72
+            # connection strings will end up looking like in the future, and
  73
+            # whether or not they are allowed to have spaces. I'll have to sync
  74
+            # up with the IPython team to address these issues -pi
  75
+            if '--profile' in s:
  76
+                k,p = s.split('--profile')
  77
+                k = k.lstrip().rstrip() # kernel part of the string
  78
+                p = p.lstrip().rstrip() # profile part of the string
  79
+                fullpath = find_connection_file(k,p)
  80
+            else:
  81
+                fullpath = find_connection_file(s.lstrip().rstrip())
  82
+        except IOError,e:
  83
+            echo(":IPython " + s + " failed", "Info")
  84
+            echo("^-- failed '" + s + "' not found", "Error")
  85
+            return
  86
+        km = BlockingKernelManager(connection_file = fullpath)
  87
+        km.load_connection_file()
  88
+    else:
  89
+        if s == '':
  90
+            echo(":IPython 0.11 requires the full connection string")
  91
+            return
  92
+        loader = KeyValueConfigLoader(s.split(), aliases=kernel_aliases)
  93
+        cfg = loader.load_config()['KernelApp']
  94
+        try:
  95
+            km = BlockingKernelManager(
  96
+                shell_address=(ip, cfg['shell_port']),
  97
+                sub_address=(ip, cfg['iopub_port']),
  98
+                stdin_address=(ip, cfg['stdin_port']),
  99
+                hb_address=(ip, cfg['hb_port']))
  100
+        except KeyError,e:
  101
+            echo(":IPython " +s + " failed", "Info")
  102
+            echo("^-- failed --"+e.message.replace('_port','')+" not specified", "Error")
  103
+            return
68 104
     km.start_channels()
69 105
     send = km.shell_channel.execute
70 106
     return km
71 107
 
72  
-
73  
-reselect = False
74  
-show_id= True
75  
-run_flags= "-i"
76  
-
77 108
 def echo(arg,style="Question"):
78 109
     try:
79 110
         vim.command("echohl %s" % style)
@@ -88,12 +119,12 @@ def disconnect():
88 119
     pass
89 120
 
90 121
 def get_doc(word):
  122
+    if km is None:
  123
+        return ["Not connected to IPython, cannot query \"%s\"" %word]
91 124
     msg_id = km.shell_channel.object_info(word)
92  
-    time.sleep(.1)
93 125
     doc = get_doc_msg(msg_id)
94  
-    #if len(doc):
95  
-    #    echo(word, 'Special')
96  
-    return doc
  126
+    # get around unicode problems when interfacing with vim
  127
+    return [d.encode(vim_encoding) for d in doc]
97 128
 
98 129
 import re
99 130
 # from http://serverfault.com/questions/71285/in-centos-4-4-how-can-i-strip-escape-sequences-from-a-text-file
@@ -102,25 +133,19 @@ def strip_color_escapes(s):
102 133
     return strip.sub('',s)
103 134
     
104 135
 def get_doc_msg(msg_id):
105  
-    content = get_child_msgs(msg_id)[0]['content']
106  
-    n = 13 # longest field name
107  
-    ##XXX: debug (print the whole message)
  136
+    n = 13 # longest field name (empirically)
108 137
     b=[]
  138
+    try:
  139
+        content = get_child_msg(msg_id)['content']
  140
+    except Empty:
  141
+        # timeout occurred
  142
+        return ["no reply from IPython kernel"]
109 143
 
110 144
     if not content['found']:
111 145
         return b
112 146
 
113  
-    ## debugging the whole message
114  
-    #for k in content:
115  
-    #    if isinstance(content[k],str) and content[k].find('\n')!=-1:
116  
-    #        b.append(k.ljust(n)+":")
117  
-    #        b.append(content[k].splitlines())
118  
-    #    else:
119  
-    #        b.append(k.ljust(n)+":"+str(content[k]))
120  
-
121 147
     for field in ['type_name','base_class','string_form','namespace',
122 148
             'file','length','definition','source','docstring']:
123  
-        # XXX: strip the 'definition' rich formatting
124 149
         c = content.get(field,None)
125 150
         if c:
126 151
             if field in ['definition']:
@@ -135,21 +160,27 @@ def get_doc_msg(msg_id):
135 160
     return b
136 161
 
137 162
 def get_doc_buffer(level=0):
138  
-    word = vim.eval('expand("<cfile>")')
  163
+    # empty string in case vim.eval return None
  164
+    word = vim.eval('expand("<cfile>")') or ''
139 165
     doc = get_doc(word)
140 166
     if len(doc) ==0:
141 167
         echo(word+" not found","Error")
142 168
         return
  169
+    # close any currently open preview windows
143 170
     vim.command('pcl')
  171
+    # documentation buffer name is same as the query made to ipython
144 172
     vim.command('new '+word)
145 173
     vim.command('setlocal pvw modifiable noro')
  174
+    # doc window quick quit keys: 'q' and 'escape'
146 175
     vim.command('map <buffer> q :q<CR>')
147  
-    vim.command('map <buffer>  :q<CR>')
148  
-    #vim.command('pedit '+docbuf.name)
  176
+    # Known issue: to enable the use of arrow keys inside the terminal when
  177
+    # viewing the documentation, comment out the next line
  178
+    vim.command('map <buffer> <Esc> :q<CR>')
  179
+    # and uncomment this line (which will work if you have a timoutlen set)
  180
+    #vim.command('map <buffer> <Esc><Esc> :q<CR>')
149 181
     b = vim.current.buffer
150  
-    #b.append(doc)
  182
+    b[:] = None
151 183
     b[:] = doc
152  
-    #b.append(doc)
153 184
     vim.command('setlocal nomodified bufhidden=wipe')
154 185
     #vim.command('setlocal previewwindow nomodifiable nomodified ro')
155 186
     #vim.command('set previewheight=%d'%len(b))# go to previous window
@@ -158,35 +189,153 @@ def get_doc_buffer(level=0):
158 189
     #vim.command('pedit doc')
159 190
     #vim.command('normal ') # go to previous window
160 191
 
161  
-def get_child_msgs(msg_id):
  192
+def update_subchannel_msgs(debug=False):
  193
+    msgs = km.sub_channel.get_msgs()
  194
+    if debug:
  195
+        #try:
  196
+        #    vim.command("b debug_msgs")
  197
+        #except vim.error:
  198
+        #    vim.command("new debug_msgs")
  199
+        #finally:
  200
+        db = vim.current.buffer
  201
+    else:
  202
+        db = []
  203
+    b = vim.current.buffer
  204
+    startedin_vimipython = vim.eval('@%')=='vim-ipython'
  205
+    if not startedin_vimipython:
  206
+        # switch to preview window
  207
+        vim.command(
  208
+            "try"
  209
+            "|silent! wincmd P"
  210
+            "|catch /^Vim\%((\a\+)\)\=:E441/"
  211
+            "|silent pedit +set\ ma vim-ipython"
  212
+            "|silent! wincmd P"
  213
+            "|endtry")
  214
+        # if the current window is called 'vim-ipython'
  215
+        if vim.eval('@%')=='vim-ipython':
  216
+            # set the preview window height to the current height
  217
+            vim.command("set pvh=" + vim.eval('winheight(0)'))
  218
+        else:
  219
+            # close preview window, it was something other than 'vim-ipython'
  220
+            vim.command("pcl")
  221
+            vim.command("silent pedit +set\ ma vim-ipython")
  222
+            vim.command("wincmd P") #switch to preview window
  223
+            # subchannel window quick quit key 'q'
  224
+            vim.command('map <buffer> q :q<CR>')
  225
+            vim.command("set bufhidden=hide buftype=nofile ft=python")
  226
+    
  227
+    #syntax highlighting for python prompt
  228
+    # QtConsole In[] is blue, but I prefer the oldschool green
  229
+    # since it makes the vim-ipython 'shell' look like the holidays!
  230
+    #vim.command("hi Blue ctermfg=Blue guifg=Blue")
  231
+    vim.command("hi Green ctermfg=Green guifg=Green")
  232
+    vim.command("hi Red ctermfg=Red guifg=Red")
  233
+    vim.command("syn keyword Green 'In\ []:'")
  234
+    vim.command("syn match Green /^In \[[0-9]*\]\:/")
  235
+    vim.command("syn match Red /^Out\[[0-9]*\]\:/")
  236
+    b = vim.current.buffer
  237
+    for m in msgs:
  238
+        #db.append(str(m).splitlines())
  239
+        s = ''
  240
+        if 'msg_type' not in m['header']:
  241
+            # debug information
  242
+            #echo('skipping a message on sub_channel','WarningMsg')
  243
+            #echo(str(m))
  244
+            continue
  245
+        elif m['header']['msg_type'] == 'status':
  246
+            continue
  247
+        elif m['header']['msg_type'] == 'stream':
  248
+            s = strip_color_escapes(m['content']['data'])
  249
+        elif m['header']['msg_type'] == 'pyout':
  250
+            s = "Out[%d]: " % m['content']['execution_count']
  251
+            s += m['content']['data']['text/plain']
  252
+        elif m['header']['msg_type'] == 'pyin':
  253
+            # TODO: the next line allows us to resend a line to ipython if
  254
+            # %doctest_mode is on. In the future, IPython will send the
  255
+            # execution_count on subchannel, so this will need to be updated
  256
+            # once that happens
  257
+            if 'execution_count' in m['content']:
  258
+                s = "\nIn [%d]: "% m['content']['execution_count']
  259
+            else:
  260
+                s = "\nIn [00]: "
  261
+            s += m['content']['code'].strip()
  262
+        elif m['header']['msg_type'] == 'pyerr':
  263
+            c = m['content']
  264
+            s = "\n".join(map(strip_color_escapes,c['traceback']))
  265
+            s += c['ename'] + ":" + c['evalue']
  266
+        if s.find('\n') == -1:
  267
+            # somewhat ugly unicode workaround from 
  268
+            # http://vim.1045645.n5.nabble.com/Limitations-of-vim-python-interface-with-respect-to-character-encodings-td1223881.html
  269
+            if isinstance(s,unicode):
  270
+                s=s.encode(vim_encoding)
  271
+            b.append(s)
  272
+        else:
  273
+            try:
  274
+                b.append(s.splitlines())
  275
+            except:
  276
+                b.append([l.encode(vim_encoding) for l in s.splitlines()])
  277
+    # make a newline so we can just start typing there
  278
+    if b[-1] != '':
  279
+        b.append([''])
  280
+    vim.command('normal G') # go to the end of the file
  281
+    if not startedin_vimipython:
  282
+        vim.command('normal p') # go back to where you were
  283
+    
  284
+def get_child_msg(msg_id):
162 285
     # XXX: message handling should be split into its own process in the future
163  
-    msgs= km.shell_channel.get_msgs()
164  
-    children = [m for m in msgs if m['parent_header']['msg_id'] == msg_id]
165  
-    return children
  286
+    while True:
  287
+        # get_msg will raise with Empty exception if no messages arrive in 1 second
  288
+        m= km.shell_channel.get_msg(timeout=1)
  289
+        if m['parent_header']['msg_id'] == msg_id:
  290
+            break
  291
+        else:
  292
+            #got a message, but not the one we were looking for
  293
+            echo('skipping a message on shell_channel','WarningMsg')
  294
+    return m
166 295
             
167  
-
168  
-
169  
-def run_this_file():
170  
-    send('run %s %s' % (run_flags, vim.current.buffer.name,))
171  
-    echo("In[]: run %s %s" % (run_flags, vim.current.buffer.name))
172  
-
173 296
 def print_prompt(prompt,msg_id=None):
174  
-    global show_id
175  
-    if show_id and msg_id:
176  
-        time.sleep(.1) # wait to get message back from kernel
177  
-        children = get_child_msgs(msg_id)
178  
-        if len(children):
179  
-            count = children[0]['content']['execution_count']
  297
+    """Print In[] or In[42] style messages"""
  298
+    global show_execution_count
  299
+    if show_execution_count and msg_id:
  300
+        # wait to get message back from kernel
  301
+        try:
  302
+            child = get_child_msg(msg_id)
  303
+            count = child['content']['execution_count']
180 304
             echo("In[%d]: %s" %(count,prompt))
181  
-        else:
182  
-            echo("In[]: %s (no reply from kernel)" % prompt)
  305
+        except Empty:
  306
+            echo("In[]: %s (no reply from IPython kernel)" % prompt)
183 307
     else:
184 308
         echo("In[]: %s" % prompt)
185 309
 
  310
+def with_subchannel(f,*args):
  311
+    "conditionally monitor subchannel"
  312
+    def f_with_update(*args):
  313
+        try:
  314
+            f(*args)
  315
+            if monitor_subchannel:
  316
+                update_subchannel_msgs()
  317
+        except AttributeError: #if km is None
  318
+            echo("not connected to IPython", 'Error')
  319
+    return f_with_update
  320
+
  321
+@with_subchannel
  322
+def run_this_file():
  323
+    msg_id = send('run %s %s' % (run_flags, repr(vim.current.buffer.name),))
  324
+    print_prompt("In[]: run %s %s" % (run_flags, repr(vim.current.buffer.name)),msg_id)
  325
+
  326
+@with_subchannel
186 327
 def run_this_line():
187 328
     msg_id = send(vim.current.line)
188 329
     print_prompt(vim.current.line, msg_id)
189 330
 
  331
+@with_subchannel
  332
+def run_command(cmd):
  333
+    msg_id = send(cmd)
  334
+    print_prompt(cmd, msg_id)
  335
+    if monitor_subchannel:
  336
+        update_subchannel_msgs()
  337
+
  338
+@with_subchannel
190 339
 def run_these_lines():
191 340
     r = vim.current.range
192 341
     lines = "\n".join(vim.current.buffer[r.start:r.end+1])
@@ -208,16 +357,19 @@ def run_these_lines():
208 357
 def dedent_run_this_line():
209 358
     vim.command("left")
210 359
     run_this_line()
211  
-    vim.command("undo")
  360
+    vim.command("silent undo")
212 361
 
213 362
 def dedent_run_these_lines():
214  
-    vim.command("'<,'>left")
  363
+    r = vim.current.range
  364
+    shiftwidth = vim.eval('&shiftwidth')
  365
+    count = int(vim.eval('indent(%d+1)/%s' % (r.start,shiftwidth)))
  366
+    vim.command("'<,'>" + "<"*count)
215 367
     run_these_lines()
216  
-    vim.command("undo")
  368
+    vim.command("silent undo")
217 369
     
218 370
 #def set_this_line():
219 371
 #    # not sure if there's a way to do this, since we have multiple clients
220  
-#    send("_ip.IP.rl_next_input= \'%s\'" % vim.current.line.replace("\'","\\\'"))
  372
+#    send("get_ipython().shell.set_next_input(\'%s\')" % vim.current.line.replace("\'","\\\'"))
221 373
 #    #print "line \'%s\' set at ipython prompt"% vim.current.line
222 374
 #    echo("line \'%s\' set at ipython prompt"% vim.current.line,'Statement')
223 375
 
@@ -262,34 +414,45 @@ fun! <SID>toggle_send_on_save()
262 414
     endif
263 415
 endfun
264 416
 
265  
-map <silent> <F5> :python run_this_file()<CR>
266  
-map <silent> <S-F5> :python run_this_line()<CR>
267  
-map <silent> <F9> :python run_these_lines()<CR>
268  
-map <leader>d :py get_doc_buffer()<CR>
269  
-map <silent> <S-F9> :python toggle_reselect()<CR>
270  
-"map <silent> <C-F6> :python send('%pdb')<CR>
271  
-"map <silent> <F6> :python set_breakpoint()<CR>
272  
-"map <silent> <s-F6> :python clear_breakpoint()<CR>
273  
-"map <silent> <F7> :python run_this_file_pdb()<CR>
274  
-"map <silent> <s-F7> :python clear_all_breaks()<CR>
275  
-imap <C-F5> <C-O><F5>
276  
-imap <S-F5> <C-O><S-F5>
277  
-imap <silent> <F5> <C-O><F5>
278  
-map <C-F5> :call <SID>toggle_send_on_save()<CR>
279  
-
280  
-"pi custom
281  
-map <silent> <C-Return> :python run_this_file()<CR>
282  
-map <silent> <C-s> :python run_this_line()<CR>
283  
-map <silent> <M-s> :python dedent_run_this_line()<CR>
284  
-vmap <silent> <C-S> :python run_these_lines()<CR>
285  
-vmap <silent> <M-s> :python dedent_run_these_lines()<CR>
286  
-"map <silent> <C-p> :python set_this_line()<CR>
287  
-map <silent> <M-c> I#<ESC>
288  
-vmap <silent> <M-c> I#<ESC>
289  
-map <silent> <M-C> :s/^\([ \t]*\)#/\1/<CR>
290  
-vmap <silent> <M-C> :s/^\([ \t]*\)#/\1/<CR>
291  
-
292  
-command! -nargs=+ IPython :py km_from_string("<args>")
  417
+" Allow custom mappings
  418
+if !exists('g:ipy_perform_mappings')
  419
+    let g:ipy_perform_mappings = 1
  420
+endif
  421
+if g:ipy_perform_mappings != 0
  422
+    map <silent> <F5> :python run_this_file()<CR>
  423
+    map <silent> <S-F5> :python run_this_line()<CR>
  424
+    map <silent> <F9> :python run_these_lines()<CR>
  425
+    map <silent> <leader>d :py get_doc_buffer()<CR>
  426
+    map <silent> <leader>s :py update_subchannel_msgs(); echo("vim-ipython shell updated",'Operator')<CR>
  427
+    map <silent> <S-F9> :python toggle_reselect()<CR>
  428
+    "map <silent> <C-F6> :python send('%pdb')<CR>
  429
+    "map <silent> <F6> :python set_breakpoint()<CR>
  430
+    "map <silent> <s-F6> :python clear_breakpoint()<CR>
  431
+    "map <silent> <F7> :python run_this_file_pdb()<CR>
  432
+    "map <silent> <s-F7> :python clear_all_breaks()<CR>
  433
+    imap <C-F5> <C-O><F5>
  434
+    imap <S-F5> <C-O><S-F5>
  435
+    imap <silent> <F5> <C-O><F5>
  436
+    map <C-F5> :call <SID>toggle_send_on_save()<CR>
  437
+    "" Example of how to quickly clear the current plot with a keystroke
  438
+    map <silent> <F12> :python run_command("plt.clf()")<cr>
  439
+    "" Example of how to quickly close all figures with a keystroke
  440
+    map <silent> <F11> :python run_command("plt.close('all')")<cr>
  441
+
  442
+    "pi custom
  443
+    map <silent> <C-Return> :python run_this_file()<CR>
  444
+    map <silent> <C-s> :python run_this_line()<CR>
  445
+    imap <silent> <C-s> <C-O>:python run_this_line()<CR>
  446
+    map <silent> <M-s> :python dedent_run_this_line()<CR>
  447
+    vmap <silent> <C-S> :python run_these_lines()<CR>
  448
+    vmap <silent> <M-s> :python dedent_run_these_lines()<CR>
  449
+    map <silent> <M-c> I#<ESC>
  450
+    vmap <silent> <M-c> I#<ESC>
  451
+    map <silent> <M-C> :s/^\([ \t]*\)#/\1/<CR>
  452
+    vmap <silent> <M-C> :s/^\([ \t]*\)#/\1/<CR>
  453
+endif
  454
+
  455
+command! -nargs=* IPython :py km_from_string("<args>")
293 456
 command! -nargs=0 IPythonClipboard :py km_from_string(vim.eval('@+'))
294 457
 command! -nargs=0 IPythonXSelection :py km_from_string(vim.eval('@*'))
295 458
 
@@ -297,13 +460,14 @@ function! IPythonBalloonExpr()
297 460
 python << endpython
298 461
 word = vim.eval('v:beval_text')
299 462
 reply = get_doc(word)
300  
-#reply = reply[:40]
301 463
 vim.command("let l:doc = %s"% reply)
302 464
 endpython
303 465
 return l:doc
304 466
 endfunction
305  
-set bexpr=IPythonBalloonExpr()
306  
-set ballooneval
  467
+if has('balloon_eval')
  468
+    set bexpr=IPythonBalloonExpr()
  469
+    set ballooneval
  470
+endif
307 471
 
308 472
 fun! CompleteIPython(findstart, base)
309 473
 	  if a:findstart
@@ -322,21 +486,35 @@ fun! CompleteIPython(findstart, base)
322 486
 base = vim.eval("a:base")
323 487
 findstart = vim.eval("a:findstart")
324 488
 msg_id = km.shell_channel.complete(base, vim.current.line, vim.eval("col('.')"))
325  
-time.sleep(.1)
326  
-m = get_child_msgs(msg_id)[0]
327  
-
328  
-matches = m['content']['matches']
329  
-#end = len(base)
330  
-#completions = [m[end:]+findstart+base for m in matches]
331  
-matches.insert(0,base) # the "no completion" version
332  
-completions = matches
333  
-vim.command("let l:completions = %s"% completions)
  489
+try:
  490
+    m = get_child_msg(msg_id)
  491
+    matches = m['content']['matches']
  492
+    matches.insert(0,base) # the "no completion" version
  493
+    # we need to be careful with unicode, because we can have unicode
  494
+    # completions for filenames (for the %run magic, for example). So the next
  495
+    # line will fail on those:
  496
+    #completions= [str(u) for u in matches]
  497
+    # because str() won't work for non-ascii characters
  498
+    # and we also have problems with unicode in vim, hence the following:
  499
+    completions = [s.encode(vim_encoding) for s in matches]
  500
+except Empty:
  501
+    echo("no reply from IPython kernel")
  502
+    completions=['']
  503
+## Additionally, we have no good way of communicating lists to vim, so we have
  504
+## to turn in into one long string, which can be problematic if e.g. the
  505
+## completions contain quotes. The next line will not work if some filenames
  506
+## contain quotes - but if that's the case, the user's just asking for
  507
+## it, right?
  508
+#completions = '["'+ '", "'.join(completions)+'"]'
  509
+#vim.command("let completions = %s" % completions)
  510
+## An alternative for the above, which will insert matches one at a time, so
  511
+## if there's a problem with turning a match into a string, it'll just not
  512
+## include the problematic match, instead of not including anything. There's a
  513
+## bit more indirection here, but I think it's worth it
  514
+for c in completions:
  515
+    vim.command('call add(res,"'+c+'")')
334 516
 endpython
335  
-	    for m in l:completions
336  
-	      "if m =~ '^' . a:base
337  
-            call add(res, m)
338  
-	      "endif
339  
-	    endfor
  517
+        "call extend(res,completions) 
340 518
 	    return res
341 519
 	  endif
342 520
 	endfun
Commit_comment_tip

Tip: You can add notes to lines in a file. Hover to the left of a line to make a note

Something went wrong with that request. Please try again.