Site Section:
Keywords:
There are a number of solutions for executing Python code in your active buffer in Vim. All of these expect the buffer lines to be well-formatted Python code, with correct indentation. Many times, however, I am working on program or other documentation (in, for example reStructuredTex or Markdown format), and the code fragments that I want to execute have extra indentation or line leaders.
For example, a reStructuredText buffer might look like:
How to Wuzzle the Wookie
-------------------------
The :func:`foo` function can be used to wuzzle the wookie by::
>>> import bar
>>> fuzzlewuzzle = bar.foo("the wookie")
>>> for fuzz in fuzzlewuzzle:
... if fuzz is bar.buzz():
... bar.wuzzle(fuzz)
While a Markdown buffer might have:
## How to Wuzzle the Wookie
The ``foo`` function can be used to to wuzzle the wookie by:
import bar
fuzzlewuzzle = bar.foo("the wookie")
for fuzz in fuzzlewuzzle:
if fuzz is bar.buzz():
bar.wuzzle(fuzz)
Simply passing the code lines in the above text to be evaluated in Python will not do: the extra decorators and indents required for embedding the code in the main document need to be dealt with.
Furthermore, many of the solutions that I could find (a) require Vim to have been built with Python enabled, and (b) use Vim's internal Python to evaluate the lines. The first seems like an unnecessary constraint, considering that native VimScript can handle the pre-processing quite well, while the second is problematical if there are external packages in your default system Python that the internal Vim Python does not have or if you prefer using the default system Python for whatever other reason. Here I describe a pure-VimScript solution that handles the execution of optionally-marked-up visually-selected line ranges in your default system Python, and either shows the results in the command window or inserts the results in the current buffer.
Installation and Usage
Include the following code in your "~/.vimrc
" or otherwise source it into your current Vim session.
Then select some lines of Python code and type ":EvalPy
" to evaluate the lines in the default Python session and show the results in the command window, or ":EvalPy!
" to evaluate the lines in the default Python session and insert the results in the current buffer.
" Execute currently selected visual range as Python. Lines are pre-processed " to remove extra indentation, leaders, or decorators that might be in place " due to the line range being part of a code block in a markup-language " document (such as ReStructured Text, Markdown, etc.) " Usage: Select a range of line in the buffer and then call ':EvalPy' to " execute those lines in the default system Python and show the results in the " command window. Using the 'bang' operator (':EvalPy!') will execute the " lines and insert the results in the current buffer. function! <SID>EvaluateCurrentRangeAsMarkedUpPython(insert_results) range "" get lines let [lnum1, col1] = getpos("'<")[1:2] let [lnum2, col2] = getpos("'>")[1:2] let lines = getline(lnum1, lnum2) " let lines[-1] = lines[-1][: col2 - 2] " let lines[0] = lines[0][col1 - 1:] "" remove blank rows let rows = [] for line in lines let row = substitute(line, '^\s*\(.\{-}\)\s*$', '\1', '') if len(row) > 0 call add(rows, line) endif endfor let lines = rows if len(lines) == 0 return endif let leader = matchstr(lines[0], '^\s*\(>>>\|\.\.\.\)\{0,1}\s*') let leader_len = len(leader) let code_lines = [] for line in lines let code_line = strpart(line, leader_len) call add(code_lines, code_line) endfor let code = join(code_lines, "\n") if empty(a:insert_results) redir => result silent execute "!python -c " . shellescape(code) redir END let rows = split(result, '\n')[1:] let result = join(rows, "\n") echo result else let endpos = getpos("'>") call setpos('.', endpos) execute "r !python -c " . shellescape(code) endif endfunction command! -bang -range EvalPy :call s:EvaluateCurrentRangeAsMarkedUpPython("<bang>")