diff --git a/docs/examples/core/ipy.vim b/docs/examples/core/ipy.vim deleted file mode 100644 index bb9e623..0000000 --- a/docs/examples/core/ipy.vim +++ /dev/null @@ -1,143 +0,0 @@ -if !exists("$IPY_SESSION") - finish -endif - -" set up the python interpreter within vim, to have all the right modules -" imported, as well as certain useful globals set -python import socket -python import os -python import vim -python from IPython.core.debugger import Pdb -python IPYSERVER = None -python reselect = True - -python << EOF -# do we have a connection to the ipython instance? -def check_server(): - global IPYSERVER - if IPYSERVER: - return True - else: - return False - -# connect to the ipython server, if we need to -def connect(): - global IPYSERVER - if check_server(): - return - try: - IPYSERVER = socket.socket(socket.AF_UNIX) - IPYSERVER.connect(os.environ.get('IPY_SERVER')) - except: - IPYSERVER = None - -def disconnect(): - if IPYSERVER: - IPYSERVER.close() - -def send(cmd): - x = 0 - while True: - x += IPYSERVER.send(cmd) - if x < len(cmd): - cmd = cmd[x:] - else: - break - -def run_this_file(): - if check_server(): - send('run %s' % (vim.current.buffer.name,)) - else: - raise Exception, "Not connected to an IPython server" - print "\'run %s\' sent to ipython" % vim.current.buffer.name - -def run_this_line(): - if check_server(): - send(vim.current.line) - print "line \'%s\' sent to ipython"% vim.current.line - else: - raise Exception, "Not connected to an IPython server" - -def run_these_lines(): - r = vim.current.range - if check_server(): - #send(str((vim.current.range.start,vim.current.range.end))) - for l in vim.current.buffer[r.start:r.end+1]: - send(str(l)+'\n') - #send(str(vim.current.buffer[vim.current.range.start:vim.current.range.end]).join("\n")) - #print "lines %d-%d sent to ipython"% (r.start,r.end) - else: - raise Exception, "Not connected to an IPython server" - - #reselect the previously highlighted block - if reselect: - vim.command("normal gv") - #vim lines start with 1 - print "lines %d-%d sent to ipython"% (r.start+1,r.end+1) - -def toggle_reselect(): - global reselect - reselect=not reselect - print "F9 will%sreselect lines after sending to ipython"% (reselect and " " or " not ") - -def set_breakpoint(): - if check_server(): - send("__IP.InteractiveTB.pdb.set_break('%s',%d)" % (vim.current.buffer.name, - vim.current.window.cursor[0])) - print "set breakpoint in %s:%d"% (vim.current.buffer.name, - vim.current.window.cursor[0]) - else: - raise Exception, "Not connected to an IPython server" - -def clear_breakpoint(): - if check_server(): - send("__IP.InteractiveTB.pdb.clear_break('%s',%d)" % (vim.current.buffer.name, - vim.current.window.cursor[0])) - print "clearing breakpoint in %s:%d" % (vim.current.buffer.name, - vim.current.window.cursor[0]) - else: - raise Exception, "Not connected to an IPython server" - -def clear_all_breakpoints(): - if check_server(): - send("__IP.InteractiveTB.pdb.clear_all_breaks()"); - print "clearing all breakpoints" - else: - raise Exception, "Not connected to an IPython server" - -def run_this_file_pdb(): - if check_server(): - send(' __IP.InteractiveTB.pdb.run(\'execfile("%s")\')' % (vim.current.buffer.name,)) - else: - raise Exception, "Not connected to an IPython server" - print "\'run %s\' using pdb sent to ipython" % vim.current.buffer.name - - #XXX: have IPYSERVER print the prompt (look at Leo example) -EOF - -fun! toggle_send_on_save() - if exists("s:ssos") && s:ssos == 1 - let s:ssos = 0 - au! BufWritePost *.py :py run_this_file() - echo "Autosend Off" - else - let s:ssos = 1 - au BufWritePost *.py :py run_this_file() - echo "Autowsend On" - endif -endfun - -map :python run_this_file() -map :python run_this_line() -map :python run_these_lines() -map :python toggle_reselect() -map :python send('%pdb') -map :python set_breakpoint() -map :python clear_breakpoint() -map :python run_this_file_pdb() -map :python clear_all_breaks() -imap a -imap a -imap a -map :call toggle_send_on_save() -py connect() diff --git a/docs/examples/vim/README.rst b/docs/examples/vim/README.rst new file mode 100644 index 0000000..8268636 --- /dev/null +++ b/docs/examples/vim/README.rst @@ -0,0 +1,107 @@ +########### +vim-ipython +########### + +A two-way integration between Vim and IPython 0.11+ + +author: Paul Ivanov (http://pirsquared.org) + +github: http://github.com/ivanov/vim-ipython + +demo: http://pirsquared.org/vim-ipython/ + +Using this plugin, you can send lines or whole files for IPython to +execute, and also get back object introspection and word completions in +Vim, like what you get with: ``object?`` and ``object.`` in +IPython. + +The big change from previous versions of ``ipy.vim`` is that it no longer +the old requires the brittle ipy_vimserver.py instantiation, and since +it uses just vim and python, it is platform independent (i.e. should work +even on windows, unlike the previous \*nix only solution) + + +----------------- +Quickstart Guide: +----------------- +Start ``ipython qtconsole`` and copy the connection string. +Source ``ipy.vim`` file, which provides new IPython command:: + + :source ipy.vim + (or copy it to ~/.vim/ftplugin/python to load automatically) + + :IPythonClipboard + (or :IPythonXSelection if you're using X11 without having to copy) + +The :IPython command allows you to put the full string, e.g.:: + + :IPython --existing --shell=41882 --iopub=43286 --stdin=34987 --hb=36697 + +The ``:IPythonClipboard`` command just uses the ``+`` register to get the +connection string, whereas ``:IPythonXSelection`` uses the ``*`` register + +------------------------ +Sending lines to IPython +------------------------ +Now type out a line and send it to IPython using ```` from Command mode:: + + import os + +You should see a notification message confirming the line was sent, along +with the input number for the line, like so ``In[1]: import os``. + +```` also works from insert mode, but doesn't show notification + +It also works blockwise in Visual Mode. Strip the leading double quotes and +send these lines using ````:: + + import this,math # secret decoder ring + a,b,c,d,e,f,g,h,i = range(1,10) + code =(c,a,d,a,e,i,) + msg = '...jrer nyy frag sebz Ivz.\nIvz+VClguba=%fyl '+this.s.split()[g] + decode=lambda x:"\n"+"".join([this.d.get(c,c) for c in x])+"!" + format=lambda x:'These lines:\n '+'\n '.join([l for l in x.splitlines()]) + secret_decoder = lambda a,b: format(a)+decode(msg)%str(b)[:-1] + '%d'*len(code)%code == str(int(math.pi*1e5)) + +Then, go to the qtconsole and run this line:: + + print secret_decoder(_i,_) + +You can also send whole files to IPython's ``%run`` magic using ````. + +------------------------------- +IPython's object? Functionality +------------------------------- + +If you're using gvim, mouse-over a variable to see IPython's ? equivalent. If +you're using vim from a terminal, or want to copy something from the +docstring, type ``d``. ```` is usually ``\`` (the backslash +key). This will open a quickpreview window, which can be closed by hitting +``q`` or ````. + +-------------------------------------- +IPython's tab-completion Functionality +-------------------------------------- +vim-ipython activates a 'completefunc' that queries IPython. +A completefunc is activated using ``Ctrl-X Ctrl-U`` in Insert Mode (vim +default). You can combine this functionality with SuperTab to get tab +completion + +--------------- +Current issues: +--------------- +For now, vim-ipython only connects to an ipython session in progress. + +ipy.vim takes a while to load, I'll eventually move the python code to its +own file and do a lazy import (only when the IPython command is called) + +The ipdb integration is not yet re-implemented. + +Need to add more message handling for sub_channel messages from IPython +(i.e. notification of changes which were not sent from vim). + +------ +Thanks +------ +@MinRK for guiding me through the IPython kernel manager protocol. diff --git a/docs/examples/vim/ipy.vim b/docs/examples/vim/ipy.vim new file mode 100644 index 0000000..943bf6b --- /dev/null +++ b/docs/examples/vim/ipy.vim @@ -0,0 +1,343 @@ +" Vim integration with IPython 0.11+ +" +" A two-way integration between Vim and IPython. +" +" Using this plugin, you can send lines or whole files for IPython to execute, +" and also get back object introspection and word completions in Vim, like +" what you get with: object? object. in IPython +" +" ----------------- +" Quickstart Guide: +" ----------------- +" Start ipython qtconsole and copy the connection string. +" Source this file, which provides new IPython command +" :source ipy.vim +" :IPythonClipboard +" (or :IPythonXSelection if you're using X11 without having to copy) +" +" written by Paul Ivanov (http://pirsquared.org) +python << EOF +import time +import vim +import sys + +try: + sys.stdout.flush +except AttributeError: + # IPython complains if stderr and stdout don't have flush + # this is fixed in newer version of Vim + class WithFlush(object): + def __init__(self,noflush): + self.write=noflush.write + self.writelines=noflush.writelines + def flush(self):pass + sys.stdout = WithFlush(sys.stdout) + sys.stderr = WithFlush(sys.stderr) + +from IPython.zmq.blockingkernelmanager import BlockingKernelManager + +from IPython.config.loader import KeyValueConfigLoader +from IPython.zmq.kernelapp import kernel_aliases + + +ip = '127.0.0.1' +try: + km +except NameError: + km = None + +def km_from_string(s): + """create kernel manager from IPKernelApp string + such as '--shell=47378 --iopub=39859 --stdin=36778 --hb=52668' + """ + global km,send + # vim interface currently only deals with existing kernels + s = s.replace('--existing','') + loader = KeyValueConfigLoader(s.split(), aliases=kernel_aliases) + cfg = loader.load_config()['KernelApp'] + try: + km = BlockingKernelManager( + shell_address=(ip, cfg['shell_port']), + sub_address=(ip, cfg['iopub_port']), + stdin_address=(ip, cfg['stdin_port']), + hb_address=(ip, cfg['hb_port'])) + except KeyError,e: + echo(":IPython " +s + " failed", "Info") + echo("^-- failed --"+e.message.replace('_port','')+" not specified", "Error") + return + km.start_channels() + send = km.shell_channel.execute + return km + + +reselect = False +show_id= True +run_flags= "-i" + +def echo(arg,style="Question"): + try: + vim.command("echohl %s" % style) + vim.command("echom \"%s\"" % arg.replace('\"','\\\"')) + vim.command("echohl None") + except vim.error: + print "-- %s" % arg + +def disconnect(): + "disconnect kernel manager" + # XXX: make a prompt here if this km owns the kernel + pass + +def get_doc(word): + msg_id = km.shell_channel.object_info(word) + time.sleep(.1) + doc = get_doc_msg(msg_id) + #if len(doc): + # echo(word, 'Special') + return doc + +import re +# from http://serverfault.com/questions/71285/in-centos-4-4-how-can-i-strip-escape-sequences-from-a-text-file +strip = re.compile('\x1B\[([0-9]{1,2}(;[0-9]{1,2})?)?[m|K]') +def strip_color_escapes(s): + return strip.sub('',s) + +def get_doc_msg(msg_id): + content = get_child_msgs(msg_id)[0]['content'] + n = 13 # longest field name + ##XXX: debug (print the whole message) + b=[] + + if not content['found']: + return b + + ## debugging the whole message + #for k in content: + # if isinstance(content[k],str) and content[k].find('\n')!=-1: + # b.append(k.ljust(n)+":") + # b.append(content[k].splitlines()) + # else: + # b.append(k.ljust(n)+":"+str(content[k])) + + for field in ['type_name','base_class','string_form','namespace', + 'file','length','definition','source','docstring']: + # XXX: strip the 'definition' rich formatting + c = content.get(field,None) + if c: + if field in ['definition']: + c = strip_color_escapes(c).rstrip() + s = field.replace('_',' ').title()+':' + s = s.ljust(n) + if c.find('\n')==-1: + b.append(s+c) + else: + b.append(s) + b.extend(c.splitlines()) + return b + +def get_doc_buffer(level=0): + word = vim.eval('expand("")') + doc = get_doc(word) + if len(doc) ==0: + echo(word+" not found","Error") + return + vim.command('pcl') + vim.command('new '+word) + vim.command('setlocal pvw modifiable noro') + vim.command('map q :q') + vim.command('map  :q') + #vim.command('pedit '+docbuf.name) + b = vim.current.buffer + #b.append(doc) + b[:] = doc + #b.append(doc) + vim.command('setlocal nomodified bufhidden=wipe') + #vim.command('setlocal previewwindow nomodifiable nomodified ro') + #vim.command('set previewheight=%d'%len(b))# go to previous window + vim.command('resize %d'%len(b)) + #vim.command('pcl') + #vim.command('pedit doc') + #vim.command('normal ') # go to previous window + +def get_child_msgs(msg_id): + # XXX: message handling should be split into its own process in the future + msgs= km.shell_channel.get_msgs() + children = [m for m in msgs if m['parent_header']['msg_id'] == msg_id] + return children + + + +def run_this_file(): + send('run %s %s' % (run_flags, vim.current.buffer.name,)) + echo("In[]: run %s %s" % (run_flags, vim.current.buffer.name)) + +def print_prompt(prompt,msg_id=None): + global show_id + if show_id and msg_id: + time.sleep(.1) # wait to get message back from kernel + children = get_child_msgs(msg_id) + if len(children): + count = children[0]['content']['execution_count'] + echo("In[%d]: %s" %(count,prompt)) + else: + echo("In[]: %s (no reply from kernel)" % prompt) + else: + echo("In[]: %s" % prompt) + +def run_this_line(): + msg_id = send(vim.current.line) + print_prompt(vim.current.line, msg_id) + +def run_these_lines(): + r = vim.current.range + lines = "\n".join(vim.current.buffer[r.start:r.end+1]) + msg_id = send(lines) + #alternative way of doing this in more recent versions of ipython + #but %paste only works on the local machine + #vim.command("\"*yy") + #send("'%paste')") + #reselect the previously highlighted block + vim.command("normal gv") + if not reselect: + vim.command("normal ") + + #vim lines start with 1 + #print "lines %d-%d sent to ipython"% (r.start+1,r.end+1) + prompt = "lines %d-%d "% (r.start+1,r.end+1) + print_prompt(prompt,msg_id) + +def dedent_run_this_line(): + vim.command("left") + run_this_line() + vim.command("undo") + +def dedent_run_these_lines(): + vim.command("'<,'>left") + run_these_lines() + vim.command("undo") + +#def set_this_line(): +# # not sure if there's a way to do this, since we have multiple clients +# send("_ip.IP.rl_next_input= \'%s\'" % vim.current.line.replace("\'","\\\'")) +# #print "line \'%s\' set at ipython prompt"% vim.current.line +# echo("line \'%s\' set at ipython prompt"% vim.current.line,'Statement') + + +def toggle_reselect(): + global reselect + reselect=not reselect + print "F9 will%sreselect lines after sending to ipython"% (reselect and " " or " not ") + +#def set_breakpoint(): +# send("__IP.InteractiveTB.pdb.set_break('%s',%d)" % (vim.current.buffer.name, +# vim.current.window.cursor[0])) +# print "set breakpoint in %s:%d"% (vim.current.buffer.name, +# vim.current.window.cursor[0]) +# +#def clear_breakpoint(): +# send("__IP.InteractiveTB.pdb.clear_break('%s',%d)" % (vim.current.buffer.name, +# vim.current.window.cursor[0])) +# print "clearing breakpoint in %s:%d" % (vim.current.buffer.name, +# vim.current.window.cursor[0]) +# +#def clear_all_breakpoints(): +# send("__IP.InteractiveTB.pdb.clear_all_breaks()"); +# print "clearing all breakpoints" +# +#def run_this_file_pdb(): +# send(' __IP.InteractiveTB.pdb.run(\'execfile("%s")\')' % (vim.current.buffer.name,)) +# #send('run -d %s' % (vim.current.buffer.name,)) +# echo("In[]: run -d %s (using pdb)" % vim.current.buffer.name) + +EOF + +fun! toggle_send_on_save() + if exists("s:ssos") && s:ssos == 0 + let s:ssos = 1 + au BufWritePost *.py :py run_this_file() + echo "Autosend On" + else + let s:ssos = 0 + au! BufWritePost *.py + echo "Autosend Off" + endif +endfun + +map :python run_this_file() +map :python run_this_line() +map :python run_these_lines() +map d :py get_doc_buffer() +map :python toggle_reselect() +"map :python send('%pdb') +"map :python set_breakpoint() +"map :python clear_breakpoint() +"map :python run_this_file_pdb() +"map :python clear_all_breaks() +imap +imap +imap +map :call toggle_send_on_save() + +"pi custom +map :python run_this_file() +map :python run_this_line() +map :python dedent_run_this_line() +vmap :python run_these_lines() +vmap :python dedent_run_these_lines() +"map :python set_this_line() +map I# +vmap I# +map :s/^\([ \t]*\)#/\1/ +vmap :s/^\([ \t]*\)#/\1/ + +command! -nargs=+ IPython :py km_from_string("") +command! -nargs=0 IPythonClipboard :py km_from_string(vim.eval('@+')) +command! -nargs=0 IPythonXSelection :py km_from_string(vim.eval('@*')) + +function! IPythonBalloonExpr() +python << endpython +word = vim.eval('v:beval_text') +reply = get_doc(word) +#reply = reply[:40] +vim.command("let l:doc = %s"% reply) +endpython +return l:doc +endfunction +set bexpr=IPythonBalloonExpr() +set ballooneval + +fun! CompleteIPython(findstart, base) + if a:findstart + " locate the start of the word + let line = getline('.') + let start = col('.') - 1 + while start > 0 && line[start-1] =~ '\k\|\.' "keyword + let start -= 1 + endwhile + echo start + return start + else + " find months matching with "a:base" + let res = [] + python << endpython +base = vim.eval("a:base") +findstart = vim.eval("a:findstart") +msg_id = km.shell_channel.complete(base, vim.current.line, vim.eval("col('.')")) +time.sleep(.1) +m = get_child_msgs(msg_id)[0] + +matches = m['content']['matches'] +#end = len(base) +#completions = [m[end:]+findstart+base for m in matches] +matches.insert(0,base) # the "no completion" version +completions = matches +vim.command("let l:completions = %s"% completions) +endpython + for m in l:completions + "if m =~ '^' . a:base + call add(res, m) + "endif + endfor + return res + endif + endfun +set completefunc=CompleteIPython