Show More
@@ -0,0 +1,107 b'' | |||
|
1 | ########### | |
|
2 | vim-ipython | |
|
3 | ########### | |
|
4 | ||
|
5 | A two-way integration between Vim and IPython 0.11+ | |
|
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/ | |
|
12 | ||
|
13 | Using this plugin, you can send lines or whole files for IPython to | |
|
14 | execute, and also get back object introspection and word completions in | |
|
15 | Vim, like what you get with: ``object?<enter>`` and ``object.<tab>`` in | |
|
16 | IPython. | |
|
17 | ||
|
18 | The big change from previous versions of ``ipy.vim`` is that it no longer | |
|
19 | the old requires the brittle ipy_vimserver.py instantiation, and since | |
|
20 | it uses just vim and python, it is platform independent (i.e. should work | |
|
21 | even on windows, unlike the previous \*nix only solution) | |
|
22 | ||
|
23 | ||
|
24 | ----------------- | |
|
25 | Quickstart Guide: | |
|
26 | ----------------- | |
|
27 | Start ``ipython qtconsole`` and copy the connection string. | |
|
28 | Source ``ipy.vim`` file, which provides new IPython command:: | |
|
29 | ||
|
30 | :source ipy.vim | |
|
31 | (or copy it to ~/.vim/ftplugin/python to load automatically) | |
|
32 | ||
|
33 | :IPythonClipboard | |
|
34 | (or :IPythonXSelection if you're using X11 without having to copy) | |
|
35 | ||
|
36 | The :IPython command allows you to put the full string, e.g.:: | |
|
37 | ||
|
38 | :IPython --existing --shell=41882 --iopub=43286 --stdin=34987 --hb=36697 | |
|
39 | ||
|
40 | The ``:IPythonClipboard`` command just uses the ``+`` register to get the | |
|
41 | connection string, whereas ``:IPythonXSelection`` uses the ``*`` register | |
|
42 | ||
|
43 | ------------------------ | |
|
44 | Sending lines to IPython | |
|
45 | ------------------------ | |
|
46 | Now type out a line and send it to IPython using ``<Ctrl-S>`` from Command mode:: | |
|
47 | ||
|
48 | import os | |
|
49 | ||
|
50 | You should see a notification message confirming the line was sent, along | |
|
51 | with the input number for the line, like so ``In[1]: import os``. | |
|
52 | ||
|
53 | ``<Ctrl-S>`` also works from insert mode, but doesn't show notification | |
|
54 | ||
|
55 | It also works blockwise in Visual Mode. Strip the leading double quotes and | |
|
56 | send these lines using ``<Ctrl-S>``:: | |
|
57 | ||
|
58 | import this,math # secret decoder ring | |
|
59 | a,b,c,d,e,f,g,h,i = range(1,10) | |
|
60 | code =(c,a,d,a,e,i,) | |
|
61 | msg = '...jrer nyy frag sebz Ivz.\nIvz+VClguba=%fyl '+this.s.split()[g] | |
|
62 | decode=lambda x:"\n"+"".join([this.d.get(c,c) for c in x])+"!" | |
|
63 | format=lambda x:'These lines:\n '+'\n '.join([l for l in x.splitlines()]) | |
|
64 | secret_decoder = lambda a,b: format(a)+decode(msg)%str(b)[:-1] | |
|
65 | '%d'*len(code)%code == str(int(math.pi*1e5)) | |
|
66 | ||
|
67 | Then, go to the qtconsole and run this line:: | |
|
68 | ||
|
69 | print secret_decoder(_i,_) | |
|
70 | ||
|
71 | You can also send whole files to IPython's ``%run`` magic using ``<F5>``. | |
|
72 | ||
|
73 | ------------------------------- | |
|
74 | IPython's object? Functionality | |
|
75 | ------------------------------- | |
|
76 | ||
|
77 | If you're using gvim, mouse-over a variable to see IPython's ? equivalent. If | |
|
78 | you're using vim from a terminal, or want to copy something from the | |
|
79 | docstring, type ``<leader>d``. ``<leader>`` is usually ``\`` (the backslash | |
|
80 | key). This will open a quickpreview window, which can be closed by hitting | |
|
81 | ``q`` or ``<escape>``. | |
|
82 | ||
|
83 | -------------------------------------- | |
|
84 | IPython's tab-completion Functionality | |
|
85 | -------------------------------------- | |
|
86 | vim-ipython activates a 'completefunc' that queries IPython. | |
|
87 | A completefunc is activated using ``Ctrl-X Ctrl-U`` in Insert Mode (vim | |
|
88 | default). You can combine this functionality with SuperTab to get tab | |
|
89 | completion | |
|
90 | ||
|
91 | --------------- | |
|
92 | Current issues: | |
|
93 | --------------- | |
|
94 | For now, vim-ipython only connects to an ipython session in progress. | |
|
95 | ||
|
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) | |
|
98 | ||
|
99 | The ipdb integration is not yet re-implemented. | |
|
100 | ||
|
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). | |
|
103 | ||
|
104 | ------ | |
|
105 | Thanks | |
|
106 | ------ | |
|
107 | @MinRK for guiding me through the IPython kernel manager protocol. |
@@ -0,0 +1,343 b'' | |||
|
1 | " Vim integration with IPython 0.11+ | |
|
2 | " | |
|
3 | " A two-way integration between Vim and IPython. | |
|
4 | " | |
|
5 | " Using this plugin, you can send lines or whole files for IPython to execute, | |
|
6 | " and also get back object introspection and word completions in Vim, like | |
|
7 | " what you get with: object?<enter> object.<tab> in IPython | |
|
8 | " | |
|
9 | " ----------------- | |
|
10 | " Quickstart Guide: | |
|
11 | " ----------------- | |
|
12 | " Start ipython qtconsole and copy the connection string. | |
|
13 | " Source this file, which provides new IPython command | |
|
14 | " :source ipy.vim | |
|
15 | " :IPythonClipboard | |
|
16 | " (or :IPythonXSelection if you're using X11 without having to copy) | |
|
17 | " | |
|
18 | " written by Paul Ivanov (http://pirsquared.org) | |
|
19 | python << EOF | |
|
20 | import time | |
|
21 | import vim | |
|
22 | import sys | |
|
23 | ||
|
24 | try: | |
|
25 | sys.stdout.flush | |
|
26 | except AttributeError: | |
|
27 | # IPython complains if stderr and stdout don't have flush | |
|
28 | # this is fixed in newer version of Vim | |
|
29 | class WithFlush(object): | |
|
30 | def __init__(self,noflush): | |
|
31 | self.write=noflush.write | |
|
32 | self.writelines=noflush.writelines | |
|
33 | def flush(self):pass | |
|
34 | sys.stdout = WithFlush(sys.stdout) | |
|
35 | sys.stderr = WithFlush(sys.stderr) | |
|
36 | ||
|
37 | from IPython.zmq.blockingkernelmanager import BlockingKernelManager | |
|
38 | ||
|
39 | from IPython.config.loader import KeyValueConfigLoader | |
|
40 | from IPython.zmq.kernelapp import kernel_aliases | |
|
41 | ||
|
42 | ||
|
43 | ip = '127.0.0.1' | |
|
44 | try: | |
|
45 | km | |
|
46 | except NameError: | |
|
47 | km = None | |
|
48 | ||
|
49 | def km_from_string(s): | |
|
50 | """create kernel manager from IPKernelApp string | |
|
51 | such as '--shell=47378 --iopub=39859 --stdin=36778 --hb=52668' | |
|
52 | """ | |
|
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 | |
|
68 | km.start_channels() | |
|
69 | send = km.shell_channel.execute | |
|
70 | return km | |
|
71 | ||
|
72 | ||
|
73 | reselect = False | |
|
74 | show_id= True | |
|
75 | run_flags= "-i" | |
|
76 | ||
|
77 | def echo(arg,style="Question"): | |
|
78 | try: | |
|
79 | vim.command("echohl %s" % style) | |
|
80 | vim.command("echom \"%s\"" % arg.replace('\"','\\\"')) | |
|
81 | vim.command("echohl None") | |
|
82 | except vim.error: | |
|
83 | print "-- %s" % arg | |
|
84 | ||
|
85 | def disconnect(): | |
|
86 | "disconnect kernel manager" | |
|
87 | # XXX: make a prompt here if this km owns the kernel | |
|
88 | pass | |
|
89 | ||
|
90 | def get_doc(word): | |
|
91 | msg_id = km.shell_channel.object_info(word) | |
|
92 | time.sleep(.1) | |
|
93 | doc = get_doc_msg(msg_id) | |
|
94 | #if len(doc): | |
|
95 | # echo(word, 'Special') | |
|
96 | return doc | |
|
97 | ||
|
98 | import re | |
|
99 | # from http://serverfault.com/questions/71285/in-centos-4-4-how-can-i-strip-escape-sequences-from-a-text-file | |
|
100 | strip = re.compile('\x1B\[([0-9]{1,2}(;[0-9]{1,2})?)?[m|K]') | |
|
101 | def strip_color_escapes(s): | |
|
102 | return strip.sub('',s) | |
|
103 | ||
|
104 | 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) | |
|
108 | b=[] | |
|
109 | ||
|
110 | if not content['found']: | |
|
111 | return b | |
|
112 | ||
|
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 | for field in ['type_name','base_class','string_form','namespace', | |
|
122 | 'file','length','definition','source','docstring']: | |
|
123 | # XXX: strip the 'definition' rich formatting | |
|
124 | c = content.get(field,None) | |
|
125 | if c: | |
|
126 | if field in ['definition']: | |
|
127 | c = strip_color_escapes(c).rstrip() | |
|
128 | s = field.replace('_',' ').title()+':' | |
|
129 | s = s.ljust(n) | |
|
130 | if c.find('\n')==-1: | |
|
131 | b.append(s+c) | |
|
132 | else: | |
|
133 | b.append(s) | |
|
134 | b.extend(c.splitlines()) | |
|
135 | return b | |
|
136 | ||
|
137 | def get_doc_buffer(level=0): | |
|
138 | word = vim.eval('expand("<cfile>")') | |
|
139 | doc = get_doc(word) | |
|
140 | if len(doc) ==0: | |
|
141 | echo(word+" not found","Error") | |
|
142 | return | |
|
143 | vim.command('pcl') | |
|
144 | vim.command('new '+word) | |
|
145 | vim.command('setlocal pvw modifiable noro') | |
|
146 | vim.command('map <buffer> q :q<CR>') | |
|
147 | vim.command('map <buffer> :q<CR>') | |
|
148 | #vim.command('pedit '+docbuf.name) | |
|
149 | b = vim.current.buffer | |
|
150 | #b.append(doc) | |
|
151 | b[:] = doc | |
|
152 | #b.append(doc) | |
|
153 | vim.command('setlocal nomodified bufhidden=wipe') | |
|
154 | #vim.command('setlocal previewwindow nomodifiable nomodified ro') | |
|
155 | #vim.command('set previewheight=%d'%len(b))# go to previous window | |
|
156 | vim.command('resize %d'%len(b)) | |
|
157 | #vim.command('pcl') | |
|
158 | #vim.command('pedit doc') | |
|
159 | #vim.command('normal ') # go to previous window | |
|
160 | ||
|
161 | def get_child_msgs(msg_id): | |
|
162 | # 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 | |
|
166 | ||
|
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 | 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'] | |
|
180 | echo("In[%d]: %s" %(count,prompt)) | |
|
181 | else: | |
|
182 | echo("In[]: %s (no reply from kernel)" % prompt) | |
|
183 | else: | |
|
184 | echo("In[]: %s" % prompt) | |
|
185 | ||
|
186 | def run_this_line(): | |
|
187 | msg_id = send(vim.current.line) | |
|
188 | print_prompt(vim.current.line, msg_id) | |
|
189 | ||
|
190 | def run_these_lines(): | |
|
191 | r = vim.current.range | |
|
192 | lines = "\n".join(vim.current.buffer[r.start:r.end+1]) | |
|
193 | msg_id = send(lines) | |
|
194 | #alternative way of doing this in more recent versions of ipython | |
|
195 | #but %paste only works on the local machine | |
|
196 | #vim.command("\"*yy") | |
|
197 | #send("'%paste')") | |
|
198 | #reselect the previously highlighted block | |
|
199 | vim.command("normal gv") | |
|
200 | if not reselect: | |
|
201 | vim.command("normal ") | |
|
202 | ||
|
203 | #vim lines start with 1 | |
|
204 | #print "lines %d-%d sent to ipython"% (r.start+1,r.end+1) | |
|
205 | prompt = "lines %d-%d "% (r.start+1,r.end+1) | |
|
206 | print_prompt(prompt,msg_id) | |
|
207 | ||
|
208 | def dedent_run_this_line(): | |
|
209 | vim.command("left") | |
|
210 | run_this_line() | |
|
211 | vim.command("undo") | |
|
212 | ||
|
213 | def dedent_run_these_lines(): | |
|
214 | vim.command("'<,'>left") | |
|
215 | run_these_lines() | |
|
216 | vim.command("undo") | |
|
217 | ||
|
218 | #def set_this_line(): | |
|
219 | # # 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("\'","\\\'")) | |
|
221 | # #print "line \'%s\' set at ipython prompt"% vim.current.line | |
|
222 | # echo("line \'%s\' set at ipython prompt"% vim.current.line,'Statement') | |
|
223 | ||
|
224 | ||
|
225 | def toggle_reselect(): | |
|
226 | global reselect | |
|
227 | reselect=not reselect | |
|
228 | print "F9 will%sreselect lines after sending to ipython"% (reselect and " " or " not ") | |
|
229 | ||
|
230 | #def set_breakpoint(): | |
|
231 | # send("__IP.InteractiveTB.pdb.set_break('%s',%d)" % (vim.current.buffer.name, | |
|
232 | # vim.current.window.cursor[0])) | |
|
233 | # print "set breakpoint in %s:%d"% (vim.current.buffer.name, | |
|
234 | # vim.current.window.cursor[0]) | |
|
235 | # | |
|
236 | #def clear_breakpoint(): | |
|
237 | # send("__IP.InteractiveTB.pdb.clear_break('%s',%d)" % (vim.current.buffer.name, | |
|
238 | # vim.current.window.cursor[0])) | |
|
239 | # print "clearing breakpoint in %s:%d" % (vim.current.buffer.name, | |
|
240 | # vim.current.window.cursor[0]) | |
|
241 | # | |
|
242 | #def clear_all_breakpoints(): | |
|
243 | # send("__IP.InteractiveTB.pdb.clear_all_breaks()"); | |
|
244 | # print "clearing all breakpoints" | |
|
245 | # | |
|
246 | #def run_this_file_pdb(): | |
|
247 | # send(' __IP.InteractiveTB.pdb.run(\'execfile("%s")\')' % (vim.current.buffer.name,)) | |
|
248 | # #send('run -d %s' % (vim.current.buffer.name,)) | |
|
249 | # echo("In[]: run -d %s (using pdb)" % vim.current.buffer.name) | |
|
250 | ||
|
251 | EOF | |
|
252 | ||
|
253 | fun! <SID>toggle_send_on_save() | |
|
254 | if exists("s:ssos") && s:ssos == 0 | |
|
255 | let s:ssos = 1 | |
|
256 | au BufWritePost *.py :py run_this_file() | |
|
257 | echo "Autosend On" | |
|
258 | else | |
|
259 | let s:ssos = 0 | |
|
260 | au! BufWritePost *.py | |
|
261 | echo "Autosend Off" | |
|
262 | endif | |
|
263 | endfun | |
|
264 | ||
|
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>") | |
|
293 | command! -nargs=0 IPythonClipboard :py km_from_string(vim.eval('@+')) | |
|
294 | command! -nargs=0 IPythonXSelection :py km_from_string(vim.eval('@*')) | |
|
295 | ||
|
296 | function! IPythonBalloonExpr() | |
|
297 | python << endpython | |
|
298 | word = vim.eval('v:beval_text') | |
|
299 | reply = get_doc(word) | |
|
300 | #reply = reply[:40] | |
|
301 | vim.command("let l:doc = %s"% reply) | |
|
302 | endpython | |
|
303 | return l:doc | |
|
304 | endfunction | |
|
305 | set bexpr=IPythonBalloonExpr() | |
|
306 | set ballooneval | |
|
307 | ||
|
308 | fun! CompleteIPython(findstart, base) | |
|
309 | if a:findstart | |
|
310 | " locate the start of the word | |
|
311 | let line = getline('.') | |
|
312 | let start = col('.') - 1 | |
|
313 | while start > 0 && line[start-1] =~ '\k\|\.' "keyword | |
|
314 | let start -= 1 | |
|
315 | endwhile | |
|
316 | echo start | |
|
317 | return start | |
|
318 | else | |
|
319 | " find months matching with "a:base" | |
|
320 | let res = [] | |
|
321 | python << endpython | |
|
322 | base = vim.eval("a:base") | |
|
323 | findstart = vim.eval("a:findstart") | |
|
324 | 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) | |
|
334 | endpython | |
|
335 | for m in l:completions | |
|
336 | "if m =~ '^' . a:base | |
|
337 | call add(res, m) | |
|
338 | "endif | |
|
339 | endfor | |
|
340 | return res | |
|
341 | endif | |
|
342 | endfun | |
|
343 | set completefunc=CompleteIPython |
|
1 | NO CONTENT: file was removed |
General Comments 0
You need to be logged in to leave comments.
Login now