1
0
mirror of https://github.com/gryf/.vim.git synced 2025-12-18 03:50:30 +01:00

Added branch pathogen

This commit is contained in:
2012-02-13 21:19:34 +01:00
parent b989a7b269
commit 5047146e53
261 changed files with 5724 additions and 3107 deletions

View File

@@ -1,10 +0,0 @@
" Helper function for (x)html snippets
if exists('s:did_snip_helper') || &cp || !exists('loaded_snips')
finish
endif
let s:did_snip_helper = 1
" Automatically closes tag if in xhtml
fun! Close()
return stridx(&ft, 'xhtml') == -1 ? '' : ' /'
endf

View File

@@ -1,58 +0,0 @@
setlocal cinkeys-=0#
setlocal indentkeys-=0#
setlocal foldlevel=100
setlocal foldmethod=indent
setlocal list
setlocal noautoindent
setlocal smartindent
setlocal cinwords=if,elif,else,for,while,try,except,finally,def,class,with
setlocal smarttab
set wildignore+=*.pyc
inoremap # X<BS>#
"set ofu=syntaxcomplete#Complete
"autocmd FileType python setlocal omnifunc=pysmell#Complete
let python_highlight_all=1
"I don't want to have pyflakes errors in qfix, it interfering with Pep8/Pylint
let g:pyflakes_use_quickfix = 0
"Load views for py files
autocmd BufWinLeave *.py mkview
autocmd BufWinEnter *.py silent loadview
compiler pylint
finish "end here. all below is just for the record.
" Pylint function, which can be optionally mapped to some keys. Currently
" not used.
if !exists('*<SID>runPyLint')
function <SID>runPyLint()
echohl Statement
echo "Running pylint (ctrl-c to cancel) ..."
echohl Normal
:Pylint
endfunction
endif
if !exists('*<SID>PyLintBuf')
function <SID>PyLintBuf()
echohl Statement
echo "Running pylint (ctrl-c to cancel) ..."
echohl Normal
let file = expand('%:p')
let cmd = 'pylint --reports=n --output-format=text "' . file . '"'
if has('win32') || has('win64')
let cmd = 'cmd /c "' . cmd . '"'
endif
exec "bel silent new " . file . ".lint"
exec "silent! read! " . cmd
endfunction
endif

View File

@@ -1,231 +0,0 @@
" Fold routines for python code, version 3.2
" Source: http://www.vim.org/scripts/script.php?script_id=2527
" Last Change: 2009 Feb 25
" Author: Jurjen Bos
" Bug fixes and helpful comments: Grissiom, David Froger, Andrew McNabb
" Principles:
" - a def/class starts a fold
" a line with indent less than the previous def/class ends a fold
" empty lines and comment lines are linked to the previous fold
" comment lines outside a def/class are never folded
" other lines outside a def/class are folded together as a group
" for algorithm, see bottom of script
" - optionally, you can get empty lines between folds, see (***)
" - another option is to ignore non-python files see (**)
" - you can also modify the def/class check,
" allowing for multiline def and class definitions see (*)
" Note for vim 7 users:
" Vim 6 line numbers always take 8 columns, while vim 7 has a numberwidth variable
" you can change the 8 below to &numberwidth if you have vim 7,
" this is only really useful when you plan to use more than 8 columns (i.e. never)
" Note for masochists trying to read this:
" I wanted to keep the functions short, so I replaced occurences of
" if condition
" statement
" by
" if condition | statement
" wherever I found that useful
" (*)
" class definitions are supposed to ontain a colon on the same line.
" function definitions are *not* required to have a colon, to allow for multiline defs.
" I you disagree, use instead of the pattern '^\s*\(class\s.*:\|def\s\)'
" to enforce : for defs: '^\s*\(class\|def\)\s.*:'
" you'll have to do this in two places.
let s:defpat = '^\s*\(@\|class\s.*:\|def\s\)'
" (**) Ignore non-python files
" Commented out because some python files are not recognized by Vim
"if &filetype != 'python'
" finish
"endif
setlocal foldmethod=expr
setlocal foldexpr=GetPythonFold(v:lnum)
setlocal foldtext=PythonFoldText()
function! PythonFoldText()
let fs = v:foldstart
while getline(fs) =~ '^\s*@' | let fs = nextnonblank(fs + 1)
endwhile
let line = getline(fs)
let nnum = nextnonblank(fs + 1)
let nextline = getline(nnum)
"get the document string: next line is ''' or """
if nextline =~ "^\\s\\+[\"']\\{3}\\s*$"
let line = line . " " . matchstr(getline(nextnonblank(nnum + 1)), '^\s*\zs.*\ze$')
"next line starts with qoutes, and has text
elseif nextline =~ "^\\s\\+[\"']\\{1,3}"
let line = line." ".matchstr(nextline, "^\\s\\+[\"']\\{1,3}\\zs.\\{-}\\ze['\"]\\{0,3}$")
elseif nextline =~ '^\s\+pass\s*$'
let line = line . ' pass'
endif
"compute the width of the visible part of the window (see Note above)
let w = winwidth(0) - &foldcolumn - (&number ? 8 : 0)
let size = 1 + v:foldend - v:foldstart
"compute expansion string
let spcs = '................'
while strlen(spcs) < w | let spcs = spcs . spcs
endwhile
"expand tabs (mail me if you have tabstop>10)
let onetab = strpart(' ', 0, &tabstop)
let line = substitute(line, '\t', onetab, 'g')
return strpart(line.spcs, 0, w-strlen(size)-7).'.'.size.' lines'
endfunction
function! GetBlockIndent(lnum)
" Auxiliary function; determines the indent level of the surrounding def/class
" "global" lines are level 0, first def &shiftwidth, and so on
" scan backwards for class/def that is shallower or equal
let ind = 100
let p = a:lnum+1
while indent(p) >= 0
let p = p - 1
" skip empty and comment lines
if getline(p) =~ '^$\|^\s*#' | continue
" zero-level regular line
elseif indent(p) == 0 | return 0
" skip deeper or equal lines
elseif indent(p) >= ind || getline(p) =~ '^$\|^\s*#' | continue
" indent is strictly less at this point: check for def/class
elseif getline(p) =~ s:defpat && getline(p) !~ '^\s*@'
" level is one more than this def/class
return indent(p) + &shiftwidth
endif
" shallower line that is neither class nor def: continue search at new level
let ind = indent(p)
endwhile
"beginning of file
return 0
endfunction
" Clever debug code, use as: call PrintIfCount(n,"Line: ".a:lnum.", value: ".x)
let s:counter=0
function! PrintIfCount(n,t)
"Print text the nth time this function is called
let s:counter = s:counter+1
if s:counter==a:n | echo a:t
endif
endfunction
function! GetPythonFold(lnum)
" Determine folding level in Python source (see "higher foldlevel theory" below)
let line = getline(a:lnum)
let ind = indent(a:lnum)
" Case D***: class and def start a fold
" If previous line is @, it is not the first
if line =~ s:defpat && getline(prevnonblank(a:lnum-1)) !~ '^\s*@'
" let's see if this range of 0 or more @'s end in a class/def
let n = a:lnum
while getline(n) =~ '^\s*@' | let n = nextnonblank(n + 1)
endwhile
" yes, we have a match: this is the first of a real def/class with decorators
if getline(n) =~ s:defpat
return ">".(ind/&shiftwidth+1)
endif
" Case E***: empty lines fold with previous
" (***) change '=' to -1 if you want empty lines/comment out of a fold
elseif line == '' | return '='
endif
" now we need the indent from previous
let p = prevnonblank(a:lnum-1)
while p>0 && getline(p) =~ '^\s*#' | let p = prevnonblank(p-1)
endwhile
let pind = indent(p)
" If previous was definition: count as one level deeper
if getline(p) =~ s:defpat && getline(prevnonblank(a:lnum - 1)) !~ '^\s*@'
let pind = pind + &shiftwidth
" if begin of file: take zero
elseif p==0 | let pind = 0
endif
" Case S*=* and C*=*: indent equal
if ind>0 && ind==pind | return '='
" Case S*>* and C*>*: indent increase
elseif ind>pind | return '='
" All cases with 0 indent
elseif ind==0
" Case C*=0*: separate global code blocks
if pind==0 && line =~ '^#' | return 0
" Case S*<0* and S*=0*: global code
elseif line !~'^#'
" Case S*<0*: new global statement if/while/for/try/with
if 0<pind && line!~'^else\s*:\|^except.*:\|^elif.*:\|^finally\s*:' | return '>1'
" Case S*=0*, after level 0 comment
elseif 0==pind && getline(prevnonblank(a:lnum-1)) =~ '^\s*#' | return '>1'
" Case S*=0*, other, stay 1
else | return '='
endif
endif
" Case C*<0= and C*<0<: compute next indent
let n = nextnonblank(a:lnum+1)
while n>0 && getline(n) =~'^\s*#' | let n = nextnonblank(n+1)
endwhile
" Case C*<0=: split definitions
if indent(n)==0 | return 0
" Case C*<0<: shallow comment
else | return -1
end
endif
" now we really need to compute the actual fold indent
" do the hard computation
let blockindent = GetBlockIndent(a:lnum)
" Case SG<* and CG<*: global code, level 1
if blockindent==0 | return 1
endif
" now we need the indent from next
let n = nextnonblank(a:lnum+1)
while n>0 && getline(n) =~'^\s*#' | let n = nextnonblank(n+1)
endwhile
let nind = indent(n)
" Case CR<= and CR<>
"if line !~ '^\s*#' | call PrintIfCount(4,"Line: ".a:lnum.", blockindent: ".blockindent.", n: ".n.", nind: ".nind.", p: ".p.", pind: ".pind)
endif
if line =~ '^\s*#' && ind>=nind | return -1
" Case CR<<: return next indent
elseif line =~ '^\s*#' | return nind / &shiftwidth
" Case SR<*: return actual indent
else | return blockindent / &shiftwidth
endif
endfunction
" higher foldlevel theory
" There are five kinds of statements: S (code), D (def/class), E (empty), C (comment)
" Note that a decorator statement (beginning with @) counts as definition,
" but that of a sequence of @,@,@,def only the first one counts
" This means that a definiion only counts if not preceded by a decorator
" There are two kinds of folds: R (regular), G (global statements)
" There are five indent situations with respect to the previous non-emtpy non-comment line:
" > (indent), < (dedent), = (same); < and = combine with 0 (indent is zero)
" Note: if the previous line is class/def, its indent is interpreted as one higher
" There are three indent situations with respect to the next (non-E non-C) line:
" > (dedent), < (indent), = (same)
" Situations (in order of the script):
" stat fold prev next
" SDEC RG ><=00 ><=
" D * * * begin fold level if previous is not @: '>'.ind/&sw+1
" E * * * keep with previous: '='
" S * = * stays the same: '='
" C * = * combine with previous: '='
" S * > * stays the same: '='
" C * > * combine with previous: '='
" C * =0 * separate blocks: 0
" S * <0 * becomes new level 1: >1 (except except/else: 1)
" S * =0 * stays 1: '=' (after level 0 comment: '>1')
" C * <0 = split definitions: 0
" C * <0 < shallow comment: -1
" C * <0 > [never occurs]
" S G < * global, not the first: 1
" C G < * indent isn't 0: 1
" C R < = foldlevel as computed for next line: -1
" C R < > foldlevel as computed for next line: -1
" S R < * compute foldlevel the hard way: use function
" C R < < foldlevel as computed for this line: use function

View File

@@ -1,135 +0,0 @@
" File: pep8_fn.vim
" Author: Roman 'gryf' Dobosz (gryf73 at gmail.com)
" Version: 1.0
" Last Modified: 2010-09-12
" Description: {{{
"
" Overview
" --------
" This plugin provides functionality to static checks for python files
" regarding PEP8 guidance[1] as ":Pep8" command.
"
" This function does not use pep8[2] command line utility, but relies on pep8
" module.
"
" This script uses python, therefore VIm should be compiled with python
" support. You can check it by issuing ":version" command, and search for
" "+python" inside features list.
"
" Couple of ideas was taken from pyflakes.vim[3] plugin.
"
" Installation
" ------------
" 1. Copy the pep8_fn.vim file to the $HOME/.vim/ftplugin/python or
" $HOME/vimfiles/ftplugin/python or $VIM/vimfiles/ftplugin/python
" directory. If python directory doesn't exists, it should be created.
" Refer to the following Vim help topics for more information about Vim
" plugins:
" :help add-plugin
" :help add-global-plugin
" :help runtimepath
" 2. It should be possible to import pep8 from python interpreter (it should
" report no error):
" >>> import pep8
" >>>
" If there are errors, install pep8 first. Simplest way to do it, is to
" use easy_install[4] shell command as a root:
" # easy_install pep8
" 3. Restart Vim.
" 4. You can now use the ":Pep8" which will examine current python buffer
" and open quickfix buffer with errors if any.
"
" [1] http://www.python.org/dev/peps/pep-0008/
" [2] http://pypi.python.org/pypi/pep8
" [3] http://www.vim.org/scripts/script.php?script_id=2441
" [4] http://pypi.python.org/pypi/setuptools
"
" }}}
if exists("b:did_pep8_plugin")
finish " only load once
else
let b:did_pep8_plugin = 1
endif
if !exists("g:pep8_exclude")
let g:pep8_exclude = []
endif
if !exists("b:did_pep8_init")
let b:did_pep8_init = 0
if !has('python')
echoerr "pep8_fn.vim plugin requires Vim to be compiled with +python"
finish
endif
python << EOF
import vim
import sys
from StringIO import StringIO
try:
import pep8
except ImportError:
raise AssertionError('Error: pep8_fn.vim requires module pep8')
class VImPep8(object):
def __init__(self):
self.fname = vim.current.buffer.name
self.bufnr = vim.current.buffer.number
self.output = []
self.exclude_list = vim.eval("g:pep8_exclude")
def reporter(self, lnum, col, text, check):
self.output.append([lnum, col, text])
def run(self):
pep8.process_options(['-r', vim.current.buffer.name])
checker = pep8.Checker(vim.current.buffer.name)
checker.report_error = self.reporter
checker.check_all()
self.process_output()
def process_output(self):
vim.command('call setqflist([])')
qf_list = []
qf_dict = {}
for line in self.output:
skip = False
for exclude_pattern in self.exclude_list:
if exclude_pattern in line[2]:
skip = True
break
if skip:
continue
qf_dict['bufnr'] = self.bufnr
qf_dict['lnum'] = line[0]
qf_dict['col'] = line[1]
qf_dict['text'] = line[2]
qf_dict['type'] = line[2][0]
qf_list.append(qf_dict)
qf_dict = {}
self.output = []
vim.command('call setqflist(%s)' % str(qf_list))
if qf_list:
vim.command('copen')
EOF
let b:did_pep8_init = 1
endif
if !exists('*s:Pep8')
function s:Pep8()
python << EOF
VImPep8().run()
EOF
endfunction
endif
if !exists(":Pep8")
command Pep8 call s:Pep8()
endif

View File

@@ -1,111 +0,0 @@
"pydoc.vim: pydoc integration for vim
"performs searches and can display the documentation of python modules
"Author: Andr<64> Kelpe <efeshundertelf at googlemail dot com>
"Author: Romain Chossart <romainchossat at gmail dot com>
"Author: Matthias Vogelgesang
"http://www.vim.org/scripts/script.php?script_id=910
"This plugin integrates the pydoc into vim. You can view the
"documentation of a module by using :Pydoc foo.bar.baz or search
"a word (uses pydoc -k) in the documentation by typing PydocSearch
"foobar. You can also view the documentation of the word under the
"cursor by pressing <leader>pw or the WORD (see :help WORD) by pressing
"<leader>pW. "This is very useful if you want to jump to a module which was found by
"PydocSearch. To have a browser like feeling you can use u and CTRL-R to
"go back and forward, just like editing normal text.
"If you want to use the script and pydoc is not in your PATH, just put a
"line like
" let g:pydoc_cmd = \"/usr/bin/pydoc" (without the backslash!!)
"in your .vimrc
"pydoc.vim is free software, you can redistribute or modify
"it under the terms of the GNU General Public License Version 2 or any
"later Version (see http://www.gnu.org/copyleft/gpl.html for details).
"Please feel free to contact me.
set switchbuf=useopen
function! ShowPyDoc(name, type)
if !exists('g:pydoc_cmd')
let g:pydoc_cmd = 'pydoc'
endif
if bufloaded("__doc__") >0
let l:buf_is_new = 0
else
let l:buf_is_new = 1
endif
if bufnr("__doc__") >0
execute "sb __doc__"
else
execute 'split __doc__'
endif
setlocal noswapfile
set buftype=nofile
setlocal modifiable
normal ggdG
" remove function/method arguments
let s:name2 = substitute(a:name, '(.*', '', 'g' )
" remove all colons
let s:name2 = substitute(s:name2, ':', '', 'g' )
if a:type==1
execute "silent read ! " . g:pydoc_cmd . " " . s:name2
else
execute "silent read ! " . g:pydoc_cmd . " -k " . s:name2
endif
setlocal nomodified
set filetype=man
normal 1G
if !exists('g:pydoc_wh')
let g:pydoc_wh = 10
end
resize -999
execute "silent resize +" . g:pydoc_wh
if !exists('g:pydoc_highlight')
let g:pydoc_highlight = 1
endif
if g:pydoc_highlight == 1
call Highlight(s:name2)
endif
let l:line = getline(2)
if l:line =~ "^no Python documentation found for.*$"
if l:buf_is_new
execute "bd!"
else
normal u
endif
redraw
echohl WarningMsg | echo l:line | echohl None
endif
endfunction
"highlighting
function! Highlight(name)
execute "sb __doc__"
set filetype=man
"syn on
execute 'syntax keyword pydoc '.a:name
hi pydoc gui=reverse
endfunction
"mappings
au FileType python,man map <buffer> <leader>pw :call ShowPyDoc('<C-R><C-W>', 1)<CR>
au FileType python,man map <buffer> <leader>pW :call ShowPyDoc('<C-R><C-A>', 1)<CR>
au FileType python,man map <buffer> <leader>pk :call ShowPyDoc('<C-R><C-W>', 0)<CR>
au FileType python,man map <buffer> <leader>pK :call ShowPyDoc('<C-R><C-A>', 0)<CR>
" remap the K (or 'help') key
nnoremap <silent> <buffer> K :call ShowPyDoc(expand("<cword>"), 1)<CR>
"commands
command! -nargs=1 Pydoc :call ShowPyDoc('<args>', 1)
command! -nargs=* PydocSearch :call ShowPyDoc('<args>', 0)

View File

@@ -1,321 +0,0 @@
" 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

View File

@@ -1,21 +0,0 @@
Copyright (c) 2005 Divmod, Inc., http://www.divmod.com/
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

View File

@@ -1,29 +0,0 @@
0.4.0 (2009-11-25):
- Fix reporting for certain SyntaxErrors which lack line number
information.
- Check for syntax errors more rigorously.
- Support checking names used with the class decorator syntax in versions
of Python which have it.
- Detect local variables which are bound but never used.
- Handle permission errors when trying to read source files.
- Handle problems with the encoding of source files.
- Support importing dotted names so as not to incorrectly report them as
redefined unused names.
- Support all forms of the with statement.
- Consider static `__all__` definitions and avoid reporting unused names
if the names are listed there.
- Fix incorrect checking of class names with respect to the names of their
bases in the class statement.
- Support the `__path__` global in `__init__.py`.
0.3.0 (2009-01-30):
- Display more informative SyntaxError messages.
- Don't hang flymake with unmatched triple quotes (only report a single
line of source for a multiline syntax error).
- Recognize __builtins__ as a defined name.
- Improve pyflakes support for python versions 2.3-2.5
- Support for if-else expressions and with statements.
- Warn instead of error on non-existant file paths.
- Check for __future__ imports after other statements.
- Add reporting for some types of import shadowing.
- Improve reporting of unbound locals

View File

@@ -1,82 +0,0 @@
pyflakes-vim
============
A Vim plugin for checking Python code on the fly.
PyFlakes catches common Python errors like mistyping a variable name or
accessing a local before it is bound, and also gives warnings for things like
unused imports.
pyflakes-vim uses the output from PyFlakes to highlight errors in your code.
To locate errors quickly, use quickfix_ commands like :cc.
Make sure to check vim.org_ for the latest updates.
.. _pyflakes.vim: http://www.vim.org/scripts/script.php?script_id=2441
.. _vim.org: http://www.vim.org/scripts/script.php?script_id=2441
.. _quickfix: http://vimdoc.sourceforge.net/htmldoc/quickfix.html#quickfix
Quick Installation
------------------
1. Make sure your ``.vimrc`` has::
filetype on " enables filetype detection
filetype plugin on " enables filetype specific plugins
2. Download the latest release_.
3. If you're using pathogen_, unzip the contents of ``pyflakes-vim.zip`` into
its own bundle directory, i.e. into ``~/.vim/bundle/pyflakes-vim/``.
Otherwise unzip ``pyflakes.vim`` and the ``pyflakes`` directory into
``~/.vim/ftplugin/python`` (or somewhere similar on your
`runtime path`_ that will be sourced for Python files).
.. _release: http://www.vim.org/scripts/script.php?script_id=2441
.. _pathogen: http://www.vim.org/scripts/script.php?script_id=2332
.. _runtime path: http://vimdoc.sourceforge.net/htmldoc/options.html#'runtimepath'
Running from source
-------------------
If you're running pyflakes-vim "from source," you'll need the PyFlakes library
on your PYTHONPATH somewhere. (It is included in the vim.org zipfile.) I recommend
getting my PyFlakes_ fork, which retains column number information, giving more
specific error locations.
.. _vim.org: http://www.vim.org/scripts/script.php?script_id=2441
.. _PyFlakes: http://github.com/kevinw/pyflakes
Hacking
-------
::
git clone git://github.com/kevinw/pyflakes-vim.git
cd pyflakes-vim
git clone git://github.com/kevinw/pyflakes.git
Options
-------
Set this option to you vimrc file to disable quickfix support::
let g:pyflakes_use_quickfix = 0
The value is set to 1 by default.
TODO
----
* signs_ support (show warning and error icons to left of the buffer area)
* configuration variables
* parse or intercept useful output from the warnings module
.. _signs: http://www.vim.org/htmldoc/sign.html
Changelog
---------
Please see http://www.vim.org/scripts/script.php?script_id=2441 for a history of
all changes.

View File

@@ -1,4 +0,0 @@
#!/usr/bin/python
from pyflakes.scripts.pyflakes import main
main()

View File

@@ -1,2 +0,0 @@
__version__ = '0.4.0'

View File

@@ -1,625 +0,0 @@
# -*- test-case-name: pyflakes -*-
# (c) 2005-2010 Divmod, Inc.
# See LICENSE file for details
import __builtin__
import os.path
import _ast
from pyflakes import messages
# utility function to iterate over an AST node's children, adapted
# from Python 2.6's standard ast module
try:
import ast
iter_child_nodes = ast.iter_child_nodes
except (ImportError, AttributeError):
def iter_child_nodes(node, astcls=_ast.AST):
"""
Yield all direct child nodes of *node*, that is, all fields that are nodes
and all items of fields that are lists of nodes.
"""
for name in node._fields:
field = getattr(node, name, None)
if isinstance(field, astcls):
yield field
elif isinstance(field, list):
for item in field:
yield item
class Binding(object):
"""
Represents the binding of a value to a name.
The checker uses this to keep track of which names have been bound and
which names have not. See L{Assignment} for a special type of binding that
is checked with stricter rules.
@ivar used: pair of (L{Scope}, line-number) indicating the scope and
line number that this binding was last used
"""
def __init__(self, name, source):
self.name = name
self.source = source
self.used = False
def __str__(self):
return self.name
def __repr__(self):
return '<%s object %r from line %r at 0x%x>' % (self.__class__.__name__,
self.name,
self.source.lineno,
id(self))
class UnBinding(Binding):
'''Created by the 'del' operator.'''
class Importation(Binding):
"""
A binding created by an import statement.
@ivar fullName: The complete name given to the import statement,
possibly including multiple dotted components.
@type fullName: C{str}
"""
def __init__(self, name, source):
self.fullName = name
name = name.split('.')[0]
super(Importation, self).__init__(name, source)
class Argument(Binding):
"""
Represents binding a name as an argument.
"""
class Assignment(Binding):
"""
Represents binding a name with an explicit assignment.
The checker will raise warnings for any Assignment that isn't used. Also,
the checker does not consider assignments in tuple/list unpacking to be
Assignments, rather it treats them as simple Bindings.
"""
class FunctionDefinition(Binding):
pass
class ExportBinding(Binding):
"""
A binding created by an C{__all__} assignment. If the names in the list
can be determined statically, they will be treated as names for export and
additional checking applied to them.
The only C{__all__} assignment that can be recognized is one which takes
the value of a literal list containing literal strings. For example::
__all__ = ["foo", "bar"]
Names which are imported and not otherwise used but appear in the value of
C{__all__} will not have an unused import warning reported for them.
"""
def names(self):
"""
Return a list of the names referenced by this binding.
"""
names = []
if isinstance(self.source, _ast.List):
for node in self.source.elts:
if isinstance(node, _ast.Str):
names.append(node.s)
return names
class Scope(dict):
importStarred = False # set to True when import * is found
def __repr__(self):
return '<%s at 0x%x %s>' % (self.__class__.__name__, id(self), dict.__repr__(self))
def __init__(self):
super(Scope, self).__init__()
class ClassScope(Scope):
pass
class FunctionScope(Scope):
"""
I represent a name scope for a function.
@ivar globals: Names declared 'global' in this function.
"""
def __init__(self):
super(FunctionScope, self).__init__()
self.globals = {}
class ModuleScope(Scope):
pass
# Globally defined names which are not attributes of the __builtin__ module.
_MAGIC_GLOBALS = ['__file__', '__builtins__']
class Checker(object):
"""
I check the cleanliness and sanity of Python code.
@ivar _deferredFunctions: Tracking list used by L{deferFunction}. Elements
of the list are two-tuples. The first element is the callable passed
to L{deferFunction}. The second element is a copy of the scope stack
at the time L{deferFunction} was called.
@ivar _deferredAssignments: Similar to C{_deferredFunctions}, but for
callables which are deferred assignment checks.
"""
nodeDepth = 0
traceTree = False
def __init__(self, tree, filename='(none)'):
self._deferredFunctions = []
self._deferredAssignments = []
self.dead_scopes = []
self.messages = []
self.filename = filename
self.scopeStack = [ModuleScope()]
self.futuresAllowed = True
self.handleChildren(tree)
self._runDeferred(self._deferredFunctions)
# Set _deferredFunctions to None so that deferFunction will fail
# noisily if called after we've run through the deferred functions.
self._deferredFunctions = None
self._runDeferred(self._deferredAssignments)
# Set _deferredAssignments to None so that deferAssignment will fail
# noisly if called after we've run through the deferred assignments.
self._deferredAssignments = None
del self.scopeStack[1:]
self.popScope()
self.check_dead_scopes()
def deferFunction(self, callable):
'''
Schedule a function handler to be called just before completion.
This is used for handling function bodies, which must be deferred
because code later in the file might modify the global scope. When
`callable` is called, the scope at the time this is called will be
restored, however it will contain any new bindings added to it.
'''
self._deferredFunctions.append((callable, self.scopeStack[:]))
def deferAssignment(self, callable):
"""
Schedule an assignment handler to be called just after deferred
function handlers.
"""
self._deferredAssignments.append((callable, self.scopeStack[:]))
def _runDeferred(self, deferred):
"""
Run the callables in C{deferred} using their associated scope stack.
"""
for handler, scope in deferred:
self.scopeStack = scope
handler()
def scope(self):
return self.scopeStack[-1]
scope = property(scope)
def popScope(self):
self.dead_scopes.append(self.scopeStack.pop())
def check_dead_scopes(self):
"""
Look at scopes which have been fully examined and report names in them
which were imported but unused.
"""
for scope in self.dead_scopes:
export = isinstance(scope.get('__all__'), ExportBinding)
if export:
all = scope['__all__'].names()
if os.path.split(self.filename)[1] != '__init__.py':
# Look for possible mistakes in the export list
undefined = set(all) - set(scope)
for name in undefined:
self.report(
messages.UndefinedExport,
scope['__all__'].source,
name)
else:
all = []
# Look for imported names that aren't used.
for importation in scope.itervalues():
if isinstance(importation, Importation):
if not importation.used and importation.name not in all:
self.report(
messages.UnusedImport,
importation.source,
importation.name)
def pushFunctionScope(self):
self.scopeStack.append(FunctionScope())
def pushClassScope(self):
self.scopeStack.append(ClassScope())
def report(self, messageClass, *args, **kwargs):
self.messages.append(messageClass(self.filename, *args, **kwargs))
def handleChildren(self, tree):
for node in iter_child_nodes(tree):
self.handleNode(node, tree)
def isDocstring(self, node):
"""
Determine if the given node is a docstring, as long as it is at the
correct place in the node tree.
"""
return isinstance(node, _ast.Str) or \
(isinstance(node, _ast.Expr) and
isinstance(node.value, _ast.Str))
def handleNode(self, node, parent):
node.parent = parent
if self.traceTree:
print ' ' * self.nodeDepth + node.__class__.__name__
self.nodeDepth += 1
if self.futuresAllowed and not \
(isinstance(node, _ast.ImportFrom) or self.isDocstring(node)):
self.futuresAllowed = False
nodeType = node.__class__.__name__.upper()
try:
handler = getattr(self, nodeType)
handler(node)
finally:
self.nodeDepth -= 1
if self.traceTree:
print ' ' * self.nodeDepth + 'end ' + node.__class__.__name__
def ignore(self, node):
pass
# "stmt" type nodes
RETURN = DELETE = PRINT = WHILE = IF = WITH = RAISE = TRYEXCEPT = \
TRYFINALLY = ASSERT = EXEC = EXPR = handleChildren
CONTINUE = BREAK = PASS = ignore
# "expr" type nodes
BOOLOP = BINOP = UNARYOP = IFEXP = DICT = SET = YIELD = COMPARE = \
CALL = REPR = ATTRIBUTE = SUBSCRIPT = LIST = TUPLE = handleChildren
NUM = STR = ELLIPSIS = ignore
# "slice" type nodes
SLICE = EXTSLICE = INDEX = handleChildren
# expression contexts are node instances too, though being constants
LOAD = STORE = DEL = AUGLOAD = AUGSTORE = PARAM = ignore
# same for operators
AND = OR = ADD = SUB = MULT = DIV = MOD = POW = LSHIFT = RSHIFT = \
BITOR = BITXOR = BITAND = FLOORDIV = INVERT = NOT = UADD = USUB = \
EQ = NOTEQ = LT = LTE = GT = GTE = IS = ISNOT = IN = NOTIN = ignore
# additional node types
COMPREHENSION = EXCEPTHANDLER = KEYWORD = handleChildren
def addBinding(self, loc, value, reportRedef=True):
'''Called when a binding is altered.
- `loc` is the location (an object with lineno and optionally
col_offset attributes) of the statement responsible for the change
- `value` is the optional new value, a Binding instance, associated
with the binding; if None, the binding is deleted if it exists.
- if `reportRedef` is True (default), rebinding while unused will be
reported.
'''
if (isinstance(self.scope.get(value.name), FunctionDefinition)
and isinstance(value, FunctionDefinition)):
self.report(messages.RedefinedFunction,
loc, value.name, self.scope[value.name].source)
if not isinstance(self.scope, ClassScope):
for scope in self.scopeStack[::-1]:
existing = scope.get(value.name)
if (isinstance(existing, Importation)
and not existing.used
and (not isinstance(value, Importation) or value.fullName == existing.fullName)
and reportRedef):
self.report(messages.RedefinedWhileUnused,
loc, value.name, scope[value.name].source)
if isinstance(value, UnBinding):
try:
del self.scope[value.name]
except KeyError:
self.report(messages.UndefinedName, loc, value.name)
else:
self.scope[value.name] = value
def GLOBAL(self, node):
"""
Keep track of globals declarations.
"""
if isinstance(self.scope, FunctionScope):
self.scope.globals.update(dict.fromkeys(node.names))
def LISTCOMP(self, node):
# handle generators before element
for gen in node.generators:
self.handleNode(gen, node)
self.handleNode(node.elt, node)
GENERATOREXP = SETCOMP = LISTCOMP
# dictionary comprehensions; introduced in Python 2.7
def DICTCOMP(self, node):
for gen in node.generators:
self.handleNode(gen, node)
self.handleNode(node.key, node)
self.handleNode(node.value, node)
def FOR(self, node):
"""
Process bindings for loop variables.
"""
vars = []
def collectLoopVars(n):
if isinstance(n, _ast.Name):
vars.append(n.id)
elif isinstance(n, _ast.expr_context):
return
else:
for c in iter_child_nodes(n):
collectLoopVars(c)
collectLoopVars(node.target)
for varn in vars:
if (isinstance(self.scope.get(varn), Importation)
# unused ones will get an unused import warning
and self.scope[varn].used):
self.report(messages.ImportShadowedByLoopVar,
node, varn, self.scope[varn].source)
self.handleChildren(node)
def NAME(self, node):
"""
Handle occurrence of Name (which can be a load/store/delete access.)
"""
# Locate the name in locals / function / globals scopes.
if isinstance(node.ctx, (_ast.Load, _ast.AugLoad)):
# try local scope
importStarred = self.scope.importStarred
try:
self.scope[node.id].used = (self.scope, node)
except KeyError:
pass
else:
return
# try enclosing function scopes
for scope in self.scopeStack[-2:0:-1]:
importStarred = importStarred or scope.importStarred
if not isinstance(scope, FunctionScope):
continue
try:
scope[node.id].used = (self.scope, node)
except KeyError:
pass
else:
return
# try global scope
importStarred = importStarred or self.scopeStack[0].importStarred
try:
self.scopeStack[0][node.id].used = (self.scope, node)
except KeyError:
if ((not hasattr(__builtin__, node.id))
and node.id not in _MAGIC_GLOBALS
and not importStarred):
if (os.path.basename(self.filename) == '__init__.py' and
node.id == '__path__'):
# the special name __path__ is valid only in packages
pass
else:
self.report(messages.UndefinedName, node, node.id)
elif isinstance(node.ctx, (_ast.Store, _ast.AugStore)):
# if the name hasn't already been defined in the current scope
if isinstance(self.scope, FunctionScope) and node.id not in self.scope:
# for each function or module scope above us
for scope in self.scopeStack[:-1]:
if not isinstance(scope, (FunctionScope, ModuleScope)):
continue
# if the name was defined in that scope, and the name has
# been accessed already in the current scope, and hasn't
# been declared global
if (node.id in scope
and scope[node.id].used
and scope[node.id].used[0] is self.scope
and node.id not in self.scope.globals):
# then it's probably a mistake
self.report(messages.UndefinedLocal,
scope[node.id].used[1],
node.id,
scope[node.id].source)
break
if isinstance(node.parent,
(_ast.For, _ast.comprehension, _ast.Tuple, _ast.List)):
binding = Binding(node.id, node)
elif (node.id == '__all__' and
isinstance(self.scope, ModuleScope)):
binding = ExportBinding(node.id, node.parent.value)
else:
binding = Assignment(node.id, node)
if node.id in self.scope:
binding.used = self.scope[node.id].used
self.addBinding(node, binding)
elif isinstance(node.ctx, _ast.Del):
if isinstance(self.scope, FunctionScope) and \
node.id in self.scope.globals:
del self.scope.globals[node.id]
else:
self.addBinding(node, UnBinding(node.id, node))
else:
# must be a Param context -- this only happens for names in function
# arguments, but these aren't dispatched through here
raise RuntimeError(
"Got impossible expression context: %r" % (node.ctx,))
def FUNCTIONDEF(self, node):
# the decorators attribute is called decorator_list as of Python 2.6
if hasattr(node, 'decorators'):
for deco in node.decorators:
self.handleNode(deco, node)
else:
for deco in node.decorator_list:
self.handleNode(deco, node)
self.addBinding(node, FunctionDefinition(node.name, node))
self.LAMBDA(node)
def LAMBDA(self, node):
for default in node.args.defaults:
self.handleNode(default, node)
def runFunction():
args = []
def addArgs(arglist):
for arg in arglist:
if isinstance(arg, _ast.Tuple):
addArgs(arg.elts)
else:
if arg.id in args:
self.report(messages.DuplicateArgument,
node, arg.id)
args.append(arg.id)
self.pushFunctionScope()
addArgs(node.args.args)
# vararg/kwarg identifiers are not Name nodes
if node.args.vararg:
args.append(node.args.vararg)
if node.args.kwarg:
args.append(node.args.kwarg)
for name in args:
self.addBinding(node, Argument(name, node), reportRedef=False)
if isinstance(node.body, list):
# case for FunctionDefs
for stmt in node.body:
self.handleNode(stmt, node)
else:
# case for Lambdas
self.handleNode(node.body, node)
def checkUnusedAssignments():
"""
Check to see if any assignments have not been used.
"""
for name, binding in self.scope.iteritems():
if (not binding.used and not name in self.scope.globals
and isinstance(binding, Assignment)):
self.report(messages.UnusedVariable,
binding.source, name)
self.deferAssignment(checkUnusedAssignments)
self.popScope()
self.deferFunction(runFunction)
def CLASSDEF(self, node):
"""
Check names used in a class definition, including its decorators, base
classes, and the body of its definition. Additionally, add its name to
the current scope.
"""
# decorator_list is present as of Python 2.6
for deco in getattr(node, 'decorator_list', []):
self.handleNode(deco, node)
for baseNode in node.bases:
self.handleNode(baseNode, node)
self.pushClassScope()
for stmt in node.body:
self.handleNode(stmt, node)
self.popScope()
self.addBinding(node, Binding(node.name, node))
def ASSIGN(self, node):
self.handleNode(node.value, node)
for target in node.targets:
self.handleNode(target, node)
def AUGASSIGN(self, node):
# AugAssign is awkward: must set the context explicitly and visit twice,
# once with AugLoad context, once with AugStore context
node.target.ctx = _ast.AugLoad()
self.handleNode(node.target, node)
self.handleNode(node.value, node)
node.target.ctx = _ast.AugStore()
self.handleNode(node.target, node)
def IMPORT(self, node):
for alias in node.names:
name = alias.asname or alias.name
importation = Importation(name, node)
self.addBinding(node, importation)
def IMPORTFROM(self, node):
if node.module == '__future__':
if not self.futuresAllowed:
self.report(messages.LateFutureImport, node,
[n.name for n in node.names])
else:
self.futuresAllowed = False
for alias in node.names:
if alias.name == '*':
self.scope.importStarred = True
self.report(messages.ImportStarUsed, node, node.module)
continue
name = alias.asname or alias.name
importation = Importation(name, node)
if node.module == '__future__':
importation.used = (self.scope, node)
self.addBinding(node, importation)

View File

@@ -1,96 +0,0 @@
# (c) 2005 Divmod, Inc. See LICENSE file for details
class Message(object):
message = ''
message_args = ()
def __init__(self, filename, loc, use_column=True):
self.filename = filename
self.lineno = loc.lineno
self.col = getattr(loc, 'col_offset', None) if use_column else None
def __str__(self):
return '%s:%s: %s' % (self.filename, self.lineno, self.message % self.message_args)
class UnusedImport(Message):
message = '%r imported but unused'
def __init__(self, filename, loc, name):
Message.__init__(self, filename, loc, use_column=False)
self.message_args = (name,)
class RedefinedWhileUnused(Message):
message = 'redefinition of unused %r from line %r'
def __init__(self, filename, loc, name, orig_loc):
Message.__init__(self, filename, loc)
self.message_args = (name, orig_loc.lineno)
class ImportShadowedByLoopVar(Message):
message = 'import %r from line %r shadowed by loop variable'
def __init__(self, filename, loc, name, orig_loc):
Message.__init__(self, filename, loc)
self.message_args = (name, orig_loc.lineno)
class ImportStarUsed(Message):
message = "'from %s import *' used; unable to detect undefined names"
def __init__(self, filename, loc, modname):
Message.__init__(self, filename, loc)
self.message_args = (modname,)
class UndefinedName(Message):
message = 'undefined name %r'
def __init__(self, filename, loc, name):
Message.__init__(self, filename, loc)
self.message_args = (name,)
class UndefinedExport(Message):
message = 'undefined name %r in __all__'
def __init__(self, filename, loc, name):
Message.__init__(self, filename, loc)
self.message_args = (name,)
class UndefinedLocal(Message):
message = "local variable %r (defined in enclosing scope on line %r) referenced before assignment"
def __init__(self, filename, loc, name, orig_loc):
Message.__init__(self, filename, loc)
self.message_args = (name, orig_loc.lineno)
class DuplicateArgument(Message):
message = 'duplicate argument %r in function definition'
def __init__(self, filename, loc, name):
Message.__init__(self, filename, loc)
self.message_args = (name,)
class RedefinedFunction(Message):
message = 'redefinition of function %r from line %r'
def __init__(self, filename, loc, name, orig_loc):
Message.__init__(self, filename, loc)
self.message_args = (name, orig_loc.lineno)
class LateFutureImport(Message):
message = 'future import(s) %r after other statements'
def __init__(self, filename, loc, names):
Message.__init__(self, filename, loc)
self.message_args = (names,)
class UnusedVariable(Message):
"""
Indicates that a variable has been explicity assigned to but not actually
used.
"""
message = 'local variable %r is assigned to but never used'
def __init__(self, filename, loc, names):
Message.__init__(self, filename, loc)
self.message_args = (names,)

View File

@@ -1,90 +0,0 @@
"""
Implementation of the command-line I{pyflakes} tool.
"""
import sys
import os
import _ast
checker = __import__('pyflakes.checker').checker
def check(codeString, filename):
"""
Check the Python source given by C{codeString} for flakes.
@param codeString: The Python source to check.
@type codeString: C{str}
@param filename: The name of the file the source came from, used to report
errors.
@type filename: C{str}
@return: The number of warnings emitted.
@rtype: C{int}
"""
# First, compile into an AST and handle syntax errors.
try:
tree = compile(codeString, filename, "exec", _ast.PyCF_ONLY_AST)
except SyntaxError, value:
msg = value.args[0]
(lineno, offset, text) = value.lineno, value.offset, value.text
# If there's an encoding problem with the file, the text is None.
if text is None:
# Avoid using msg, since for the only known case, it contains a
# bogus message that claims the encoding the file declared was
# unknown.
print >> sys.stderr, "%s: problem decoding source" % (filename, )
else:
line = text.splitlines()[-1]
if offset is not None:
offset = offset - (len(text) - len(line))
print >> sys.stderr, '%s:%d: %s' % (filename, lineno, msg)
print >> sys.stderr, line
if offset is not None:
print >> sys.stderr, " " * offset, "^"
return 1
else:
# Okay, it's syntactically valid. Now check it.
w = checker.Checker(tree, filename)
w.messages.sort(lambda a, b: cmp(a.lineno, b.lineno))
for warning in w.messages:
print warning
return len(w.messages)
def checkPath(filename):
"""
Check the given path, printing out any warnings detected.
@return: the number of warnings printed
"""
try:
return check(file(filename, 'U').read() + '\n', filename)
except IOError, msg:
print >> sys.stderr, "%s: %s" % (filename, msg.args[1])
return 1
def main():
warnings = 0
args = sys.argv[1:]
if args:
for arg in args:
if os.path.isdir(arg):
for dirpath, dirnames, filenames in os.walk(arg):
for filename in filenames:
if filename.endswith('.py'):
warnings += checkPath(os.path.join(dirpath, filename))
else:
warnings += checkPath(arg)
else:
warnings += check(sys.stdin.read(), '<stdin>')
raise SystemExit(warnings > 0)

View File

@@ -1,27 +0,0 @@
import textwrap
import _ast
from twisted.trial import unittest
from pyflakes import checker
class Test(unittest.TestCase):
def flakes(self, input, *expectedOutputs, **kw):
ast = compile(textwrap.dedent(input), "<test>", "exec",
_ast.PyCF_ONLY_AST)
w = checker.Checker(ast, **kw)
outputs = [type(o) for o in w.messages]
expectedOutputs = list(expectedOutputs)
outputs.sort()
expectedOutputs.sort()
self.assert_(outputs == expectedOutputs, '''\
for input:
%s
expected outputs:
%s
but got:
%s''' % (input, repr(expectedOutputs), '\n'.join([str(o) for o in w.messages])))
return w

View File

@@ -1,673 +0,0 @@
from sys import version_info
from pyflakes import messages as m
from pyflakes.test import harness
class Test(harness.Test):
def test_unusedImport(self):
self.flakes('import fu, bar', m.UnusedImport, m.UnusedImport)
self.flakes('from baz import fu, bar', m.UnusedImport, m.UnusedImport)
def test_aliasedImport(self):
self.flakes('import fu as FU, bar as FU', m.RedefinedWhileUnused, m.UnusedImport)
self.flakes('from moo import fu as FU, bar as FU', m.RedefinedWhileUnused, m.UnusedImport)
def test_usedImport(self):
self.flakes('import fu; print fu')
self.flakes('from baz import fu; print fu')
def test_redefinedWhileUnused(self):
self.flakes('import fu; fu = 3', m.RedefinedWhileUnused)
self.flakes('import fu; del fu', m.RedefinedWhileUnused)
self.flakes('import fu; fu, bar = 3', m.RedefinedWhileUnused)
self.flakes('import fu; [fu, bar] = 3', m.RedefinedWhileUnused)
def test_redefinedByFunction(self):
self.flakes('''
import fu
def fu():
pass
''', m.RedefinedWhileUnused)
def test_redefinedInNestedFunction(self):
"""
Test that shadowing a global name with a nested function definition
generates a warning.
"""
self.flakes('''
import fu
def bar():
def baz():
def fu():
pass
''', m.RedefinedWhileUnused, m.UnusedImport)
def test_redefinedByClass(self):
self.flakes('''
import fu
class fu:
pass
''', m.RedefinedWhileUnused)
def test_redefinedBySubclass(self):
"""
If an imported name is redefined by a class statement which also uses
that name in the bases list, no warning is emitted.
"""
self.flakes('''
from fu import bar
class bar(bar):
pass
''')
def test_redefinedInClass(self):
"""
Test that shadowing a global with a class attribute does not produce a
warning.
"""
self.flakes('''
import fu
class bar:
fu = 1
print fu
''')
def test_usedInFunction(self):
self.flakes('''
import fu
def fun():
print fu
''')
def test_shadowedByParameter(self):
self.flakes('''
import fu
def fun(fu):
print fu
''', m.UnusedImport)
self.flakes('''
import fu
def fun(fu):
print fu
print fu
''')
def test_newAssignment(self):
self.flakes('fu = None')
def test_usedInGetattr(self):
self.flakes('import fu; fu.bar.baz')
self.flakes('import fu; "bar".fu.baz', m.UnusedImport)
def test_usedInSlice(self):
self.flakes('import fu; print fu.bar[1:]')
def test_usedInIfBody(self):
self.flakes('''
import fu
if True: print fu
''')
def test_usedInIfConditional(self):
self.flakes('''
import fu
if fu: pass
''')
def test_usedInElifConditional(self):
self.flakes('''
import fu
if False: pass
elif fu: pass
''')
def test_usedInElse(self):
self.flakes('''
import fu
if False: pass
else: print fu
''')
def test_usedInCall(self):
self.flakes('import fu; fu.bar()')
def test_usedInClass(self):
self.flakes('''
import fu
class bar:
bar = fu
''')
def test_usedInClassBase(self):
self.flakes('''
import fu
class bar(object, fu.baz):
pass
''')
def test_notUsedInNestedScope(self):
self.flakes('''
import fu
def bleh():
pass
print fu
''')
def test_usedInFor(self):
self.flakes('''
import fu
for bar in range(9):
print fu
''')
def test_usedInForElse(self):
self.flakes('''
import fu
for bar in range(10):
pass
else:
print fu
''')
def test_redefinedByFor(self):
self.flakes('''
import fu
for fu in range(2):
pass
''', m.RedefinedWhileUnused)
def test_shadowedByFor(self):
"""
Test that shadowing a global name with a for loop variable generates a
warning.
"""
self.flakes('''
import fu
fu.bar()
for fu in ():
pass
''', m.ImportShadowedByLoopVar)
def test_shadowedByForDeep(self):
"""
Test that shadowing a global name with a for loop variable nested in a
tuple unpack generates a warning.
"""
self.flakes('''
import fu
fu.bar()
for (x, y, z, (a, b, c, (fu,))) in ():
pass
''', m.ImportShadowedByLoopVar)
def test_usedInReturn(self):
self.flakes('''
import fu
def fun():
return fu
''')
def test_usedInOperators(self):
self.flakes('import fu; 3 + fu.bar')
self.flakes('import fu; 3 % fu.bar')
self.flakes('import fu; 3 - fu.bar')
self.flakes('import fu; 3 * fu.bar')
self.flakes('import fu; 3 ** fu.bar')
self.flakes('import fu; 3 / fu.bar')
self.flakes('import fu; 3 // fu.bar')
self.flakes('import fu; -fu.bar')
self.flakes('import fu; ~fu.bar')
self.flakes('import fu; 1 == fu.bar')
self.flakes('import fu; 1 | fu.bar')
self.flakes('import fu; 1 & fu.bar')
self.flakes('import fu; 1 ^ fu.bar')
self.flakes('import fu; 1 >> fu.bar')
self.flakes('import fu; 1 << fu.bar')
def test_usedInAssert(self):
self.flakes('import fu; assert fu.bar')
def test_usedInSubscript(self):
self.flakes('import fu; fu.bar[1]')
def test_usedInLogic(self):
self.flakes('import fu; fu and False')
self.flakes('import fu; fu or False')
self.flakes('import fu; not fu.bar')
def test_usedInList(self):
self.flakes('import fu; [fu]')
def test_usedInTuple(self):
self.flakes('import fu; (fu,)')
def test_usedInTry(self):
self.flakes('''
import fu
try: fu
except: pass
''')
def test_usedInExcept(self):
self.flakes('''
import fu
try: fu
except: pass
''')
def test_redefinedByExcept(self):
self.flakes('''
import fu
try: pass
except Exception, fu: pass
''', m.RedefinedWhileUnused)
def test_usedInRaise(self):
self.flakes('''
import fu
raise fu.bar
''')
def test_usedInYield(self):
self.flakes('''
import fu
def gen():
yield fu
''')
def test_usedInDict(self):
self.flakes('import fu; {fu:None}')
self.flakes('import fu; {1:fu}')
def test_usedInParameterDefault(self):
self.flakes('''
import fu
def f(bar=fu):
pass
''')
def test_usedInAttributeAssign(self):
self.flakes('import fu; fu.bar = 1')
def test_usedInKeywordArg(self):
self.flakes('import fu; fu.bar(stuff=fu)')
def test_usedInAssignment(self):
self.flakes('import fu; bar=fu')
self.flakes('import fu; n=0; n+=fu')
def test_usedInListComp(self):
self.flakes('import fu; [fu for _ in range(1)]')
self.flakes('import fu; [1 for _ in range(1) if fu]')
def test_redefinedByListComp(self):
self.flakes('import fu; [1 for fu in range(1)]', m.RedefinedWhileUnused)
def test_usedInTryFinally(self):
self.flakes('''
import fu
try: pass
finally: fu
''')
self.flakes('''
import fu
try: fu
finally: pass
''')
def test_usedInWhile(self):
self.flakes('''
import fu
while 0:
fu
''')
self.flakes('''
import fu
while fu: pass
''')
def test_usedInGlobal(self):
self.flakes('''
import fu
def f(): global fu
''', m.UnusedImport)
def test_usedInBackquote(self):
self.flakes('import fu; `fu`')
def test_usedInExec(self):
self.flakes('import fu; exec "print 1" in fu.bar')
def test_usedInLambda(self):
self.flakes('import fu; lambda: fu')
def test_shadowedByLambda(self):
self.flakes('import fu; lambda fu: fu', m.UnusedImport)
def test_usedInSliceObj(self):
self.flakes('import fu; "meow"[::fu]')
def test_unusedInNestedScope(self):
self.flakes('''
def bar():
import fu
fu
''', m.UnusedImport, m.UndefinedName)
def test_methodsDontUseClassScope(self):
self.flakes('''
class bar:
import fu
def fun(self):
fu
''', m.UnusedImport, m.UndefinedName)
def test_nestedFunctionsNestScope(self):
self.flakes('''
def a():
def b():
fu
import fu
''')
def test_nestedClassAndFunctionScope(self):
self.flakes('''
def a():
import fu
class b:
def c(self):
print fu
''')
def test_importStar(self):
self.flakes('from fu import *', m.ImportStarUsed)
def test_packageImport(self):
"""
If a dotted name is imported and used, no warning is reported.
"""
self.flakes('''
import fu.bar
fu.bar
''')
def test_unusedPackageImport(self):
"""
If a dotted name is imported and not used, an unused import warning is
reported.
"""
self.flakes('import fu.bar', m.UnusedImport)
def test_duplicateSubmoduleImport(self):
"""
If a submodule of a package is imported twice, an unused import warning
and a redefined while unused warning are reported.
"""
self.flakes('''
import fu.bar, fu.bar
fu.bar
''', m.RedefinedWhileUnused)
self.flakes('''
import fu.bar
import fu.bar
fu.bar
''', m.RedefinedWhileUnused)
def test_differentSubmoduleImport(self):
"""
If two different submodules of a package are imported, no duplicate
import warning is reported for the package.
"""
self.flakes('''
import fu.bar, fu.baz
fu.bar, fu.baz
''')
self.flakes('''
import fu.bar
import fu.baz
fu.bar, fu.baz
''')
def test_assignRHSFirst(self):
self.flakes('import fu; fu = fu')
self.flakes('import fu; fu, bar = fu')
self.flakes('import fu; [fu, bar] = fu')
self.flakes('import fu; fu += fu')
def test_tryingMultipleImports(self):
self.flakes('''
try:
import fu
except ImportError:
import bar as fu
''')
test_tryingMultipleImports.todo = ''
def test_nonGlobalDoesNotRedefine(self):
self.flakes('''
import fu
def a():
fu = 3
return fu
fu
''')
def test_functionsRunLater(self):
self.flakes('''
def a():
fu
import fu
''')
def test_functionNamesAreBoundNow(self):
self.flakes('''
import fu
def fu():
fu
fu
''', m.RedefinedWhileUnused)
def test_ignoreNonImportRedefinitions(self):
self.flakes('a = 1; a = 2')
def test_importingForImportError(self):
self.flakes('''
try:
import fu
except ImportError:
pass
''')
test_importingForImportError.todo = ''
def test_importedInClass(self):
'''Imports in class scope can be used through self'''
self.flakes('''
class c:
import i
def __init__(self):
self.i
''')
test_importedInClass.todo = 'requires evaluating attribute access'
def test_futureImport(self):
'''__future__ is special'''
self.flakes('from __future__ import division')
self.flakes('''
"docstring is allowed before future import"
from __future__ import division
''')
def test_futureImportFirst(self):
"""
__future__ imports must come before anything else.
"""
self.flakes('''
x = 5
from __future__ import division
''', m.LateFutureImport)
self.flakes('''
from foo import bar
from __future__ import division
bar
''', m.LateFutureImport)
class TestSpecialAll(harness.Test):
"""
Tests for suppression of unused import warnings by C{__all__}.
"""
def test_ignoredInFunction(self):
"""
An C{__all__} definition does not suppress unused import warnings in a
function scope.
"""
self.flakes('''
def foo():
import bar
__all__ = ["bar"]
''', m.UnusedImport, m.UnusedVariable)
def test_ignoredInClass(self):
"""
An C{__all__} definition does not suppress unused import warnings in a
class scope.
"""
self.flakes('''
class foo:
import bar
__all__ = ["bar"]
''', m.UnusedImport)
def test_warningSuppressed(self):
"""
If a name is imported and unused but is named in C{__all__}, no warning
is reported.
"""
self.flakes('''
import foo
__all__ = ["foo"]
''')
def test_unrecognizable(self):
"""
If C{__all__} is defined in a way that can't be recognized statically,
it is ignored.
"""
self.flakes('''
import foo
__all__ = ["f" + "oo"]
''', m.UnusedImport)
self.flakes('''
import foo
__all__ = [] + ["foo"]
''', m.UnusedImport)
def test_unboundExported(self):
"""
If C{__all__} includes a name which is not bound, a warning is emitted.
"""
self.flakes('''
__all__ = ["foo"]
''', m.UndefinedExport)
# Skip this in __init__.py though, since the rules there are a little
# different.
for filename in ["foo/__init__.py", "__init__.py"]:
self.flakes('''
__all__ = ["foo"]
''', filename=filename)
def test_usedInGenExp(self):
"""
Using a global in a generator expression results in no warnings.
"""
self.flakes('import fu; (fu for _ in range(1))')
self.flakes('import fu; (1 for _ in range(1) if fu)')
def test_redefinedByGenExp(self):
"""
Re-using a global name as the loop variable for a generator
expression results in a redefinition warning.
"""
self.flakes('import fu; (1 for fu in range(1))', m.RedefinedWhileUnused)
def test_usedAsDecorator(self):
"""
Using a global name in a decorator statement results in no warnings,
but using an undefined name in a decorator statement results in an
undefined name warning.
"""
self.flakes('''
from interior import decorate
@decorate
def f():
return "hello"
''')
self.flakes('''
from interior import decorate
@decorate('value')
def f():
return "hello"
''')
self.flakes('''
@decorate
def f():
return "hello"
''', m.UndefinedName)
class Python26Tests(harness.Test):
"""
Tests for checking of syntax which is valid in PYthon 2.6 and newer.
"""
if version_info < (2, 6):
skip = "Python 2.6 required for class decorator tests."
def test_usedAsClassDecorator(self):
"""
Using an imported name as a class decorator results in no warnings,
but using an undefined name as a class decorator results in an
undefined name warning.
"""
self.flakes('''
from interior import decorate
@decorate
class foo:
pass
''')
self.flakes('''
from interior import decorate
@decorate("foo")
class bar:
pass
''')
self.flakes('''
@decorate
class foo:
pass
''', m.UndefinedName)

View File

@@ -1,575 +0,0 @@
# (c) 2005-2010 Divmod, Inc.
# See LICENSE file for details
"""
Tests for various Pyflakes behavior.
"""
from sys import version_info
from pyflakes import messages as m
from pyflakes.test import harness
class Test(harness.Test):
def test_duplicateArgs(self):
self.flakes('def fu(bar, bar): pass', m.DuplicateArgument)
def test_localReferencedBeforeAssignment(self):
self.flakes('''
a = 1
def f():
a; a=1
f()
''', m.UndefinedName)
test_localReferencedBeforeAssignment.todo = 'this requires finding all assignments in the function body first'
def test_redefinedFunction(self):
"""
Test that shadowing a function definition with another one raises a
warning.
"""
self.flakes('''
def a(): pass
def a(): pass
''', m.RedefinedFunction)
def test_redefinedClassFunction(self):
"""
Test that shadowing a function definition in a class suite with another
one raises a warning.
"""
self.flakes('''
class A:
def a(): pass
def a(): pass
''', m.RedefinedFunction)
def test_functionDecorator(self):
"""
Test that shadowing a function definition with a decorated version of
that function does not raise a warning.
"""
self.flakes('''
from somewhere import somedecorator
def a(): pass
a = somedecorator(a)
''')
def test_classFunctionDecorator(self):
"""
Test that shadowing a function definition in a class suite with a
decorated version of that function does not raise a warning.
"""
self.flakes('''
class A:
def a(): pass
a = classmethod(a)
''')
def test_unaryPlus(self):
'''Don't die on unary +'''
self.flakes('+1')
def test_undefinedBaseClass(self):
"""
If a name in the base list of a class definition is undefined, a
warning is emitted.
"""
self.flakes('''
class foo(foo):
pass
''', m.UndefinedName)
def test_classNameUndefinedInClassBody(self):
"""
If a class name is used in the body of that class's definition and
the name is not already defined, a warning is emitted.
"""
self.flakes('''
class foo:
foo
''', m.UndefinedName)
def test_classNameDefinedPreviously(self):
"""
If a class name is used in the body of that class's definition and
the name was previously defined in some other way, no warning is
emitted.
"""
self.flakes('''
foo = None
class foo:
foo
''')
def test_comparison(self):
"""
If a defined name is used on either side of any of the six comparison
operators, no warning is emitted.
"""
self.flakes('''
x = 10
y = 20
x < y
x <= y
x == y
x != y
x >= y
x > y
''')
def test_identity(self):
"""
If a deefined name is used on either side of an identity test, no
warning is emitted.
"""
self.flakes('''
x = 10
y = 20
x is y
x is not y
''')
def test_containment(self):
"""
If a defined name is used on either side of a containment test, no
warning is emitted.
"""
self.flakes('''
x = 10
y = 20
x in y
x not in y
''')
def test_loopControl(self):
"""
break and continue statements are supported.
"""
self.flakes('''
for x in [1, 2]:
break
''')
self.flakes('''
for x in [1, 2]:
continue
''')
def test_ellipsis(self):
"""
Ellipsis in a slice is supported.
"""
self.flakes('''
[1, 2][...]
''')
def test_extendedSlice(self):
"""
Extended slices are supported.
"""
self.flakes('''
x = 3
[1, 2][x,:]
''')
class TestUnusedAssignment(harness.Test):
"""
Tests for warning about unused assignments.
"""
def test_unusedVariable(self):
"""
Warn when a variable in a function is assigned a value that's never
used.
"""
self.flakes('''
def a():
b = 1
''', m.UnusedVariable)
def test_assignToGlobal(self):
"""
Assigning to a global and then not using that global is perfectly
acceptable. Do not mistake it for an unused local variable.
"""
self.flakes('''
b = 0
def a():
global b
b = 1
''')
def test_assignToMember(self):
"""
Assigning to a member of another object and then not using that member
variable is perfectly acceptable. Do not mistake it for an unused
local variable.
"""
# XXX: Adding this test didn't generate a failure. Maybe not
# necessary?
self.flakes('''
class b:
pass
def a():
b.foo = 1
''')
def test_assignInForLoop(self):
"""
Don't warn when a variable in a for loop is assigned to but not used.
"""
self.flakes('''
def f():
for i in range(10):
pass
''')
def test_assignInListComprehension(self):
"""
Don't warn when a variable in a list comprehension is assigned to but
not used.
"""
self.flakes('''
def f():
[None for i in range(10)]
''')
def test_generatorExpression(self):
"""
Don't warn when a variable in a generator expression is assigned to but not used.
"""
self.flakes('''
def f():
(None for i in range(10))
''')
def test_assignmentInsideLoop(self):
"""
Don't warn when a variable assignment occurs lexically after its use.
"""
self.flakes('''
def f():
x = None
for i in range(10):
if i > 2:
return x
x = i * 2
''')
def test_tupleUnpacking(self):
"""
Don't warn when a variable included in tuple unpacking is unused. It's
very common for variables in a tuple unpacking assignment to be unused
in good Python code, so warning will only create false positives.
"""
self.flakes('''
def f():
(x, y) = 1, 2
''')
def test_listUnpacking(self):
"""
Don't warn when a variable included in list unpacking is unused.
"""
self.flakes('''
def f():
[x, y] = [1, 2]
''')
def test_closedOver(self):
"""
Don't warn when the assignment is used in an inner function.
"""
self.flakes('''
def barMaker():
foo = 5
def bar():
return foo
return bar
''')
def test_doubleClosedOver(self):
"""
Don't warn when the assignment is used in an inner function, even if
that inner function itself is in an inner function.
"""
self.flakes('''
def barMaker():
foo = 5
def bar():
def baz():
return foo
return bar
''')
class Python25Test(harness.Test):
"""
Tests for checking of syntax only available in Python 2.5 and newer.
"""
if version_info < (2, 5):
skip = "Python 2.5 required for if-else and with tests"
def test_ifexp(self):
"""
Test C{foo if bar else baz} statements.
"""
self.flakes("a = 'moo' if True else 'oink'")
self.flakes("a = foo if True else 'oink'", m.UndefinedName)
self.flakes("a = 'moo' if True else bar", m.UndefinedName)
def test_withStatementNoNames(self):
"""
No warnings are emitted for using inside or after a nameless C{with}
statement a name defined beforehand.
"""
self.flakes('''
from __future__ import with_statement
bar = None
with open("foo"):
bar
bar
''')
def test_withStatementSingleName(self):
"""
No warnings are emitted for using a name defined by a C{with} statement
within the suite or afterwards.
"""
self.flakes('''
from __future__ import with_statement
with open('foo') as bar:
bar
bar
''')
def test_withStatementAttributeName(self):
"""
No warnings are emitted for using an attribute as the target of a
C{with} statement.
"""
self.flakes('''
from __future__ import with_statement
import foo
with open('foo') as foo.bar:
pass
''')
def test_withStatementSubscript(self):
"""
No warnings are emitted for using a subscript as the target of a
C{with} statement.
"""
self.flakes('''
from __future__ import with_statement
import foo
with open('foo') as foo[0]:
pass
''')
def test_withStatementSubscriptUndefined(self):
"""
An undefined name warning is emitted if the subscript used as the
target of a C{with} statement is not defined.
"""
self.flakes('''
from __future__ import with_statement
import foo
with open('foo') as foo[bar]:
pass
''', m.UndefinedName)
def test_withStatementTupleNames(self):
"""
No warnings are emitted for using any of the tuple of names defined by
a C{with} statement within the suite or afterwards.
"""
self.flakes('''
from __future__ import with_statement
with open('foo') as (bar, baz):
bar, baz
bar, baz
''')
def test_withStatementListNames(self):
"""
No warnings are emitted for using any of the list of names defined by a
C{with} statement within the suite or afterwards.
"""
self.flakes('''
from __future__ import with_statement
with open('foo') as [bar, baz]:
bar, baz
bar, baz
''')
def test_withStatementComplicatedTarget(self):
"""
If the target of a C{with} statement uses any or all of the valid forms
for that part of the grammar (See
U{http://docs.python.org/reference/compound_stmts.html#the-with-statement}),
the names involved are checked both for definedness and any bindings
created are respected in the suite of the statement and afterwards.
"""
self.flakes('''
from __future__ import with_statement
c = d = e = g = h = i = None
with open('foo') as [(a, b), c[d], e.f, g[h:i]]:
a, b, c, d, e, g, h, i
a, b, c, d, e, g, h, i
''')
def test_withStatementSingleNameUndefined(self):
"""
An undefined name warning is emitted if the name first defined by a
C{with} statement is used before the C{with} statement.
"""
self.flakes('''
from __future__ import with_statement
bar
with open('foo') as bar:
pass
''', m.UndefinedName)
def test_withStatementTupleNamesUndefined(self):
"""
An undefined name warning is emitted if a name first defined by a the
tuple-unpacking form of the C{with} statement is used before the
C{with} statement.
"""
self.flakes('''
from __future__ import with_statement
baz
with open('foo') as (bar, baz):
pass
''', m.UndefinedName)
def test_withStatementSingleNameRedefined(self):
"""
A redefined name warning is emitted if a name bound by an import is
rebound by the name defined by a C{with} statement.
"""
self.flakes('''
from __future__ import with_statement
import bar
with open('foo') as bar:
pass
''', m.RedefinedWhileUnused)
def test_withStatementTupleNamesRedefined(self):
"""
A redefined name warning is emitted if a name bound by an import is
rebound by one of the names defined by the tuple-unpacking form of a
C{with} statement.
"""
self.flakes('''
from __future__ import with_statement
import bar
with open('foo') as (bar, baz):
pass
''', m.RedefinedWhileUnused)
def test_withStatementUndefinedInside(self):
"""
An undefined name warning is emitted if a name is used inside the
body of a C{with} statement without first being bound.
"""
self.flakes('''
from __future__ import with_statement
with open('foo') as bar:
baz
''', m.UndefinedName)
def test_withStatementNameDefinedInBody(self):
"""
A name defined in the body of a C{with} statement can be used after
the body ends without warning.
"""
self.flakes('''
from __future__ import with_statement
with open('foo') as bar:
baz = 10
baz
''')
def test_withStatementUndefinedInExpression(self):
"""
An undefined name warning is emitted if a name in the I{test}
expression of a C{with} statement is undefined.
"""
self.flakes('''
from __future__ import with_statement
with bar as baz:
pass
''', m.UndefinedName)
self.flakes('''
from __future__ import with_statement
with bar as bar:
pass
''', m.UndefinedName)
class Python27Test(harness.Test):
"""
Tests for checking of syntax only available in Python 2.7 and newer.
"""
if version_info < (2, 7):
skip = "Python 2.7 required for dict/set comprehension tests"
def test_dictComprehension(self):
"""
Dict comprehensions are properly handled.
"""
self.flakes('''
a = {1: x for x in range(10)}
''')
def test_setComprehensionAndLiteral(self):
"""
Set comprehensions are properly handled.
"""
self.flakes('''
a = {1, 2, 3}
b = {x for x in range(10)}
''')

View File

@@ -1,185 +0,0 @@
"""
Tests for L{pyflakes.scripts.pyflakes}.
"""
import sys
from StringIO import StringIO
from twisted.python.filepath import FilePath
from twisted.trial.unittest import TestCase
from pyflakes.scripts.pyflakes import checkPath
def withStderrTo(stderr, f):
"""
Call C{f} with C{sys.stderr} redirected to C{stderr}.
"""
(outer, sys.stderr) = (sys.stderr, stderr)
try:
return f()
finally:
sys.stderr = outer
class CheckTests(TestCase):
"""
Tests for L{check} and L{checkPath} which check a file for flakes.
"""
def test_missingTrailingNewline(self):
"""
Source which doesn't end with a newline shouldn't cause any
exception to be raised nor an error indicator to be returned by
L{check}.
"""
fName = self.mktemp()
FilePath(fName).setContent("def foo():\n\tpass\n\t")
self.assertFalse(checkPath(fName))
def test_checkPathNonExisting(self):
"""
L{checkPath} handles non-existing files.
"""
err = StringIO()
count = withStderrTo(err, lambda: checkPath('extremo'))
self.assertEquals(err.getvalue(), 'extremo: No such file or directory\n')
self.assertEquals(count, 1)
def test_multilineSyntaxError(self):
"""
Source which includes a syntax error which results in the raised
L{SyntaxError.text} containing multiple lines of source are reported
with only the last line of that source.
"""
source = """\
def foo():
'''
def bar():
pass
def baz():
'''quux'''
"""
# Sanity check - SyntaxError.text should be multiple lines, if it
# isn't, something this test was unprepared for has happened.
def evaluate(source):
exec source
exc = self.assertRaises(SyntaxError, evaluate, source)
self.assertTrue(exc.text.count('\n') > 1)
sourcePath = FilePath(self.mktemp())
sourcePath.setContent(source)
err = StringIO()
count = withStderrTo(err, lambda: checkPath(sourcePath.path))
self.assertEqual(count, 1)
self.assertEqual(
err.getvalue(),
"""\
%s:8: invalid syntax
'''quux'''
^
""" % (sourcePath.path,))
def test_eofSyntaxError(self):
"""
The error reported for source files which end prematurely causing a
syntax error reflects the cause for the syntax error.
"""
source = "def foo("
sourcePath = FilePath(self.mktemp())
sourcePath.setContent(source)
err = StringIO()
count = withStderrTo(err, lambda: checkPath(sourcePath.path))
self.assertEqual(count, 1)
self.assertEqual(
err.getvalue(),
"""\
%s:1: unexpected EOF while parsing
def foo(
^
""" % (sourcePath.path,))
def test_nonDefaultFollowsDefaultSyntaxError(self):
"""
Source which has a non-default argument following a default argument
should include the line number of the syntax error. However these
exceptions do not include an offset.
"""
source = """\
def foo(bar=baz, bax):
pass
"""
sourcePath = FilePath(self.mktemp())
sourcePath.setContent(source)
err = StringIO()
count = withStderrTo(err, lambda: checkPath(sourcePath.path))
self.assertEqual(count, 1)
self.assertEqual(
err.getvalue(),
"""\
%s:1: non-default argument follows default argument
def foo(bar=baz, bax):
""" % (sourcePath.path,))
def test_nonKeywordAfterKeywordSyntaxError(self):
"""
Source which has a non-keyword argument after a keyword argument should
include the line number of the syntax error. However these exceptions
do not include an offset.
"""
source = """\
foo(bar=baz, bax)
"""
sourcePath = FilePath(self.mktemp())
sourcePath.setContent(source)
err = StringIO()
count = withStderrTo(err, lambda: checkPath(sourcePath.path))
self.assertEqual(count, 1)
self.assertEqual(
err.getvalue(),
"""\
%s:1: non-keyword arg after keyword arg
foo(bar=baz, bax)
""" % (sourcePath.path,))
def test_permissionDenied(self):
"""
If the a source file is not readable, this is reported on standard
error.
"""
sourcePath = FilePath(self.mktemp())
sourcePath.setContent('')
sourcePath.chmod(0)
err = StringIO()
count = withStderrTo(err, lambda: checkPath(sourcePath.path))
self.assertEquals(count, 1)
self.assertEquals(
err.getvalue(), "%s: Permission denied\n" % (sourcePath.path,))
def test_misencodedFile(self):
"""
If a source file contains bytes which cannot be decoded, this is
reported on stderr.
"""
source = u"""\
# coding: ascii
x = "\N{SNOWMAN}"
""".encode('utf-8')
sourcePath = FilePath(self.mktemp())
sourcePath.setContent(source)
err = StringIO()
count = withStderrTo(err, lambda: checkPath(sourcePath.path))
self.assertEquals(count, 1)
self.assertEquals(
err.getvalue(), "%s: problem decoding source\n" % (sourcePath.path,))

View File

@@ -1,265 +0,0 @@
from _ast import PyCF_ONLY_AST
from twisted.trial.unittest import TestCase
from pyflakes import messages as m, checker
from pyflakes.test import harness
class Test(harness.Test):
def test_undefined(self):
self.flakes('bar', m.UndefinedName)
def test_definedInListComp(self):
self.flakes('[a for a in range(10) if a]')
def test_functionsNeedGlobalScope(self):
self.flakes('''
class a:
def b():
fu
fu = 1
''')
def test_builtins(self):
self.flakes('range(10)')
def test_magicGlobalsFile(self):
"""
Use of the C{__file__} magic global should not emit an undefined name
warning.
"""
self.flakes('__file__')
def test_magicGlobalsBuiltins(self):
"""
Use of the C{__builtins__} magic global should not emit an undefined
name warning.
"""
self.flakes('__builtins__')
def test_magicGlobalsName(self):
"""
Use of the C{__name__} magic global should not emit an undefined name
warning.
"""
self.flakes('__name__')
def test_magicGlobalsPath(self):
"""
Use of the C{__path__} magic global should not emit an undefined name
warning, if you refer to it from a file called __init__.py.
"""
self.flakes('__path__', m.UndefinedName)
self.flakes('__path__', filename='package/__init__.py')
def test_globalImportStar(self):
'''Can't find undefined names with import *'''
self.flakes('from fu import *; bar', m.ImportStarUsed)
def test_localImportStar(self):
'''A local import * still allows undefined names to be found in upper scopes'''
self.flakes('''
def a():
from fu import *
bar
''', m.ImportStarUsed, m.UndefinedName)
def test_unpackedParameter(self):
'''Unpacked function parameters create bindings'''
self.flakes('''
def a((bar, baz)):
bar; baz
''')
def test_definedByGlobal(self):
'''"global" can make an otherwise undefined name in another function defined'''
self.flakes('''
def a(): global fu; fu = 1
def b(): fu
''')
test_definedByGlobal.todo = ''
def test_globalInGlobalScope(self):
"""
A global statement in the global scope is ignored.
"""
self.flakes('''
global x
def foo():
print x
''', m.UndefinedName)
def test_del(self):
'''del deletes bindings'''
self.flakes('a = 1; del a; a', m.UndefinedName)
def test_delGlobal(self):
'''del a global binding from a function'''
self.flakes('''
a = 1
def f():
global a
del a
a
''')
def test_delUndefined(self):
'''del an undefined name'''
self.flakes('del a', m.UndefinedName)
def test_globalFromNestedScope(self):
'''global names are available from nested scopes'''
self.flakes('''
a = 1
def b():
def c():
a
''')
def test_laterRedefinedGlobalFromNestedScope(self):
"""
Test that referencing a local name that shadows a global, before it is
defined, generates a warning.
"""
self.flakes('''
a = 1
def fun():
a
a = 2
return a
''', m.UndefinedLocal)
def test_laterRedefinedGlobalFromNestedScope2(self):
"""
Test that referencing a local name in a nested scope that shadows a
global declared in an enclosing scope, before it is defined, generates
a warning.
"""
self.flakes('''
a = 1
def fun():
global a
def fun2():
a
a = 2
return a
''', m.UndefinedLocal)
def test_intermediateClassScopeIgnored(self):
"""
If a name defined in an enclosing scope is shadowed by a local variable
and the name is used locally before it is bound, an unbound local
warning is emitted, even if there is a class scope between the enclosing
scope and the local scope.
"""
self.flakes('''
def f():
x = 1
class g:
def h(self):
a = x
x = None
print x, a
print x
''', m.UndefinedLocal)
def test_doubleNestingReportsClosestName(self):
"""
Test that referencing a local name in a nested scope that shadows a
variable declared in two different outer scopes before it is defined
in the innermost scope generates an UnboundLocal warning which
refers to the nearest shadowed name.
"""
exc = self.flakes('''
def a():
x = 1
def b():
x = 2 # line 5
def c():
x
x = 3
return x
return x
return x
''', m.UndefinedLocal).messages[0]
self.assertEqual(exc.message_args, ('x', 5))
def test_laterRedefinedGlobalFromNestedScope3(self):
"""
Test that referencing a local name in a nested scope that shadows a
global, before it is defined, generates a warning.
"""
self.flakes('''
def fun():
a = 1
def fun2():
a
a = 1
return a
return a
''', m.UndefinedLocal)
def test_nestedClass(self):
'''nested classes can access enclosing scope'''
self.flakes('''
def f(foo):
class C:
bar = foo
def f(self):
return foo
return C()
f(123).f()
''')
def test_badNestedClass(self):
'''free variables in nested classes must bind at class creation'''
self.flakes('''
def f():
class C:
bar = foo
foo = 456
return foo
f()
''', m.UndefinedName)
def test_definedAsStarArgs(self):
'''star and double-star arg names are defined'''
self.flakes('''
def f(a, *b, **c):
print a, b, c
''')
def test_definedInGenExp(self):
"""
Using the loop variable of a generator expression results in no
warnings.
"""
self.flakes('(a for a in xrange(10) if a)')
class NameTests(TestCase):
"""
Tests for some extra cases of name handling.
"""
def test_impossibleContext(self):
"""
A Name node with an unrecognized context results in a RuntimeError being
raised.
"""
tree = compile("x = 10", "<test>", "exec", PyCF_ONLY_AST)
# Make it into something unrecognizable.
tree.body[0].targets[0].ctx = object()
self.assertRaises(RuntimeError, checker.Checker, tree)

View File

@@ -1,28 +0,0 @@
#!/usr/bin/python
# (c) 2005-2009 Divmod, Inc. See LICENSE file for details
from distutils.core import setup
setup(
name="pyflakes",
license="MIT",
version="0.4.0",
description="passive checker of Python programs",
author="Phil Frost",
maintainer="Moe Aboulkheir",
maintainer_email="moe@divmod.com",
url="http://www.divmod.org/trac/wiki/DivmodPyflakes",
packages=["pyflakes", "pyflakes.scripts", "pyflakes.test"],
scripts=["bin/pyflakes"],
long_description="""Pyflakes is program to analyze Python programs and detect various errors. It
works by parsing the source file, not importing it, so it is safe to use on
modules with side effects. It's also much faster.""",
classifiers=[
"Development Status :: 6 - Mature",
"Environment :: Console",
"Intended Audience :: Developers",
"License :: OSI Approved :: MIT License",
"Programming Language :: Python",
"Topic :: Software Development",
"Topic :: Utilities",
])

View File

@@ -1,146 +0,0 @@
" File: pylint_fn.vim
" Author: Roman 'gryf' Dobosz (gryf73 at gmail.com)
" Version: 1.0
" Last Modified: 2010-09-11
"
" Description: " {{{
"
" Overview
" --------
" This plugin provides ":Pylint" command, which put pylint result into quickfix
" buffer. This function does not uses pylint[1] command line utility, only
" python pylint.lint module is used instead. So it makes the pylint
" egg/package required for running this script.
"
" This script uses python, therefore VIm should be compiled with python
" support. You can check it by issuing ":version" command, and search for
" "+python" inside features list.
"
" Couple of ideas was taken from pyflakes.vim[2] plugin.
"
" Installation
" ------------
" 1. Copy the pylint_fn.vim file to the $HOME/.vim/ftplugin/python or
" $HOME/vimfiles/ftplugin/python or $VIM/vimfiles/ftplugin/python
" directory. If python directory doesn't exists, it should be created.
" Refer to the following Vim help topics for more information about Vim
" plugins:
" :help add-plugin
" :help add-global-plugin
" :help runtimepath
" 2. It should be possible to import pylint from python interpreter (it should
" report no error):
" >>> import pylint
" >>>
" If there are errors, install pylint first. Simplest way to do it, is to
" use easy_install[3] shell command as a root:
" # easy_install pylint
" 3. Restart Vim.
" 4. You can now use the ":Pylint" which will examine current python buffer
" and open quickfix buffer with errors if any.
"
" [1] http://www.logilab.org/project/pylint
" [2] http://www.vim.org/scripts/script.php?script_id=2441
" [3] http://pypi.python.org/pypi/setuptools
" }}}
if exists("b:did_pylint_plugin")
finish " only load once
else
let b:did_pylint_plugin = 1
endif
if !exists("b:did_pylint_init")
let b:did_pylint_init = 0
if !has('python')
echoerr "Error: pylint_fn.vim requires Vim to be compiled with +python"
finish
endif
python << EOF
import vim
import sys
from StringIO import StringIO
try:
from pylint import lint
from pylint.reporters.text import TextReporter
except ImportError:
raise AssertionError('Pylint is required for this plugin')
class VImPylint(object):
sys_stderr = sys.stderr
dummy_stderr = StringIO()
conf_msg = 'No config file found, using default configuration\n'
@classmethod
def run(self):
"""execute pylint and fill the quickfix"""
# clear QF window
vim.command('call setqflist([])')
# args
args = ['-rn', # display only the messages instead of full report
'-iy', # Include message's id in output
vim.current.buffer.name]
buf = StringIO() # file-like buffer, instead of stdout
reporter = TextReporter(buf)
sys.stderr = self.dummy_stderr
lint.Run(args, reporter=reporter, exit=False)
sys.stderr = self.sys_stderr
self.dummy_stderr.seek(0)
error_list = self.dummy_stderr.readlines()
self.dummy_stderr.truncate(0)
if error_list and self.conf_msg in error_list:
error_list.remove(self.conf_msg)
if error_list:
raise Exception(''.join(error_list))
buf.seek(0)
bufnr = vim.current.buffer.number
code_line = {}
error_list = []
carriage_re = re.compile(r'\s*\^+$')
error_re = re.compile(r'^([C,R,W,E,F].+):\s+?([0-9]+):?.*:\s(.*)$')
for line in buf:
line = line.rstrip() # remove trailing newline character
if error_re.match(line):
if code_line:
code_line['bufnr'] = bufnr
error_list.append(code_line)
code_line = {}
code_line['type'], code_line['lnum'], code_line['text'] = \
error_re.match(line).groups()
if carriage_re.match(line) and code_line:
code_line['col'] = carriage_re.match(line).group().find('^') \
+ 1
vim.command('call setqflist(%s)' % str(error_list))
if error_list:
vim.command('copen')
EOF
let b:did_pylint_init = 1
endif
if !exists('*s:Pylint')
function s:Pylint()
python << EOF
VImPylint.run()
EOF
endfunction
endif
if !exists(":Pylint")
command Pylint call s:Pylint()
endif

View File

@@ -1,447 +0,0 @@
" -*- vim -*-
" FILE: python_fn.vim
" LAST MODIFICATION: 2008-08-28 8:19pm
" (C) Copyright 2001-2005 Mikael Berthe <bmikael@lists.lilotux.net>
" Maintained by Jon Franklin <jvfranklin@gmail.com>
" Version: 1.13
" USAGE:
"
" Save this file to $VIMFILES/ftplugin/python.vim. You can have multiple
" python ftplugins by creating $VIMFILES/ftplugin/python and saving your
" ftplugins in that directory. If saving this to the global ftplugin
" directory, this is the recommended method, since vim ships with an
" ftplugin/python.vim file already.
" You can set the global variable "g:py_select_leading_comments" to 0
" if you don't want to select comments preceding a declaration (these
" are usually the description of the function/class).
" You can set the global variable "g:py_select_trailing_comments" to 0
" if you don't want to select comments at the end of a function/class.
" If these variables are not defined, both leading and trailing comments
" are selected.
" Example: (in your .vimrc) "let g:py_select_leading_comments = 0"
" You may want to take a look at the 'shiftwidth' option for the
" shift commands...
"
" REQUIREMENTS:
" vim (>= 7)
"
" Shortcuts:
" ]t -- Jump to beginning of block
" ]e -- Jump to end of block
" ]v -- Select (Visual Line Mode) block
" ]< -- Shift block to left
" ]> -- Shift block to right
" ]# -- Comment selection
" ]u -- Uncomment selection
" ]c -- Select current/previous class
" ]d -- Select current/previous function
" ]<up> -- Jump to previous line with the same/lower indentation
" ]<down> -- Jump to next line with the same/lower indentation
" Only do this when not done yet for this buffer
if exists("b:loaded_py_ftplugin")
finish
endif
let b:loaded_py_ftplugin = 1
map ]t :PBoB<CR>
vmap ]t :<C-U>PBOB<CR>m'gv``
map ]e :PEoB<CR>
vmap ]e :<C-U>PEoB<CR>m'gv``
map ]v ]tV]e
map ]< ]tV]e<
vmap ]< <
map ]> ]tV]e>
vmap ]> >
map ]# :call PythonCommentSelection()<CR>
vmap ]# :call PythonCommentSelection()<CR>
map ]u :call PythonUncommentSelection()<CR>
vmap ]u :call PythonUncommentSelection()<CR>
" gryf: change mapping for class selection
map ]C :call PythonSelectObject("class")<CR>
map ]d :call PythonSelectObject("function")<CR>
map ]<up> :call PythonNextLine(-1)<CR>
map ]<down> :call PythonNextLine(1)<CR>
" You may prefer use <s-up> and <s-down>... :-)
" jump to previous class
map ]J :call PythonDec("class", -1)<CR>
vmap ]J :call PythonDec("class", -1)<CR>
" jump to next class
map ]j :call PythonDec("class", 1)<CR>
vmap ]j :call PythonDec("class", 1)<CR>
" jump to previous function
map ]F :call PythonDec("function", -1)<CR>
vmap ]F :call PythonDec("function", -1)<CR>
" jump to next function
map ]f :call PythonDec("function", 1)<CR>
vmap ]f :call PythonDec("function", 1)<CR>
" Menu entries
nmenu <silent> &Python.Update\ IM-Python\ Menu
\:call UpdateMenu()<CR>
nmenu &Python.-Sep1- :
nmenu <silent> &Python.Beginning\ of\ Block<Tab>[t
\]t
nmenu <silent> &Python.End\ of\ Block<Tab>]e
\]e
nmenu &Python.-Sep2- :
nmenu <silent> &Python.Shift\ Block\ Left<Tab>]<
\]<
vmenu <silent> &Python.Shift\ Block\ Left<Tab>]<
\]<
nmenu <silent> &Python.Shift\ Block\ Right<Tab>]>
\]>
vmenu <silent> &Python.Shift\ Block\ Right<Tab>]>
\]>
nmenu &Python.-Sep3- :
vmenu <silent> &Python.Comment\ Selection<Tab>]#
\]#
nmenu <silent> &Python.Comment\ Selection<Tab>]#
\]#
vmenu <silent> &Python.Uncomment\ Selection<Tab>]u
\]u
nmenu <silent> &Python.Uncomment\ Selection<Tab>]u
\]u
nmenu &Python.-Sep4- :
nmenu <silent> &Python.Previous\ Class<Tab>]J
\]J
nmenu <silent> &Python.Next\ Class<Tab>]j
\]j
nmenu <silent> &Python.Previous\ Function<Tab>]F
\]F
nmenu <silent> &Python.Next\ Function<Tab>]f
\]f
nmenu &Python.-Sep5- :
nmenu <silent> &Python.Select\ Block<Tab>]v
\]v
nmenu <silent> &Python.Select\ Function<Tab>]d
\]d
nmenu <silent> &Python.Select\ Class<Tab>]c
\]c
nmenu &Python.-Sep6- :
nmenu <silent> &Python.Previous\ Line\ wrt\ indent<Tab>]<up>
\]<up>
nmenu <silent> &Python.Next\ Line\ wrt\ indent<Tab>]<down>
\]<down>
:com! PBoB execute "normal ".PythonBoB(line('.'), -1, 1)."G"
:com! PEoB execute "normal ".PythonBoB(line('.'), 1, 1)."G"
:com! UpdateMenu call UpdateMenu()
" Go to a block boundary (-1: previous, 1: next)
" If force_sel_comments is true, 'g:py_select_trailing_comments' is ignored
function! PythonBoB(line, direction, force_sel_comments)
let ln = a:line
let ind = indent(ln)
let mark = ln
let indent_valid = strlen(getline(ln))
let ln = ln + a:direction
if (a:direction == 1) && (!a:force_sel_comments) &&
\ exists("g:py_select_trailing_comments") &&
\ (!g:py_select_trailing_comments)
let sel_comments = 0
else
let sel_comments = 1
endif
while((ln >= 1) && (ln <= line('$')))
if (sel_comments) || (match(getline(ln), "^\\s*#") == -1)
if (!indent_valid)
let indent_valid = strlen(getline(ln))
let ind = indent(ln)
let mark = ln
else
if (strlen(getline(ln)))
if (indent(ln) < ind)
break
endif
let mark = ln
endif
endif
endif
let ln = ln + a:direction
endwhile
return mark
endfunction
" Go to previous (-1) or next (1) class/function definition
function! PythonDec(obj, direction)
if (a:obj == "class")
let objregexp = "^\\s*class\\s\\+[a-zA-Z0-9_]\\+"
\ . "\\s*\\((\\([a-zA-Z0-9_,. \\t\\n]\\)*)\\)\\=\\s*:"
else
let objregexp = "^\\s*def\\s\\+[a-zA-Z0-9_]\\+\\s*(\\_[^:#]*)\\s*:"
endif
let flag = "W"
if (a:direction == -1)
let flag = flag."b"
endif
let res = search(objregexp, flag)
endfunction
" Comment out selected lines
" commentString is inserted in non-empty lines, and should be aligned with
" the block
function! PythonCommentSelection() range
let commentString = "#"
let cl = a:firstline
let ind = 1000 " I hope nobody use so long lines! :)
" Look for smallest indent
while (cl <= a:lastline)
if strlen(getline(cl))
let cind = indent(cl)
let ind = ((ind < cind) ? ind : cind)
endif
let cl = cl + 1
endwhile
if (ind == 1000)
let ind = 1
else
let ind = ind + 1
endif
let cl = a:firstline
execute ":".cl
" Insert commentString in each non-empty line, in column ind
while (cl <= a:lastline)
if strlen(getline(cl))
execute "normal ".ind."|i".commentString
endif
execute "normal \<Down>"
let cl = cl + 1
endwhile
endfunction
" Uncomment selected lines
function! PythonUncommentSelection() range
" commentString could be different than the one from CommentSelection()
" For example, this could be "# \\="
let commentString = "#"
let cl = a:firstline
while (cl <= a:lastline)
let ul = substitute(getline(cl),
\"\\(\\s*\\)".commentString."\\(.*\\)$", "\\1\\2", "")
call setline(cl, ul)
let cl = cl + 1
endwhile
endfunction
" Select an object ("class"/"function")
function! PythonSelectObject(obj)
" Go to the object declaration
normal $
call PythonDec(a:obj, -1)
let beg = line('.')
if !exists("g:py_select_leading_comments") || (g:py_select_leading_comments)
let decind = indent(beg)
let cl = beg
while (cl>1)
let cl = cl - 1
if (indent(cl) == decind) && (getline(cl)[decind] == "#")
let beg = cl
else
break
endif
endwhile
endif
if (a:obj == "class")
let eod = "\\(^\\s*class\\s\\+[a-zA-Z0-9_]\\+\\s*"
\ . "\\((\\([a-zA-Z0-9_,. \\t\\n]\\)*)\\)\\=\\s*\\)\\@<=:"
else
let eod = "\\(^\\s*def\\s\\+[a-zA-Z0-9_]\\+\\s*(\\_[^:#]*)\\s*\\)\\@<=:"
endif
" Look for the end of the declaration (not always the same line!)
call search(eod, "")
" Is it a one-line definition?
if match(getline('.'), "^\\s*\\(#.*\\)\\=$", col('.')) == -1
let cl = line('.')
execute ":".beg
execute "normal V".cl."G"
else
" Select the whole block
execute "normal \<Down>"
let cl = line('.')
execute ":".beg
execute "normal V".PythonBoB(cl, 1, 0)."G"
endif
endfunction
" Jump to the next line with the same (or lower) indentation
" Useful for moving between "if" and "else", for example.
function! PythonNextLine(direction)
let ln = line('.')
let ind = indent(ln)
let indent_valid = strlen(getline(ln))
let ln = ln + a:direction
while((ln >= 1) && (ln <= line('$')))
if (!indent_valid) && strlen(getline(ln))
break
else
if (strlen(getline(ln)))
if (indent(ln) <= ind)
break
endif
endif
endif
let ln = ln + a:direction
endwhile
execute "normal ".ln."G"
endfunction
function! UpdateMenu()
" delete menu if it already exists, then rebuild it.
" this is necessary in case you've got multiple buffers open
" a future enhancement to this would be to make the menu aware of
" all buffers currently open, and group classes and functions by buffer
if exists("g:menuran")
aunmenu IM-Python
endif
let restore_fe = &foldenable
set nofoldenable
" preserve disposition of window and cursor
let cline=line('.')
let ccol=col('.') - 1
norm H
let hline=line('.')
" create the menu
call MenuBuilder()
" restore disposition of window and cursor
exe "norm ".hline."Gzt"
let dnscroll=cline-hline
exe "norm ".dnscroll."j".ccol."l"
let &foldenable = restore_fe
endfunction
function! MenuBuilder()
norm gg0
let currentclass = -1
let classlist = []
let parentclass = ""
while line(".") < line("$")
" search for a class or function
if match ( getline("."), '^\s*class\s\+[_a-zA-Z].*\|^\s*def\s\+[_a-zA-Z].*' ) != -1
norm ^
let linenum = line('.')
let indentcol = col('.')
norm "nye
let classordef=@n
norm w"nywge
let objname=@n
let parentclass = FindParentClass(classlist, indentcol)
if classordef == "class"
call AddClass(objname, linenum, parentclass)
else " this is a function
call AddFunction(objname, linenum, parentclass)
endif
" We actually created a menu, so lets set the global variable
let g:menuran=1
call RebuildClassList(classlist, [objname, indentcol], classordef)
endif " line matched
norm j
endwhile
endfunction
" classlist contains the list of nested classes we are in.
" in most cases it will be empty or contain a single class
" but where a class is nested within another, it will contain 2 or more
" this function adds or removes classes from the list based on indentation
function! RebuildClassList(classlist, newclass, classordef)
let i = len(a:classlist) - 1
while i > -1
if a:newclass[1] <= a:classlist[i][1]
call remove(a:classlist, i)
endif
let i = i - 1
endwhile
if a:classordef == "class"
call add(a:classlist, a:newclass)
endif
endfunction
" we found a class or function, determine its parent class based on
" indentation and what's contained in classlist
function! FindParentClass(classlist, indentcol)
let i = 0
let parentclass = ""
while i < len(a:classlist)
if a:indentcol <= a:classlist[i][1]
break
else
if len(parentclass) == 0
let parentclass = a:classlist[i][0]
else
let parentclass = parentclass.'\.'.a:classlist[i][0]
endif
endif
let i = i + 1
endwhile
return parentclass
endfunction
" add a class to the menu
function! AddClass(classname, lineno, parentclass)
if len(a:parentclass) > 0
let classstring = a:parentclass.'\.'.a:classname
else
let classstring = a:classname
endif
exe 'menu IM-Python.classes.'.classstring.' :call <SID>JumpToAndUnfold('.a:lineno.')<CR>'
endfunction
" add a function to the menu, grouped by member class
function! AddFunction(functionname, lineno, parentclass)
if len(a:parentclass) > 0
let funcstring = a:parentclass.'.'.a:functionname
else
let funcstring = a:functionname
endif
exe 'menu IM-Python.functions.'.funcstring.' :call <SID>JumpToAndUnfold('.a:lineno.')<CR>'
endfunction
function! s:JumpToAndUnfold(line)
" Go to the right line
execute 'normal '.a:line.'gg'
" Check to see if we are in a fold
let lvl = foldlevel(a:line)
if lvl != 0
" and if so, then expand the fold out, other wise, ignore this part.
execute 'normal 15zo'
endif
endfunction
"" This one will work only on vim 6.2 because of the try/catch expressions.
" function! s:JumpToAndUnfoldWithExceptions(line)
" try
" execute 'normal '.a:line.'gg15zo'
" catch /^Vim\((\a\+)\)\=:E490:/
" " Do nothing, just consume the error
" endtry
"endfunction
" vim:set et sts=2 sw=2:

View File

@@ -1,763 +0,0 @@
" File: pythonhelper.vim
" Author: Michal Vitecek <fuf-at-mageo-dot-cz>
" Version: 0.83
" Last Modified: Jan 4, 2010
"
" Overview
" --------
" Vim script to help moving around in larger Python source files. It displays
" current class, method or function the cursor is placed in on the status
" line for every python file. It's more clever than Yegappan Lakshmanan's
" taglist.vim because it takes into account indetation and comments to
" determine what tag the cursor is placed in.
"
" Requirements
" ------------
" This script needs only VIM compiled with Python interpreter. It doesn't rely
" on exuberant ctags utility. You can determine whether your VIM has Python
" support by issuing command :ver and looking for +python in the list of
" features.
"
" Installation
" ------------
" 1. Make sure your Vim has python feature on (+python). If not, you will need
" to recompile it with --with-pythoninterp option to the configure script
" 2. Copy script pythonhelper.vim to the $HOME/.vim/plugin directory
" 3. Run Vim and open any python file.
"
python << EOS
# import of required modules {{{
import re
import sys
import time
import traceback
import vim
# }}}
# global dictionaries of tags and their line numbers, keys are buffer numbers {{{
TAGS = {}
TAGLINENUMBERS = {}
BUFFERTICKS = {}
# }}}
# class PythonTag() {{{
class PythonTag(object):
# DOC {{{
"""A simple storage class representing a python tag.
"""
# }}}
# STATIC VARIABLES {{{
# possible tag types {{{
TT_CLASS = 0
TT_METHOD = 1
TT_FUNCTION = 2
# }}}
# tag type names {{{
TAG_TYPE_NAME = {
TT_CLASS : "class",
TT_METHOD : "method",
TT_FUNCTION : "function",
}
# }}}
# }}}
# METHODS {{{
def __init__(self, type, name, fullName, lineNumber, indentLevel):
# DOC {{{
"""Initializes instances of PythonTag().
Parameters
type -- tag type
name -- short tag name
fullName -- full tag name (in dotted notation)
lineNumber -- line number on which the tag starts
indentLevel -- indentation level of the tag
"""
# }}}
# CODE {{{
# remember the settings {{{
self.type = type
self.name = name
self.fullName = fullName
self.lineNumber = lineNumber
self.indentLevel = indentLevel
# }}}
# }}}
def __str__(self):
# DOC {{{
"""Returns a string representation of the tag.
"""
# }}}
# CODE {{{
return "%s (%s) [%s, %u, %u]" % (self.name, PythonTag.TAG_TYPE_NAME[self.type],
self.fullName, self.lineNumber, self.indentLevel,)
# }}}
__repr__ = __str__
# }}}
# }}}
# class SimplePythonTagsParser() {{{
class SimplePythonTagsParser(object):
# DOC {{{
"""Provides a simple python tag parser.
"""
# }}}
# STATIC VARIABLES {{{
# how many chars a single tab represents (visually)
TABSIZE = 8
# regexp used to extract indentation and strip comments
COMMENTS_INDENT_RE = re.compile('([ \t]*)([^\n#]*).*')
# regexp used to extract a class name
CLASS_RE = re.compile('class[ \t]+([^(:]+).*')
# regexp used to extract a method or function name
METHOD_RE = re.compile('def[ \t]+([^(]+).*')
# }}}
# METHODS {{{
def __init__(self, source):
# DOC {{{
"""Initializes instances of SimplePythonTagsParser().
Parameters
source -- source for which the tags will be generated. It must
provide callable method readline (i.e. as file objects do).
"""
# }}}
# CODE {{{
# make sure source has readline() method {{{
if ((hasattr(source, 'readline') == 0) or
(callable(source.readline) == 0)):
raise AttributeError("Source must have callable readline method.")
# }}}
# remember what the source is
self.source = source
# }}}
def getTags(self):
# DOC {{{
"""Determines all the tags for the buffer. Returns a tuple in format
(tagLineNumbers, tags,).
"""
# }}}
# CODE {{{
# initialize the resulting list of the tag line numbers and the tag information {{{
tagLineNumbers = []
tags = {}
# }}}
# initalize local auxiliary variables {{{
tagsStack = []
lineNumber = 0
# }}}
# go through all the lines in the source and localize all python tags in it {{{
while 1:
# get next line
line = self.source.readline()
# finish if this is the end of the source {{{
if (line == ''):
break
# }}}
# increase the line number
lineNumber += 1
# extract the line indentation characters and its content {{{
lineMatch = self.COMMENTS_INDENT_RE.match(line)
lineContent = lineMatch.group(2)
# }}}
# handle the class tag {{{
# match for the class tag
tagMatch = self.CLASS_RE.match(lineContent)
# if the class tag has been found, store some information on it {{{
if (tagMatch):
currentTag = self.getPythonTag(tagsStack, lineNumber, lineMatch.group(1),
tagMatch.group(1), self.tagClassTypeDecidingMethod)
tagLineNumbers.append(lineNumber)
tags[lineNumber] = currentTag
# }}}
# }}}
# handle the function/method/none tag {{{
else:
# match for the method/function tag
tagMatch = self.METHOD_RE.match(lineContent)
# if the method/function tag has been found, store some information on it {{{
if (tagMatch):
currentTag = self.getPythonTag(tagsStack, lineNumber, lineMatch.group(1),
tagMatch.group(1), self.tagFunctionTypeDecidingMethod)
tagLineNumbers.append(lineNumber)
tags[lineNumber] = currentTag
# }}}
# }}}
# }}}
# return the tags data for the source
return (tagLineNumbers, tags,)
# }}}
def getParentTag(self, tagsStack):
# DOC {{{
"""Returns the parent/enclosing tag (instance of PythonTag()) from the
specified tag list. If no such parent tag exists, returns None.
Parameters
tagsStack -- list (stack) of currently open PythonTag() instances
"""
# }}}
# CODE {{{
# determine the parent tag {{{
if (len(tagsStack)):
parentTag = tagsStack[-1]
else:
parentTag = None
# }}}
# return the tag
return parentTag
# }}}
def computeIndentationLevel(indentChars):
# DOC {{{
"""Computes the indentation level from the specified string.
Parameters
indentChars -- white space before any other character on line
"""
# }}}
# CODE {{{
# initialize the indentation level
indentLevel = 0
# compute the indentation level (expand tabs) {{{
for char in indentChars:
if (char == '\t'):
indentLevel += SimplePythonTagsParser.TABSIZE
else:
indentLevel += 1
# }}}
# return the computed indentation level
return indentLevel
# }}}
computeIndentationLevel = staticmethod(computeIndentationLevel)
def getPythonTag(self, tagsStack, lineNumber, indentChars, tagName, tagTypeDecidingMethod):
# DOC {{{
"""Returns instance of PythonTag() based on the specified data.
Parameters
tagsStack -- list (stack) of tags currently active. Note: Modified
in this method!
lineNumber -- current line number
indentChars -- characters making up the indentation level of the
current tag
tagName -- short name of the current tag
tagTypeDecidingMethod -- reference to method that is called to
determine the type of the current tag
"""
# }}}
# CODE {{{
# compute the indentation level
indentLevel = self.computeIndentationLevel(indentChars)
# get the parent tag
parentTag = self.getParentTag(tagsStack)
# handle an enclosed tag {{{
while (parentTag):
# if the indent level of the parent tag is greater than of the current tag, use parent tag of the parent tag {{{
if (parentTag.indentLevel >= indentLevel):
del tagsStack[-1]
# }}}
# otherwise we have all information on the current tag and can return it {{{
else:
# create the tag
tag = PythonTag(tagTypeDecidingMethod(parentTag.type), tagName, "%s.%s" % (parentTag.fullName, tagName,), lineNumber, indentLevel)
# break the loop
break
# }}}
# use parent tag of the parent tag
parentTag = self.getParentTag(tagsStack)
# }}}
# handle a top-indent level tag {{{
else:
# create the tag
tag = PythonTag(tagTypeDecidingMethod(None), tagName, tagName, lineNumber, indentLevel)
# }}}
# add the tag to the list of tags
tagsStack.append(tag)
# return the tag
return tag
# }}}
def tagClassTypeDecidingMethod(self, parentTagType):
# DOC {{{
"""Returns tag type of the current tag based on its previous tag (super
tag) for classes.
Parameters
parentTagType -- type of the enclosing/parent tag
"""
# }}}
# CODE {{{
# is always class no matter what
return PythonTag.TT_CLASS
# }}}
def tagFunctionTypeDecidingMethod(self, parentTagType):
# DOC {{{
"""Returns tag type of the current tag based on its previous tag (super
tag) for functions/methods.
Parameters
parentTagType -- type of the enclosing/parent tag
"""
# }}}
# CODE {{{
if (parentTagType == PythonTag.TT_CLASS):
return PythonTag.TT_METHOD
else:
return PythonTag.TT_FUNCTION
# }}}
# }}}
# }}}
# class VimReadlineBuffer() {{{
class VimReadlineBuffer(object):
# DOC {{{
"""A simple wrapper class around vim's buffer that provides readline
method.
"""
# }}}
# METHODS {{{
def __init__(self, vimBuffer):
# DOC {{{
"""Initializes instances of VimReadlineBuffer().
Parameters
vimBuffer -- VIM's buffer
"""
# }}}
# CODE {{{
# remember the settings
self.vimBuffer = vimBuffer
# initialize instance attributes {{{
self.currentLine = -1
self.bufferLines = len(vimBuffer)
# }}}
# }}}
def readline(self):
# DOC {{{
"""Returns next line from the buffer. If all the buffer has been read,
returns empty string.
"""
# }}}
# CODE {{{
# increase the current line counter
self.currentLine += 1
# notify end of file if we reached beyond the last line {{{
if (self.currentLine == self.bufferLines):
return ''
# }}}
# return the line with an added newline (vim stores the lines without it)
return "%s\n" % (self.vimBuffer[self.currentLine],)
# }}}
# }}}
# }}}
def getNearestLineIndex(row, tagLineNumbers):
# DOC {{{
"""Returns the index of line in 'tagLineNumbers' list that is nearest to the
specified cursor row.
Parameters
row -- current cursor row
tagLineNumbers -- list of tags' line numbers (ie. their position)
"""
# }}}
# CODE {{{
# initialize local auxiliary variables {{{
nearestLineNumber = -1
nearestLineIndex = -1
# }}}
# go through all tag line numbers and find the one nearest to the specified row {{{
for lineIndex, lineNumber in enumerate(tagLineNumbers):
# if the current line is nearer the current cursor position, take it {{{
if (nearestLineNumber < lineNumber <= row):
nearestLineNumber = lineNumber
nearestLineIndex = lineIndex
# }}}
# if we've got past the current cursor position, let's end the search {{{
if (lineNumber >= row):
break
# }}}
# }}}
# return index of the line with the nearest tag
return nearestLineIndex
# }}}
def getTags(bufferNumber, changedTick):
# DOC {{{
"""Reads the tags for the specified buffer number. Returns a tuple
(taglinenumber[buffer], tags[buffer],).
Parameters
bufferNumber -- number of the current buffer
changedTick -- ever increasing number used to tell if the buffer has
been modified since the last time
"""
# }}}
# CODE {{{
# define global variables
global TAGLINENUMBERS, TAGS, BUFFERTICKS
# return immediately if there's no need to update the tags {{{
if (BUFFERTICKS.get(bufferNumber, None) == changedTick):
return (TAGLINENUMBERS[bufferNumber], TAGS[bufferNumber],)
# }}}
# get the tags {{{
simpleTagsParser = SimplePythonTagsParser(VimReadlineBuffer(vim.current.buffer))
tagLineNumbers, tags = simpleTagsParser.getTags()
# }}}
# update the global variables {{{
TAGS[bufferNumber] = tags
TAGLINENUMBERS[bufferNumber] = tagLineNumbers
BUFFERTICKS[bufferNumber] = changedTick
# }}}
# return the tuple (tagLineNumbers, tags,)
return (tagLineNumbers, tags,)
# }}}
def findTag(bufferNumber, changedTick):
# DOC {{{
"""Tries to find the best tag for the current cursor position.
Parameters
bufferNumber -- number of the current buffer
changedTick -- ever increasing number used to tell if the buffer has
been modified since the last time
"""
# }}}
# CODE {{{
# try to find the best tag {{{
try:
# get the tags data for the current buffer
tagLineNumbers, tags = getTags(bufferNumber, changedTick)
# link to vim's internal data {{{
currentBuffer = vim.current.buffer
currentWindow = vim.current.window
row, col = currentWindow.cursor
# }}}
# get the index of the nearest line
nearestLineIndex = getNearestLineIndex(row, tagLineNumbers)
# if any line was found, try to find if the tag is appropriate {{{
# (ie. the cursor can be below the last tag but on a code that has nothing
# to do with the tag, because it's indented differently, in such case no
# appropriate tag has been found.)
while (nearestLineIndex > -1):
# get the line number of the nearest tag
nearestLineNumber = tagLineNumbers[nearestLineIndex]
# walk through all the lines in range (nearestTagLine, cursorRow) {{{
for lineNumber in xrange(nearestLineNumber + 1, row):
# get the current line
line = currentBuffer[lineNumber]
# count the indentation of the line, if it's lower than the tag's, the tag is invalid {{{
if (len(line)):
# initialize local auxiliary variables {{{
lineStart = 0
i = 0
# }}}
# compute the indentation of the line {{{
while ((i < len(line)) and (line[i].isspace())):
# move the start of the line code {{{
if (line[i] == '\t'):
lineStart += SimplePythonTagsParser.TABSIZE
else:
lineStart += 1
# }}}
# go to the next character on the line
i += 1
# }}}
# if the line contains only spaces, skip it {{{
if (i == len(line)):
continue
# }}}
# if the next character is a '#' (python comment), skip the line {{{
if (line[i] == '#'):
continue
# }}}
# if the line's indentation starts before or at the nearest tag's one, the tag is invalid {{{
if (lineStart <= tags[nearestLineNumber].indentLevel):
nearestLineIndex -= 1
break
# }}}
# }}}
# }}}
# the tag is appropriate, so use it {{{
else:
break
# }}}
# }}}
# no appropriate tag has been found {{{
else:
nearestLineNumber = -1
# }}}
# describe the cursor position (what tag the cursor is on) {{{
# reset the description
tagDescription = ""
# if an appropriate tag has been found, set the description accordingly {{{
if (nearestLineNumber > -1):
tagInfo = tags[nearestLineNumber]
tagDescription = "[in %s (%s)]" % (tagInfo.fullName, PythonTag.TAG_TYPE_NAME[tagInfo.type],)
# }}}
# }}}
# update the variable for the status line so it get updated with the new description
vim.command("let w:PHStatusLine=\"%s\"" % (tagDescription,))
# }}}
# handle possible exceptions {{{
except Exception:
# bury into the traceback {{{
ec, ei, tb = sys.exc_info()
while (tb != None):
if (tb.tb_next == None):
break
tb = tb.tb_next
# }}}
# spit out the error {{{
print "ERROR: %s %s %s:%u" % (ec.__name__, ei, tb.tb_frame.f_code.co_filename, tb.tb_lineno,)
time.sleep(0.5)
# }}}
# }}}
# }}}
def deleteTags(bufferNumber):
# DOC {{{
"""Removes tags data for the specified buffer number.
Parameters
bufferNumber -- number of the buffer
"""
# }}}
# CODE {{{
# define global variables
global TAGS, TAGLINENUMBERS, BUFFERTICKS
# try to delete the tags for the buffer {{{
try:
del TAGS[bufferNumber]
del TAGLINENUMBERS[bufferNumber]
del BUFFERTICKS[bufferNumber]
except:
pass
# }}}
# }}}
EOS
" VIM functions {{{
function! PHCursorHold()
" only python is supported {{{
if (!exists('b:current_syntax') || (b:current_syntax != 'python'))
let w:PHStatusLine = ''
return
endif
" }}}
" call python function findTag() with the current buffer number and changed ticks
execute 'python findTag(' . expand("<abuf>") . ', ' . b:changedtick . ')'
endfunction
function! PHBufferDelete()
" set PHStatusLine for this window to empty string
let w:PHStatusLine = ""
" call python function deleteTags() with the cur
execute 'python deleteTags(' . expand("<abuf>") . ')'
endfunction
function! TagInStatusLine()
" return value of w:PHStatusLine in case it's set
if (exists("w:PHStatusLine"))
return w:PHStatusLine
" otherwise just return empty string
else
return ""
endif
endfunction
function! PHPreviousClassMethod()
call search('^[ \t]*\(class\|def\)\>', 'bw')
endfunction
function! PHNextClassMethod()
call search('^[ \t]*\(class\|def\)\>', 'w')
endfunction
function! PHPreviousClass()
call search('^[ \t]*class\>', 'bw')
endfunction
function! PHNextClass()
call search('^[ \t]*class\>', 'w')
endfunction
function! PHPreviousMethod()
call search('^[ \t]*def\>', 'bw')
endfunction
function! PHNextMethod()
call search('^[ \t]*def\>', 'w')
endfunction
" }}}
" event binding, vim customizing {{{
" autocommands binding
autocmd CursorHold * call PHCursorHold()
autocmd CursorHoldI * call PHCursorHold()
autocmd BufDelete * silent call PHBufferDelete()
" time that determines after how long time of no activity the CursorHold event
" is fired up
set updatetime=1000
" color of the current tag in the status line (bold cyan on black)
" gryf: i don't like coloring apart from current colorscheme. keep it simple.
"highlight User1 gui=bold guifg=cyan guibg=black
" color of the modified flag in the status line (bold black on red)
" gryf: i don't like coloring apart from current colorscheme. keep it simple.
"highlight User2 gui=bold guifg=black guibg=red
" the status line will be displayed for every window
set laststatus=2
" set the status line to display some useful information
"set stl=%-f%r\ %2*%m%*\ \ \ \ %1*%{TagInStatusLine()}%*%=[%l:%c]\ \ \ \ [buf\ %n]
" gryf: I like my status bar. Don't change it. Just add information.
setlocal statusline=%<%F\ \ \ %{TagInStatusLine()}\ %h%m%r%=%(%l,%c%V%)\ %3p%%
" }}}
" vim:foldmethod=marker

View File

@@ -1,16 +0,0 @@
" Some common settings for all reSt files
setlocal textwidth=80
setlocal makeprg=rst2html.py\ \"%\"\ \"%:p:r.html\"
setlocal spell
setlocal smartindent
setlocal autoindent
setlocal formatoptions=tcq "set VIms default
let g:blogger_login="gryf73"
let g:blogger_name="rdobosz"
let g:blogger_browser=1
let g:blogger_stylesheets=["css/widget_css_2_bundle.css", "css/style_custom.css", "css/style_blogger.css", "css/wombat_pygments.css", "css/lucius_pygments.css"]
let g:blogger_pygments_class="wombat"
map <F6> :PreviewBlogArticle<cr>
map <F7> :SendBlogArticle<cr>

View File

@@ -1 +0,0 @@
# module rst2blogger

View File

@@ -1,214 +0,0 @@
"""
File: blogger.py
Author: Roman 'gryf' Dobosz
Description: This is blogger activity connected module. It is using gdata[1]
blogger module to provide add/modify/delete articles interface.
[1] http://code.google.com/p/gdata-python-client
"""
import datetime
import re
import atom
from gdata.blogger.client import BloggerClient, BLOG_POST_URL
from gdata.blogger.data import BlogPost
class VimBlogger(object):
"""
Communicate with blogger through gdata.blogger modules
"""
DATE_PATTERN = re.compile(r"^(\d{4}-\d{2}-\d{2})"
"T(\d{2}:\d{2}:\d{2})(\.\d{3})?[+-]"
"(\d{2}:\d{2})$")
DATE_FORMAT = "%Y-%m-%d"
TIME_FORMAT = "%H:%M:%S"
TZ_FORMAT = "%H:%M"
def __init__(self, blogname, login, password):
"""
Initialization.
"""
self.draft = True
self.blog_id = None
self.blog = None
self.client = BloggerClient()
self._authorize(login, password)
self.feed = self.client.get_blogs()
self._set_blog(blogname)
def get_articles(self, maxarticles=0):
"""
Return list of articles
"""
feed = self.client.get_posts(self.blog_id)
posts = []
for index, entry in enumerate(feed.entry):
if maxarticles and index >= maxarticles:
break
posts.append((entry.get_post_id(),
entry.title.text,
self._extract_date(entry.published.text)))
return posts
def create_article(self, html_doc, attrs=None):
"""
Create new article
html_doc is content of the article in HTML format, without headers,
preamble, doctype and body tags.
attrs is a dictionary that should hold title, date and tags.
return BlogPost object
"""
if not attrs:
attrs = {}
title = 'title' in attrs and attrs['title'] or ""
title = atom.data.Title(text=title, type="text")
html_doc = atom.data.Content(text=html_doc, type="html")
new_post = BlogPost(title=title, content=html_doc)
if 'tags' in attrs and attrs['tags']:
for tag in attrs['tags'].split(','):
new_post.add_label(tag.strip())
if 'date' in attrs and attrs['date'] and \
self._check_date(attrs['date']):
new_post.published = atom.data.Published(text=attrs['date'])
if self.draft:
new_post.control = atom.data.Control(\
draft=atom.data.Draft(text='yes'))
return self.client.post(new_post, BLOG_POST_URL % self.blog_id)
def update_article(self, html_doc, attrs):
"""
Update article.
html_doc is content of the article in HTML format, without headers,
preamble, doctype and body tags.
attrs is a dictionary that should hold title, date and tags.
return BlogPost object
"""
if "id" not in attrs:
raise Exception("Post Id not found in attributes!")
post = self._get_post(attrs['id'])
post.content = atom.data.Content(text=html_doc, type="html")
# update published date
if 'date' in attrs and attrs['date'] and \
self._check_date(attrs['date']):
post.published = atom.data.Published(text=attrs['date'])
if 'title' in attrs and attrs['title']:
post.title = atom.data.Title(text=attrs['title'], type="text")
#
# update tag list
if 'tags' in attrs:
tags = [tag.strip() for tag in attrs['tags'].split(',')]
for index, label in enumerate(post.category):
if label.term not in tags:
del(post.category[index])
for tag in tags:
self._add_tag(post, tag.strip())
return self.client.update(post)
def delete_article(self, post_id):
"""
Delete selected article
"""
if not post_id:
return "No article id provided"
post = self._get_post(post_id)
self.client.delete(post)
return None
def _get_post(self, post_id):
"""
Return post with specified ID
"""
post_href = self.blog.get_post_link().href
return self.client.get_feed(post_href + "/%s" % post_id,
desired_class=BlogPost)
def _add_tag(self, post, tag):
"""
post - BlogPost object
tag - string with tag/label to add
"""
for label in post.category:
if label.term == tag:
return
post.add_label(tag)
def _extract_date(self, date_string, time=False):
"""
Extract date from the string and optionally time
"""
if not self.DATE_PATTERN.match(date_string):
return False
if not time:
return self.DATE_PATTERN.match(date_string).groups()[0]
groups = self.DATE_PATTERN.match(date_string).groups()
return groups[0] + " " + groups[1]
def _check_date(self, date):
"""
Parse date as RFC 3339 format, for example:
2010-11-30T21:06:48.678+01:00
or
2010-11-30T21:06:48+01:00
Returns true, if date is acceptable, false otherwise
"""
if not self.DATE_PATTERN.match(date):
return False
groups = self.DATE_PATTERN.match(date).groups()
_date = groups[0]
_time = groups[1]
_tz = len(groups) == 3 and groups[2] or groups[3]
try:
datetime.datetime.strptime(_date, self.DATE_FORMAT)
datetime.datetime.strptime(_time, self.TIME_FORMAT)
datetime.datetime.strptime(_tz, self.TZ_FORMAT)
except ValueError:
return False
return True
def _authorize(self, login, password):
"""
Try to authorize in Google service.
Authorization is kept in client object. In case of wrong credentials,
exception is thrown.
"""
source = 'Vim rst2blogger interface'
service = 'blogger'
self.client.client_login(login,
password,
source=source,
service=service)
def _set_blog(self, blogname):
"""
Set correct blog, as defined in blogname
"""
for blog in self.feed.entry:
if blog.get_blog_name() == blogname:
self.blog_id = blog.get_blog_id()
self.blog = blog
break

View File

@@ -1,214 +0,0 @@
# vim: fileencoding=utf8
"""
File: main.py
Author: Roman 'gryf' Dobosz
Description: main file to provide fuctionality between vim and moudles rest
and blogger
"""
import webbrowser
from xml.dom import minidom
from xml.parsers.expat import ExpatError
import vim
from rst2blogger.rest import blogPreview, blogArticleString
try:
from rst2blogger.rest import register
except ImportError:
pass
from rst2blogger.blogger import VimBlogger
class Rst2Blogger(object):
"""
Provide convenient way to communicate between vim and blogger through reST
"""
def __init__(self):
vim.command('call setqflist([])')
self.buff = vim.current.buffer
self.docinfo_len = 0
self._set_docinfo_len()
self.login = vim.eval("g:blogger_login")
self.password = vim.eval("g:blogger_pass")
self.blogname = vim.eval("g:blogger_name")
self.buffer_encoding = vim.eval("&fileencoding")
self.vim_encoding = vim.eval("&encoding")
self.draft = int(vim.eval("g:blogger_draft"))
self.maxarticles = int(vim.eval("g:blogger_maxarticles"))
self.confirm_del = int(vim.eval("g:blogger_confirm_del"))
self.stylesheets = vim.eval("g:blogger_stylesheets")
self.pygments_class = vim.eval("g:blogger_pygments_class")
try:
register(self.pygments_class)
except NameError:
pass
def preview(self):
"""
Generate HTML Blogger article preview and (optionally) display it in
systems' web browser
"""
bufcontent = "\n".join(self.buff)
name = self.buff.name
name = name[:-4] + ".html"
html = blogPreview(bufcontent, self.stylesheets)
self._open_qf(self._check_html(html))
output_file = open(name, "w")
output_file.write(html)
output_file.close()
if vim.eval("g:blogger_browser"):
webbrowser.open(name)
return "Generated HTML has been opened in browser"
else:
return "Generated HTML has been written to %s" % name
def post(self):
"""
Do post article
"""
bufcontent = "\n".join(self.buff)
html, attrs = blogArticleString(bufcontent)
parse_msg = self._check_html(html, True)
if parse_msg:
self._open_qf(parse_msg)
return "There are errors in generated document"
if not self.password:
self.password = \
vim.eval('inputsecret("Enter your gmail password: ")')
blog = VimBlogger(self.blogname, self.login, self.password)
blog.draft = self.draft > 0
if 'id' in attrs and attrs['id']:
post = blog.update_article(html, attrs=attrs)
msg = unicode("Article '%s' has been updated" % post.title.text)
msg = msg.encode(self.vim_encoding)
else:
post = blog.create_article(html, attrs=attrs)
msg = "New article with id %s has been created" % \
post.get_post_id()
for item, value in (('id', post.get_post_id()),
('date', post.published.text),
('title', post.title.text),
('modified', post.updated.text),
('tags',
", ".join([cat.term for cat in post.category]))):
self._update_docinfo(item, value)
return msg
def delete(self):
"""
Get list of articles, display it to the user, make him choose one and
delete
"""
if not self.password:
self.password = \
vim.eval('inputsecret("Enter your gmail password: ")')
blog = VimBlogger(self.blogname, self.login, self.password)
posts = blog.get_articles(self.maxarticles)
msg = u"inputlist(["
for index, entries in enumerate(posts):
line = "%2d %s %s" % (index + 1,
entries[1],
entries[2])
msg += u'"' + line.replace('"', '\\"') + u'",'
msg = msg[:-1]
msg += u"])"
msg = unicode(msg).encode(self.vim_encoding)
choice = int(vim.eval(msg))
if choice:
art = posts[choice - 1]
msg = 'confirm("You are about to delete article \'%s\'. '
msg += 'Are you sure?"'
msg = unicode(msg % art[1]).encode(self.vim_encoding)
msg += ', "&No\n&Yes")'
if self.confirm_del:
choice = int(vim.eval(msg))
else:
choice = 2
if choice == 2:
blog.delete_article(art[0])
return "Article deleted"
return "No articles deleted"
def _update_docinfo(self, attr, val):
"""
Update current buffer with attributes value
"""
val = unicode(":%s: %s" % (attr.capitalize(), val))
val = val.encode(self.buffer_encoding)
if not self.docinfo_len:
self.buff.append(val, 0)
return
for num, line in enumerate(self.buff[:self.docinfo_len]):
if ':%s:' % attr in line.lower() and line.startswith(":"):
self.buff[num] = val
return
self.buff.append(val, 0)
self.docinfo_len += 1
def _set_docinfo_len(self):
"""
Set docinfo_len, which means number of lines from the beginning of the
buffer to the first empty line.
"""
for num, line in enumerate(self.buff):
if line and line.startswith(':'):
continue
elif not line:
self.docinfo_len = num
break
else:
self.docinfo_len = 0
break
def _open_qf(self, msg):
"""
Open VIm QuickFix window with message, if argument msg is non empty
string.
"""
if msg:
msg1 = "There are problems reported by XML parser:"
msg2 = "Check generated html for errors."
vim.command('call setqflist([{"text": "%s"}, {"text": "%s"}, '
'{"text": "%s"}])' % (msg1, msg, msg2))
vim.command('copen')
def _check_html(self, html, add_container=False):
"""
Check HTML generated document, by simply use minidom parser
If add_container is set to True, entire document is wrapped inside
additional div
returns empty string if parses succeed, else exception message.
"""
# minidom doesn't understand html entities like '&nbsp;' For checking
# purpose it is perfectly ok, to switch them with '&amp;'
html = html.replace("&nbsp;", "&amp;")
if add_container:
html = "<div>" + html + "</div>"
message = ""
try:
minidom.parseString(html)
except ExpatError as ex:
message = str(ex)
return message

View File

@@ -1,330 +0,0 @@
"""
File: rest.py
Author: Roman 'gryf' Dobosz
Description: This module is responsible for conversion between reST and HTML
with some goods added.
"""
import re
from docutils import core
from docutils import nodes
from docutils.parsers.rst import directives, Directive
from docutils.writers.html4css1 import Writer, HTMLTranslator
try:
from pygments import highlight
from pygments.lexers import get_lexer_by_name, TextLexer
from pygments.formatters import HtmlFormatter
def register(cssclass=None):
if cssclass:
Pygments.cssclass = cssclass
directives.register_directive('sourcecode', Pygments)
def _positive_int_or_1(argument):
"""
Converts the argument into an integer. Returns positive integer. In
case of integers smaller than 1, returns 1. In case of None, returns
1.
"""
if argument is None:
return 1
retval = 1
try:
retval = int(argument)
except ValueError:
pass
if retval < 1:
return 1
return retval
class Pygments(Directive):
"""
Source code syntax highlighting.
"""
required_arguments = 1
optional_arguments = 0
final_argument_whitespace = True
option_spec = {'linenos': _positive_int_or_1,
'cssclass': directives.unchanged_required}
has_content = True
cssclass = None
def run(self):
self.assert_has_content()
try:
lexer = get_lexer_by_name(self.arguments[0])
except ValueError:
# no lexer found - use the text one instead of an exception
lexer = TextLexer()
# take an arbitrary option if more than one is given
kwargs = {'full': False,
'noclasses': False}
if self.options and 'linenos' in self.options:
kwargs['linenos'] = 'inline'
kwargs['linenostart'] = self.options['linenos']
if Pygments.cssclass:
kwargs['cssclass'] = Pygments.cssclass
if self.options and 'cssclass' in self.options:
kwargs['cssclass'] = self.options['cssclass']
formatter = HtmlFormatter(**kwargs)
parsed = highlight(u'\n'.join(self.content), lexer, formatter)
return [nodes.raw('', parsed, format='html')]
register()
except ImportError:
pass
class Attrs(object):
ATTRS = {}
class CustomHTMLTranslator(HTMLTranslator):
"""
Base class for reST files translations.
There are couple of customizations for docinfo fields behaviour and
abbreviations and acronyms.
"""
def __init__(self, document):
"""
Set some nice defaults for articles translations
"""
HTMLTranslator.__init__(self, document)
self.initial_header_level = 4
def visit_section(self, node):
"""
Don't affect document, just keep track of the section levels
"""
self.section_level += 1
def depart_section(self, node):
self.section_level -= 1
def visit_meta(self, node):
pass
def depart_meta(self, node):
pass
def visit_document(self, node):
pass
def depart_document(self, node):
pass
def depart_docinfo(self, node):
"""
Reset body, remove unnecessary content.
"""
self.body = []
def visit_date(self, node):
pass
def depart_date(self, node):
pass
def visit_literal(self, node):
"""
This is almos the same as the original one from HTMLTranslator class.
The only difference is in used HTML tag: it uses 'code' instead of
'tt'
"""
self.body.append(self.starttag(node, 'code', ''))
text = node.astext()
for token in self.words_and_spaces.findall(text):
if token.strip():
# Protect text like "--an-option" and the regular expression
# ``[+]?(\d+(\.\d*)?|\.\d+)`` from bad line wrapping
if self.sollbruchstelle.search(token):
self.body.append('<span class="pre">%s</span>'
% self.encode(token))
else:
self.body.append(self.encode(token))
elif token in ('\n', ' '):
# Allow breaks at whitespace:
self.body.append(token)
else:
# Protect runs of multiple spaces; the last space can wrap:
self.body.append('&nbsp;' * (len(token) - 1) + ' ')
self.body.append('</code>')
# Content already processed:
raise nodes.SkipNode
def visit_acronym(self, node):
"""
Define missing acronym HTML tag
"""
node_text = node.children[0].astext()
node_text = node_text.replace('\n', ' ')
patt = re.compile(r'^(.+)\s<(.+)>')
if patt.match(node_text):
node.children[0] = nodes.Text(patt.match(node_text).groups()[0])
self.body.append(\
self.starttag(node, 'acronym',
'', title=patt.match(node_text).groups()[1]))
else:
self.body.append(self.starttag(node, 'acronym', ''))
def visit_abbreviation(self, node):
"""
Define missing abbr HTML tag
"""
node_text = node.children[0].astext()
node_text = node_text.replace('\n', ' ')
patt = re.compile(r'^(.+)\s<(.+)>')
if patt.match(node_text):
node.children[0] = nodes.Text(patt.match(node_text).groups()[0])
self.body.append(\
self.starttag(node, 'abbr',
'', title=patt.match(node_text).groups()[1]))
else:
self.body.append(self.starttag(node, 'abbr', ''))
class NoHeaderHTMLTranslator(CustomHTMLTranslator):
"""
Special subclass for generating only body of an article
"""
def __init__(self, document):
"""
Remove all needless parts of HTML document.
"""
CustomHTMLTranslator.__init__(self, document)
self.head = []
self.meta = []
self.head_prefix = ['', '', '', '', '']
self.body_prefix = []
self.body_suffix = []
self.stylesheet = []
self.generator = ('')
def visit_field(self, node):
"""
Harvest docinfo fields and store it in global dictionary.
"""
key, val = [n.astext() for n in node]
Attrs.ATTRS[key.lower()] = val.strip()
def visit_date(self, node):
"""
Store published date in global dictionary.
"""
Attrs.ATTRS['date'] = node.astext()
class PreviewHTMLTranslator(CustomHTMLTranslator):
"""
Class for display article in the browser as a preview.
"""
CSS = []
def __init__(self, document):
"""
Alter levels for the heading tags, define custom, blog specific
stylesheets. Note, that style_custom is present only locally to adjust
way of display the page
"""
CustomHTMLTranslator.__init__(self, document)
self.initial_header_level = 1
self.section_level = 1
# order of css files is important
self.default_stylesheets = PreviewHTMLTranslator.CSS
self.stylesheet = [self.stylesheet_link % self.encode(css) \
for css in self.default_stylesheets]
self.body_ = []
def depart_docinfo(self, node):
"""
Overwrite body with some custom one. body_ will hold the first heading
with title of the document.
"""
self.body = self.body_
def visit_field(self, node):
"""
Make title visible as a heading
"""
key, node_ = [n.astext() for n in node]
key = key.lower()
if key == 'title':
self.head.append('<title>%s</title>\n' % self.encode(node_))
self.body_.append('<h1 class="post-title entry-title">'
'<a href="#">%s</a></h1>\n' % self.encode(node_))
class BlogBodyWriter(Writer):
"""
Custom Writer class for generating HTML partial with the article
"""
def __init__(self):
Writer.__init__(self)
self.translator_class = NoHeaderHTMLTranslator
def translate(self):
self.document.settings.output_encoding = "utf-8"
Writer.translate(self)
class BlogPreviewWriter(Writer):
"""
Custom Writer class for generating full HTML of the article
"""
def __init__(self, stylesheets=None):
Writer.__init__(self)
if not stylesheets:
stylesheets = []
self.translator_class = PreviewHTMLTranslator
self.translator_class.CSS = stylesheets
def translate(self):
self.document.settings.output_encoding = "utf-8"
Writer.translate(self)
def blogPreview(string, stylesheets=None):
"""
Returns full HTML of the article.
string argument is an article in reST
"""
if not stylesheets:
stylesheets = []
html_output = core.publish_string(string,
writer=BlogPreviewWriter(stylesheets))
html_output = html_output.strip()
html_output = html_output.replace("<!-- more -->", "\n<!-- more -->\n")
return html_output
def blogArticleString(string):
"""
Returns partial HTML of the article, and attribute dictionary
string argument is an article in reST
"""
# reset ATTRS
Attrs.ATTRS = {}
html_output = core.publish_string(string, writer=BlogBodyWriter())
html_output = html_output.strip()
html_output = html_output.replace("<!-- more -->", "\n<!-- more -->\n")
attrs = {}
for key in Attrs.ATTRS:
if Attrs.ATTRS[key]:
attrs[key] = Attrs.ATTRS[key]
return html_output, attrs

View File

@@ -1,73 +0,0 @@
#!/usr/bin/env python
"""
Generate CSS stylesheet out of provided Style class module, which is an output
from the vim2pygments.py[1] script.
That stylesheet (with any necessary, additional modifications) can be used
with vimblogger_ft[2] VIm plugin, but also for general pygments usage.
Usage:
style2css <module>
[1] vim2pygments is part of the Pygments module, and can be found in scripts
directory of the Pygments <http://pygments.org> distribution.
[2] <http://www.vim.org/scripts/script.php?script_id=3367>
"""
import optparse
import os
from pygments.formatters import HtmlFormatter
class Pygments2CSS(object):
def __init__(self, modulefn, cssclass):
self.style_class = None
self.cssclass = cssclass
if not self.cssclass.startswith("."):
self.cssclass = "." + self.cssclass
mod = os.path.splitext(os.path.basename(modulefn))[0]
try:
module = __import__("%s" % mod)
except ImportError:
print('Error: %s should be in PYTHONPATH or current'
' directory, and should contain valid Style derived'
' class' % modulefn)
raise
for item in dir(module):
if item != 'Style' and item.endswith('Style'):
self.style_class = getattr(module, item)
break
else:
raise ValueError("Error: Wrong module?")
def out(self):
formatter = HtmlFormatter(style=self.style_class)
print "%s { background-color: %s }" % \
(self.cssclass, self.style_class.background_color)
for line in formatter.get_style_defs().split("\n"):
print "%s" % self.cssclass, line
if __name__ == "__main__":
parser = optparse.OptionParser("usage: %prog [options] stylefile.py\n"
"Where stylefile.py is a product of the"
" vim2pygments.py script Pygments "
"distribution.")
parser.add_option("-c", "--class",
dest="cssclass",
type="str",
help="Main CSS class name. Defaults to 'syntax'",
default="syntax")
(options, args) = parser.parse_args()
if len(args) != 1:
parser.error("stylefile.py is required")
if not (os.path.exists(args[0]) and os.path.isfile(args[0])):
parser.error("%s not found" % args[0])
p2css = Pygments2CSS(args[0], options.cssclass)
p2css.out()

View File

@@ -1 +0,0 @@
# module rst2blogger.tests

View File

@@ -1,267 +0,0 @@
# vim: set fileencoding=utf-8
import sys
import os
from datetime import datetime
from tempfile import mkstemp
LOGIN = "John"
PASS = "secret"
REST_ARTICLE = u""":Title: Title — This is a test
:Date: 2010-12-12T12:36:36+01:00
:Tags: this is a test, Blogger, rest
.. meta::
:description: meta are completely ignored in blogger parsers
`Amet`, convallis sollicitudin, commodo a, purus. Nulla vitae eros a diam
blandit **mollis**. Proin luctus ``ls --color ~/`` feugiat eros.
.. more
Pellentesque habitant morbi tristique senectus et *netus* et malesuada fames
ac turpis egestas. Duis ultricies urna: ``easy_install pygments``. Etiam enim
urna, pharetra suscipit, varius et, congue quis, odio. Donec `NES <Nintendo
Entertainment System>`:acronym: lobortis, elit bibendum euismod faucibus,
velit nibh egestas libero, vitae pellentesque elit augue ut massa.
test empty `acronym`:acronym: and `abbrev`:abbreviation:
Section 1
---------
Nulla consequat erat at massa. Vivamus id mi. Morbi purus enim, dapibus a,
facilisis non, tincidunt at, enim. Vestibulum ante ipsum primis in faucibus
orci luctus et ultrices posuere cubilia Curae; `WTF? <What the
fcuk?>`:abbreviation: Duis imperdiet eleifend arcu. Cras magna ligula,
consequat at, tempor non, posuere.
Subsection 1.1
..............
.. sourcecode:: python
import vim
print vim.current.buffer.name
.. sourcecode:: unknown_lexer
Cras dignissim vulputate metus.
Phasellus eu quam. Quisque interdum cursus purus. In.
End.
"""
class Eval(object):
"""
Communication class
"""
value = ""
blog = None
gdata_delete = 0
class Dummy(sys.__class__):
"""
Dummy class, for faking modules and other objects, not directly needed
"""
def __getattr__(self, attrname):
""" The dummy class should have no attribute """
if attrname == 'util':
return Dummy("util")
return None
# fake vim module.
sys.modules["vim"] = Dummy("vim")
class MockBuffer(list):
"""
Vim buffer-like class
"""
def append(self, val, line=None):
"""
Override append method to mimic vim.buffer append behaviour
"""
if line is None:
super(MockBuffer, self).append(val)
else:
super(MockBuffer, self).insert(line, val)
class Mock(object):
"""
Generic all-purpose mock class
"""
pass
import vim
vim.command = lambda x: None
vim.current = Mock()
vim.current.buffer = MockBuffer(REST_ARTICLE.split("\n"))
fdesc, vim.current.buffer.name = mkstemp()
vim.current.buffer.name += ".rst"
os.close(fdesc) # close descriptor, only filename is needed
def mock_vim_eval(string):
ints = ("g:blogger_draft", "g:blogger_maxarticles",
"g:blogger_confirm_del")
if string in ints:
return "0"
elif string == "g:blogger_stylesheets":
return []
else:
return Eval.value
vim.eval = mock_vim_eval
class MockBlog(object):
"""
Mock blog class
"""
def __init__(self, name, id):
self.name = name
self.id = id
def get_blog_name(self):
return self.name
def get_blog_id(self):
return self.id
def get_post_link(self):
link = Mock()
link.href = "http://www.mock.org"
return link
def get_post_id(self):
return self.id
class MockPost(object):
"""
Mock class imitating posts
"""
def __init__(self):
self.category = Mock()
self.category = []
self.id = None
self.title = Mock()
self.title.text = ""
self.published = Mock()
self.published.text = ""
def add_label(self, label):
item = Mock()
item.term = label
self.category.append(item)
def get_post_id(self):
return self.id
class MockBlogFeed(object):
"""
Mock class for feed objects
"""
def __init__(self, *args, **kwargs):
self.entry = []
if Eval.blog:
for bid, bname in {1: 'one', 3: 'test', 7: 'blog_name'}.items():
blog = MockBlog(bname, bid)
self.entry.append(blog)
class MockPostFeed(object):
"""
Mock class for feed objects
"""
def __init__(self, *args, **kwargs):
self.entry = []
from atom.data import Id, Updated
from gdata.blogger.client import BloggerClient
BloggerClient.get_blogs = lambda x: MockBlogFeed()
from gdata.client import BadAuthentication
def mock_client_login(self, login, password, source=None, service=None):
"""
Mock method for client login.
"""
if login != LOGIN or password != PASS:
raise BadAuthentication("Incorrect username or password")
BloggerClient.client_login = mock_client_login
def mock_client_post(self, post, url=None):
"""
Mimic post method
"""
if Eval.value == 10:
return None
new_id = Id(text='1234567890')
post.id = new_id
date = datetime.utcnow()
milli = str(date.microsecond)[:3]
date = date.strftime("%Y-%m-%dT%H:%M:%S")
date = date + ".%s+00:00" % milli
post.updated = Updated(text=date)
return post
BloggerClient.post = mock_client_post
BloggerClient.update = mock_client_post
def mock_client_delete(self, post):
"""
Mock delete method
"""
if not post:
raise AttributeError("%s object has no attribute 'etag'" % type(post))
if Eval.gdata_delete:
return "404 Mock"
return None
BloggerClient.delete = mock_client_delete
def mock_client_get_posts(self, blog_id):
"""
Mock get_posts method
"""
posts = (('title1', 1, "2000-01-01T00:04:00.001+01:00"),
('title2', 2, "2001-01-01T00:02:19.001+01:00"),
('title3', 3, "2002-01-01T00:01:00.001+01:00"),
('title4', 4, "2006-01-01T00:02:00.001+02:00"))
feed = MockPostFeed()
for p in posts:
a = MockPost()
a.id = p[1]
a.title.text = p[0]
a.published.text = p[2]
feed.entry.append(a)
return feed
BloggerClient.get_posts = mock_client_get_posts
def mock_client_get_feed(self, uri, desired_class=None):
"""
Mock get_feed method
"""
post = MockPost()
post.add_label('test1')
return post
BloggerClient.get_feed = mock_client_get_feed
from gdata.blogger.data import BlogPost
def mock_get_post_id(self):
return self.id.text
BlogPost.get_post_id = mock_get_post_id

View File

@@ -1,514 +0,0 @@
import os
import sys
import unittest
this_dir = os.path.dirname(os.path.abspath(__file__))
this_dir = os.path.abspath(os.path.join(this_dir, "../.."))
sys.path.insert(0, this_dir)
from rst2blogger.tests import shared
from rst2blogger.blogger import VimBlogger
class TestCheckDates(unittest.TestCase):
"""
Tests for method VimBlogger._check_date
"""
def setUp(self):
"""
Create VimBlogger object
"""
self.vimb = VimBlogger(None, shared.LOGIN, shared.PASS)
def test_happy_case_CET(self):
"""
Test on good date string on Central and East Europe
"""
date = "2000-01-01T00:00:00.001+01:00"
self.assertTrue(self.vimb._check_date(date))
def test_happy_case_HST(self):
"""
Test on good date string on Hawaii Time Zone
"""
date = "2000-01-01T00:00:00.001-10:00"
self.assertTrue(self.vimb._check_date(date))
def test_happy_case_GMT(self):
"""
Test UTC date string
"""
date = "2000-01-01T00:00:00.001-00:00"
self.assertTrue(self.vimb._check_date(date))
def test_without_milliseconds(self):
"""
Test on date string without milliseconds
"""
date = "2000-01-01T00:00:00+01:00"
self.assertTrue(self.vimb._check_date(date))
def test_wrong_tz_format(self):
"""
Test date with wrong timezone format (hour have no leading 0)
"""
date = "2000-01-01T00:00:00.001+1:00"
self.assertFalse(self.vimb._check_date(date))
# Test date with wrong timezone format (minute have only one digit)
date = "2000-01-01T00:00:00.001+01:0"
self.assertFalse(self.vimb._check_date(date))
# Test date with wrong timezone format (hours and minutes hasn't been
# separated by colon)
date = "2000-01-01T00:00:00.001+0100"
self.assertFalse(self.vimb._check_date(date))
def test_wrong_milliseconds(self):
"""
Test date with wrong format of milliseconds (.01 instead of .010)
"""
date = "2000-01-01T00:00:00.01+01:00"
self.assertFalse(self.vimb._check_date(date))
# Test date with wrong format of milliseconds (.1 instead of .100)
date = "2000-01-01T00:00:00.1+01:00"
self.assertFalse(self.vimb._check_date(date))
# Test date with spolied format (dot for milliseconds, but no digits)
date = "2000-01-01T00:00:00.+01:00"
self.assertFalse(self.vimb._check_date(date))
def test_good_milliseconds(self):
"""
Test date with correct format of milliseconds
"""
date = "2000-01-01T00:00:00.000+01:00"
self.assertTrue(self.vimb._check_date(date), date + " is incorrect")
date = "2000-01-01T00:00:00.999+01:00"
self.assertTrue(self.vimb._check_date(date), date + " is incorrect")
def test_wrong_hours(self):
"""
Test date with wrong hours value
"""
date = "2000-01-01T24:00:00.001+01:00"
self.assertFalse(self.vimb._check_date(date))
def test_good_hours(self):
"""
Test date with correct hours values
"""
date = "2000-01-01T00:00:00.001+01:00"
self.assertTrue(self.vimb._check_date(date), date + " is incorrect")
date = "2000-01-01T23:00:00.001+01:00"
self.assertTrue(self.vimb._check_date(date), date + " is incorrect")
def test_wrong_minutes(self):
"""
Test date with wrong minutes value
"""
date = "2000-01-01T00:60:00.001+01:00"
self.assertFalse(self.vimb._check_date(date))
date = "2000-01-01T00:000:00.001+01:00"
self.assertFalse(self.vimb._check_date(date))
date = "2000-01-01T00:1:00.001+01:00"
self.assertFalse(self.vimb._check_date(date))
def test_good_minutes(self):
"""
Test date with correct minutes values
"""
date = "2000-01-01T00:01:00.001+01:00"
self.assertTrue(self.vimb._check_date(date))
date = "2000-01-01T00:59:00.001+01:00"
self.assertTrue(self.vimb._check_date(date))
def test_wrong_seconds(self):
"""
Test date with wrong seconds value
"""
date = "2000-01-01T00:00:60.001+01:00"
self.assertFalse(self.vimb._check_date(date))
def test_good_seconds(self):
"""
Test date with good seconds values
"""
for second in range(60):
date = "2000-01-01T00:00:%0.2d.001+01:00" % second
self.assertTrue(self.vimb._check_date(date))
def test_wrong_days(self):
"""
Test date with incorrect days (january has always 31 days, no month
has lower number than 1)
"""
date = "2000-01-32T00:00:00.001+01:00"
self.assertFalse(self.vimb._check_date(date))
date = "2000-01-00T00:00:00.001+01:00"
self.assertFalse(self.vimb._check_date(date))
def test_good_days(self):
"""
Test date with correct days (january has always 31 days)
"""
date = "2000-01-01T00:00:00.001+01:00"
self.assertTrue(self.vimb._check_date(date))
date = "2000-01-31T00:00:00.001+01:00"
self.assertTrue(self.vimb._check_date(date))
def test_wrong_month(self):
"""
Test date with wrong month
"""
date = "2000-00-01T00:00:00.001+01:00"
self.assertFalse(self.vimb._check_date(date))
date = "2000-13-01T00:00:00.001+01:00"
self.assertFalse(self.vimb._check_date(date))
date = "2000-1-01T00:00:00.001+01:00"
self.assertFalse(self.vimb._check_date(date))
date = "2000-001-01T00:00:00.001+01:00"
self.assertFalse(self.vimb._check_date(date))
def test_good_month(self):
"""
Test date with correct months
"""
date = "2000-01-01T00:00:00.001+01:00"
self.assertTrue(self.vimb._check_date(date))
date = "2000-12-01T00:00:00.001+01:00"
self.assertTrue(self.vimb._check_date(date))
def test_wrong_year(self):
"""
Test date with wrong year
"""
date = "0000-01-01T00:00:00.001+01:00"
self.assertFalse(self.vimb._check_date(date))
date = "10000-01-01T00:00:00.001+01:00"
self.assertFalse(self.vimb._check_date(date))
date = "900-01-01T00:00:00.001+01:00"
self.assertFalse(self.vimb._check_date(date))
def test_good_year(self):
"""
Test date with correct years
"""
date = "0001-01-01T00:00:00.001+01:00"
self.assertTrue(self.vimb._check_date(date))
date = "9999-01-01T00:00:00.001+01:00"
self.assertTrue(self.vimb._check_date(date))
class TestAuthorize(unittest.TestCase):
"""
Test method VimBlogger._authorize
"""
def setUp(self):
"""
Create VimBlogger object (with good credentials, yes :>)
"""
self.vimob = VimBlogger(None, shared.LOGIN, shared.PASS)
def test_happy_case(self):
"""
Try to login with good credentials
"""
self.assertTrue(self.vimob._authorize(shared.LOGIN,
shared.PASS) is None)
def test_wrong_login(self):
"""
Try to login with wrong login
"""
self.assertRaises(shared.BadAuthentication, self.vimob._authorize,
'joe', shared.PASS)
def test_wrong_pass(self):
"""
Try to login with wrong password
"""
self.assertRaises(shared.BadAuthentication, self.vimob._authorize,
'joe', shared.PASS)
class TestAddTag(unittest.TestCase):
"""
Test method VimBlogger._add_tag
"""
def setUp(self):
"""
Create VimBlogger object
"""
self.vimob = VimBlogger(None, shared.LOGIN, shared.PASS)
self.post = shared.MockPost()
def test_add_tag(self):
"""
Add items to existing categories. List should be uniq.
"""
self.vimob._add_tag(self.post, 'item')
self.assertTrue(len(self.post.category) == 1)
# Item number should not change on the same label
self.vimob._add_tag(self.post, 'item')
self.assertTrue(len(self.post.category) == 1)
self.vimob._add_tag(self.post, 'item2')
self.assertTrue(len(self.post.category) == 2)
class TestExtractDate(unittest.TestCase):
"""
Test method VimBlogger._extract_date
"""
def setUp(self):
"""
Create VimBlogger object
"""
self.vimob = VimBlogger(None, shared.LOGIN, shared.PASS)
def test_extract_date(self):
"""
Date should be already verified by _check_date method, so only
extraction is tested
"""
date = "2000-01-01T00:00:00.001-10:00"
# wrong scenario
self.assertFalse(self.vimob._extract_date('wrong_date_string'))
# only date should be returned
self.assertEqual(self.vimob._extract_date(date), "2000-01-01")
# date and time should be returned
self.assertEqual(self.vimob._extract_date(date, True),
"2000-01-01 00:00:00")
class TestGetPost(unittest.TestCase):
"""
Test method VimBlogger._get_post
"""
def setUp(self):
"""
Create VimBlogger object
"""
self.vimob = VimBlogger(None, shared.LOGIN, shared.PASS)
self.vimob.blog = shared.Mock()
link = shared.Mock()
link.href = "mock.com"
link.feed = shared.Mock()
self.vimob.blog.get_post_link = lambda: link
def test_get_post(self):
"""
Nothing really to test here. Maybe in the future :)
"""
result = self.vimob._get_post('1234')
self.assertEqual(type(result), shared.MockPost)
class TestSetBlog(unittest.TestCase):
"""
Test method VimBlogger._set_blog
"""
def setUp(self):
"""
Create VimBlogger object
"""
self.vimob = VimBlogger(None, shared.LOGIN, shared.PASS)
for bid, bname in {1: 'one', 3: 'test', 7: 'blog_name'}.items():
blog = shared.MockBlog(bname, bid)
self.vimob.feed.entry.append(blog)
def test_set_blog(self):
"""
Test setting a blog
"""
self.vimob._set_blog("no_valid_blog_name")
self.assertEqual(self.vimob.blog_id, None)
self.assertEqual(self.vimob.blog, None)
self.vimob._set_blog("blog_name")
self.assertEqual(self.vimob.blog_id, 7)
self.assertEqual(self.vimob.blog.get_blog_name(), 'blog_name')
self.vimob._set_blog("test")
self.assertEqual(self.vimob.blog_id, 3)
self.assertEqual(self.vimob.blog.get_blog_name(), 'test')
self.vimob._set_blog("one")
self.assertEqual(self.vimob.blog_id, 1)
self.assertEqual(self.vimob.blog.get_blog_name(), 'one')
class TestCreateArticle(unittest.TestCase):
"""
Test method VimBlogger.create_article
"""
def setUp(self):
"""
Create VimBlogger object
"""
self.vimob = VimBlogger(None, shared.LOGIN, shared.PASS)
def test_create_simple_article(self):
"""
Test creation of article with minimum requirements
"""
html = "<p>article</p>"
post = self.vimob.create_article(html)
self.vimob.draft = True
self.assertEqual(post.id.text, '1234567890')
self.assertEqual(post.content.text, html)
self.assertEqual(post.published, None)
self.assertTrue(post.updated is not None)
self.assertEqual(post.title.text, "")
self.assertEqual(post.category, [])
self.assertEqual(post.control.draft.text, "yes")
def test_create_article(self):
"""
Test creation of article with full attrs
"""
html = u"<p>article \xe2\x80\x94 article</p>"
labels = "tag with spaces|vim|python|blogger".split("|")
attrs = {"title": u'Title \xe2\x80\x94 title',
"tags": ", ".join(labels),
"date": "2010-12-10T14:18:32+00:00"}
self.vimob.draft = False
post = self.vimob.create_article(html, attrs)
self.assertEqual(post.id.text, '1234567890')
self.assertEqual(post.content.text, html)
self.assertEqual(post.published.text, attrs['date'])
self.assertTrue(post.updated is not None)
self.assertEqual(post.title.text, attrs['title'])
self.assertEqual(len(post.category), 4)
for label in post.category:
self.assertTrue(label.term in labels)
del(labels[labels.index(label.term)])
self.assertEqual(post.control, None)
class TestDeleteArticle(unittest.TestCase):
"""
Test method VimBlogger.create_article
"""
def setUp(self):
"""
Create VimBlogger object
"""
self.vimob = VimBlogger(None, shared.LOGIN, shared.PASS)
for bid, bname in {1: 'one', 3: 'test', 7: 'blog_name'}.items():
blog = shared.MockBlog(bname, bid)
self.vimob.feed.entry.append(blog)
self.vimob._set_blog('test')
def test_delete_non_existing_article(self):
"""
Test removing article without id
"""
self.assertEqual(self.vimob.delete_article(None),
"No article id provided")
def test_delete_article(self):
"""
Test removing article
"""
html = u"<p>article \xe2\x80\x94 article</p>"
labels = "tag with spaces|vim|python|blogger".split("|")
attrs = {"title": u'Title \xe2\x80\x94 title',
"tags": ", ".join(labels),
"date": "2010-12-10T14:18:32+00:00"}
self.vimob.draft = False
post = self.vimob.create_article(html, attrs)
self.assertEqual(self.vimob.delete_article(post.id.text), None)
class TestGetArticles(unittest.TestCase):
"""
Test method VimBlogger.get_articles
"""
def setUp(self):
"""
Create VimBlogger object
"""
self.vimob = VimBlogger(None, shared.LOGIN, shared.PASS)
def test_get_articles(self):
"""
Test removing article without id
"""
articles = self.vimob.get_articles()
self.assertEqual(len(articles), 4)
articles = self.vimob.get_articles(maxarticles=2)
self.assertEqual(len(articles), 2)
class TestUpdateArticle(unittest.TestCase):
"""
Test method VimBlogger.update_article
"""
def setUp(self):
"""
Create VimBlogger object
"""
self.vimob = VimBlogger(None, shared.LOGIN, shared.PASS)
for bid, bname in {1: 'one', 3: 'test', 7: 'blog_name'}.items():
blog = shared.MockBlog(bname, bid)
self.vimob.feed.entry.append(blog)
self.vimob._set_blog('test')
def test_wrong_argument_types(self):
"""
Test update_article method with wrong argument types
"""
self.assertRaises(TypeError, self.vimob.update_article, None, None)
def test_no_id_in_attrs(self):
"""
Test update_article method with no id in attrs
"""
self.assertRaises(Exception, self.vimob.update_article,
'<p>update</p>', [])
def test_update(self):
"""
Test update_article method with no id in attrs
"""
attrs = {'id': 1234567890, 'title': 'update',
'date': '2001-01-01T00:02:19.001+01:00',
'tags': "tag1, tag2, tag3"}
post = self.vimob.update_article('<p>update</p>', attrs)
self.assertEqual(post.title.text, 'update')
self.assertEqual(post.id.text, '1234567890')
self.assertEqual(post.content.text, '<p>update</p>')
self.assertTrue(post.updated.text is not None)
if __name__ == "__main__":
unittest.main()

View File

@@ -1,295 +0,0 @@
# vim: set fileencoding=utf-8
import os
import sys
import unittest
import webbrowser
webbrowser.open = lambda x: None
this_dir = os.path.dirname(os.path.abspath(__file__))
this_dir = os.path.abspath(os.path.join(this_dir, "../.."))
sys.path.insert(0, this_dir)
from rst2blogger.tests.shared import LOGIN, PASS, Eval, MockBuffer
from rst2blogger.main import Rst2Blogger
from gdata.client import BadAuthentication
class TestRst2Blogger(unittest.TestCase):
"""
Tests for vim - rest - blogger interface
"""
def setUp(self):
"""
Create Rst2Blogger object
"""
self.obj = Rst2Blogger()
def test_object_creation(self):
"""
Create Rst2Blogger object and test it.
"""
self.assertTrue(self.obj is not None)
self.assertEqual(self.obj.docinfo_len, 3)
self.assertEqual(self.obj.login, "")
self.assertEqual(self.obj.password, "")
self.assertEqual(self.obj.blogname, "")
self.assertEqual(self.obj.buffer_encoding, "")
self.assertEqual(self.obj.vim_encoding, "")
self.assertEqual(self.obj.maxarticles, 0)
self.assertEqual(self.obj.draft, 0)
self.assertEqual(self.obj.confirm_del, 0)
self.assertEqual(self.obj.stylesheets, [])
class TestRst2BloggerSetDocinfoLen(unittest.TestCase):
"""
Test _set_docinfo_len method on different docinfo configurations
"""
def setUp(self):
"""
Create Rst2Blogger object
"""
self.obj = Rst2Blogger()
def test_set_docinfo_len(self):
"""
Test with no defined docinfo
"""
self.obj.buff = self.obj.buff[4:]
self.obj._set_docinfo_len()
self.assertEqual(self.obj.docinfo_len, 0)
def test_set_docinfo_len2(self):
"""
Test with one docinfo entry
"""
self.obj.buff = self.obj.buff[:1] + [''] + self.obj.buff[4:]
self.obj._set_docinfo_len()
self.assertEqual(self.obj.docinfo_len, 1)
def test_set_docinfo_len3(self):
"""
Test with wrong docinfo definition
"""
self.obj.buff = self.obj.buff[:1] + self.obj.buff[4:]
self.obj._set_docinfo_len()
self.assertEqual(self.obj.docinfo_len, 0)
class TestCheckHtml(unittest.TestCase):
"""
Check HTML parser
"""
def setUp(self):
"""
Create Rst2Blogger object
"""
self.obj = Rst2Blogger()
def test_check_html1(self):
"""
Parse (generated) html string, should return empty string
"""
html = "<html><head><title>test</title></head><body></body></html>"
self.assertEqual(self.obj._check_html(html), "")
self.assertEqual(self.obj._check_html(html, True), "")
def test_check_html2(self):
"""
Parse html fragment string
"""
html = "<p>first paragraph</p><p>another paragraph</p>"
self.assertEqual(self.obj._check_html(html),
"junk after document element: line 1, column 22")
self.assertEqual(self.obj._check_html(html, True), "")
def test_check_html3(self):
"""
Parse wrong html string (crossed tags)
"""
html = "<p>first paragraph<b></p>another paragraph</b>"
self.assertEqual(self.obj._check_html(html),
"mismatched tag: line 1, column 23")
self.assertEqual(self.obj._check_html(html, True),
"mismatched tag: line 1, column 28")
class TestRst2BloggerDelete(unittest.TestCase):
"""
Test delete method
"""
def setUp(self):
"""
Create Rst2Blogger object
"""
self.obj = Rst2Blogger()
self.obj.login = LOGIN
self.obj.password = PASS
self.obj.blogname = "test"
self.obj.vim_encoding = "utf-8"
def test_delete_without_password(self):
"""
Delete article, while password is incorrect/nonexistend
"""
self.obj.password = ""
self.assertRaises(BadAuthentication, self.obj.delete)
def test_delete(self):
"""
Delete article. Set confirmation attribute.
"""
self.obj.confirm_del = 1
Eval.value = 2 # set choice to answer "Y" for confirmation
Eval.blog = "test"
self.assertEqual(self.obj.delete(), "Article deleted")
def test_delete2(self):
"""
Delete article. Set confirmation attribute. Refuse to delete.
"""
self.obj.confirm_del = 1
Eval.value = 1 # set choice to answer "N" for confirmation
Eval.blog = "test"
self.assertEqual(self.obj.delete(), "No articles deleted")
def test_delete3(self):
"""
Delete article. Unset confirmation attribute. Delete returns something
else then None.
"""
Eval.value = 2
Eval.blog = "test"
Eval.gdata_delete = 1
self.assertEqual(self.obj.delete(), "Article deleted")
class TestRst2BloggerPost(unittest.TestCase):
"""
Test post method
"""
def setUp(self):
"""
Create Rst2Blogger object
"""
self.obj = Rst2Blogger()
self.obj.login = LOGIN
self.obj.password = PASS
self.obj.blogname = "test"
self.obj.vim_encoding = "utf-8"
self.obj.buffer_encoding = "utf-8"
# create copy of the buffer list and assign copy to the buff attribute
self._rest = MockBuffer(self.obj.buff[:])
self.obj.buff = self._rest
def test_without_password(self):
"""
Post article, while password is incorrect/nonexistend
"""
self.obj.password = ""
self.assertRaises(BadAuthentication, self.obj.post)
def test_with_wrong_data(self):
"""
Try to post not well formed html
"""
self.obj.buff.append('')
self.obj.buff.append('.. raw:: html')
self.obj.buff.append('')
self.obj.buff.append(' <p>foo<b>bar</p>baz</b>')
self.obj.buff.append('')
self.obj.post()
self.assertEqual(self.obj.post(),
'There are errors in generated document')
def test_post_create(self):
"""
Try to post well formed html, as a new article
"""
self.assertEqual(self.obj.post(),
'New article with id 1234567890 has been created')
def test_post_update(self):
"""
Try to post well formed html, as a new article
"""
self.obj.buff.append(':Id: 1234567890', 0)
self.assertEqual(self.obj.post(),
"Article 'Title \xe2\x80\x94 This is a test' "
"has been updated")
class TestRst2BloggerUpdateDocinfo(unittest.TestCase):
"""
Test _update_docinfo
"""
def setUp(self):
"""
Create Rst2Blogger object
"""
self.obj = Rst2Blogger()
self.obj.login = LOGIN
self.obj.password = PASS
self.obj.blogname = "test"
self.obj.vim_encoding = "utf-8"
self.obj.buffer_encoding = "utf-8"
# create copy of the buffer list and assign copy to the buff attribute
self._rest = MockBuffer(self.obj.buff[:])
self.obj.buff = self._rest
def test_with_empty_docinfo(self):
"""
Try to post not well formed html
"""
self.obj.buff = MockBuffer(self.obj.buff[4:])
self.obj.docinfo_len = 0
self.obj._update_docinfo('title', 'title2')
class TestRst2BloggerPreview(unittest.TestCase):
"""
Test preview
"""
def setUp(self):
"""
Create Rst2Blogger object
"""
self.obj = Rst2Blogger()
self.obj.login = LOGIN
self.obj.password = PASS
self.obj.blogname = "test"
def tearDown(self):
"""
Remove leftovers in fs
"""
try:
os.unlink(self.obj.buff.name[:-4])
except OSError:
pass
try:
os.unlink(self.obj.buff.name[:-4] + ".html")
except OSError:
pass
def test_preview_open_in_browser(self):
"""
Try to post not well formed html
"""
Eval.value = 1
self.assertEqual(self.obj.preview(),
'Generated HTML has been opened in browser')
def test_preview_save_to_file(self):
"""
Try to post not well formed html
"""
Eval.value = 0
name = self.obj.buff.name[:-4] + ".html"
self.assertEqual(self.obj.preview(),
"Generated HTML has been written to %s" % name)
if __name__ == "__main__":
unittest.main()

View File

@@ -1,201 +0,0 @@
# vim: set fileencoding=utf-8
import os
import sys
import unittest
import re
this_dir = os.path.dirname(os.path.abspath(__file__))
this_dir = os.path.abspath(os.path.join(this_dir, "../.."))
sys.path.insert(0, this_dir)
from rst2blogger.rest import blogArticleString, blogPreview
from rst2blogger.tests.shared import REST_ARTICLE
LINENOS1 = """
.. sourcecode:: python
:linenos:
import vim
print vim.current.buffer.name
"""
LINENOS2 = """
.. sourcecode:: python
:linenos: -1
import vim
print vim.current.buffer.name
"""
LINENOS3 = """
.. sourcecode:: python
:linenos: 0
import vim
print vim.current.buffer.name
"""
LINENOS4 = """
.. sourcecode:: python
:linenos: 12
import vim
print vim.current.buffer.name
"""
LINENOS5 = """
.. sourcecode:: python
:linenos: this is wrong
import vim
print vim.current.buffer.name
"""
CSSCLASS1 = """
.. sourcecode:: python
:cssclass:
import vim
print vim.current.buffer.name
"""
CSSCLASS2 = """
.. sourcecode:: python
:cssclass: Dessert256
import vim
print vim.current.buffer.name
"""
class TestBlogPreview(unittest.TestCase):
"""
Test generating HTML out of prepared reST text. It tests only for some
aspects of the entire thing, because it is not intendend to test all of
reST directives.
"""
def test_content(self):
"""
Simple case, check output
"""
html_out = blogPreview(REST_ARTICLE)
self.assertTrue(len(html_out) > 0)
self.assertTrue("<html" in html_out)
self.assertTrue("</html>" in html_out)
self.assertTrue("<?xml version=\"1.0\" encoding=\"utf-8\"" in
html_out)
self.assertTrue("\n\n<!-- more -->\n\n" in html_out)
self.assertTrue("<title>Title — This is a test</title>" in html_out)
self.assertTrue('type="text/css"' not in html_out)
self.assertTrue(re.search(r"<h1.*><a href=\"#\">Title — This is a"
" test</a></h1>", html_out))
self.assertTrue(re.search(r"<h2>Section 1</h2>", html_out))
self.assertTrue(re.search(r"<h3>Subsection 1.1</h3>", html_out))
self.assertTrue("description" not in html_out)
def test_stylesheets(self):
"""
Test output for stylesheets
"""
html_out = blogPreview(REST_ARTICLE, ["css/style1.css",
"css/blogger1.css"])
self.assertTrue('type="text/css"' in html_out)
match = re.search(r'<link rel="stylesheet" '
'href=".*" type="text/css" />', html_out)
self.assertTrue(match is not None)
self.assertEqual(len(match.span()), 2)
class TestBlogArticleString(unittest.TestCase):
"""
Test blogArticleString function, wich should return part of html and
dictionary with attributes.
"""
def test_blogArticleString(self):
html_out, attrs = blogArticleString(REST_ARTICLE)
self.assertEqual(len(attrs), 3)
self.assertTrue(len(html_out) > 0)
self.assertTrue("<html" not in html_out)
self.assertTrue("</html>" not in html_out)
self.assertTrue("<?xml version=\"1.0\" encoding=\"utf-8\"" not in
html_out)
self.assertTrue("\n\n<!-- more -->\n\n" in html_out)
self.assertTrue("<title>Title — This is a test</title>" not in
html_out)
self.assertTrue('type="text/css"' not in html_out)
self.assertTrue(re.search(r"<h4>Section 1</h4>", html_out))
self.assertTrue(re.search(r"<h5>Subsection 1.1</h5>", html_out))
self.assertTrue("description" not in html_out)
self.assertEqual(attrs['title'], u"Title — This is a test")
self.assertEqual(attrs['date'], "2010-12-12T12:36:36+01:00")
self.assertEqual(attrs['tags'], "this is a test, Blogger, rest")
class TestBlogArticlePytgments(unittest.TestCase):
"""
Test cases for sourcecode directive
"""
def test_linenos_no_args(self):
"""
Test linenos option with no additional arguments
"""
html_out, _ = blogArticleString(LINENOS1)
self.assertTrue('<pre><span class="lineno">1</span>' in html_out)
def test_linenos_with_arg1(self):
"""
Test linenos option with correct argument type but wrong value.
Should count from 1 in this case.
"""
html_out, _ = blogArticleString(LINENOS2)
self.assertTrue('<pre><span class="lineno">1</span>' in html_out)
def test_linenos_with_arg2(self):
"""
Test linenos option with correct argument type but wrong value.
Should count from 1 in this case.
"""
html_out, _ = blogArticleString(LINENOS3)
self.assertTrue('<pre><span class="lineno">1</span>' in html_out)
def test_linenos_with_arg3(self):
"""
Test linenos option with correct argument type and correct value.
Should count from 1 in this case.
"""
html_out, _ = blogArticleString(LINENOS4)
self.assertTrue('<pre><span class="lineno">12</span>' in html_out)
def test_linenos_with_wrong_arg(self):
"""
Test linenos option with wrong argument type. Should count from 1.
"""
html_out, _ = blogArticleString(LINENOS5)
self.assertTrue('<pre><span class="lineno">1</span>' in html_out)
def test_cssclass_failure(self):
"""
Test cssclass option with no arguments. Should complain with system
message.
"""
html_out, _ = blogArticleString(CSSCLASS1)
self.assertTrue('System Message: ERROR/3' in html_out)
def test_cssclass_correct(self):
"""
Test cssclass option with Dessert256 as an argument. Should be used as
a main div CSS class.
"""
html_out, _ = blogArticleString(CSSCLASS2)
self.assertTrue('<div class="Dessert256">' in html_out)
if __name__ == "__main__":
unittest.main()

View File

@@ -1,75 +0,0 @@
" reST to blogger vim interface.
" Provide some convinient commands for creating preview from the reST file
" and to send articles to blog.
" VERSION: 0.2
if exists("b:did_rst_plugin")
finish " load only once
else
let b:did_blogger_plugin = 1
endif
if exists(':PreviewBlogArticle')
finish
endif
if !exists("g:blogger_browser")
let g:blogger_browser = 0
endif
if !exists("g:blogger_name")
let g:blogger_name = ""
endif
if !exists("g:blogger_login")
let g:blogger_login= ""
endif
if !exists("g:blogger_pass")
let g:blogger_pass = ""
endif
if !exists("g:blogger_draft")
let g:blogger_draft = 1
endif
if !exists("g:blogger_maxarticles")
let g:blogger_maxarticles = 0
endif
if !exists("g:blogger_confirm_del")
let g:blogger_confirm_del = 1
endif
if !exists("g:blogger_stylesheets")
let g:blogger_stylesheets = []
endif
if !exists("g:blogger_pygments_class")
let g:blogger_pygments_class = ""
endif
python << EOF
import os
import sys
import vim
scriptdir = os.path.dirname(vim.eval('expand("<sfile>")'))
sys.path.insert(0, scriptdir)
# Will raise exception, if one of required moudles is missing
from rst2blogger.main import Rst2Blogger
EOF
if !exists(":PreviewBlogArticle")
command PreviewBlogArticle py print Rst2Blogger().preview()
endif
if !exists(":SendBlogArticle")
command SendBlogArticle py print Rst2Blogger().post()
endif
if !exists(":DeleteBlogArticle")
command DeleteBlogArticle py print Rst2Blogger().delete()
endif

View File

@@ -1,29 +0,0 @@
function! WordFrequency() range
let all = split(join(getline(a:firstline, a:lastline)), '\k\+')
let frequencies = {}
for word in all
let frequencies[word] = get(frequencies, word, 0) + 1
endfor
new
setlocal buftype=nofile bufhidden=hide noswapfile tabstop=4
for [key,value] in items(frequencies)
call append('$', value."\t".key)
endfor
sort i
endfunction
command! -range=% WordFrequency <line1>,<line2>call WordFrequency()
function! CreateDict() range
let all = split(join(getline(a:firstline, a:lastline)), '[^A-Za-zęóąśłżźćńĘÓĄŚŁŻŹĆŃ]\+')
let frequencies = {}
for word in all
let frequencies[word] = get(frequencies, word, 0) + 1
endfor
new
setlocal buftype=nofile bufhidden=hide noswapfile
for [key,value] in items(frequencies)
call append('$', key)
endfor
sort i
endfunction
command! -range=% CreateDict <line1>,<line2>call CreateDict()

View File

@@ -1,8 +0,0 @@
set nolist
set tabstop=4
set autoindent
"set foldmethod=manual
set noexpandtab
set shiftwidth=4
set noexpandtab
set list

View File

@@ -1,4 +0,0 @@
set nolist
set nosmartindent
set autoindent
set foldmethod=manual

View File

@@ -1,2 +0,0 @@
compiler rubber
map <F5> :make<cr>

View File

@@ -1,4 +0,0 @@
set nolist
set nosmartindent
set autoindent
set foldmethod=manual

View File

@@ -1,418 +0,0 @@
" vim:tabstop=2:shiftwidth=2:expandtab:foldmethod=marker:textwidth=79
" Vimwiki filetype plugin file
" Author: Maxim Kim <habamax@gmail.com>
" Home: http://code.google.com/p/vimwiki/
if exists("b:did_ftplugin")
finish
endif
let b:did_ftplugin = 1 " Don't load another plugin for this buffer
" UNDO list {{{
" Reset the following options to undo this plugin.
let b:undo_ftplugin = "setlocal ".
\ "suffixesadd< isfname< comments< ".
\ "autowriteall< ".
\ "formatoptions< foldtext< ".
\ "foldmethod< foldexpr< commentstring< "
" UNDO }}}
" MISC STUFF {{{
setlocal autowriteall
setlocal commentstring=%%%s
if g:vimwiki_conceallevel && exists("+conceallevel")
let &conceallevel = g:vimwiki_conceallevel
endif
" MISC }}}
" GOTO FILE: gf {{{
execute 'setlocal suffixesadd='.VimwikiGet('ext')
setlocal isfname-=[,]
" gf}}}
" Autocreate list items {{{
" for list items, and list items with checkboxes
if VimwikiGet('syntax') == 'default'
setl comments=b:*,b:#,b:-
setl formatlistpat=^\\s*[*#-]\\s*
else
setl comments=n:*,n:#
endif
setlocal formatoptions=tnro
if !empty(&langmap)
" Valid only if langmap is a comma separated pairs of chars
let l_o = matchstr(&langmap, '\C,\zs.\zeo,')
if l_o
exe 'nnoremap <buffer> '.l_o.' :call vimwiki#lst#kbd_oO("o")<CR>a'
endif
let l_O = matchstr(&langmap, '\C,\zs.\zeO,')
if l_O
exe 'nnoremap <buffer> '.l_O.' :call vimwiki#lst#kbd_oO("O")<CR>a'
endif
endif
" COMMENTS }}}
" FOLDING for headers and list items using expr fold method. {{{
function! VimwikiFoldLevel(lnum) "{{{
let line = getline(a:lnum)
" Header folding...
if line =~ g:vimwiki_rxHeader
let n = vimwiki#base#count_first_sym(line)
return '>'.n
endif
if g:vimwiki_fold_trailing_empty_lines == 0 && line =~ '^\s*$'
let nnline = getline(nextnonblank(a:lnum + 1))
else
let nnline = getline(a:lnum + 1)
endif
if nnline =~ g:vimwiki_rxHeader
let n = vimwiki#base#count_first_sym(nnline)
return '<'.n
endif
" List item folding...
if g:vimwiki_fold_lists
let base_level = s:get_base_level(a:lnum)
let rx_list_item = '\('.
\ g:vimwiki_rxListBullet.'\|'.g:vimwiki_rxListNumber.
\ '\)'
if line =~ rx_list_item
let [nnum, nline] = s:find_forward(rx_list_item, a:lnum)
let level = s:get_li_level(a:lnum)
let leveln = s:get_li_level(nnum)
let adj = s:get_li_level(s:get_start_list(rx_list_item, a:lnum))
if leveln > level
return ">".(base_level+leveln-adj)
else
return (base_level+level-adj)
endif
else
" process multilined list items
let [pnum, pline] = s:find_backward(rx_list_item, a:lnum)
if pline =~ rx_list_item
if indent(a:lnum) > indent(pnum)
let level = s:get_li_level(pnum)
let adj = s:get_li_level(s:get_start_list(rx_list_item, pnum))
let [nnum, nline] = s:find_forward(rx_list_item, a:lnum)
if nline =~ rx_list_item
let leveln = s:get_li_level(nnum)
if leveln > level
return (base_level+leveln-adj)
endif
endif
return (base_level+level-adj)
endif
endif
endif
return base_level
endif
return -1
endfunction "}}}
function! s:get_base_level(lnum) "{{{
let lnum = a:lnum - 1
while lnum > 0
if getline(lnum) =~ g:vimwiki_rxHeader
return vimwiki#base#count_first_sym(getline(lnum))
endif
let lnum -= 1
endwhile
return 0
endfunction "}}}
function! s:find_forward(rx_item, lnum) "{{{
let lnum = a:lnum + 1
while lnum <= line('$')
let line = getline(lnum)
if line =~ a:rx_item
\ || line =~ '^\S'
\ || line =~ g:vimwiki_rxHeader
break
endif
let lnum += 1
endwhile
return [lnum, getline(lnum)]
endfunction "}}}
function! s:find_backward(rx_item, lnum) "{{{
let lnum = a:lnum - 1
while lnum > 1
let line = getline(lnum)
if line =~ a:rx_item
\ || line =~ '^\S'
break
endif
let lnum -= 1
endwhile
return [lnum, getline(lnum)]
endfunction "}}}
function! s:get_li_level(lnum) "{{{
if VimwikiGet('syntax') == 'media'
let level = vimwiki#base#count_first_sym(getline(a:lnum))
else
let level = (indent(a:lnum) / &sw)
endif
return level
endfunction "}}}
function! s:get_start_list(rx_item, lnum) "{{{
let lnum = a:lnum
while lnum >= 1
let line = getline(lnum)
if line !~ a:rx_item && line =~ '^\S'
return nextnonblank(lnum + 1)
endif
let lnum -= 1
endwhile
return 0
endfunction "}}}
function! VimwikiFoldText() "{{{
let line = substitute(getline(v:foldstart), '\t',
\ repeat(' ', &tabstop), 'g')
return line.' ['.(v:foldend - v:foldstart).']'
endfunction "}}}
" FOLDING }}}
" COMMANDS {{{
command! -buffer Vimwiki2HTML
\ w <bar> call vimwiki#html#Wiki2HTML(expand(VimwikiGet('path_html')),
\ expand('%'))
command! -buffer Vimwiki2HTMLBrowse
\ w <bar> call VimwikiWeblinkHandler(
\ vimwiki#html#Wiki2HTML(expand(VimwikiGet('path_html')),
\ expand('%')))
command! -buffer VimwikiAll2HTML
\ call vimwiki#html#WikiAll2HTML(expand(VimwikiGet('path_html')))
command! -buffer VimwikiNextLink call vimwiki#base#find_next_link()
command! -buffer VimwikiPrevLink call vimwiki#base#find_prev_link()
command! -buffer VimwikiDeleteLink call vimwiki#base#delete_link()
command! -buffer VimwikiRenameLink call vimwiki#base#rename_link()
command! -buffer VimwikiFollowLink call vimwiki#base#follow_link('nosplit')
command! -buffer VimwikiGoBackLink call vimwiki#base#go_back_link()
command! -buffer VimwikiSplitLink call vimwiki#base#follow_link('split')
command! -buffer VimwikiVSplitLink call vimwiki#base#follow_link('vsplit')
command! -buffer VimwikiTabnewLink call vimwiki#base#follow_link('tabnew')
command! -buffer -range VimwikiToggleListItem call vimwiki#lst#ToggleListItem(<line1>, <line2>)
command! -buffer VimwikiGenerateLinks call vimwiki#base#generate_links()
exe 'command! -buffer -nargs=* VimwikiSearch lvimgrep <args> '.
\ escape(VimwikiGet('path').'**/*'.VimwikiGet('ext'), ' ')
exe 'command! -buffer -nargs=* VWS lvimgrep <args> '.
\ escape(VimwikiGet('path').'**/*'.VimwikiGet('ext'), ' ')
command! -buffer -nargs=1 VimwikiGoto call vimwiki#base#goto("<args>")
" table commands
command! -buffer -nargs=* VimwikiTable call vimwiki#tbl#create(<f-args>)
command! -buffer VimwikiTableAlignQ call vimwiki#tbl#align_or_cmd('gqq')
command! -buffer VimwikiTableAlignW call vimwiki#tbl#align_or_cmd('gww')
command! -buffer VimwikiTableMoveColumnLeft call vimwiki#tbl#move_column_left()
command! -buffer VimwikiTableMoveColumnRight call vimwiki#tbl#move_column_right()
" diary commands
command! -buffer VimwikiDiaryNextDay call vimwiki#diary#goto_next_day()
command! -buffer VimwikiDiaryPrevDay call vimwiki#diary#goto_prev_day()
" COMMANDS }}}
" KEYBINDINGS {{{
if g:vimwiki_use_mouse
nmap <buffer> <S-LeftMouse> <NOP>
nmap <buffer> <C-LeftMouse> <NOP>
nnoremap <silent><buffer> <2-LeftMouse> :VimwikiFollowLink<CR>
nnoremap <silent><buffer> <S-2-LeftMouse> <LeftMouse>:VimwikiSplitLink<CR>
nnoremap <silent><buffer> <C-2-LeftMouse> <LeftMouse>:VimwikiVSplitLink<CR>
nnoremap <silent><buffer> <RightMouse><LeftMouse> :VimwikiGoBackLink<CR>
endif
if !hasmapto('<Plug>Vimwiki2HTML')
nmap <buffer> <Leader>wh <Plug>Vimwiki2HTML
endif
nnoremap <script><buffer>
\ <Plug>Vimwiki2HTML :Vimwiki2HTML<CR>
if !hasmapto('<Plug>Vimwiki2HTMLBrowse')
nmap <buffer> <Leader>whh <Plug>Vimwiki2HTMLBrowse
endif
nnoremap <script><buffer>
\ <Plug>Vimwiki2HTMLBrowse :Vimwiki2HTMLBrowse<CR>
if !hasmapto('<Plug>VimwikiFollowLink')
nmap <silent><buffer> <CR> <Plug>VimwikiFollowLink
endif
nnoremap <silent><script><buffer>
\ <Plug>VimwikiFollowLink :VimwikiFollowLink<CR>
if !hasmapto('<Plug>VimwikiSplitLink')
nmap <silent><buffer> <S-CR> <Plug>VimwikiSplitLink
endif
nnoremap <silent><script><buffer>
\ <Plug>VimwikiSplitLink :VimwikiSplitLink<CR>
if !hasmapto('<Plug>VimwikiVSplitLink')
nmap <silent><buffer> <C-CR> <Plug>VimwikiVSplitLink
endif
nnoremap <silent><script><buffer>
\ <Plug>VimwikiVSplitLink :VimwikiVSplitLink<CR>
if !hasmapto('<Plug>VimwikiTabnewLink')
nmap <silent><buffer> <D-CR> <Plug>VimwikiTabnewLink
nmap <silent><buffer> <C-S-CR> <Plug>VimwikiTabnewLink
endif
nnoremap <silent><script><buffer>
\ <Plug>VimwikiTabnewLink :VimwikiTabnewLink<CR>
if !hasmapto('<Plug>VimwikiGoBackLink')
nmap <silent><buffer> <BS> <Plug>VimwikiGoBackLink
endif
nnoremap <silent><script><buffer>
\ <Plug>VimwikiGoBackLink :VimwikiGoBackLink<CR>
if !hasmapto('<Plug>VimwikiNextLink')
nmap <silent><buffer> <TAB> <Plug>VimwikiNextLink
endif
nnoremap <silent><script><buffer>
\ <Plug>VimwikiNextLink :VimwikiNextLink<CR>
if !hasmapto('<Plug>VimwikiPrevLink')
nmap <silent><buffer> <S-TAB> <Plug>VimwikiPrevLink
endif
nnoremap <silent><script><buffer>
\ <Plug>VimwikiPrevLink :VimwikiPrevLink<CR>
if !hasmapto('<Plug>VimwikiDeleteLink')
nmap <silent><buffer> <Leader>wd <Plug>VimwikiDeleteLink
endif
nnoremap <silent><script><buffer>
\ <Plug>VimwikiDeleteLink :VimwikiDeleteLink<CR>
if !hasmapto('<Plug>VimwikiRenameLink')
nmap <silent><buffer> <Leader>wr <Plug>VimwikiRenameLink
endif
nnoremap <silent><script><buffer>
\ <Plug>VimwikiRenameLink :VimwikiRenameLink<CR>
if !hasmapto('<Plug>VimwikiToggleListItem')
nmap <silent><buffer> <C-Space> <Plug>VimwikiToggleListItem
vmap <silent><buffer> <C-Space> <Plug>VimwikiToggleListItem
if has("unix")
nmap <silent><buffer> <C-@> <Plug>VimwikiToggleListItem
endif
endif
nnoremap <silent><script><buffer>
\ <Plug>VimwikiToggleListItem :VimwikiToggleListItem<CR>
if !hasmapto('<Plug>VimwikiDiaryNextDay')
nmap <silent><buffer> <C-Down> <Plug>VimwikiDiaryNextDay
endif
nnoremap <silent><script><buffer>
\ <Plug>VimwikiDiaryNextDay :VimwikiDiaryNextDay<CR>
if !hasmapto('<Plug>VimwikiDiaryPrevDay')
nmap <silent><buffer> <C-Up> <Plug>VimwikiDiaryPrevDay
endif
nnoremap <silent><script><buffer>
\ <Plug>VimwikiDiaryPrevDay :VimwikiDiaryPrevDay<CR>
function! s:CR() "{{{
let res = vimwiki#lst#kbd_cr()
if res == "\<CR>" && g:vimwiki_table_auto_fmt
let res = vimwiki#tbl#kbd_cr()
endif
return res
endfunction "}}}
" List and Table <CR> mapping
inoremap <buffer> <expr> <CR> <SID>CR()
" List mappings
nnoremap <buffer> o :<C-U>call vimwiki#lst#kbd_oO('o')<CR>
nnoremap <buffer> O :<C-U>call vimwiki#lst#kbd_oO('O')<CR>
" Table mappings
if g:vimwiki_table_auto_fmt
inoremap <expr> <buffer> <Tab> vimwiki#tbl#kbd_tab()
inoremap <expr> <buffer> <S-Tab> vimwiki#tbl#kbd_shift_tab()
endif
nnoremap <buffer> gqq :VimwikiTableAlignQ<CR>
nnoremap <buffer> gww :VimwikiTableAlignW<CR>
if !hasmapto('<Plug>VimwikiTableMoveColumnLeft')
nmap <silent><buffer> <A-Left> <Plug>VimwikiTableMoveColumnLeft
endif
nnoremap <silent><script><buffer>
\ <Plug>VimwikiTableMoveColumnLeft :VimwikiTableMoveColumnLeft<CR>
if !hasmapto('<Plug>VimwikiTableMoveColumnRight')
nmap <silent><buffer> <A-Right> <Plug>VimwikiTableMoveColumnRight
endif
nnoremap <silent><script><buffer>
\ <Plug>VimwikiTableMoveColumnRight :VimwikiTableMoveColumnRight<CR>
" Misc mappings
inoremap <buffer> <S-CR> <br /><CR>
" Text objects {{{
onoremap <silent><buffer> ah :<C-U>call vimwiki#base#TO_header(0, 0)<CR>
vnoremap <silent><buffer> ah :<C-U>call vimwiki#base#TO_header(0, 1)<CR>
onoremap <silent><buffer> ih :<C-U>call vimwiki#base#TO_header(1, 0)<CR>
vnoremap <silent><buffer> ih :<C-U>call vimwiki#base#TO_header(1, 1)<CR>
onoremap <silent><buffer> a\ :<C-U>call vimwiki#base#TO_table_cell(0, 0)<CR>
vnoremap <silent><buffer> a\ :<C-U>call vimwiki#base#TO_table_cell(0, 1)<CR>
onoremap <silent><buffer> i\ :<C-U>call vimwiki#base#TO_table_cell(1, 0)<CR>
vnoremap <silent><buffer> i\ :<C-U>call vimwiki#base#TO_table_cell(1, 1)<CR>
onoremap <silent><buffer> ac :<C-U>call vimwiki#base#TO_table_col(0, 0)<CR>
vnoremap <silent><buffer> ac :<C-U>call vimwiki#base#TO_table_col(0, 1)<CR>
onoremap <silent><buffer> ic :<C-U>call vimwiki#base#TO_table_col(1, 0)<CR>
vnoremap <silent><buffer> ic :<C-U>call vimwiki#base#TO_table_col(1, 1)<CR>
nnoremap <silent><buffer> = :call vimwiki#base#AddHeaderLevel()<CR>
nnoremap <silent><buffer> - :call vimwiki#base#RemoveHeaderLevel()<CR>
" }}}
" KEYBINDINGS }}}
" AUTOCOMMANDS {{{
if VimwikiGet('auto_export')
" Automatically generate HTML on page write.
augroup vimwiki
au BufWritePost <buffer> Vimwiki2HTML
augroup END
endif
" AUTOCOMMANDS }}}