##// END OF EJS Templates
Merge pull request #1955 from ivanov/vim-ipython...
Min RK -
r7568:69f93d47 merge
parent child Browse files
Show More
@@ -1,189 +1,253
1 1 ###########
2 2 vim-ipython
3 3 ###########
4 4
5 5 A two-way integration between Vim and IPython 0.11+
6 6
7 7 * author: Paul Ivanov (http://pirsquared.org)
8 8 * github: http://github.com/ivanov/vim-ipython
9 9 * demos: http://pirsquared.org/vim-ipython/
10 10 * blogpost: http://pirsquared.org/blog/2011/07/28/vim-ipython/
11 11
12 12 Using this plugin, you can send lines or whole files for IPython to
13 13 execute, and also get back object introspection and word completions in
14 14 Vim, like what you get with: ``object?<enter>`` and ``object.<tab>`` in
15 15 IPython.
16 16
17 17 The big change from previous versions of ``ipy.vim`` is that it no longer
18 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
19 it uses just vim and python, it is platform independent (i.e. works
20 20 even on windows, unlike the previous \*nix only solution). The requirements
21 21 are IPython 0.11+ with zeromq capabilities, vim compiled with +python.
22 22
23 23 If you can launch ``ipython qtconsole`` or ``ipython kernel``, and
24 24 ``:echo has('python')`` returns 1 in vim, you should be good to go.
25 25
26 26 -----------------
27 27 Quickstart Guide:
28 28 -----------------
29 29 Start ``ipython qtconsole`` [*]_ and copy the connection string.
30 30 Source ``ipy.vim`` file, which provides new IPython command::
31 31
32 32 :source ipy.vim
33 33 (or copy it to ~/.vim/ftplugin/python to load automatically)
34 34
35 35 :IPythonClipboard
36 36 (or :IPythonXSelection if you're using X11 without having to copy)
37 37
38 38 The :IPython command allows you to put the full connection string. For IPython
39 39 0.11, it would look like this::
40 40
41 41 :IPython --existing --shell=41882 --iopub=43286 --stdin=34987 --hb=36697
42 42
43 43 and for IPython 0.12, like this::
44 44
45 45 :IPython --existing kernel-85997.json
46 46
47 47 The ``:IPythonClipboard`` command just uses the ``+`` register to get the
48 connection string, whereas ``:IPythonXSelection`` uses the ``*`` register
48 connection string, whereas ``:IPythonXSelection`` uses the ``*`` register.
49
50 **NEW in IPython 0.12**!
51 Since IPython 0.12, you can simply use::
52
53 :IPython
54
55 without arguments to connect to the most recent IPython session (this is the
56 same as passing just the ``--existing`` flag to ``ipython qtconsole`` and
57 ``ipython console``.
49 58
50 59 .. [*] Though the demos above use ``qtconsole``, it is not required
51 60 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()"``
61 make use of the new functionality in 0.11 release. Since IPython 0.12, you
62 can use ``ipython kernel`` to create a kernel and get the connection
63 string to use for any frontend (including vim-ipython), or use ``ipython
64 console`` to create a kernel and immediately connect to it using a
65 terminal-based client. You can even connect to an active IPython Notebook
66 kernel - just watch for the connection string that gets printed when you
67 open the notebook, or use the ``%connect_info`` magic to get the
68 connection string. If you are still using 0.11, you can launch a regular
69 kernel using ``python -c "from IPython.zmq.ipkernel import main; main()"``
57 70
58 71 ------------------------
59 72 Sending lines to IPython
60 73 ------------------------
61 74 Now type out a line and send it to IPython using ``<Ctrl-S>`` from Command mode::
62 75
63 76 import os
64 77
65 78 You should see a notification message confirming the line was sent, along
66 79 with the input number for the line, like so ``In[1]: import os``.
67 80
68 81 ``<Ctrl-S>`` also works from insert mode, but doesn't show notification,
69 82 unless ``monitor_subchannel`` is set to ``True`` (see `vim-ipython 'shell'`_,
70 83 below)
71 84
72 85 It also works blockwise in Visual Mode. Select and send these lines using
73 86 ``<Ctrl-S>``::
74 87
75 88 import this,math # secret decoder ring
76 89 a,b,c,d,e,f,g,h,i = range(1,10)
77 90 code =(c,a,d,a,e,i,)
78 91 msg = '...jrer nyy frag sebz Ivz.\nIvz+VClguba=%fyl '+this.s.split()[g]
79 92 decode=lambda x:"\n"+"".join([this.d.get(c,c) for c in x])+"!"
80 93 format=lambda x:'These lines:\n '+'\n '.join([l for l in x.splitlines()])
81 94 secret_decoder = lambda a,b: format(a)+decode(msg)%str(b)[:-1]
82 95 '%d'*len(code)%code == str(int(math.pi*1e5))
83 96
84 97 Then, go to the qtconsole and run this line::
85 98
86 99 print secret_decoder(_i,_)
87 100
88 101 You can also send whole files to IPython's ``%run`` magic using ``<F5>``.
89 102
103 **NEW in IPython 0.12**!
104 If you're trying to do run code fragments that have leading whitespace, use
105 ``<Alt-S>`` instead - it will dedent a single line, and remove the leading
106 whitespace of the first line from all lines in a visual mode selection.
107
90 108 -------------------------------
91 109 IPython's object? Functionality
92 110 -------------------------------
93 111
94 If you're using gvim, mouse-over a variable to see IPython's ? equivalent. If
95 you're using vim from a terminal, or want to copy something from the
112 If you're using gvim, mouse-over a variable to see IPython's ``?`` equivalent.
113 If you're using vim from a terminal, or want to copy something from the
96 114 docstring, type ``<leader>d``. ``<leader>`` is usually ``\`` (the backslash
97 115 key). This will open a quickpreview window, which can be closed by hitting
98 116 ``q`` or ``<escape>``.
99 117
100 118 --------------------------------------
101 119 IPython's tab-completion Functionality
102 120 --------------------------------------
103 121 vim-ipython activates a 'completefunc' that queries IPython.
104 122 A completefunc is activated using ``Ctrl-X Ctrl-U`` in Insert Mode (vim
105 123 default). You can combine this functionality with SuperTab to get tab
106 124 completion.
107 125
108 126 -------------------
109 127 vim-ipython 'shell'
110 128 -------------------
111 **NEW since IPython 0.11**!
112 129
113 130 By monitoring km.sub_channel, we can recreate what messages were sent to
114 131 IPython, and what IPython sends back in response.
115 132
116 133 ``monitor_subchannel`` is a parameter that sets whether this 'shell' should
117 134 updated on every sent command (default: True).
118 135
119 136 If at any later time you wish to bring this shell up, including if you've set
120 137 ``monitor_subchannel=False``, hit ``<leader>s``.
121 138
139 **NEW since IPython 0.12**
140 For local kernels (kernels running on the same machine as vim), `Ctrl-C` in
141 the vim-ipython 'shell' sends an keyboard interrupt. (Note: this feature may
142 not work on Windows, please report the issue to ).
143
122 144 -------
123 145 Options
124 146 -------
125 147 You can change these at the top of the ipy.vim::
126 148
127 149 reselect = False # reselect lines after sending from Visual mode
128 150 show_execution_count = True # wait to get numbers for In[43]: feedback?
129 151 monitor_subchannel = True # update vim-ipython 'shell' on every send?
130 152 run_flags= "-i" # flags to for IPython's run magic when using <F5>
131 153
132 154 **Disabling default mappings**
133 155 In your own ``.vimrc``, if you don't like the mappings provided by default,
134 156 you can define a variable ``let g:ipy_perform_mappings=0`` which will prevent
135 157 vim-ipython from defining any of the default mappings.
136 158
159 **NEW since IPython 0.12**
160 **Making completefunc local to a buffer, or disabling it**
161 By default, vim-ipython activates the custom completefunc globally.
162 Sometimes, having a completefunc breaks other plugins' completions. Putting
163 the line ``let g:ipy_completefunc = 'local'`` in one's vimrc will activate the
164 IPython-based completion only for current buffer. Setting `g:ipy_completefunc`
165 to anything other than `'local'` or `'global'` disables it altogether.
166
137 167 ---------------
138 168 Current issues:
139 169 ---------------
140 170 - For now, vim-ipython only connects to an ipython session in progress.
141 171 - The ipdb integration is not yet re-implemented.
142 172 - If you're running inside ``screen``, read about the ``<CTRL-S>`` issue `here
143 173 <http://munkymorgy.blogspot.com/2008/07/screen-ctrl-s-bug.html>`_, and add
144 174 this line to your ``.bashrc`` to fix it::
145 175
146 176 stty stop undef # to unmap ctrl-s
147 177
148 178 - In vim, if you're getting ``ImportError: No module named
149 179 IPython.zmq.blockingkernelmanager`` but are able to import it in regular
150 180 python, **either**
151 181
152 182 1. your ``sys.path`` in vim differs from the ``sys.path`` in regular python.
153 183 Try running these two lines, and comparing their output files::
154 184
155 185 $ vim -c 'py import vim, sys; vim.current.buffer.append(sys.path)' -c ':wq vim_syspath'
156 186 $ python -c "import sys; f=file('python_syspath','w'); f.write('\n'.join(sys.path)); f.close()"
157 187
158 188 **or**
159 189
160 190 2. your vim is compiled against a different python than you are launching. See
161 191 if there's a difference between ::
162 192
163 193 $ vim -c ':py import os; print os.__file__' -c ':q'
164 $ python -c ':py import os; print os.__file__'
194 $ python -c 'import os; print os.__file__'
165 195
166 196 - For vim inside a terminal, using the arrow keys won't work inside a
167 197 documentation buffer, because the mapping for ``<Esc>`` overlaps with
168 198 ``^[OA`` and so on, and we use ``<Esc>`` as a quick way of closing the
169 199 documentation preview window. If you want go without this quick close
170 200 functionality and want to use the arrow keys instead, look for instructions
171 201 starting with "Known issue: to enable the use of arrow keys..." in the
172 202 ``get_doc_buffer`` function.
173 203
174 204 - @fholgado's update to ``minibufexpl.vim`` that is up on GitHub will always
175 205 put the cursor in the minibuf after sending a command when
176 206 ``monitor_subchannel`` is set. This is a bug in minibufexpl.vim and the workaround
177 207 is described in vim-ipython issue #7.
178 208
179 209 ----------------------------
180 210 Thanks and Bug Participation
181 211 ----------------------------
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)
212 Here's a brief acknowledgment of the folks who have graciously pitched in. If
213 you've been missed, don't hesitate to contact me, or better yet, submit a
214 pull request with your attribution.
215
216 * @minrk for guiding me through the IPython kernel manager protocol, and
217 support of connection_file-based IPython connection (#13)
218 * @nakamuray and @tcheneau for reporting and providing a fix for when vim is
219 compiled without a gui (#1)
220 * @unpingco for reporting Windows bugs (#3,#4), providing better multiline
221 dedenting (#15), and suggesting that a resized vim-ipython shell stays
222 resized (#16).
185 223 * @simon-b for terminal vim arrow key issue (#5)
186 * @jorgesca and @kwgoodman for shell (#6)
224 * @jorgesca and @kwgoodman for shell update problems (#6)
225 * @xowlinx and @vladimiroff for Ctrl-S issues in Konsole (#8)
187 226 * @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)
227 * @jorgesca for reporting the lack of profile handling capability (#14),
228 only open updating 'shell' if it is open (#29)
229 * @enzbang for removing mapping that's not currently functional (#17)
230 * @ogrisel for fixing documentation typo (#19)
231 * @koepsell for gracefully exiting in case python is not available (#23)
232 * @mrterry for activating completefunc only after a connection is made (#25),
233 Ctrl-C implementation in vim-ipython 'shell' (#28)
234 * @nonameentername for completion on import statements (#26)
235 * @dstahlke for setting syntax of doc window to ReST
236 * @jtratner for docs with quotes (#30)
237 * @pielgrzym for setting completefunc locally to a buffer (#32)
238
239 Similar Projects
240 ----------------
241 * `vim-slime`_ - Grab some text and "send" it to a GNU Screen / tmux session
242 (Jonathan Palardy)
243 * `screen.vba`_ - Simulate a split shell, using GNU Screen / tmux, that you
244 can send commands to (Eric Van Dewoestine)
245 * conque_ - terminal emulator which uses a Vim buffer to display the program
246 output (Nico Raffo)
247 * `ipyqtmacvim`_ - plugin to send commands from MacVim to IPython Qt console
248 (Justin Kitzes)
249
250 .. _vim-slime: https://github.com/jpalardy/vim-slime
251 .. _screen.vba: https://github.com/ervandew/screen
252 .. _conque: http://code.google.com/p/conque/
253 .. _ipyqtmacvim: https://github.com/jkitzes/ipyqtmacvim/
@@ -1,521 +1,665
1 1 " Vim integration with IPython 0.11+
2 2 "
3 " A two-way integration between Vim and IPython.
3 " A two-way integration between Vim and IPython.
4 4 "
5 5 " Using this plugin, you can send lines or whole files for IPython to execute,
6 6 " and also get back object introspection and word completions in Vim, like
7 7 " what you get with: object?<enter> object.<tab> in IPython
8 8 "
9 9 " -----------------
10 10 " Quickstart Guide:
11 11 " -----------------
12 12 " Start ipython qtconsole and copy the connection string.
13 13 " Source this file, which provides new IPython command
14 " :source ipy.vim
15 " :IPythonClipboard
14 " :source ipy.vim
15 " :IPythonClipboard
16 16 " (or :IPythonXSelection if you're using X11 without having to copy)
17 17 "
18 18 " written by Paul Ivanov (http://pirsquared.org)
19 "
20 if !has('python')
21 " exit if python is not available.
22 finish
23 endif
24
25 " Allow custom mappings.
26 if !exists('g:ipy_perform_mappings')
27 let g:ipy_perform_mappings = 1
28 endif
29
30 " Register IPython completefunc
31 " 'global' -- for all of vim (default).
32 " 'local' -- only for the current buffer.
33 " otherwise -- don't register it at all.
34 "
35 " you can later set it using ':set completefunc=CompleteIPython', which will
36 " correspond to the 'global' behavior, or with ':setl ...' to get the 'local'
37 " behavior
38 if !exists('g:ipy_completefunc')
39 let g:ipy_completefunc = 'global'
40 endif
41
19 42 python << EOF
20 43 reselect = False # reselect lines after sending from Visual mode
21 44 show_execution_count = True # wait to get numbers for In[43]: feedback?
22 45 monitor_subchannel = True # update vim-ipython 'shell' on every send?
23 46 run_flags= "-i" # flags to for IPython's run magic when using <F5>
47 current_line = ''
24 48
25 49 import vim
26 50 import sys
27 51
28 52 # get around unicode problems when interfacing with vim
29 53 vim_encoding=vim.eval('&encoding') or 'utf-8'
30 54
31 55 try:
32 56 sys.stdout.flush
33 57 except AttributeError:
34 58 # IPython complains if stderr and stdout don't have flush
35 59 # this is fixed in newer version of Vim
36 60 class WithFlush(object):
37 61 def __init__(self,noflush):
38 62 self.write=noflush.write
39 63 self.writelines=noflush.writelines
40 64 def flush(self):pass
41 65 sys.stdout = WithFlush(sys.stdout)
42 66 sys.stderr = WithFlush(sys.stderr)
43 67
44 68
45 69
46 70 ip = '127.0.0.1'
47 71 try:
48 72 km
49 73 except NameError:
50 74 km = None
75 try:
76 pid
77 except NameError:
78 pid = None
51 79
52 80 def km_from_string(s=''):
53 81 """create kernel manager from IPKernelApp string
54 82 such as '--shell=47378 --iopub=39859 --stdin=36778 --hb=52668' for IPython 0.11
55 83 or just 'kernel-12345.json' for IPython 0.12
56 84 """
57 85 from os.path import join as pjoin
58 86 from IPython.zmq.blockingkernelmanager import BlockingKernelManager, Empty
59 87 from IPython.config.loader import KeyValueConfigLoader
60 88 from IPython.zmq.kernelapp import kernel_aliases
61 89 global km,send,Empty
62 90
63 91 s = s.replace('--existing', '')
64 92 if 'connection_file' in BlockingKernelManager.class_trait_names():
65 93 from IPython.lib.kernel import find_connection_file
66 94 # 0.12 uses files instead of a collection of ports
67 95 # include default IPython search path
68 96 # filefind also allows for absolute paths, in which case the search
69 97 # is ignored
70 98 try:
71 99 # XXX: the following approach will be brittle, depending on what
72 100 # connection strings will end up looking like in the future, and
73 101 # whether or not they are allowed to have spaces. I'll have to sync
74 102 # up with the IPython team to address these issues -pi
75 103 if '--profile' in s:
76 104 k,p = s.split('--profile')
77 105 k = k.lstrip().rstrip() # kernel part of the string
78 106 p = p.lstrip().rstrip() # profile part of the string
79 107 fullpath = find_connection_file(k,p)
80 108 else:
81 109 fullpath = find_connection_file(s.lstrip().rstrip())
82 110 except IOError,e:
83 111 echo(":IPython " + s + " failed", "Info")
84 112 echo("^-- failed '" + s + "' not found", "Error")
85 113 return
86 114 km = BlockingKernelManager(connection_file = fullpath)
87 115 km.load_connection_file()
88 116 else:
89 117 if s == '':
90 118 echo(":IPython 0.11 requires the full connection string")
91 119 return
92 120 loader = KeyValueConfigLoader(s.split(), aliases=kernel_aliases)
93 121 cfg = loader.load_config()['KernelApp']
94 122 try:
95 123 km = BlockingKernelManager(
96 124 shell_address=(ip, cfg['shell_port']),
97 125 sub_address=(ip, cfg['iopub_port']),
98 126 stdin_address=(ip, cfg['stdin_port']),
99 127 hb_address=(ip, cfg['hb_port']))
100 128 except KeyError,e:
101 129 echo(":IPython " +s + " failed", "Info")
102 130 echo("^-- failed --"+e.message.replace('_port','')+" not specified", "Error")
103 131 return
104 132 km.start_channels()
105 133 send = km.shell_channel.execute
134
135 # now that we're connect to an ipython kernel, activate completion
136 # machinery, but do so only for the local buffer if the user added the
137 # following line the vimrc:
138 # let g:ipy_completefunc = 'local'
139 vim.command("""
140 if g:ipy_completefunc == 'global'
141 set completefunc=CompleteIPython
142 elseif g:ipy_completefunc == 'local'
143 setl completefunc=CompleteIPython
144 endif
145 """)
146 # also activate GUI doc balloons if in gvim
147 vim.command("""
148 if has('balloon_eval')
149 set bexpr=IPythonBalloonExpr()
150 set ballooneval
151 endif
152 """)
153 set_pid()
106 154 return km
107 155
108 156 def echo(arg,style="Question"):
109 157 try:
110 158 vim.command("echohl %s" % style)
111 159 vim.command("echom \"%s\"" % arg.replace('\"','\\\"'))
112 160 vim.command("echohl None")
113 161 except vim.error:
114 162 print "-- %s" % arg
115 163
116 164 def disconnect():
117 165 "disconnect kernel manager"
118 166 # XXX: make a prompt here if this km owns the kernel
119 167 pass
120 168
121 169 def get_doc(word):
122 170 if km is None:
123 return ["Not connected to IPython, cannot query \"%s\"" %word]
171 return ["Not connected to IPython, cannot query: %s" % word]
124 172 msg_id = km.shell_channel.object_info(word)
125 173 doc = get_doc_msg(msg_id)
126 174 # get around unicode problems when interfacing with vim
127 175 return [d.encode(vim_encoding) for d in doc]
128 176
129 177 import re
130 178 # from http://serverfault.com/questions/71285/in-centos-4-4-how-can-i-strip-escape-sequences-from-a-text-file
131 179 strip = re.compile('\x1B\[([0-9]{1,2}(;[0-9]{1,2})?)?[m|K]')
132 180 def strip_color_escapes(s):
133 181 return strip.sub('',s)
134
182
135 183 def get_doc_msg(msg_id):
136 184 n = 13 # longest field name (empirically)
137 185 b=[]
138 186 try:
139 187 content = get_child_msg(msg_id)['content']
140 188 except Empty:
141 189 # timeout occurred
142 190 return ["no reply from IPython kernel"]
143 191
144 192 if not content['found']:
145 193 return b
146 194
147 195 for field in ['type_name','base_class','string_form','namespace',
148 196 'file','length','definition','source','docstring']:
149 197 c = content.get(field,None)
150 198 if c:
151 199 if field in ['definition']:
152 200 c = strip_color_escapes(c).rstrip()
153 201 s = field.replace('_',' ').title()+':'
154 202 s = s.ljust(n)
155 203 if c.find('\n')==-1:
156 204 b.append(s+c)
157 205 else:
158 206 b.append(s)
159 207 b.extend(c.splitlines())
160 208 return b
161 209
162 210 def get_doc_buffer(level=0):
163 211 # empty string in case vim.eval return None
164 212 word = vim.eval('expand("<cfile>")') or ''
165 213 doc = get_doc(word)
166 214 if len(doc) ==0:
167 echo(word+" not found","Error")
215 echo(repr(word)+" not found","Error")
168 216 return
169 # close any currently open preview windows
170 vim.command('pcl')
171 217 # documentation buffer name is same as the query made to ipython
172 218 vim.command('new '+word)
173 vim.command('setlocal pvw modifiable noro')
219 vim.command('setlocal modifiable noro')
174 220 # doc window quick quit keys: 'q' and 'escape'
175 221 vim.command('map <buffer> q :q<CR>')
176 222 # Known issue: to enable the use of arrow keys inside the terminal when
177 223 # viewing the documentation, comment out the next line
178 224 vim.command('map <buffer> <Esc> :q<CR>')
179 225 # and uncomment this line (which will work if you have a timoutlen set)
180 226 #vim.command('map <buffer> <Esc><Esc> :q<CR>')
181 227 b = vim.current.buffer
182 228 b[:] = None
183 229 b[:] = doc
184 230 vim.command('setlocal nomodified bufhidden=wipe')
185 231 #vim.command('setlocal previewwindow nomodifiable nomodified ro')
186 232 #vim.command('set previewheight=%d'%len(b))# go to previous window
187 233 vim.command('resize %d'%len(b))
188 234 #vim.command('pcl')
189 235 #vim.command('pedit doc')
190 236 #vim.command('normal ') # go to previous window
237 # use the ReST formatting that ships with stock vim
238 vim.command('setlocal syntax=rst')
239
240 def vim_ipython_is_open():
241 """
242 Helper function to let us know if the vim-ipython shell is currently
243 visible
244 """
245 for w in vim.windows:
246 if w.buffer.name is not None and w.buffer.name.endswith("vim-ipython"):
247 return True
248 return False
191 249
192 def update_subchannel_msgs(debug=False):
250 def update_subchannel_msgs(debug=False, force=False):
251 """
252 Grab any pending messages and place them inside the vim-ipython shell.
253 This function will do nothing if the vim-ipython shell is not visible,
254 unless force=True argument is passed.
255 """
256 if km is None or (not vim_ipython_is_open() and not force):
257 return False
193 258 msgs = km.sub_channel.get_msgs()
194 259 if debug:
195 260 #try:
196 261 # vim.command("b debug_msgs")
197 262 #except vim.error:
198 263 # vim.command("new debug_msgs")
199 264 #finally:
200 265 db = vim.current.buffer
201 266 else:
202 267 db = []
203 268 b = vim.current.buffer
204 269 startedin_vimipython = vim.eval('@%')=='vim-ipython'
205 270 if not startedin_vimipython:
206 271 # switch to preview window
207 272 vim.command(
208 273 "try"
209 274 "|silent! wincmd P"
210 275 "|catch /^Vim\%((\a\+)\)\=:E441/"
211 276 "|silent pedit +set\ ma vim-ipython"
212 277 "|silent! wincmd P"
213 278 "|endtry")
214 279 # if the current window is called 'vim-ipython'
215 280 if vim.eval('@%')=='vim-ipython':
216 281 # set the preview window height to the current height
217 282 vim.command("set pvh=" + vim.eval('winheight(0)'))
218 283 else:
219 284 # close preview window, it was something other than 'vim-ipython'
220 285 vim.command("pcl")
221 286 vim.command("silent pedit +set\ ma vim-ipython")
222 287 vim.command("wincmd P") #switch to preview window
223 288 # subchannel window quick quit key 'q'
224 289 vim.command('map <buffer> q :q<CR>')
225 290 vim.command("set bufhidden=hide buftype=nofile ft=python")
291 # make shift-enter and control-enter in insert mode behave same as in ipython notebook
292 # shift-enter send the current line, control-enter send the line
293 # but keeps it around for further editing.
294 vim.command("imap <buffer> <s-Enter> <esc>dd:python run_command('''<C-r>\"''')<CR>i")
295 # pkddA: paste, go up one line which is blank after run_command,
296 # delete it, and then back to insert mode
297 vim.command("imap <buffer> <c-Enter> <esc>dd:python run_command('''<C-r>\"''')<CR>pkddA")
298 # ctrl-C gets sent to the IPython process as a signal on POSIX
299 vim.command("map <buffer>  :IPythonInterrupt<cr>")
226 300
227 301 #syntax highlighting for python prompt
228 302 # QtConsole In[] is blue, but I prefer the oldschool green
229 303 # since it makes the vim-ipython 'shell' look like the holidays!
230 304 #vim.command("hi Blue ctermfg=Blue guifg=Blue")
231 305 vim.command("hi Green ctermfg=Green guifg=Green")
232 306 vim.command("hi Red ctermfg=Red guifg=Red")
233 307 vim.command("syn keyword Green 'In\ []:'")
234 308 vim.command("syn match Green /^In \[[0-9]*\]\:/")
235 309 vim.command("syn match Red /^Out\[[0-9]*\]\:/")
236 310 b = vim.current.buffer
311 update_occured = False
237 312 for m in msgs:
238 313 #db.append(str(m).splitlines())
239 314 s = ''
240 315 if 'msg_type' not in m['header']:
241 316 # debug information
242 317 #echo('skipping a message on sub_channel','WarningMsg')
243 318 #echo(str(m))
244 319 continue
245 320 elif m['header']['msg_type'] == 'status':
246 321 continue
247 322 elif m['header']['msg_type'] == 'stream':
248 323 s = strip_color_escapes(m['content']['data'])
249 324 elif m['header']['msg_type'] == 'pyout':
250 325 s = "Out[%d]: " % m['content']['execution_count']
251 326 s += m['content']['data']['text/plain']
252 327 elif m['header']['msg_type'] == 'pyin':
253 328 # TODO: the next line allows us to resend a line to ipython if
254 329 # %doctest_mode is on. In the future, IPython will send the
255 330 # execution_count on subchannel, so this will need to be updated
256 331 # once that happens
257 332 if 'execution_count' in m['content']:
258 333 s = "\nIn [%d]: "% m['content']['execution_count']
259 334 else:
260 335 s = "\nIn [00]: "
261 336 s += m['content']['code'].strip()
262 337 elif m['header']['msg_type'] == 'pyerr':
263 338 c = m['content']
264 339 s = "\n".join(map(strip_color_escapes,c['traceback']))
265 340 s += c['ename'] + ":" + c['evalue']
266 341 if s.find('\n') == -1:
267 342 # somewhat ugly unicode workaround from
268 343 # http://vim.1045645.n5.nabble.com/Limitations-of-vim-python-interface-with-respect-to-character-encodings-td1223881.html
269 344 if isinstance(s,unicode):
270 345 s=s.encode(vim_encoding)
271 346 b.append(s)
272 347 else:
273 348 try:
274 349 b.append(s.splitlines())
275 350 except:
276 351 b.append([l.encode(vim_encoding) for l in s.splitlines()])
352 update_occured = True
277 353 # make a newline so we can just start typing there
278 354 if b[-1] != '':
279 355 b.append([''])
280 356 vim.command('normal G') # go to the end of the file
281 357 if not startedin_vimipython:
282 358 vim.command('normal p') # go back to where you were
359 return update_occured
283 360
284 361 def get_child_msg(msg_id):
285 362 # XXX: message handling should be split into its own process in the future
286 363 while True:
287 364 # get_msg will raise with Empty exception if no messages arrive in 1 second
288 365 m= km.shell_channel.get_msg(timeout=1)
289 366 if m['parent_header']['msg_id'] == msg_id:
290 367 break
291 368 else:
292 369 #got a message, but not the one we were looking for
293 370 echo('skipping a message on shell_channel','WarningMsg')
294 371 return m
295
372
296 373 def print_prompt(prompt,msg_id=None):
297 374 """Print In[] or In[42] style messages"""
298 375 global show_execution_count
299 376 if show_execution_count and msg_id:
300 377 # wait to get message back from kernel
301 378 try:
302 379 child = get_child_msg(msg_id)
303 380 count = child['content']['execution_count']
304 381 echo("In[%d]: %s" %(count,prompt))
305 382 except Empty:
306 383 echo("In[]: %s (no reply from IPython kernel)" % prompt)
307 384 else:
308 385 echo("In[]: %s" % prompt)
309 386
310 387 def with_subchannel(f,*args):
311 388 "conditionally monitor subchannel"
312 389 def f_with_update(*args):
313 390 try:
314 391 f(*args)
315 392 if monitor_subchannel:
316 393 update_subchannel_msgs()
317 394 except AttributeError: #if km is None
318 395 echo("not connected to IPython", 'Error')
319 396 return f_with_update
320 397
321 398 @with_subchannel
322 399 def run_this_file():
323 400 msg_id = send('run %s %s' % (run_flags, repr(vim.current.buffer.name),))
324 401 print_prompt("In[]: run %s %s" % (run_flags, repr(vim.current.buffer.name)),msg_id)
325 402
326 403 @with_subchannel
327 404 def run_this_line():
328 405 msg_id = send(vim.current.line)
329 406 print_prompt(vim.current.line, msg_id)
330 407
331 408 @with_subchannel
332 409 def run_command(cmd):
333 410 msg_id = send(cmd)
334 411 print_prompt(cmd, msg_id)
335 if monitor_subchannel:
336 update_subchannel_msgs()
337 412
338 413 @with_subchannel
339 414 def run_these_lines():
340 415 r = vim.current.range
341 416 lines = "\n".join(vim.current.buffer[r.start:r.end+1])
342 417 msg_id = send(lines)
343 418 #alternative way of doing this in more recent versions of ipython
344 419 #but %paste only works on the local machine
345 420 #vim.command("\"*yy")
346 421 #send("'%paste')")
347 422 #reselect the previously highlighted block
348 423 vim.command("normal gv")
349 424 if not reselect:
350 425 vim.command("normal ")
351 426
352 427 #vim lines start with 1
353 428 #print "lines %d-%d sent to ipython"% (r.start+1,r.end+1)
354 429 prompt = "lines %d-%d "% (r.start+1,r.end+1)
355 430 print_prompt(prompt,msg_id)
356 431
432
433 def set_pid():
434 """
435 Explicitly ask the ipython kernel for its pid
436 """
437 global km, pid
438 lines = '\n'.join(['import os', '_pid = os.getpid()'])
439 msg_id = send(lines, silent=True, user_variables=['_pid'])
440
441 # wait to get message back from kernel
442 try:
443 child = get_child_msg(msg_id)
444 except Empty:
445 echo("no reply from IPython kernel")
446 return
447
448 pid = int(child['content']['user_variables']['_pid'])
449 return pid
450
451
452 def interrupt_kernel_hack():
453 """
454 Sends the interrupt signal to the remote kernel. This side steps the
455 (non-functional) ipython interrupt mechanisms.
456 Only works on posix.
457 """
458 global pid
459 import signal
460 import os
461 if pid is None:
462 # Avoid errors if we couldn't get pid originally,
463 # by trying to obtain it now
464 pid = set_pid()
465
466 if pid is None:
467 echo("cannot get kernel PID, Ctrl-C will not be supported")
468 return
469 echo("KeyboardInterrupt (sent to ipython: pid " +
470 "%i with signal %i)" % (pid, signal.SIGINT),"Operator")
471 try:
472 os.kill(pid, signal.SIGINT)
473 except OSError:
474 echo("unable to kill pid %d" % pid)
475 pid = None
476
357 477 def dedent_run_this_line():
358 478 vim.command("left")
359 479 run_this_line()
360 480 vim.command("silent undo")
361 481
362 482 def dedent_run_these_lines():
363 483 r = vim.current.range
364 484 shiftwidth = vim.eval('&shiftwidth')
365 485 count = int(vim.eval('indent(%d+1)/%s' % (r.start,shiftwidth)))
366 486 vim.command("'<,'>" + "<"*count)
367 487 run_these_lines()
368 488 vim.command("silent undo")
369
489
370 490 #def set_this_line():
371 491 # # not sure if there's a way to do this, since we have multiple clients
372 492 # send("get_ipython().shell.set_next_input(\'%s\')" % vim.current.line.replace("\'","\\\'"))
373 493 # #print "line \'%s\' set at ipython prompt"% vim.current.line
374 494 # echo("line \'%s\' set at ipython prompt"% vim.current.line,'Statement')
375 495
376 496
377 497 def toggle_reselect():
378 498 global reselect
379 499 reselect=not reselect
380 500 print "F9 will%sreselect lines after sending to ipython"% (reselect and " " or " not ")
381 501
382 502 #def set_breakpoint():
383 503 # send("__IP.InteractiveTB.pdb.set_break('%s',%d)" % (vim.current.buffer.name,
384 504 # vim.current.window.cursor[0]))
385 # print "set breakpoint in %s:%d"% (vim.current.buffer.name,
505 # print "set breakpoint in %s:%d"% (vim.current.buffer.name,
386 506 # vim.current.window.cursor[0])
387 #
507 #
388 508 #def clear_breakpoint():
389 509 # send("__IP.InteractiveTB.pdb.clear_break('%s',%d)" % (vim.current.buffer.name,
390 510 # vim.current.window.cursor[0]))
391 511 # print "clearing breakpoint in %s:%d" % (vim.current.buffer.name,
392 512 # vim.current.window.cursor[0])
393 513 #
394 514 #def clear_all_breakpoints():
395 515 # send("__IP.InteractiveTB.pdb.clear_all_breaks()");
396 516 # print "clearing all breakpoints"
397 517 #
398 518 #def run_this_file_pdb():
399 519 # send(' __IP.InteractiveTB.pdb.run(\'execfile("%s")\')' % (vim.current.buffer.name,))
400 520 # #send('run -d %s' % (vim.current.buffer.name,))
401 521 # echo("In[]: run -d %s (using pdb)" % vim.current.buffer.name)
402 522
403 523 EOF
404 524
405 525 fun! <SID>toggle_send_on_save()
406 526 if exists("s:ssos") && s:ssos == 0
407 527 let s:ssos = 1
408 528 au BufWritePost *.py :py run_this_file()
409 529 echo "Autosend On"
410 530 else
411 531 let s:ssos = 0
412 532 au! BufWritePost *.py
413 533 echo "Autosend Off"
414 534 endif
415 535 endfun
416 536
417 " Allow custom mappings
418 if !exists('g:ipy_perform_mappings')
419 let g:ipy_perform_mappings = 1
420 endif
537 " Update the vim-ipython shell when the cursor is not moving.
538 " You can change how quickly this happens after you stop moving the cursor by
539 " setting 'updatetime' (in milliseconds). For example, to have this event
540 " trigger after 1 second:
541 "
542 " :set updatetime 1000
543 "
544 " NOTE: This will only be triggered once, after the first 'updatetime'
545 " milliseconds, *not* every 'updatetime' milliseconds. see :help CursorHold
546 " for more info.
547 "
548 " TODO: Make this easily configurable on the fly, so that an introspection
549 " buffer we may have opened up doesn't get closed just because of an idle
550 " event (i.e. user pressed \d and then left the buffer that popped up, but
551 " expects it to stay there).
552 au CursorHold *.*,vim-ipython :python if update_subchannel_msgs(): echo("vim-ipython shell updated (on idle)",'Operator')
553
554 " XXX: broken - cursor hold update for insert mode moves the cursor one
555 " character to the left of the last character (update_subchannel_msgs must be
556 " doing this)
557 "au CursorHoldI *.* :python if update_subchannel_msgs(): echo("vim-ipython shell updated (on idle)",'Operator')
558
559 " Same as above, but on regaining window focus (mostly for GUIs)
560 au FocusGained *.*,vim-ipython :python if update_subchannel_msgs(): echo("vim-ipython shell updated (on input focus)",'Operator')
561
562 " Update vim-ipython buffer when we move the cursor there. A message is only
563 " displayed if vim-ipython buffer has been updated.
564 au BufEnter vim-ipython :python if update_subchannel_msgs(): echo("vim-ipython shell updated (on buffer enter)",'Operator')
565
421 566 if g:ipy_perform_mappings != 0
422 567 map <silent> <F5> :python run_this_file()<CR>
423 568 map <silent> <S-F5> :python run_this_line()<CR>
424 569 map <silent> <F9> :python run_these_lines()<CR>
425 570 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>
571 map <silent> <leader>s :py if update_subchannel_msgs(force=True): echo("vim-ipython shell updated",'Operator')<CR>
427 572 map <silent> <S-F9> :python toggle_reselect()<CR>
428 573 "map <silent> <C-F6> :python send('%pdb')<CR>
429 574 "map <silent> <F6> :python set_breakpoint()<CR>
430 575 "map <silent> <s-F6> :python clear_breakpoint()<CR>
431 576 "map <silent> <F7> :python run_this_file_pdb()<CR>
432 577 "map <silent> <s-F7> :python clear_all_breaks()<CR>
433 578 imap <C-F5> <C-O><F5>
434 579 imap <S-F5> <C-O><S-F5>
435 580 imap <silent> <F5> <C-O><F5>
436 581 map <C-F5> :call <SID>toggle_send_on_save()<CR>
437 582 "" Example of how to quickly clear the current plot with a keystroke
438 map <silent> <F12> :python run_command("plt.clf()")<cr>
583 "map <silent> <F12> :python run_command("plt.clf()")<cr>
439 584 "" Example of how to quickly close all figures with a keystroke
440 map <silent> <F11> :python run_command("plt.close('all')")<cr>
585 "map <silent> <F11> :python run_command("plt.close('all')")<cr>
441 586
442 587 "pi custom
443 588 map <silent> <C-Return> :python run_this_file()<CR>
444 589 map <silent> <C-s> :python run_this_line()<CR>
445 590 imap <silent> <C-s> <C-O>:python run_this_line()<CR>
446 591 map <silent> <M-s> :python dedent_run_this_line()<CR>
447 592 vmap <silent> <C-S> :python run_these_lines()<CR>
448 593 vmap <silent> <M-s> :python dedent_run_these_lines()<CR>
449 594 map <silent> <M-c> I#<ESC>
450 595 vmap <silent> <M-c> I#<ESC>
451 596 map <silent> <M-C> :s/^\([ \t]*\)#/\1/<CR>
452 597 vmap <silent> <M-C> :s/^\([ \t]*\)#/\1/<CR>
453 598 endif
454 599
455 600 command! -nargs=* IPython :py km_from_string("<args>")
456 601 command! -nargs=0 IPythonClipboard :py km_from_string(vim.eval('@+'))
457 602 command! -nargs=0 IPythonXSelection :py km_from_string(vim.eval('@*'))
603 command! -nargs=0 IPythonInterrupt :py interrupt_kernel_hack()
458 604
459 605 function! IPythonBalloonExpr()
460 606 python << endpython
461 607 word = vim.eval('v:beval_text')
462 608 reply = get_doc(word)
463 609 vim.command("let l:doc = %s"% reply)
464 610 endpython
465 611 return l:doc
466 612 endfunction
467 if has('balloon_eval')
468 set bexpr=IPythonBalloonExpr()
469 set ballooneval
470 endif
471 613
472 614 fun! CompleteIPython(findstart, base)
473 if a:findstart
474 " locate the start of the word
475 let line = getline('.')
476 let start = col('.') - 1
477 while start > 0 && line[start-1] =~ '\k\|\.' "keyword
478 let start -= 1
479 endwhile
615 if a:findstart
616 " locate the start of the word
617 let line = getline('.')
618 let start = col('.') - 1
619 while start > 0 && line[start-1] =~ '\k\|\.' "keyword
620 let start -= 1
621 endwhile
480 622 echo start
481 return start
482 else
483 " find months matching with "a:base"
484 let res = []
623 python << endpython
624 current_line = vim.current.line
625 endpython
626 return start
627 else
628 " find months matching with "a:base"
629 let res = []
485 630 python << endpython
486 631 base = vim.eval("a:base")
487 632 findstart = vim.eval("a:findstart")
488 msg_id = km.shell_channel.complete(base, vim.current.line, vim.eval("col('.')"))
633 msg_id = km.shell_channel.complete(base, current_line, vim.eval("col('.')"))
489 634 try:
490 635 m = get_child_msg(msg_id)
491 636 matches = m['content']['matches']
492 637 matches.insert(0,base) # the "no completion" version
493 638 # we need to be careful with unicode, because we can have unicode
494 639 # completions for filenames (for the %run magic, for example). So the next
495 640 # line will fail on those:
496 641 #completions= [str(u) for u in matches]
497 642 # because str() won't work for non-ascii characters
498 643 # and we also have problems with unicode in vim, hence the following:
499 644 completions = [s.encode(vim_encoding) for s in matches]
500 645 except Empty:
501 646 echo("no reply from IPython kernel")
502 647 completions=['']
503 648 ## Additionally, we have no good way of communicating lists to vim, so we have
504 649 ## to turn in into one long string, which can be problematic if e.g. the
505 650 ## completions contain quotes. The next line will not work if some filenames
506 651 ## contain quotes - but if that's the case, the user's just asking for
507 652 ## it, right?
508 653 #completions = '["'+ '", "'.join(completions)+'"]'
509 654 #vim.command("let completions = %s" % completions)
510 655 ## An alternative for the above, which will insert matches one at a time, so
511 656 ## if there's a problem with turning a match into a string, it'll just not
512 657 ## include the problematic match, instead of not including anything. There's a
513 658 ## bit more indirection here, but I think it's worth it
514 659 for c in completions:
515 660 vim.command('call add(res,"'+c+'")')
516 661 endpython
517 662 "call extend(res,completions)
518 return res
519 endif
520 endfun
521 set completefunc=CompleteIPython
663 return res
664 endif
665 endfun
General Comments 0
You need to be logged in to leave comments. Login now