##// END OF EJS Templates
add channel-selection to clear_output...
add channel-selection to clear_output example notebook updated accordingly

File last commit:

r4409:fe093dc2
r5085:0a8f09f8
Show More
ipy.vim
343 lines | 10.7 KiB | text/x-vim | VimLexer
" 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?<enter> object.<tab> 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("<cfile>")')
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 <buffer> q :q<CR>')
vim.command('map <buffer>  :q<CR>')
#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! <SID>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 <silent> <F5> :python run_this_file()<CR>
map <silent> <S-F5> :python run_this_line()<CR>
map <silent> <F9> :python run_these_lines()<CR>
map <leader>d :py get_doc_buffer()<CR>
map <silent> <S-F9> :python toggle_reselect()<CR>
"map <silent> <C-F6> :python send('%pdb')<CR>
"map <silent> <F6> :python set_breakpoint()<CR>
"map <silent> <s-F6> :python clear_breakpoint()<CR>
"map <silent> <F7> :python run_this_file_pdb()<CR>
"map <silent> <s-F7> :python clear_all_breaks()<CR>
imap <C-F5> <C-O><F5>
imap <S-F5> <C-O><S-F5>
imap <silent> <F5> <C-O><F5>
map <C-F5> :call <SID>toggle_send_on_save()<CR>
"pi custom
map <silent> <C-Return> :python run_this_file()<CR>
map <silent> <C-s> :python run_this_line()<CR>
map <silent> <M-s> :python dedent_run_this_line()<CR>
vmap <silent> <C-S> :python run_these_lines()<CR>
vmap <silent> <M-s> :python dedent_run_these_lines()<CR>
"map <silent> <C-p> :python set_this_line()<CR>
map <silent> <M-c> I#<ESC>
vmap <silent> <M-c> I#<ESC>
map <silent> <M-C> :s/^\([ \t]*\)#/\1/<CR>
vmap <silent> <M-C> :s/^\([ \t]*\)#/\1/<CR>
command! -nargs=+ IPython :py km_from_string("<args>")
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