##// END OF EJS Templates
add ipy_vimserver.py extension, and ipy.vim to doc/examples. Both contributed by Erich Heine
Ville M. Vainio -
Show More
@@ -0,0 +1,239 b''
1 """ Integration with gvim, by Erich Heine
2
3 Provides a %vim magic command, and reuses the same vim session. Uses
4 unix domain sockets for communication between vim and IPython. ipy.vim is
5 available in doc/examples of the IPython distribution.
6
7 Slightly touched up email announcement (and description how to use it) by
8 Erich Heine is here:
9
10 Ive recently been playing with ipython, and like it quite a bit. I did
11 however discover a bit of frustration, namely with editor interaction.
12 I am a gvim user, and using the command edit on a new file causes
13 ipython to try and run that file as soon as the text editor opens
14 up. The -x command of course fixes this, but its still a bit annoying,
15 switching windows to do a run file, then back to the text
16 editor. Being a heavy tab user in gvim, another annoyance is not being
17 able to specify weather a new tab is how I choose to open the file.
18
19 Not being one to shirk my open source duties (and seeing this as a
20 good excuse to poke around ipython internals), Ive created a script
21 for having gvim and ipython work very nicely together. Ive attached
22 both to this email (hoping of course that the mailing list allows such
23 things).
24
25 There are 2 files:
26
27 ipy_vimserver.py -- this file contains the ipython stuff
28 ipy.vim -- this file contains the gvim stuff
29
30 In combination they allow for a few functionalities:
31
32 #1. the vim magic command. This is a fancy wrapper around the edit
33 magic, that allows for a new option, -t, which opens the text in a new
34 gvim tab. Otherwise it works the same as edit -x. (it internally
35 calls edit -x). This magic command also juggles vim server management,
36 so when it is called when there is not a gvim running, it creates a
37 new gvim instance, named after the ipython session name. Once such a
38 gvim instance is running, it will be used for subsequent uses of the
39 vim command.
40
41 #2. ipython - gvim interaction. Once a file has been opened with the
42 vim magic (and a session set up, see below), pressing the F5 key in
43 vim will cause the calling ipython instance to execute run
44 filename.py. (if you typo like I do, this is very useful)
45
46 #3. ipython server - this is a thread wich listens on a unix domain
47 socket, and runs commands sent to that socket.
48
49 Note, this only works on POSIX systems, that allow for AF_UNIX type
50 sockets. It has only been tested on linux (a fairly recent debian
51 testing distro).
52
53 To install it put, the ipserver.py in your favorite locaion for
54 sourcing ipython scripts. I put the ipy.vim in
55 ~/.vim/after/ftplugin/python/.
56
57 To use (this can be scripted im sure, but i usually have 2 or 3
58 ipythons and corresponding gvims open):
59
60 import ipy_vimserver
61 ipy_vimserver.setup('sessionname')
62
63 (Editors note - you can probably add these to your ipy_user_conf.py)
64
65 Then use ipython as you normally would, until you need to edit
66 something. Instead of edit, use the vim magic. Thats it!
67
68 """
69
70 import IPython.ipapi
71 #import ipythonhooks
72 import socket, select
73 import os, threading, subprocess
74 import re
75
76 ERRCONDS = select.POLLHUP|select.POLLERR
77 SERVER = None
78 ip = IPython.ipapi.get()
79
80 # this listens to a unix domain socket in a separate thread, so that comms
81 # between a vim instance and ipython can happen in a fun and productive way
82 class IpyServer(threading.Thread):
83 def __init__(self, sname):
84 super(IpyServer, self).__init__()
85 self.keep_running = True
86 self.__sname = sname
87 self.socket = socket.socket(socket.AF_UNIX)
88 self.poller = select.poll()
89 self.current_conns = dict()
90 self.setDaemon(True)
91
92 def listen(self):
93 self.socket.bind(self.__sname)
94 self.socket.listen(1)
95
96 def __handle_error(self, socket):
97 if socket == self.socket.fileno():
98 self.keep_running = False
99 for a in self.current_conns.values():
100 a.close()
101 return False
102 else:
103 y = self.current_conns[socket]
104 del self.current_conns[socket]
105 y.close()
106 self.poller.unregister(socket)
107
108 def serve_me(self):
109 self.listen()
110 self.poller.register(self.socket,select.POLLIN|ERRCONDS)
111
112 while self.keep_running:
113 try:
114 avail = self.poller.poll(1)
115 except:
116 continue
117
118 if not avail: continue
119
120 for sock, conds in avail:
121 if conds & (ERRCONDS):
122 if self.__handle_error(sock): continue
123 else: break
124
125 if sock == self.socket.fileno():
126 y = self.socket.accept()[0]
127 self.poller.register(y, select.POLLIN|ERRCONDS)
128 self.current_conns[y.fileno()] = y
129 else: y = self.current_conns.get(sock)
130
131 self.handle_request(y)
132
133 os.remove(self.__sname)
134
135 run = serve_me
136
137 def stop(self):
138 self.keep_running = False
139
140 def handle_request(self,sock):
141 sock.settimeout(1)
142 while self.keep_running:
143 try:
144 x = sock.recv(4096)
145 except socket.timeout:
146 pass
147 else:
148 break
149 self.do_it(x)
150
151 def do_it(self, data):
152 data = data.split('\n')
153 cmds = list()
154 for line in data:
155 cmds.append(line)
156 ip.runlines(cmds)
157
158
159 # try to help ensure that the unix domain socket is cleaned up proper
160 def shutdown_server(self):
161 if SERVER:
162 SERVER.stop()
163 SERVER.join(3)
164 raise IPython.ipapi.TryNext
165
166 ip.set_hook('shutdown_hook', shutdown_server, 10)
167
168 # this fun function exists to make setup easier for all, and makes the
169 # vimhook function ready for instance specific communication
170 def setup(sessionname='',socketdir=os.path.expanduser('~/.ipython/')):
171 global SERVER
172
173 if sessionname:
174 session = sessionname
175 elif os.environ.get('IPY_SESSION'):
176 session = os.environ.get('IPY_SESSION')
177 else:
178 session = 'IPYS'
179 vimhook.vimserver=session
180 vimhook.ipyserver = os.path.join(socketdir, session)
181 if not SERVER:
182 SERVER = IpyServer(vimhook.ipyserver)
183 SERVER.start()
184
185
186
187 # calls gvim, with all ops happening on the correct gvim instance for this
188 # ipython instance. it then calls edit -x (since gvim will return right away)
189 # things of note: it sets up a special environment, so that the ipy.vim script
190 # can connect back to the ipython instance and do fun things, like run the file
191 def vimhook(self, fname, line):
192 env = os.environ.copy()
193 vserver = vimhook.vimserver.upper()
194 check = subprocess.Popen('gvim --serverlist', stdout = subprocess.PIPE,
195 shell=True)
196 check.wait()
197 cval = [l for l in check.stdout.readlines() if vserver in l]
198
199 if cval:
200 vimargs = '--remote%s' % (vimhook.extras,)
201 else:
202 vimargs = ''
203 vimhook.extras = ''
204
205 env['IPY_SESSION'] = vimhook.vimserver
206 env['IPY_SERVER'] = vimhook.ipyserver
207
208 if line is None: line = ''
209 else: line = '+' + line
210 vim_cmd = 'gvim --servername %s %s %s %s' % (vimhook.vimserver, vimargs,
211 line, fname)
212 subprocess.call(vim_cmd, env=env, shell=True)
213
214
215 #default values to keep it sane...
216 vimhook.vimserver = ''
217 vimhook.ipyserver = ''
218
219 ip.set_hook('editor',vimhook)
220
221 # this is set up so more vim specific commands can be added, instead of just
222 # the current -t. all thats required is a compiled regex, a call to do_arg(pat)
223 # and the logic to deal with the new feature
224 newtab = re.compile(r'-t(?:\s|$)')
225 def vim(self, argstr):
226 def do_arg(pat, rarg):
227 x = len(pat.findall(argstr))
228 if x:
229 a = pat.sub('',argstr)
230 return rarg, a
231 else: return '', argstr
232
233 t, argstr = do_arg(newtab, '-tab')
234 vimhook.extras = t
235 argstr = 'edit -x ' + argstr
236 ip.magic(argstr)
237
238 ip.expose_magic('vim', vim)
239
@@ -0,0 +1,67 b''
1 if !exists("$IPY_SESSION")
2 finish
3 endif
4
5 " set up the python interpreter within vim, to have all the right modules
6 " imported, as well as certain useful globals set
7 python import socket
8 python import os
9 python import vim
10 python IPYSERVER = None
11
12 python << EOF
13 # do we have a connection to the ipython instance?
14 def check_server():
15 global IPYSERVER
16 if IPYSERVER:
17 return True
18 else:
19 return False
20
21 # connect to the ipython server, if we need to
22 def connect():
23 global IPYSERVER
24 if check_server():
25 return
26 try:
27 IPYSERVER = socket.socket(socket.AF_UNIX)
28 IPYSERVER.connect(os.environ.get('IPY_SERVER'))
29 except:
30 IPYSERVER = None
31
32 def disconnect():
33 if IPYSERVER:
34 IPYSERVER.close()
35
36 def send(cmd):
37 x = 0
38 while True:
39 x += IPYSERVER.send(cmd)
40 if x < len(cmd):
41 cmd = cmd[x:]
42 else:
43 break
44
45 def run_this_file():
46 if check_server():
47 send('run %s' % (vim.current.buffer.name,))
48 else:
49 raise Exception, "Not connected to an IPython server"
50 EOF
51
52 fun! <SID>toggle_send_on_save()
53 if exists("s:ssos") && s:ssos == 1
54 let s:ssos = 0
55 au! BufWritePost *.py :py run_this_file()
56 echo "Autosend Off"
57 else
58 let s:ssos = 1
59 au BufWritePost *.py :py run_this_file()
60 echo "Autowsend On"
61 endif
62 endfun
63
64 map <silent> <F5> :python run_this_file()<CR>
65 imap <silent> <C-F5> <ESC><F5>a
66 map <F7> :call <SID>toggle_send_on_save()<CR>
67 py connect()
General Comments 0
You need to be logged in to leave comments. Login now