├── .gitignore ├── .travis.yml ├── CONTRIBUTING.md ├── README.rst ├── TODO.md ├── ftplugin └── python │ ├── ipy.vim │ └── vim_ipython.py └── test └── simple.vader /.gitignore: -------------------------------------------------------------------------------- 1 | *.pyc 2 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: vim 2 | 3 | before_script: | 4 | git clone https://github.com/junegunn/vader.vim.git 5 | 6 | script: | 7 | vim -Nu <(cat << VIMRC 8 | filetype off 9 | set rtp+=vader.vim 10 | set rtp+=. 11 | set rtp+=after 12 | filetype plugin indent on 13 | VIMRC) -c 'Vader! test/*' > /dev/null 14 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | Thanks so much for reporting issues or proposing new changes to vim-ipython. 2 | 3 | # Issues 4 | 5 | If you are reporting an issue, please be sure to read through the [Known 6 | Issues](https://github.com/ivanov/vim-ipython#known-issues) portion of [the 7 | README document](/README.rst), as the most common issues, and their workaround 8 | are described there 9 | 10 | # Pull requests 11 | 12 | Thanks for making a pull request. Please be sure to add your GitHub username to 13 | the [Thanks and Bug 14 | Participation](https://github.com/ivanov/vim-ipython#thanks-and-bug-participation) 15 | list, and if it's a significant enough of a feature, to also add it somewhere 16 | within the overall guide found in the README. 17 | 18 | best, 19 | pi 20 | -------------------------------------------------------------------------------- /README.rst: -------------------------------------------------------------------------------- 1 | ########### 2 | vim-ipython 3 | ########### 4 | 5 | A two-way integration between Vim and IPython. 6 | 7 | IPython versions 0.11.x, 0.12.x, 0.13.x, 1.x, 2.x and 3.x 8 | 9 | * author: Paul Ivanov (http://pirsquared.org) 10 | * github: http://github.com/ivanov/vim-ipython 11 | * demos: http://pirsquared.org/vim-ipython/ 12 | * blogpost: http://pirsquared.org/blog/vim-ipython.html 13 | 14 | Using this plugin, you can send lines or whole files for IPython to 15 | execute, and also get back object introspection and word completions in 16 | Vim, like what you get with: ``object?`` and ``object.`` in 17 | IPython. 18 | 19 | The big change from previous versions of ``ipy.vim`` is that it no longer 20 | requires the old brittle ``ipy_vimserver.py`` instantiation, and since 21 | it uses just vim and python, it is platform independent (i.e. works 22 | even on windows, unlike the previous \*nix only solution). The requirements 23 | are IPython 0.11 or newer with zeromq capabilities, vim compiled with +python. 24 | 25 | If you can launch ``ipython qtconsole`` or ``ipython kernel``, and 26 | ``:echo has('python')`` returns 1 in vim, you should be good to go. 27 | 28 | ----------------- 29 | Quickstart Guide: 30 | ----------------- 31 | Start ``ipython qtconsole`` [*]_. Source ``ipy.vim`` file, which provides new 32 | IPython command:: 33 | 34 | :source ipy.vim 35 | (or copy it to ~/.vim/ftplugin/python to load automatically) 36 | 37 | :IPython 38 | 39 | The ``:IPython`` command allows you to put the full connection string. For 40 | IPython 0.11, it would look like this:: 41 | 42 | :IPython --existing --shell=41882 --iopub=43286 --stdin=34987 --hb=36697 43 | 44 | and for IPython 0.12 through IPython 2.0 like this:: 45 | 46 | :IPython --existing kernel-85997.json 47 | 48 | There also exists to convenience commands: ``:IPythonClipboard`` just uses the 49 | ``+`` register to get the connection string, whereas ``:IPythonXSelection`` 50 | uses the ``*`` register and passes it to ``:IPython``. 51 | 52 | **NEW in IPython 2.0** 53 | 54 | vim-ipython can now interoperate with non-Python kernels. 55 | 56 | 57 | **NEW in IPython 0.12**! 58 | Since IPython 0.12, you can simply use:: 59 | 60 | :IPython 61 | 62 | without arguments to connect to the most recent IPython session (this is the 63 | same as passing just the ``--existing`` flag to ``ipython qtconsole`` and 64 | ``ipython console``. 65 | 66 | .. [*] Though the demos above use ``qtconsole``, it is not required 67 | for this workflow, it's just that it was the easiest way to show how to 68 | make use of the new functionality in 0.11 release. Since IPython 0.12, you 69 | can use ``ipython kernel`` to create a kernel and get the connection 70 | string to use for any frontend (including vim-ipython), or use ``ipython 71 | console`` to create a kernel and immediately connect to it using a 72 | terminal-based client. You can even connect to an active IPython Notebook 73 | kernel - just watch for the connection string that gets printed when you 74 | open the notebook, or use the ``%connect_info`` magic to get the 75 | connection string. If you are still using 0.11, you can launch a regular 76 | kernel using ``python -c "from IPython.zmq.ipkernel import main; main()"`` 77 | 78 | ------------------------ 79 | Sending lines to IPython 80 | ------------------------ 81 | Now type out a line and send it to IPython using ```` from Command mode:: 82 | 83 | import os 84 | 85 | You should see a notification message confirming the line was sent, along 86 | with the input number for the line, like so ``In[1]: import os``. If 87 | ```` did **not** work, see the `Known Issues <#known-issues>`_ for a 88 | work-around. 89 | 90 | ```` also works from insert mode, but doesn't show notification, 91 | unless ``monitor_subchannel`` is set to ``True`` (see `vim-ipython 'shell'`_, 92 | below) 93 | 94 | It also works blockwise in Visual Mode. Select and send these lines using 95 | ````:: 96 | 97 | import this,math # secret decoder ring 98 | a,b,c,d,e,f,g,h,i = range(1,10) 99 | code =(c,a,d,a,e,i,) 100 | msg = '...jrer nyy frag sebz Ivz.\nIvz+VClguba=%fyl '+this.s.split()[g] 101 | decode=lambda x:"\n"+"".join([this.d.get(c,c) for c in x])+"!" 102 | format=lambda x:'These lines:\n '+'\n '.join([l for l in x.splitlines()]) 103 | secret_decoder = lambda a,b: format(a)+decode(msg)%str(b)[:-1] 104 | '%d'*len(code)%code == str(int(math.pi*1e5)) 105 | 106 | Then, go to the qtconsole and run this line:: 107 | 108 | print secret_decoder(_i,_) 109 | 110 | You can also send whole files to IPython's ``%run`` magic using ````. 111 | 112 | **NEW in IPython 0.12**! 113 | If you're trying to do run code fragments that have leading whitespace, use 114 | ```` instead - it will dedent a single line, and remove the leading 115 | whitespace of the first line from all lines in a visual mode selection. 116 | 117 | ------------------------------- 118 | IPython's object? Functionality 119 | ------------------------------- 120 | 121 | If you're using gvim, mouse-over a variable to see IPython's ``?`` equivalent. 122 | If you're using vim from a terminal, or want to copy something from the 123 | docstring, type ``d``. ```` is usually ``\`` (the backslash 124 | key). This will open a quickpreview window, which can be closed by hitting 125 | ``q`` or ````. 126 | 127 | -------------------------------------- 128 | IPython's tab-completion Functionality 129 | -------------------------------------- 130 | vim-ipython activates a 'completefunc' that queries IPython. 131 | A completefunc is activated using ``Ctrl-X Ctrl-U`` in Insert Mode (vim 132 | default). You can combine this functionality with SuperTab to get tab 133 | completion. 134 | 135 | ------------------- 136 | vim-ipython 'shell' 137 | ------------------- 138 | 139 | By monitoring km.sub_channel, we can recreate what messages were sent to 140 | IPython, and what IPython sends back in response. 141 | 142 | ``monitor_subchannel`` is a parameter that sets whether this 'shell' should 143 | updated on every sent command (default: True). 144 | 145 | If at any later time you wish to bring this shell up, including if you've set 146 | ``monitor_subchannel=False``, hit ``s``. 147 | 148 | **NEW since IPython 0.12** 149 | For local kernels (kernels running on the same machine as vim), `Ctrl-C` in 150 | the vim-ipython 'shell' sends an keyboard interrupt. (Note: this feature may 151 | not work on Windows, please report the issue to ). 152 | 153 | ------- 154 | Options 155 | ------- 156 | You can change these at the top of the vim_ipython.py:: 157 | 158 | reselect = False # reselect lines after sending from Visual mode 159 | show_execution_count = True # wait to get numbers for In[43]: feedback? 160 | monitor_subchannel = True # update vim-ipython 'shell' on every send? 161 | run_flags= "-i" # flags to for IPython's run magic when using 162 | 163 | **Disabling default mappings** 164 | In your own ``.vimrc``, if you don't like the mappings provided by default, 165 | you can define a variable ``let g:ipy_perform_mappings=0`` which will prevent 166 | vim-ipython from defining any of the default mappings. 167 | 168 | **NEW since IPython 0.12** 169 | **Making completefunc local to a buffer, or disabling it** 170 | By default, vim-ipython activates the custom completefunc globally. 171 | Sometimes, having a completefunc breaks other plugins' completions. Putting 172 | the line ``let g:ipy_completefunc = 'local'`` in one's vimrc will activate the 173 | IPython-based completion only for current buffer. Setting `g:ipy_completefunc` 174 | to anything other than `'local'` or `'global'` disables it altogether. 175 | 176 | **NEW since IPython 0.13** 177 | 178 | **Sending ? and ?? now works just like IPython** 179 | This is only supported for single lines that end with ? and ??, which works 180 | just the same as it does in IPython (The ?? variant will show the code, not 181 | just the docstring 182 | 183 | **Sending arbitrary signal to IPython kernel** 184 | `:IPythonInterrupt` now supports sending of arbitrary signals. There's a 185 | convenience alias for sending SIGTERM via `:IPythonTerminate`, but you can 186 | also send any signal by just passing an argument to `:IPythonInterrupt`. 187 | Here's an example. First, send this code (or just run it in your kernel):: 188 | 189 | import signal 190 | def greeting_user(signum, stack): 191 | import sys 192 | sys.stdout.flush() 193 | print "Hello, USER!" 194 | sys.stdout.flush() 195 | signal.signal(signal.SIGUSR1, greeting_user) 196 | 197 | Now, proceed to connect up using vim-ipython and run `:IPythonInterrupt 10` - 198 | where 10 happens to be signal.SIGUSR1 in the POSIX world. This functionality, 199 | along with the sourcing of profile-dependent code on startup ( 200 | ``vi `ipython locate profile default`/startup/README`` ), brings the forgotten 201 | world of inter-process communication through signals to your favorite text 202 | editor and REPL combination. 203 | 204 | 205 | --------------- 206 | Known issues: 207 | --------------- 208 | - For now, vim-ipython only connects to an ipython session in progress. 209 | - The standard ipython clients (console, qtconsole, notebook) do not currently 210 | display the result of computation which they did not initialize. This means 211 | that if you send print statements for execution from within vim, they will 212 | only be shown inside the vim-ipython shell buffer, but **not** within any of 213 | the standard clients. This is not a limitation of vim-ipython, but a 214 | limitation of those built-in clients, see `ipython/ipython#1873 215 | `_ 216 | - The ipdb integration is not yet re-implemented. Pending 217 | [IPython PR #3089](https://github.com/ipython/ipython/pull/3089) 218 | - If ```` does not work inside your terminal, but you are able to run 219 | some of the other commands successfully (````, for example), try running 220 | this command before launching vim in the terminal (add it to your 221 | ``.bashrc`` if it fixes the issue):: 222 | 223 | stty stop undef # to unmap ctrl-s 224 | 225 | - In vim, if you're getting ``ImportError: No module named 226 | IPython.zmq.blockingkernelmanager`` but are able to import it in regular 227 | python, **either** 228 | 229 | 1. your ``sys.path`` in vim differs from the ``sys.path`` in regular python. 230 | Try running these two lines, and comparing their output files:: 231 | 232 | $ vim -c 'py import vim, sys; vim.current.buffer.append(sys.path)' -c ':wq vim_syspath' 233 | $ python -c "import sys; f=file('python_syspath','w'); f.write('\n'.join(sys.path)); f.close()" 234 | 235 | **or** 236 | 237 | 2. your vim is compiled against a different python than you are launching. See 238 | if there's a difference between :: 239 | 240 | $ vim -c ':py import os; print os.__file__' -c ':q' 241 | $ python -c 'import os; print os.__file__' 242 | 243 | - For vim inside a terminal, using the arrow keys won't work inside a 244 | documentation buffer, because the mapping for ```` overlaps with 245 | ``^[OA`` and so on, and we use ```` as a quick way of closing the 246 | documentation preview window. If you want go without this quick close 247 | functionality and want to use the arrow keys instead, look for instructions 248 | starting with "Known issue: to enable the use of arrow keys..." in the 249 | ``get_doc_buffer`` function. 250 | 251 | - @fholgado's update to ``minibufexpl.vim`` that is up on GitHub will always 252 | put the cursor in the minibuf after sending a command when 253 | ``monitor_subchannel`` is set. This is a bug in minibufexpl.vim and the workaround 254 | is described in vim-ipython issue #7. 255 | 256 | - the vim-ipython buffer is set to filetype=python, which provides syntax 257 | highlighting, but that syntax highlighting will be broken if a stack trace 258 | is returned which contains one half of a quote delimiter. 259 | 260 | - vim-ipython is currently for Python2.X only. 261 | 262 | ---------------------------- 263 | Thanks and Bug Participation 264 | ---------------------------- 265 | Here's a brief acknowledgment of the `folks who have graciously pitched in`_. If 266 | you've been missed, don't hesitate to contact me, or better yet, submit a 267 | pull request with your attribution. 268 | 269 | * @minrk for guiding me through the IPython kernel manager protocol, and 270 | support of connection_file-based IPython connection (#13), and keeping 271 | vim-ipython working across IPython API changes. 272 | * @nakamuray and @tcheneau for reporting and providing a fix for when vim is 273 | compiled without a gui (#1) 274 | * @unpingco for reporting Windows bugs (#3,#4), providing better multiline 275 | dedenting (#15), and suggesting that a resized vim-ipython shell stays 276 | resized (#16). 277 | * @simon-b for terminal vim arrow key issue (#5) 278 | * @jorgesca and @kwgoodman for shell update problems (#6) 279 | * @xowlinx and @vladimiroff for Ctrl-S issues in Konsole (#8) 280 | * @zeekay for easily allowing custom mappings (#9) 281 | * @jorgesca for reporting the lack of profile handling capability (#14), 282 | only open updating 'shell' if it is open (#29) 283 | * @enzbang for removing mapping that's not currently functional (#17) 284 | * @ogrisel for fixing documentation typo (#19) 285 | * @koepsell for gracefully exiting in case python is not available (#23) 286 | * @mrterry for activating completefunc only after a connection is made (#25), 287 | Ctrl-C implementation in vim-ipython 'shell' (#28) 288 | * @nonameentername for completion on import statements (#26) 289 | * @dstahlke for setting syntax of doc window to ReST 290 | * @jtratner for docs with quotes (#30) 291 | * @pielgrzym for setting completefunc locally to a buffer (#32) 292 | * @flacjacket for pointing out and providing fix for IPython API change 293 | * @memeplex for fixing the identifier grabbing on e.g. non-PEP8 compliant code 294 | * @pydave for IPythonTerminate (sending SIGTERM using our hack) 295 | * @luispedro for IPythonNew 296 | * @jjhelmus and @wmvanvliet for IPython 3.x support. 297 | 298 | Similar Projects 299 | ---------------- 300 | * `ipython-vimception`_ - vim-within-vim in the IPython Notebook (Paul Ivanov) 301 | * `vim-slime`_ - Grab some text and "send" it to a GNU Screen / tmux session 302 | (Jonathan Palardy) 303 | * `screen.vba`_ - Simulate a split shell, using GNU Screen / tmux, that you 304 | can send commands to (Eric Van Dewoestine) 305 | * `vimux`_ - vim plugin to interact with tmux (Ben Mills) 306 | * `vimux-pyutils`_ - send code to tmux ipython session (Julien Rebetez) 307 | * conque_ - terminal emulator which uses a Vim buffer to display the program 308 | output (Nico Raffo) 309 | * `ipyqtmacvim`_ - plugin to send commands from MacVim to IPython Qt console 310 | (Justin Kitzes) 311 | * `tslime_ipython`_ - "cell" execution , with cells defined by marks 312 | * `vipy`_ - used vim-ipython as a starting point and ran with it in a slightly 313 | different direction. (John David Giese) 314 | 315 | 316 | .. _ipython-vimception: https://github.com/ivanov/ipython-vimception 317 | .. _vim-slime: https://github.com/jpalardy/vim-slime 318 | .. _screen.vba: https://github.com/ervandew/screen 319 | .. _conque: http://code.google.com/p/conque/ 320 | .. _vimux: https://github.com/benmills/vimux 321 | .. _vimux-pyutils: https://github.com/julienr/vimux-pyutils 322 | .. _ipyqtmacvim: https://github.com/jkitzes/ipyqtmacvim/ 323 | .. _tslime_ipython: https://github.com/eldridgejm/tslime_ipython 324 | .. _vipy: https://github.com/johndgiese/vipy 325 | .. _folks who have graciously pitched in: https://github.com/ivanov/vim-ipython/graphs/contributors 326 | 327 | Bottom Line 328 | ----------- 329 | If you find this project useful, please consider donating money to the 330 | `John Hunter Memorial Fund`_. A giant in our community, John lead by example 331 | and gave us all so much. This is one small way we can give back to his family. 332 | 333 | .. _John Hunter Memorial Fund: http://numfocus.org/johnhunter/ 334 | -------------------------------------------------------------------------------- /TODO.md: -------------------------------------------------------------------------------- 1 | 2 | # TODO 3 | 4 | This is a list of things I'm planning to work on with vim-ipython 5 | 6 | [ ] opening docs while shell buffer is open somehow scroll-locks things, and 7 | does not compute the proper length 8 | 9 | [x] split up vim-specific things from python-specific things 10 | (make it easier to become py3k compliant) 11 | 12 | [x] py3k support 13 | 14 | [ ] vim ipython magic has no documentation that gets installed (fix this) 15 | 16 | [ ] support for non-python kernels (IJulia, IHaskell kernel) 17 | 18 | [ ] provide g:ipy variables to set the initial state of python vars 19 | e.g. monitor_subchannel 20 | 21 | [ ] put debugging support back in 22 | - http://jacobandreas.github.io/writing/tools/vim-ipython-stack-trace.html 23 | - example: https://github.com/jacobandreas/vim-ipython 24 | 25 | [ ] notebook io branch merged 26 | ping about this once it lands: 27 | http://spaceli.wordpress.com/2013/10/04/add-vim-key-bindings-for-ipython-1-0-0/ 28 | 29 | [x] make it possible to run :IPython command multiple times 30 | Traceback (most recent call last): 31 | File "", line 1, in 32 | File "", line 116, in km_from_string 33 | File "/home/pi/code/ipython/IPython/kernel/connect.py", line 205, in find_connection_file 34 | app = IPApp.instance() 35 | File "/home/pi/code/ipython/IPython/config/configurable.py", line 367, in instance 36 | '%s are being created.' % cls.__name__ 37 | IPython.config.configurable.MultipleInstanceError: Multiple incompatible subclass instances of BaseIPythonApplication are being created. 38 | 39 | - This was actually an IPython limitation. Works fine in IPython rel-2.1.0 40 | 41 | 42 | [ ] support profiledir 43 | -------------------------------------------------------------------------------- /ftplugin/python/ipy.vim: -------------------------------------------------------------------------------- 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? object. in IPython 8 | " 9 | " ----------------- 10 | " Quickstart Guide: 11 | " ----------------- 12 | " Start `ipython qtconsole`, `ipython console`, or `ipython notebook` and 13 | " open a notebook using you web browser. Source this file, which provides new 14 | " IPython command 15 | " 16 | " :source ipy.vim 17 | " :IPython 18 | " 19 | " written by Paul Ivanov (http://pirsquared.org) 20 | " 21 | if !has('python') 22 | " exit if python is not available. 23 | " XXX: raise an error message here 24 | finish 25 | endif 26 | 27 | " Allow custom mappings. 28 | if !exists('g:ipy_perform_mappings') 29 | let g:ipy_perform_mappings = 1 30 | endif 31 | 32 | " Register IPython completefunc 33 | " 'global' -- for all of vim (default). 34 | " 'local' -- only for the current buffer. 35 | " otherwise -- don't register it at all. 36 | " 37 | " you can later set it using ':set completefunc=CompleteIPython', which will 38 | " correspond to the 'global' behavior, or with ':setl ...' to get the 'local' 39 | " behavior 40 | if !exists('g:ipy_completefunc') 41 | let g:ipy_completefunc = 'global' 42 | endif 43 | 44 | python << EOF 45 | import vim 46 | import sys 47 | vim_ipython_path = vim.eval("expand(':h')") 48 | sys.path.append(vim_ipython_path) 49 | from vim_ipython import * 50 | 51 | EOF 52 | 53 | fun! toggle_send_on_save() 54 | if exists("s:ssos") && s:ssos == 0 55 | let s:ssos = 1 56 | au BufWritePost *.py :py run_this_file() 57 | echo "Autosend On" 58 | else 59 | let s:ssos = 0 60 | au! BufWritePost *.py 61 | echo "Autosend Off" 62 | endif 63 | endfun 64 | 65 | " Update the vim-ipython shell when the cursor is not moving. 66 | " You can change how quickly this happens after you stop moving the cursor by 67 | " setting 'updatetime' (in milliseconds). For example, to have this event 68 | " trigger after 1 second: 69 | " 70 | " :set updatetime 1000 71 | " 72 | " NOTE: This will only be triggered once, after the first 'updatetime' 73 | " milliseconds, *not* every 'updatetime' milliseconds. see :help CursorHold 74 | " for more info. 75 | " 76 | " TODO: Make this easily configurable on the fly, so that an introspection 77 | " buffer we may have opened up doesn't get closed just because of an idle 78 | " event (i.e. user pressed \d and then left the buffer that popped up, but 79 | " expects it to stay there). 80 | au CursorHold *.*,vim-ipython :python if update_subchannel_msgs(): echo("vim-ipython shell updated (on idle)",'Operator') 81 | 82 | " XXX: broken - cursor hold update for insert mode moves the cursor one 83 | " character to the left of the last character (update_subchannel_msgs must be 84 | " doing this) 85 | "au CursorHoldI *.* :python if update_subchannel_msgs(): echo("vim-ipython shell updated (on idle)",'Operator') 86 | 87 | " Same as above, but on regaining window focus (mostly for GUIs) 88 | au FocusGained *.*,vim-ipython :python if update_subchannel_msgs(): echo("vim-ipython shell updated (on input focus)",'Operator') 89 | 90 | " Update vim-ipython buffer when we move the cursor there. A message is only 91 | " displayed if vim-ipython buffer has been updated. 92 | au BufEnter vim-ipython :python if update_subchannel_msgs(): echo("vim-ipython shell updated (on buffer enter)",'Operator') 93 | 94 | " Setup plugin mappings for the most common ways to interact with ipython. 95 | noremap (IPython-RunFile) :python run_this_file() 96 | noremap (IPython-RunLine) :python run_this_line() 97 | noremap (IPython-RunLines) :python run_these_lines() 98 | noremap (IPython-OpenPyDoc) :python get_doc_buffer() 99 | noremap (IPython-UpdateShell) :python if update_subchannel_msgs(force=True): echo("vim-ipython shell updated",'Operator') 100 | noremap (IPython-ToggleReselect) :python toggle_reselect() 101 | "noremap (IPython-StartDebugging) :python send('%pdb') 102 | "noremap (IPython-BreakpointSet) :python set_breakpoint() 103 | "noremap (IPython-BreakpointClear) :python clear_breakpoint() 104 | "noremap (IPython-DebugThisFile) :python run_this_file_pdb() 105 | "noremap (IPython-BreakpointClearAll) :python clear_all_breaks() 106 | noremap (IPython-ToggleSendOnSave) :call toggle_send_on_save() 107 | noremap (IPython-PlotClearCurrent) :python run_command("plt.clf()") 108 | noremap (IPython-PlotCloseAll) :python run_command("plt.close('all')") 109 | noremap (IPython-RunLineAsTopLevel) :python dedent_run_this_line() 110 | xnoremap (IPython-RunLinesAsTopLevel) :python dedent_run_these_lines() 111 | 112 | if g:ipy_perform_mappings != 0 113 | map (IPython-RunFile) 114 | map (IPython-RunLine) 115 | map (IPython-RunLines) 116 | map d (IPython-OpenPyDoc) 117 | map s (IPython-UpdateShell) 118 | map (IPython-ToggleReselect) 119 | "map (IPython-StartDebugging) 120 | "map (IPython-BreakpointSet) 121 | "map (IPython-BreakpointClear) 122 | "map (IPython-DebugThisFile) 123 | "map (IPython-BreakpointClearAll) 124 | imap (IPython-RunFile) 125 | imap (IPython-RunLines) 126 | imap (IPython-RunFile) 127 | map (IPython-ToggleSendOnSave) 128 | "" Example of how to quickly clear the current plot with a keystroke 129 | "map (IPython-PlotClearCurrent) 130 | "" Example of how to quickly close all figures with a keystroke 131 | "map (IPython-PlotCloseAll) 132 | 133 | "pi custom 134 | map (IPython-RunFile) 135 | map (IPython-RunLine) 136 | imap (IPython-RunLine) 137 | map (IPython-RunLineAsTopLevel) 138 | xmap (IPython-RunLines) 139 | xmap (IPython-RunLinesAsTopLevel) 140 | 141 | noremap I# 142 | xnoremap I# 143 | noremap :s/^\([ \t]*\)#/\1/ 144 | xnoremap :s/^\([ \t]*\)#/\1/ 145 | endif 146 | 147 | command! -nargs=* IPython :py km_from_string("") 148 | command! -nargs=0 IPythonClipboard :py km_from_string(vim.eval('@+')) 149 | command! -nargs=0 IPythonXSelection :py km_from_string(vim.eval('@*')) 150 | command! -nargs=* IPythonNew :py new_ipy("") 151 | command! -nargs=* IPythonInterrupt :py interrupt_kernel_hack("") 152 | command! -nargs=0 IPythonTerminate :py terminate_kernel_hack() 153 | 154 | function! IPythonBalloonExpr() 155 | python << endpython 156 | word = vim.eval('v:beval_text') 157 | reply = get_doc(word) 158 | vim.command("let l:doc = %s"% reply) 159 | endpython 160 | return l:doc 161 | endfunction 162 | 163 | fun! CompleteIPython(findstart, base) 164 | if a:findstart 165 | " locate the start of the word 166 | let line = getline('.') 167 | let start = col('.') - 1 168 | while start > 0 && line[start-1] =~ '\k\|\.' "keyword 169 | let start -= 1 170 | endwhile 171 | echo start 172 | python << endpython 173 | current_line = vim.current.line 174 | endpython 175 | return start 176 | else 177 | " find months matching with "a:base" 178 | let res = [] 179 | python << endpython 180 | base = vim.eval("a:base") 181 | findstart = vim.eval("a:findstart") 182 | matches = ipy_complete(base, current_line, vim.eval("col('.')")) 183 | # we need to be careful with unicode, because we can have unicode 184 | # completions for filenames (for the %run magic, for example). So the next 185 | # line will fail on those: 186 | #completions= [str(u) for u in matches] 187 | # because str() won't work for non-ascii characters 188 | # and we also have problems with unicode in vim, hence the following: 189 | completions = [s.encode(vim_encoding) for s in matches] 190 | ## Additionally, we have no good way of communicating lists to vim, so we have 191 | ## to turn in into one long string, which can be problematic if e.g. the 192 | ## completions contain quotes. The next line will not work if some filenames 193 | ## contain quotes - but if that's the case, the user's just asking for 194 | ## it, right? 195 | #completions = '["'+ '", "'.join(completions)+'"]' 196 | #vim.command("let completions = %s" % completions) 197 | ## An alternative for the above, which will insert matches one at a time, so 198 | ## if there's a problem with turning a match into a string, it'll just not 199 | ## include the problematic match, instead of not including anything. There's a 200 | ## bit more indirection here, but I think it's worth it 201 | for c in completions: 202 | vim.command('call add(res,"'+c+'")') 203 | endpython 204 | "call extend(res,completions) 205 | return res 206 | endif 207 | endfun 208 | -------------------------------------------------------------------------------- /ftplugin/python/vim_ipython.py: -------------------------------------------------------------------------------- 1 | reselect = False # reselect lines after sending from Visual mode 2 | show_execution_count = True # wait to get numbers for In[43]: feedback? 3 | monitor_subchannel = True # update vim-ipython 'shell' on every send? 4 | run_flags= "-i" # flags to for IPython's run magic when using 5 | current_line = '' 6 | 7 | try: 8 | from queue import Empty # python3 convention 9 | except ImportError: 10 | from Queue import Empty 11 | 12 | try: 13 | import vim 14 | except ImportError: 15 | class NoOp(object): 16 | def __getattribute__(self, key): 17 | return lambda *args: '0' 18 | vim = NoOp() 19 | print("uh oh, not running inside vim") 20 | 21 | import sys 22 | 23 | # get around unicode problems when interfacing with vim 24 | vim_encoding=vim.eval('&encoding') or 'utf-8' 25 | 26 | try: 27 | sys.stdout.flush 28 | except AttributeError: 29 | # IPython complains if stderr and stdout don't have flush 30 | # this is fixed in newer version of Vim 31 | class WithFlush(object): 32 | def __init__(self,noflush): 33 | self.write=noflush.write 34 | self.writelines=noflush.writelines 35 | def flush(self):pass 36 | sys.stdout = WithFlush(sys.stdout) 37 | sys.stderr = WithFlush(sys.stderr) 38 | 39 | def vim_variable(name, default=None): 40 | exists = int(vim.eval("exists('%s')" % name)) 41 | return vim.eval(name) if exists else default 42 | 43 | def vim_regex_escape(x): 44 | for old, new in (("[", "\\["), ("]", "\\]"), (":", "\\:"), (".", "\."), ("*", "\\*")): 45 | x = x.replace(old, new) 46 | return x 47 | 48 | # status buffer settings 49 | status_prompt_in = vim_variable('g:ipy_status_in', 'In [%(line)d]: ') 50 | status_prompt_out = vim_variable('g:ipy_status_out', 'Out[%(line)d]: ') 51 | 52 | status_prompt_colors = { 53 | 'in_ctermfg': vim_variable('g:ipy_status_in_console_color', 'Green'), 54 | 'in_guifg': vim_variable('g:ipy_status_in_gui_color', 'Green'), 55 | 'out_ctermfg': vim_variable('g:ipy_status_out_console_color', 'Red'), 56 | 'out_guifg': vim_variable('g:ipy_status_out_gui_color', 'Red'), 57 | 'out2_ctermfg': vim_variable('g:ipy_status_out2_console_color', 'Gray'), 58 | 'out2_guifg': vim_variable('g:ipy_status_out2_gui_color', 'Gray'), 59 | } 60 | 61 | status_blank_lines = int(vim_variable('g:ipy_status_blank_lines', '1')) 62 | 63 | 64 | ip = '127.0.0.1' 65 | # this allows us to load vim_ipython multiple times 66 | try: 67 | km 68 | kc 69 | pid 70 | except NameError: 71 | km = None 72 | kc = None 73 | pid = None 74 | 75 | _install_instructions = """You *must* install IPython into the Python that 76 | your vim is linked against. If you are seeing this message, this usually means 77 | either (1) installing IPython using the system Python that vim is using, or 78 | (2) recompiling Vim against the Python where you already have IPython 79 | installed. This is only a requirement to allow Vim to speak with an IPython 80 | instance using IPython's own machinery. It does *not* mean that the IPython 81 | instance with which you communicate via vim-ipython needs to be running the 82 | same version of Python. 83 | """ 84 | 85 | def new_ipy(s=''): 86 | """Create a new IPython kernel (optionally with extra arguments) 87 | 88 | XXX: Allow passing of profile information here 89 | 90 | Examples 91 | -------- 92 | 93 | new_ipy() 94 | 95 | """ 96 | from IPython.kernel import KernelManager 97 | km = KernelManager() 98 | km.start_kernel() 99 | return km_from_string(km.connection_file) 100 | 101 | def km_from_string(s=''): 102 | """create kernel manager from IPKernelApp string 103 | such as '--shell=47378 --iopub=39859 --stdin=36778 --hb=52668' for IPython 0.11 104 | or just 'kernel-12345.json' for IPython 0.12 105 | """ 106 | try: 107 | import IPython 108 | except ImportError: 109 | raise ImportError("Could not find IPython. " + _install_instructions) 110 | from IPython.config.loader import KeyValueConfigLoader 111 | try: 112 | from IPython.kernel import ( 113 | KernelManager, 114 | find_connection_file, 115 | ) 116 | except ImportError: 117 | # IPython < 1.0 118 | from IPython.zmq.blockingkernelmanager import BlockingKernelManager as KernelManager 119 | from IPython.zmq.kernelapp import kernel_aliases 120 | try: 121 | from IPython.lib.kernel import find_connection_file 122 | except ImportError: 123 | # < 0.12, no find_connection_file 124 | pass 125 | 126 | global km, kc, send 127 | 128 | s = s.replace('--existing', '') 129 | if 'connection_file' in KernelManager.class_trait_names(): 130 | # 0.12 uses files instead of a collection of ports 131 | # include default IPython search path 132 | # filefind also allows for absolute paths, in which case the search 133 | # is ignored 134 | try: 135 | # XXX: the following approach will be brittle, depending on what 136 | # connection strings will end up looking like in the future, and 137 | # whether or not they are allowed to have spaces. I'll have to sync 138 | # up with the IPython team to address these issues -pi 139 | if '--profile' in s: 140 | k,p = s.split('--profile') 141 | k = k.lstrip().rstrip() # kernel part of the string 142 | p = p.lstrip().rstrip() # profile part of the string 143 | fullpath = find_connection_file(k,p) 144 | else: 145 | fullpath = find_connection_file(s.lstrip().rstrip()) 146 | except IOError as e: 147 | echo(":IPython " + s + " failed", "Info") 148 | echo("^-- failed '" + s + "' not found", "Error") 149 | return 150 | km = KernelManager(connection_file = fullpath) 151 | km.load_connection_file() 152 | else: 153 | if s == '': 154 | echo(":IPython 0.11 requires the full connection string") 155 | return 156 | loader = KeyValueConfigLoader(s.split(), aliases=kernel_aliases) 157 | cfg = loader.load_config()['KernelApp'] 158 | try: 159 | km = KernelManager( 160 | shell_address=(ip, cfg['shell_port']), 161 | sub_address=(ip, cfg['iopub_port']), 162 | stdin_address=(ip, cfg['stdin_port']), 163 | hb_address=(ip, cfg['hb_port'])) 164 | except KeyError as e: 165 | echo(":IPython " +s + " failed", "Info") 166 | echo("^-- failed --"+e.message.replace('_port','')+" not specified", "Error") 167 | return 168 | 169 | try: 170 | kc = km.client() 171 | except AttributeError: 172 | # 0.13 173 | kc = km 174 | kc.start_channels() 175 | 176 | try: 177 | send = kc.execute 178 | except AttributeError: 179 | # < 3.0 180 | send = kc.shell_channel.execute 181 | 182 | #XXX: backwards compatibility for IPython < 0.13 183 | try: 184 | import inspect 185 | sc = kc.shell_channel 186 | num_oinfo_args = len(inspect.getargspec(sc.object_info).args) 187 | if num_oinfo_args == 2: 188 | # patch the object_info method which used to only take one argument 189 | klass = sc.__class__ 190 | klass._oinfo_orig = klass.object_info 191 | klass.object_info = lambda s,x,y: s._oinfo_orig(x) 192 | except: 193 | pass 194 | 195 | #XXX: backwards compatibility for IPython < 1.0 196 | if not hasattr(kc, 'iopub_channel'): 197 | kc.iopub_channel = kc.sub_channel 198 | 199 | # now that we're connect to an ipython kernel, activate completion 200 | # machinery, but do so only for the local buffer if the user added the 201 | # following line the vimrc: 202 | # let g:ipy_completefunc = 'local' 203 | vim.command(""" 204 | if g:ipy_completefunc == 'global' 205 | set completefunc=CompleteIPython 206 | elseif g:ipy_completefunc == 'local' 207 | setl completefunc=CompleteIPython 208 | endif 209 | """) 210 | # also activate GUI doc balloons if in gvim 211 | vim.command(""" 212 | if has('balloon_eval') 213 | set bexpr=IPythonBalloonExpr() 214 | endif 215 | """) 216 | set_pid() 217 | return km 218 | 219 | def echo(arg,style="Question"): 220 | try: 221 | vim.command("echohl %s" % style) 222 | vim.command("echom \"%s\"" % arg.replace('\"','\\\"')) 223 | vim.command("echohl None") 224 | except vim.error: 225 | print("-- %s" % arg) 226 | 227 | def disconnect(): 228 | "disconnect kernel manager" 229 | # XXX: make a prompt here if this km owns the kernel 230 | pass 231 | 232 | def get_doc(word, level=0): 233 | if kc is None: 234 | return ["Not connected to IPython, cannot query: %s" % word] 235 | msg_id = kc.shell_channel.object_info(word, level) 236 | doc = get_doc_msg(msg_id) 237 | # get around unicode problems when interfacing with vim 238 | return [d.encode(vim_encoding) for d in doc] 239 | 240 | import re 241 | # from http://serverfault.com/questions/71285/in-centos-4-4-how-can-i-strip-escape-sequences-from-a-text-file 242 | strip = re.compile('\x1B\[([0-9]{1,2}(;[0-9]{1,2})?)?[m|K]') 243 | def strip_color_escapes(s): 244 | return strip.sub('',s) 245 | 246 | def get_doc_msg(msg_id): 247 | n = 13 # longest field name (empirically) 248 | b=[] 249 | try: 250 | content = get_child_msg(msg_id)['content'] 251 | except Empty: 252 | # timeout occurred 253 | return ["no reply from IPython kernel"] 254 | 255 | if not content['found']: 256 | return b 257 | 258 | # IPython 3.0+ the documentation message is encoding by the kernel 259 | if 'data' in content: 260 | try: 261 | text = content['data']['text/plain'] 262 | for line in text.split('\n'): 263 | b.append(strip_color_escapes(line).rstrip()) 264 | return b 265 | except KeyError: # no text/plain key 266 | return b 267 | 268 | for field in ['type_name','base_class','string_form','namespace', 269 | 'file','length','definition','source','docstring']: 270 | c = content.get(field,None) 271 | if c: 272 | if field in ['definition']: 273 | c = strip_color_escapes(c).rstrip() 274 | s = field.replace('_',' ').title()+':' 275 | s = s.ljust(n) 276 | if c.find('\n')==-1: 277 | b.append(s+c) 278 | else: 279 | b.append(s) 280 | b.extend(c.splitlines()) 281 | return b 282 | 283 | def get_doc_buffer(level=0): 284 | # empty string in case vim.eval return None 285 | vim.command("let isk_save = &isk") # save iskeyword list 286 | vim.command("let &isk = '@,48-57,_,192-255,.'") 287 | word = vim.eval('expand("")') or '' 288 | vim.command("let &isk = isk_save") # restore iskeyword list 289 | doc = get_doc(word, level) 290 | if len(doc) ==0: 291 | echo(repr(word)+" not found","Error") 292 | return 293 | # documentation buffer name is same as the query made to ipython 294 | vim.command('new '+word) 295 | vim.command('setlocal modifiable noro') 296 | # doc window quick quit keys: 'q' and 'escape' 297 | vim.command('nnoremap q :q') 298 | # Known issue: to enable the use of arrow keys inside the terminal when 299 | # viewing the documentation, comment out the next line 300 | vim.command('nnoremap :q') 301 | # and uncomment this line (which will work if you have a timoutlen set) 302 | #vim.command('nnoremap :q') 303 | b = vim.current.buffer 304 | b[:] = None 305 | b[:] = doc 306 | vim.command('setlocal nomodified bufhidden=wipe') 307 | #vim.command('setlocal previewwindow nomodifiable nomodified ro') 308 | #vim.command('set previewheight=%d'%len(b))# go to previous window 309 | vim.command('resize %d'%len(b)) 310 | #vim.command('pcl') 311 | #vim.command('pedit doc') 312 | #vim.command('normal! ') # go to previous window 313 | if level == 0: 314 | # use the ReST formatting that ships with stock vim 315 | vim.command('setlocal syntax=rst') 316 | else: 317 | # use Python syntax highlighting 318 | vim.command('setlocal syntax=python') 319 | 320 | def ipy_complete(base, current_line, pos): 321 | # pos is the location of the start of base, add the length 322 | # to get the completion position 323 | msg_id = kc.shell_channel.complete(base, current_line, 324 | int(pos) + len(base) - 1) 325 | try: 326 | m = get_child_msg(msg_id) 327 | matches = m['content']['matches'] 328 | matches.insert(0,base) # the "no completion" version 329 | # we need to be careful with unicode, because we can have unicode 330 | # completions for filenames (for the %run magic, for example). So the next 331 | # line will fail on those: 332 | #completions= [str(u) for u in matches] 333 | # because str() won't work for non-ascii characters 334 | # and we also have problems with unicode in vim, hence the following: 335 | return matches 336 | except Empty: 337 | echo("no reply from IPython kernel") 338 | return [''] 339 | 340 | def vim_ipython_is_open(): 341 | """ 342 | Helper function to let us know if the vim-ipython shell is currently 343 | visible 344 | """ 345 | for w in vim.windows: 346 | if w.buffer.name is not None and w.buffer.name.endswith("vim-ipython"): 347 | return True 348 | return False 349 | 350 | def update_subchannel_msgs(debug=False, force=False): 351 | """ 352 | Grab any pending messages and place them inside the vim-ipython shell. 353 | This function will do nothing if the vim-ipython shell is not visible, 354 | unless force=True argument is passed. 355 | """ 356 | if kc is None or (not vim_ipython_is_open() and not force): 357 | return False 358 | msgs = kc.iopub_channel.get_msgs() 359 | b = vim.current.buffer 360 | startedin_vimipython = vim.eval('@%')=='vim-ipython' 361 | if not startedin_vimipython: 362 | # switch to preview window 363 | vim.command( 364 | "try" 365 | "|silent! wincmd P" 366 | "|catch /^Vim\%((\a\+)\)\=:E441/" 367 | "|silent pedit +set\ ma vim-ipython" 368 | "|silent! wincmd P" 369 | "|endtry") 370 | # if the current window is called 'vim-ipython' 371 | if vim.eval('@%')=='vim-ipython': 372 | # set the preview window height to the current height 373 | vim.command("set pvh=" + vim.eval('winheight(0)')) 374 | else: 375 | # close preview window, it was something other than 'vim-ipython' 376 | vim.command("pcl") 377 | vim.command("silent pedit +set\ ma vim-ipython") 378 | vim.command("wincmd P") #switch to preview window 379 | # subchannel window quick quit key 'q' 380 | vim.command('nnoremap q :q') 381 | vim.command("set bufhidden=hide buftype=nofile ft=python") 382 | vim.command("setlocal nobuflisted") # don't come up in buffer lists 383 | vim.command("setlocal nonumber") # no line numbers, we have in/out nums 384 | vim.command("setlocal noswapfile") # no swap file (so no complaints cross-instance) 385 | # make shift-enter and control-enter in insert mode behave same as in ipython notebook 386 | # shift-enter send the current line, control-enter send the line 387 | # but keeps it around for further editing. 388 | vim.command("inoremap dd:python run_command('''\"''')i") 389 | # pkddA: paste, go up one line which is blank after run_command, 390 | # delete it, and then back to insert mode 391 | vim.command("inoremap dd:python run_command('''\"''')pkddA") 392 | # ctrl-C gets sent to the IPython process as a signal on POSIX 393 | vim.command("noremap  :IPythonInterrupt") 394 | 395 | #syntax highlighting for python prompt 396 | # QtConsole In[] is blue, but I prefer the oldschool green 397 | # since it makes the vim-ipython 'shell' look like the holidays! 398 | colors = status_prompt_colors 399 | vim.command("hi IPyPromptIn ctermfg=%s guifg=%s" % (colors['in_ctermfg'], colors['in_guifg'])) 400 | vim.command("hi IPyPromptOut ctermfg=%s guifg=%s" % (colors['out_ctermfg'], colors['out_guifg'])) 401 | vim.command("hi IPyPromptOut2 ctermfg=%s guifg=%s" % (colors['out2_ctermfg'], colors['out2_guifg'])) 402 | in_expression = vim_regex_escape(status_prompt_in % {'line': 999}).replace('999', '[ 0-9]*') 403 | vim.command("syn match IPyPromptIn /^%s/" % in_expression) 404 | out_expression = vim_regex_escape(status_prompt_out % {'line': 999}).replace('999', '[ 0-9]*') 405 | vim.command("syn match IPyPromptOut /^%s/" % out_expression) 406 | vim.command("syn match IPyPromptOut2 /^\\.\\.\\.* /") 407 | b = vim.current.buffer 408 | update_occured = False 409 | for m in msgs: 410 | s = '' 411 | if 'msg_type' not in m['header']: 412 | # debug information 413 | #echo('skipping a message on sub_channel','WarningMsg') 414 | #echo(str(m)) 415 | continue 416 | header = m['header']['msg_type'] 417 | if header == 'status': 418 | continue 419 | elif header == 'stream': 420 | # TODO: alllow for distinguishing between stdout and stderr (using 421 | # custom syntax markers in the vim-ipython buffer perhaps), or by 422 | # also echoing the message to the status bar 423 | try: 424 | s = strip_color_escapes(m['content']['data']) 425 | except KeyError: # changed in IPython 3.0.0 426 | s = strip_color_escapes(m['content']['text']) 427 | elif header == 'pyout' or header == 'execute_result': 428 | s = status_prompt_out % {'line': m['content']['execution_count']} 429 | s += m['content']['data']['text/plain'] 430 | elif header == 'display_data': 431 | # TODO: handle other display data types (HMTL? images?) 432 | s += m['content']['data']['text/plain'] 433 | elif header == 'pyin' or header == 'execute_input': 434 | # TODO: the next line allows us to resend a line to ipython if 435 | # %doctest_mode is on. In the future, IPython will send the 436 | # execution_count on subchannel, so this will need to be updated 437 | # once that happens 438 | line_number = m['content'].get('execution_count', 0) 439 | prompt = status_prompt_in % {'line': line_number} 440 | s = prompt 441 | # add a continuation line (with trailing spaces if the prompt has them) 442 | dots = '.' * len(prompt.rstrip()) 443 | dots += prompt[len(prompt.rstrip()):] 444 | s += m['content']['code'].rstrip().replace('\n', '\n' + dots) 445 | elif header == 'pyerr' or header == 'error': 446 | c = m['content'] 447 | s = "\n".join(map(strip_color_escapes,c['traceback'])) 448 | s += c['ename'] + ":" + c['evalue'] 449 | 450 | if s.find('\n') == -1: 451 | # somewhat ugly unicode workaround from 452 | # http://vim.1045645.n5.nabble.com/Limitations-of-vim-python-interface-with-respect-to-character-encodings-td1223881.html 453 | if isinstance(s,unicode): 454 | s=s.encode(vim_encoding) 455 | b.append(s) 456 | else: 457 | try: 458 | b.append(s.splitlines()) 459 | except: 460 | b.append([l.encode(vim_encoding) for l in s.splitlines()]) 461 | update_occured = True 462 | # make a newline so we can just start typing there 463 | if status_blank_lines: 464 | if b[-1] != '': 465 | b.append(['']) 466 | if update_occured or force: 467 | vim.command('normal! G') # go to the end of the file 468 | if not startedin_vimipython: 469 | vim.command('normal! p') # go back to where you were 470 | return update_occured 471 | 472 | def get_child_msg(msg_id): 473 | # XXX: message handling should be split into its own process in the future 474 | while True: 475 | # get_msg will raise with Empty exception if no messages arrive in 1 second 476 | m = kc.shell_channel.get_msg(timeout=1) 477 | if m['parent_header']['msg_id'] == msg_id: 478 | break 479 | else: 480 | #got a message, but not the one we were looking for 481 | echo('skipping a message on shell_channel','WarningMsg') 482 | return m 483 | 484 | def print_prompt(prompt,msg_id=None): 485 | """Print In[] or In[42] style messages""" 486 | global show_execution_count 487 | if show_execution_count and msg_id: 488 | # wait to get message back from kernel 489 | try: 490 | child = get_child_msg(msg_id) 491 | count = child['content']['execution_count'] 492 | echo("In[%d]: %s" %(count,prompt)) 493 | except Empty: 494 | echo("In[]: %s (no reply from IPython kernel)" % prompt) 495 | else: 496 | echo("In[]: %s" % prompt) 497 | 498 | def with_subchannel(f,*args): 499 | "conditionally monitor subchannel" 500 | def f_with_update(*args): 501 | try: 502 | f(*args) 503 | if monitor_subchannel: 504 | update_subchannel_msgs(force=True) 505 | except AttributeError: #if kc is None 506 | echo("not connected to IPython", 'Error') 507 | return f_with_update 508 | 509 | @with_subchannel 510 | def run_this_file(): 511 | msg_id = send('%%run %s %s' % (run_flags, repr(vim.current.buffer.name),)) 512 | print_prompt("In[]: %%run %s %s" % (run_flags, repr(vim.current.buffer.name)),msg_id) 513 | 514 | @with_subchannel 515 | def run_this_line(dedent=False): 516 | line = vim.current.line 517 | if dedent: 518 | line = line.lstrip() 519 | if line.rstrip().endswith('?'): 520 | # intercept question mark queries -- move to the word just before the 521 | # question mark and call the get_doc_buffer on it 522 | w = vim.current.window 523 | original_pos = w.cursor 524 | new_pos = (original_pos[0], vim.current.line.index('?')-1) 525 | w.cursor = new_pos 526 | if line.rstrip().endswith('??'): 527 | # double question mark should display source 528 | # XXX: it's not clear what level=2 is for, level=1 is sufficient 529 | # to get the code -- follow up with IPython team on this 530 | get_doc_buffer(1) 531 | else: 532 | get_doc_buffer() 533 | # leave insert mode, so we're in command mode 534 | vim.command('stopi') 535 | w.cursor = original_pos 536 | return 537 | msg_id = send(line) 538 | print_prompt(line, msg_id) 539 | 540 | @with_subchannel 541 | def run_command(cmd): 542 | msg_id = send(cmd) 543 | print_prompt(cmd, msg_id) 544 | 545 | @with_subchannel 546 | def run_these_lines(dedent=False): 547 | r = vim.current.range 548 | if dedent: 549 | lines = list(vim.current.buffer[r.start:r.end+1]) 550 | nonempty_lines = [x for x in lines if x.strip()] 551 | if not nonempty_lines: 552 | return 553 | first_nonempty = nonempty_lines[0] 554 | leading = len(first_nonempty) - len(first_nonempty.lstrip()) 555 | lines = "\n".join(x[leading:] for x in lines) 556 | else: 557 | lines = "\n".join(vim.current.buffer[r.start:r.end+1]) 558 | msg_id = send(lines) 559 | #alternative way of doing this in more recent versions of ipython 560 | #but %paste only works on the local machine 561 | #vim.command("\"*yy") 562 | #send("'%paste')") 563 | #reselect the previously highlighted block 564 | vim.command("normal! gv") 565 | if not reselect: 566 | vim.command("normal! ") 567 | 568 | #vim lines start with 1 569 | #print("lines %d-%d sent to ipython"% (r.start+1,r.end+1)) 570 | prompt = "lines %d-%d "% (r.start+1,r.end+1) 571 | print_prompt(prompt,msg_id) 572 | 573 | 574 | def set_pid(): 575 | """ 576 | Explicitly ask the ipython kernel for its pid 577 | """ 578 | global pid 579 | lines = '\n'.join(['import os', '_pid = os.getpid()']) 580 | 581 | try: 582 | msg_id = send(lines, silent=True, user_variables=['_pid']) 583 | except TypeError: # change in IPython 3.0+ 584 | msg_id = send(lines, silent=True, user_expressions={'_pid':'_pid'}) 585 | 586 | # wait to get message back from kernel 587 | try: 588 | child = get_child_msg(msg_id) 589 | except Empty: 590 | echo("no reply from IPython kernel") 591 | return 592 | try: 593 | pid = int(child['content']['user_variables']['_pid']) 594 | except TypeError: # change in IPython 1.0.dev moved this out 595 | pid = int(child['content']['user_variables']['_pid']['data']['text/plain']) 596 | except KeyError: # change in IPython 3.0+ 597 | pid = int( 598 | child['content']['user_expressions']['_pid']['data']['text/plain']) 599 | except KeyError: # change in IPython 1.0.dev moved this out 600 | echo("Could not get PID information, kernel not running Python?") 601 | return pid 602 | 603 | 604 | def terminate_kernel_hack(): 605 | "Send SIGTERM to our the IPython kernel" 606 | import signal 607 | interrupt_kernel_hack(signal.SIGTERM) 608 | 609 | def interrupt_kernel_hack(signal_to_send=None): 610 | """ 611 | Sends the interrupt signal to the remote kernel. This side steps the 612 | (non-functional) ipython interrupt mechanisms. 613 | Only works on posix. 614 | """ 615 | global pid 616 | import signal 617 | import os 618 | if pid is None: 619 | # Avoid errors if we couldn't get pid originally, 620 | # by trying to obtain it now 621 | pid = set_pid() 622 | 623 | if pid is None: 624 | echo("cannot get kernel PID, Ctrl-C will not be supported") 625 | return 626 | if not signal_to_send: 627 | signal_to_send = signal.SIGINT 628 | 629 | echo("KeyboardInterrupt (sent to ipython: pid " + 630 | "%i with signal %s)" % (pid, signal_to_send),"Operator") 631 | try: 632 | os.kill(pid, int(signal_to_send)) 633 | except OSError: 634 | echo("unable to kill pid %d" % pid) 635 | pid = None 636 | 637 | def dedent_run_this_line(): 638 | run_this_line(True) 639 | 640 | def dedent_run_these_lines(): 641 | run_these_lines(True) 642 | 643 | #def set_this_line(): 644 | # # not sure if there's a way to do this, since we have multiple clients 645 | # send("get_ipython().shell.set_next_input(\'%s\')" % vim.current.line.replace("\'","\\\'")) 646 | # #print("line \'%s\' set at ipython prompt"% vim.current.line) 647 | # echo("line \'%s\' set at ipython prompt"% vim.current.line,'Statement') 648 | 649 | 650 | def toggle_reselect(): 651 | global reselect 652 | reselect=not reselect 653 | print("F9 will%sreselect lines after sending to ipython" % 654 | (reselect and " " or " not ")) 655 | 656 | #def set_breakpoint(): 657 | # send("__IP.InteractiveTB.pdb.set_break('%s',%d)" % (vim.current.buffer.name, 658 | # vim.current.window.cursor[0])) 659 | # print("set breakpoint in %s:%d"% (vim.current.buffer.name, 660 | # vim.current.window.cursor[0])) 661 | # 662 | #def clear_breakpoint(): 663 | # send("__IP.InteractiveTB.pdb.clear_break('%s',%d)" % (vim.current.buffer.name, 664 | # vim.current.window.cursor[0])) 665 | # print("clearing breakpoint in %s:%d" % (vim.current.buffer.name, 666 | # vim.current.window.cursor[0])) 667 | # 668 | #def clear_all_breakpoints(): 669 | # send("__IP.InteractiveTB.pdb.clear_all_breaks()"); 670 | # print("clearing all breakpoints") 671 | # 672 | #def run_this_file_pdb(): 673 | # send(' __IP.InteractiveTB.pdb.run(\'execfile("%s")\')' % (vim.current.buffer.name,)) 674 | # #send('run -d %s' % (vim.current.buffer.name,)) 675 | # echo("In[]: run -d %s (using pdb)" % vim.current.buffer.name) 676 | 677 | -------------------------------------------------------------------------------- /test/simple.vader: -------------------------------------------------------------------------------- 1 | Given (): 2 | Hello 3 | 4 | Execute python ( check Python support ): 5 | import os 6 | import vim 7 | from vim import current, vars 8 | vim.command('normal! yy2p') 9 | current.buffer.append(os.path.basename(vars['vader_file'])) 10 | 11 | Expect: 12 | Hello 13 | Hello 14 | Hello 15 | simple.vader 16 | 17 | 18 | Execute python (check IPython import): 19 | import vim 20 | from vim import current, vars 21 | import IPython 22 | current.buffer.append(str(IPython.version_info[0] >= 1)) 23 | 24 | Expect: 25 | Hello 26 | True 27 | 28 | Execute python (check vim_ipython import): 29 | import vim 30 | vim.command("set ft=python") 31 | vim.command("IPython") 32 | import vim_ipython 33 | current.buffer.append("vim_ipython loaded") 34 | 35 | Expect: 36 | Hello 37 | vim_ipython loaded 38 | --------------------------------------------------------------------------------