Wednesday, July 22, 2009

Python File Type Plugin for Vim - Part 1

* Made a correction below. Using the ~/.vim/ftplugin directory for a file type plugin causes the plugin to be reloaded repeatedly causing any autocommands to be appended for BufWrite actions. This causes multiple executions of every utocommand every time you save the file. A better location is the ~/.vim/plugin directory. Where the plugin is load once at startup. I have changed the location below. *

I wanted to add some IDE style conveniences to my preferred editor, console Vim. Rather than reinventing the wheel I decided to search the Internet and start with what was already out there. I found a bunch of very useful scripts and snippets. In part 1 I am documenting some of what I found here by publishing a snippet that I have only made minor changes to to make it useful for my needs.

This script needs to be put in a file named python.vim and saved in ~/.vim/plugin. If the directory does not exist it needs to be created. The scripts create the pyflakes, pylinks, and pychecker commands that can be used at the vim command prompt, ':'. The pylint, pyflakes, pychecker packages will have to be installed as prerequisites for using these commands.

All three commands act on the current buffer's file name. Running and one of the commands at the vim command prompt will open a Vim quickfix window which will seem familiar to anyone who has used a graphical IDE for development.

You can press c to close the quickfix window when it has the focus. You can double click with a mouse under X or press enter to go to the error or warning associated with the current quickfix line. This will take you to the line referred to by that message. You will have to restart vim if you have already loaded a python file during the currently loaded Vim session.

Here is the code:

function! PythonGrep(tool)
set lazyredraw
" Close any existing cwindows.
cclose
let l:grepformat_save = &grepformat
let l:grepprogram_save = &grepprg
set grepformat&vim
set grepformat&vim
let &grepformat = '%f:%l:%m'
if a:tool == "pylint"
let &grepprg = 'pylint --output-format=parseable --reports=n --indent-string=" "'
elseif a:tool == "pychecker"
let &grepprg = 'pychecker --quiet -q'
elseif a:tool == "pyflakes"
let &grepprg = 'pyflakes'
else
echohl WarningMsg
echo "PythonGrep Error: Unknown Tool"
echohl none
endif
if &readonly == 0 | update | endif
silent! grep! %
let &grepformat = l:grepformat_save
let &grepprg = l:grepprogram_save
let l:mod_total = 0
let l:win_count = 1
" Determine correct window height
windo let l:win_count = l:win_count + 1
if l:win_count <= 2 | let l:win_count = 4 | endif
windo let l:mod_total = l:mod_total + winheight(0)/l:win_count |
\ execute 'resize +'.l:mod_total
" Open cwindow
execute 'belowright cw '.l:mod_total
nnoremap c :cclose
set nolazyredraw
redraw!
endfunction

command! Pyflakes call PythonGrep('pyflakes')
command! PyFlakes call PythonGrep('pyflakes')
command! Pychecker call PythonGrep('pychecker')
command! PyChecker call PythonGrep('pychecker')
command! Pylint call PythonGrep('pylint')
command! PyLint call PythonGrep('pylint')

" These three are successively more informative and aggressive in their
" warnings with pyflakes as the least noisy. Only uncomment one.
"autocmd BufWrite *.{py} :Pyflakes
autocmd BufWrite *.{py} :Pychecker
"autocmd BufWrite *.{py} :Pylint


In Vim a single double quote, ", is considered the beginning of a comment for the rest of the line.

The benefit of having the autocmd run one of the Python lint programs every time you save the file is that you can never get to far from sane working code as any errors and warnings pop up. This in your face style of development can keep you from pulling your hair out over something as simple as a semicolon or comma typo and can also warn you about more complex problems and proper coding style.

More to follow. I will try to combine the output of the three commands as their output doesn't seem to overlap for the most part. And the noisier programs (pychecker and pylint) don't appear to give the same advice when it comes to warnings. pylinker is by far the noisiest of them all but all it's warnings are configurable.

Warning: If you are using tabs for indenting you will have to modify the pylint parameter '--indent-string='. Set it to the empty string for tabs, or the actual number of spaces used for indenting. In my code above I have it set for 8 spaces which is project specific.

Thursday, April 2, 2009

Step One: Insert Foot in Mouth

This is a follow up to my Your Fancy Languuage is Burdensome and Dangerous post.

Python and Ruby don't have the APL array/vector/matrix syntax built in to the core language. But a little nudge from someone made me do the little bit of research I should have done before I wrote that post. And I rediscovered that I did not originate the these languages need array syntax thought.

There is a gem for Ruby called NArray and an egg for Python called Numpy that not only add array syntax but also coherent coercion rules and the ability to apply functions across arrays without calling map. I'm glad I found it because they are easy as pie to use and do exactly what I wanted and a heck of a lot more.

Check out this Python example:

from numpy import *
a = array([1,2,3])
b = array([4,5,6])
print a+b #equals array([5,7,9])
print (a+b)/4
print (a+b)%6

Outputs
[5,7,9]
[1,1,2]
[5,1,3]

As you can see Numpy also replicates the integer type bug/feature which is very C like but is being dropped in Python 3000 in favor of coercing integers to float on divide. You can typecast the divisor to float to get floating point division and float results.

Tuesday, March 24, 2009

Vim auto completion

I responded to a comment on the Daily Vim about auto completion. I decided to post it here as well as the comment ended up being kind of long. The comment by Casey asks if there is a way to turn off omni auto completion for perl as it goes through the entire POD collection evey time. I provide several solutions. Read the original article for a quicj intro to auto completion in insert mode in Vim.

The original article points out that there is built in auto completion in Vim. All you have to do is use it is type Ctrl-x Ctrl-o in insert mode and vim will try to complete what you have started typing or pop up a list of all completions if the cursor is not immediately preceded by anything.

Original comment follows:

Try this command to change the auto completion to the simpler syntax highlighting hints as the auto completer.

:setlocal omnifunc=syntaxcomplete#Complete

If that is what you always want for Perl add this to your .vimrc after all your other auto commands.

autocmd Filetype perl setlocal omnifunc=syntaxcomplete#Complete

If you want syntax completion rather than omni completion for all file types use * for the file type. If you want to fail over to syntax completion for file types that don't have omni completion put this in your .vimrc after your other auto commands.

if has("autocmd") && exists("+omnifunc")
autocmd Filetype *
\ if &omnifunc == "" |
\ setlocal omnifunc=syntaxcomplete#Complete |
\ endif
endif

You can also do something a little more complex which just disable the perlPOD part of the perl filetype omni complete.

Try this command:

let g:omni_syntax_group_exclude_perl = 'perlPOD'

generically it's:

let g:omni_syntax_group_exclude_{filetype} = 'comma,separated,list'

And you can get the complete list of syntax groups while in a file with the filetype in question with this command:

:syntax list

Then just add that command to your .vimrc to make it permanent.

Check out this help topic for more info:

:h ft-syntax-omni

*Updated

And for the complete low down on the idiosyncrasies of each filetype check out:

:h compl-omni-filetypes

And here's another tip I picked up Ctrl-o : in insert mode will allow you to run a command and then return to insert mode. Neatly avoiding the Esc : ... i or a syndrome.

*Updated again

FYI Pressing Ctrl-o in insert mode puts you in normal mode for one command. You are not limited to using : to get to the ex command line. You can use p to put or y to yank etc.

*Further updates

For those times when you just want to save keystrokes or avoid typos:

Ctrl-P completes from previous words in document
Ctrl-N completes from following words in document
Ctrl-X Ctrl-F completes file names
0 Ctrl-D removes all indent for the current line