| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360 |
- " 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')
- " 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
- if !exists('g:pyflakes_autostart')
- let g:pyflakes_autostart = 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')
- if scriptdir not in sys.path:
- 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
- filename = '(none)' if filename is None else filename
- 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()
- if !exists("*s:PyflakesToggle")
- function s:PyflakesToggle()
- if ! exists("b:pyflakes_off") || b:pyflakes_off == 1
- silent call s:RunPyflakes()
- echo 'pyflake on'
- 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()
- noremap <buffer><silent> dd dd:PyflakesUpdate<CR>
- noremap <buffer><silent> dw dw:PyflakesUpdate<CR>
- noremap <buffer><silent> u u:PyflakesUpdate<CR>
- let b:pyflakes_off = 0
- else
- silent call s:ClearPyflakes()
- echo 'pyflake off'
- au! BufEnter <buffer>
- au! InsertLeave <buffer>
- au! InsertEnter <buffer>
- au! BufWritePost <buffer>
- au! CursorHold <buffer>
- au! CursorHoldI <buffer>
- au! CursorMoved <buffer>
- unmap <buffer><silent> dd
- unmap <buffer><silent> dw
- unmap <buffer><silent> u
- let b:pyflakes_off = 1
- endif
- endfunction
- endif
- 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
- " 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:/
- catch /E788:/
- 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
- if g:pyflakes_autostart == 1
- call s:PyflakesToggle()
- endif
- command! -nargs=0 -bar PyflakesToggle call s:PyflakesToggle()
|