diff vim/vimfiles/bundle/pyflakes-vim/ftplugin/python/pyflakes.vim @ 8:097c95760fd0

Added pyflakes-vim plugin support.
author Brian Neal <bgneal@gmail.com>
date Sun, 29 Apr 2012 16:30:44 -0500
parents
children
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/vim/vimfiles/bundle/pyflakes-vim/ftplugin/python/pyflakes.vim	Sun Apr 29 16:30:44 2012 -0500
@@ -0,0 +1,321 @@
+" pyflakes.vim - A script to highlight Python code on the fly with warnings
+" from Pyflakes, a Python lint tool.
+"
+" Place this script and the accompanying pyflakes directory in
+" .vim/ftplugin/python.
+"
+" See README for additional installation and information.
+"
+" Thanks to matlib.vim for ideas/code on interactive linting.
+"
+" Maintainer: Kevin Watters <kevin.watters@gmail.com>
+" Version: 0.1
+
+if exists("b:did_pyflakes_plugin")
+    finish " only load once
+else
+    let b:did_pyflakes_plugin = 1
+endif
+
+if !exists('g:pyflakes_builtins')
+    let g:pyflakes_builtins = []
+endif
+
+if !exists("b:did_python_init")
+    let b:did_python_init = 0
+
+    if !has('python')
+        echoerr "Error: the pyflakes.vim plugin requires Vim to be compiled with +python"
+        finish
+    endif
+
+if !exists('g:pyflakes_use_quickfix')
+    let g:pyflakes_use_quickfix = 1
+endif
+
+
+    python << EOF
+import vim
+import os.path
+import sys
+
+if sys.version_info[:2] < (2, 5):
+    raise AssertionError('Vim must be compiled with Python 2.5 or higher; you have ' + sys.version)
+
+# get the directory this script is in: the pyflakes python module should be installed there.
+scriptdir = os.path.join(os.path.dirname(vim.eval('expand("<sfile>")')), 'pyflakes')
+sys.path.insert(0, scriptdir)
+
+import ast
+from pyflakes import checker, messages
+from operator import attrgetter
+import re
+
+class loc(object):
+    def __init__(self, lineno, col=None):
+        self.lineno = lineno
+        self.col_offset = col
+
+class SyntaxError(messages.Message):
+    message = 'could not compile: %s'
+    def __init__(self, filename, lineno, col, message):
+        messages.Message.__init__(self, filename, loc(lineno, col))
+        self.message_args = (message,)
+
+class blackhole(object):
+    write = flush = lambda *a, **k: None
+
+def check(buffer):
+    filename = buffer.name
+    contents = buffer[:]
+
+    # shebang usually found at the top of the file, followed by source code encoding marker.
+    # assume everything else that follows is encoded in the encoding.
+    encoding_found = False
+    for n, line in enumerate(contents):
+        if n >= 2:
+            break
+        elif re.match(r'#.*coding[:=]\s*([-\w.]+)', line):
+            contents = ['']*(n+1) + contents[n+1:]
+            break
+
+    contents = '\n'.join(contents) + '\n'
+
+    vimenc = vim.eval('&encoding')
+    if vimenc:
+        contents = contents.decode(vimenc)
+
+    builtins = set(['__file__'])
+    try:
+        builtins.update(set(eval(vim.eval('string(g:pyflakes_builtins)'))))
+    except Exception:
+        pass
+
+    try:
+        # TODO: use warnings filters instead of ignoring stderr
+        old_stderr, sys.stderr = sys.stderr, blackhole()
+        try:
+            tree = ast.parse(contents, filename or '<unknown>')
+        finally:
+            sys.stderr = old_stderr
+    except:
+        try:
+            value = sys.exc_info()[1]
+            lineno, offset, line = value[1][1:]
+        except IndexError:
+            lineno, offset, line = 1, 0, ''
+        if line and line.endswith("\n"):
+            line = line[:-1]
+
+        return [SyntaxError(filename, lineno, offset, str(value))]
+    else:
+        # pyflakes looks to _MAGIC_GLOBALS in checker.py to see which
+        # UndefinedNames to ignore
+        old_globals = getattr(checker,' _MAGIC_GLOBALS', [])
+        checker._MAGIC_GLOBALS = set(old_globals) | builtins
+
+        w = checker.Checker(tree, filename)
+
+        checker._MAGIC_GLOBALS = old_globals
+
+        w.messages.sort(key = attrgetter('lineno'))
+        return w.messages
+
+
+def vim_quote(s):
+    return s.replace("'", "''")
+EOF
+    let b:did_python_init = 1
+endif
+
+if !b:did_python_init
+    finish
+endif
+
+au BufLeave <buffer> call s:ClearPyflakes()
+
+au BufEnter <buffer> call s:RunPyflakes()
+au InsertLeave <buffer> call s:RunPyflakes()
+au InsertEnter <buffer> call s:RunPyflakes()
+au BufWritePost <buffer> call s:RunPyflakes()
+
+au CursorHold <buffer> call s:RunPyflakes()
+au CursorHoldI <buffer> call s:RunPyflakes()
+
+au CursorHold <buffer> call s:GetPyflakesMessage()
+au CursorMoved <buffer> call s:GetPyflakesMessage()
+
+if !exists("*s:PyflakesUpdate")
+    function s:PyflakesUpdate()
+        silent call s:RunPyflakes()
+        call s:GetPyflakesMessage()
+    endfunction
+endif
+
+" Call this function in your .vimrc to update PyFlakes
+if !exists(":PyflakesUpdate")
+  command PyflakesUpdate :call s:PyflakesUpdate()
+endif
+
+" Hook common text manipulation commands to update PyFlakes
+"   TODO: is there a more general "text op" autocommand we could register
+"   for here?
+noremap <buffer><silent> dd dd:PyflakesUpdate<CR>
+noremap <buffer><silent> dw dw:PyflakesUpdate<CR>
+noremap <buffer><silent> u u:PyflakesUpdate<CR>
+noremap <buffer><silent> <C-R> <C-R>:PyflakesUpdate<CR>
+
+" WideMsg() prints [long] message up to (&columns-1) length
+" guaranteed without "Press Enter" prompt.
+if !exists("*s:WideMsg")
+    function s:WideMsg(msg)
+        let x=&ruler | let y=&showcmd
+        set noruler noshowcmd
+        redraw
+        echo strpart(a:msg, 0, &columns-1)
+        let &ruler=x | let &showcmd=y
+    endfun
+endif
+
+if !exists("*s:GetQuickFixStackCount")
+    function s:GetQuickFixStackCount()
+        let l:stack_count = 0
+        try
+            silent colder 9
+        catch /E380:/
+        endtry
+
+        try
+            for i in range(9)
+                silent cnewer
+                let l:stack_count = l:stack_count + 1
+            endfor
+        catch /E381:/
+            return l:stack_count
+        endtry
+    endfunction
+endif
+
+if !exists("*s:ActivatePyflakesQuickFixWindow")
+    function s:ActivatePyflakesQuickFixWindow()
+        try
+            silent colder 9 " go to the bottom of quickfix stack
+        catch /E380:/
+        endtry
+
+        if s:pyflakes_qf > 0
+            try
+                exe "silent cnewer " . s:pyflakes_qf
+            catch /E381:/
+                echoerr "Could not activate Pyflakes Quickfix Window."
+            endtry
+        endif
+    endfunction
+endif
+
+if !exists("*s:RunPyflakes")
+    function s:RunPyflakes()
+        highlight link PyFlakes SpellBad
+
+        if exists("b:cleared")
+            if b:cleared == 0
+                silent call s:ClearPyflakes()
+                let b:cleared = 1
+            endif
+        else
+            let b:cleared = 1
+        endif
+        
+        let b:matched = []
+        let b:matchedlines = {}
+
+        let b:qf_list = []
+        let b:qf_window_count = -1
+        
+        python << EOF
+for w in check(vim.current.buffer):
+    vim.command('let s:matchDict = {}')
+    vim.command("let s:matchDict['lineNum'] = " + str(w.lineno))
+    vim.command("let s:matchDict['message'] = '%s'" % vim_quote(w.message % w.message_args))
+    vim.command("let b:matchedlines[" + str(w.lineno) + "] = s:matchDict")
+    
+    vim.command("let l:qf_item = {}")
+    vim.command("let l:qf_item.bufnr = bufnr('%')")
+    vim.command("let l:qf_item.filename = expand('%')")
+    vim.command("let l:qf_item.lnum = %s" % str(w.lineno))
+    vim.command("let l:qf_item.text = '%s'" % vim_quote(w.message % w.message_args))
+    vim.command("let l:qf_item.type = 'E'")
+
+    if getattr(w, 'col', None) is None or isinstance(w, SyntaxError):
+        # without column information, just highlight the whole line
+        # (minus the newline)
+        vim.command(r"let s:mID = matchadd('PyFlakes', '\%" + str(w.lineno) + r"l\n\@!')")
+    else:
+        # with a column number, highlight the first keyword there
+        vim.command(r"let s:mID = matchadd('PyFlakes', '^\%" + str(w.lineno) + r"l\_.\{-}\zs\k\+\k\@!\%>" + str(w.col) + r"c')")
+
+        vim.command("let l:qf_item.vcol = 1")
+        vim.command("let l:qf_item.col = %s" % str(w.col + 1))
+
+    vim.command("call add(b:matched, s:matchDict)")
+    vim.command("call add(b:qf_list, l:qf_item)")
+EOF
+        if g:pyflakes_use_quickfix == 1
+            if exists("s:pyflakes_qf")
+                " if pyflakes quickfix window is already created, reuse it
+                call s:ActivatePyflakesQuickFixWindow()
+                call setqflist(b:qf_list, 'r')
+            else
+                " one pyflakes quickfix window for all buffer
+                call setqflist(b:qf_list, '')
+                let s:pyflakes_qf = s:GetQuickFixStackCount()
+            endif
+        endif
+
+        let b:cleared = 0
+    endfunction
+end
+
+" keep track of whether or not we are showing a message
+let b:showing_message = 0
+
+if !exists("*s:GetPyflakesMessage")
+    function s:GetPyflakesMessage()
+        let s:cursorPos = getpos(".")
+
+        " Bail if RunPyflakes hasn't been called yet.
+        if !exists('b:matchedlines')
+            return
+        endif
+
+        " if there's a message for the line the cursor is currently on, echo
+        " it to the console
+        if has_key(b:matchedlines, s:cursorPos[1])
+            let s:pyflakesMatch = get(b:matchedlines, s:cursorPos[1])
+            call s:WideMsg(s:pyflakesMatch['message'])
+            let b:showing_message = 1
+            return
+        endif
+
+        " otherwise, if we're showing a message, clear it
+        if b:showing_message == 1
+            echo
+            let b:showing_message = 0
+        endif
+    endfunction
+endif
+
+if !exists('*s:ClearPyflakes')
+    function s:ClearPyflakes()
+        let s:matches = getmatches()
+        for s:matchId in s:matches
+            if s:matchId['group'] == 'PyFlakes'
+                call matchdelete(s:matchId['id'])
+            endif
+        endfor
+        let b:matched = []
+        let b:matchedlines = {}
+        let b:cleared = 1
+    endfunction
+endif
+