Permalink
Browse files

Added :PyRef command, converted to autoload script

The plug-in now defines the :PyRef command in Python buffers. Also most
of the code was moved to an auto-load that won't be loaded until the
Python file type is used. Finally all sanity checking is now done at
runtime.
  • Loading branch information...
1 parent b059112 commit a37a24fe6630f40d7145a62e8d86c6ea07a5e5d5 @xolox committed Sep 18, 2010
Showing with 151 additions and 151 deletions.
  1. +3 −3 README.md
  2. +145 −0 autoload.vim
  3. +3 −148 pyref.vim
View
@@ -1,14 +1,14 @@
# Context-sensitive documentation <br> for Python source code in Vim
-The `pyref.vim` script is a plug-in for the [Vim text editor](http://www.vim.org/) that maps the `<F1>` key in [Python](http://python.org/) buffers to search through the [Python language reference](http://docs.python.org/reference/index.html) and [library reference](http://docs.python.org/library/index.html) documentation for the keyword or identifier at the current cursor position and open the first match in your web browser. When no GUI is available a command-line web browser like `lynx` or `w3m` will be used, otherwise the plug-in prefers a graphical web browser like Mozilla Firefox or Google Chrome.
+The `pyref.vim` script is a plug-in for the [Vim text editor](http://www.vim.org/) that looks up keywords and identifiers in the [Python language reference](http://docs.python.org/reference/index.html) and [library reference](http://docs.python.org/library/index.html) documentation using your web browser. The `:PyRef` command looks up the identifier given as an argument while the `<F1>` mapping looks up the item at the text cursor. Both are only made available inside Python buffers.
## How does it work?
-The search works by scanning through a special index file with keyword, URL pairs separated by tabs and delimited by newlines. The index file is included in the ZIP archive linked to below but you can also create it yourself using the Python script [spider.py](http://github.com/xolox/vim-pyref/blob/master/spider.py).
+The search works by scanning through a special index file with keyword, URL pairs separated by tabs and delimited by newlines. The index file is included in the ZIP archive linked below but you can also create it yourself using the Python script [spider.py](http://github.com/xolox/vim-pyref/blob/master/spider.py).
## Install & usage
-Unzip the most recent [ZIP archive](http://peterodding.com/code/vim/downloads/pyref) file inside your Vim profile directory (usually this is `~/.vim` on UNIX and `%USERPROFILE%\vimfiles` on Windows), restart Vim and execute the command `:helptags ~/.vim/doc` (use `:helptags ~\vimfiles\doc` instead on Windows). Now try it out: Open a Python script and press the `<F1>` key.
+Unzip the most recent [ZIP archive](http://peterodding.com/code/vim/downloads/pyref) file inside your Vim profile directory (usually this is `~/.vim` on UNIX and `%USERPROFILE%\vimfiles` on Windows), restart Vim and execute the command `:helptags ~/.vim/doc` (use `:helptags ~\vimfiles\doc` instead on Windows). Now try it out: Open a Python script and press the `<F1>` key on something interesting.
The following paragraphs explain the available options:
View
@@ -0,0 +1,145 @@
+" Vim auto-load script
+" Author: Peter Odding <peter@peterodding.com>
+" Last Change: September 18, 2010
+" URL: http://peterodding.com/code/vim/pyref/
+
+let s:script = expand('<sfile>:p:~')
+
+function! xolox#pyref#enable() " {{{1
+ command! -buffer -nargs=? PyRef call xolox#pyref#lookup(<q-args>)
+ let command = '%s <silent> <buffer> %s %s:call xolox#pyref#at_cursor()<CR>'
+ let mapping = exists('g:pyref_mapping') ? g:pyref_mapping : '<F1>'
+ execute printf(command, 'nmap', mapping, '')
+ if mapping =~ '^<[^>]\+>'
+ execute printf(command, 'imap', mapping, '<C-O>')
+ endif
+endfunction
+
+function! xolox#pyref#at_cursor() " {{{1
+ try
+ let isk_save = &isk
+ let &isk = '@,48-57,_,192-255,.'
+ let ident = expand('<cword>')
+ finally
+ let &isk = isk_save
+ endtry
+ call xolox#pyref#lookup(ident)
+endfunction
+
+function! xolox#pyref#lookup(identifier) " {{{1
+
+ let mirror = s:find_mirror()
+ let ident = xolox#trim(a:identifier)
+
+ " Do something useful when there's nothing at the current position.
+ if ident == ''
+ call xolox#open#url(mirror . '/contents.html')
+ return
+ endif
+
+ " Escape any dots in the expression so it can be used as a pattern.
+ let pattern = substitute(ident, '\.', '\\.', 'g')
+
+ " Search for an exact match of a module name or identifier in the index.
+ let indexfile = s:find_index()
+ try
+ let lines = readfile(indexfile)
+ catch
+ let lines = []
+ call xolox#warning("%s: Failed to read index file! (%s)", s:script, indexfile)
+ endtry
+ if s:try_lookup(lines, mirror, '^\C\(module-\|exceptions\.\)\?' . pattern . '\t')
+ return
+ endif
+
+ " Search for a substring match on word boundaries.
+ if s:try_lookup(lines, mirror, '\C\<' . pattern . '\>.*\t')
+ return
+ endif
+
+ " Try to match a method name of one of the standard Python types: strings,
+ " lists, dictionaries and files (not exactly ideal but better than nothing).
+ for [url, method_pattern] in s:object_methods
+ let method = matchstr(ident, method_pattern)
+ if method != ''
+ if url =~ '%s'
+ let url = printf(url, method)
+ endif
+ call xolox#open#url(mirror . '/' . url)
+ return
+ endif
+ endfor
+
+ " Search for a substring match in the index.
+ if s:try_lookup(lines, mirror, '\C' . pattern . '.*\t')
+ return
+ endif
+
+ " Split the expression on all dots and search for a progressively smaller
+ " suffix to resolve object attributes like "self.parser.add_option" to
+ " global identifiers like "optparse.OptionParser.add_option". This relies
+ " on the uniqueness of the method names in the standard library.
+ let parts = split(ident, '\.')
+ while len(parts) > 1
+ call remove(parts, 0)
+ let pattern = '\C\<' . join(parts, '\.') . '$'
+ if s:try_lookup(lines, mirror, pattern)
+ return
+ endif
+ endwhile
+
+ " As a last resort, search all of http://docs.python.org/ using Google.
+ call xolox#open#url('http://google.com/search?btnI&q=inurl:docs.python.org/+' . ident)
+
+endfunction
+
+" This list of lists contains [url_format, method_pattern] pairs that are used
+" to recognize calls to methods of objects that are one of Python's standard
+" types: strings, lists, dictionaries and file handles.
+let s:object_methods = [
+ \ ['library/stdtypes.html#str.%s', '\C\.\@<=\(capitalize\|center\|count\|decode\|encode\|endswith\|expandtabs\|find\|format\|index\|isalnum\|isalpha\|isdigit\|islower\|isspace\|istitle\|isupper\|join\|ljust\|lower\|lstrip\|partition\|replace\|rfind\|rindex\|rjust\|rpartition\|rsplit\|rstrip\|split\|splitlines\|startswith\|strip\|swapcase\|title\|translate\|upper\|zfill\)$'],
+ \ ['tutorial/datastructures.html#more-on-lists', '\C\.\@<=\(append\|count\|extend\|index\|insert\|pop\|remove\|reverse\|sort\)$'],
+ \ ['library/stdtypes.html#dict.%s', '\C\.\@<=\(clear\|copy\|fromkeys\|get\|has_key\|items\|iteritems\|iterkeys\|itervalues\|keys\|pop\|popitem\|setdefault\|update\|values\)$'],
+ \ ['library/stdtypes.html#file.%s', '\C\.\@<=\(close\|closed\|encoding\|errors\|fileno\|flush\|isatty\|mode\|name\|newlines\|next\|read\|readinto\|readline\|readlines\|seek\|softspace\|tell\|truncate\|write\|writelines\|xreadlines\)$']]
+
+function! s:try_lookup(lines, mirror, pattern) " {{{1
+ call xolox#debug("%s: Trying to match pattern %s", s:script, a:pattern)
+ let index = match(a:lines, a:pattern)
+ if index >= 0
+ let url = split(a:lines[index], '\t')[1]
+ call xolox#open#url(a:mirror . '/' . url)
+ return 1
+ endif
+endfunction
+
+function! s:find_mirror() " {{{1
+ if exists('g:pyref_mirror')
+ return g:pyref_mirror
+ else
+ let local_mirror = '/usr/share/doc/python2.6/html'
+ if isdirectory(local_mirror)
+ return 'file://' . local_mirror
+ else
+ return 'http://docs.python.org'
+ endif
+ endif
+endfunction
+
+function! s:find_index() " {{{1
+ if exists('g:pyref_index')
+ let index = g:pyref_index
+ elseif xolox#is_windows()
+ let index = '~/vimfiles/misc/pyref_index'
+ else
+ let index = '~/.vim/misc/pyref_index'
+ endif
+ let abspath = fnamemodify(index, ':p')
+ if !filereadable(abspath)
+ let msg = "%s: The index file doesn't exist or isn't readable! (%s)"
+ call xolox#warning(msg, s:script, index)
+ return
+ endif
+ return abspath
+endfunction
+
+" vim: ts=2 sw=2 et nowrap
View
151 pyref.vim
@@ -11,159 +11,14 @@
" Don't source the plug-in when its already been loaded or &compatible is set.
if &cp || exists('g:loaded_pyref')
finish
-endif
-
-" Configuration defaults. {{{1
-
-" Use a script-local function to define the configuration defaults so that we
-" don't pollute Vim's global scope with temporary variables.
-
-function! s:CheckOptions()
- if !exists('g:pyref_mapping')
- let g:pyref_mapping = '<F1>'
- endif
- if !exists('g:pyref_mirror')
- let local_mirror = '/usr/share/doc/python2.6/html'
- if isdirectory(local_mirror)
- let g:pyref_mirror = 'file://' . local_mirror
- else
- let g:pyref_mirror = 'http://docs.python.org'
- endif
- endif
- if !exists('g:pyref_index')
- if has('win32') || has('win64')
- let g:pyref_index = '~/vimfiles/misc/pyref_index'
- else
- let g:pyref_index = '~/.vim/misc/pyref_index'
- endif
- endif
- if !filereadable(fnamemodify(g:pyref_index, ':p'))
- let msg = "pyref.vim: The index file doesn't exist or isn't readable! (%s)"
- echoerr printf(msg, g:pyref_index)
- return 0 " Initialization failed.
- endif
- return 1 " Initialization successful.
-endfunction
-
-if s:CheckOptions()
- " Don't reload the plug-in once its been successfully initialized.
- let g:loaded_pyref = 1
else
- " Don't finish sourcing the script when there's no point.
- finish
+ let g:loaded_pyref = 1
endif
-" Automatic command to define key-mapping. {{{1
+" Automatic command to enable plug-in for Python buffers only.
augroup PluginPyRef
- autocmd! FileType python call s:DefineMappings()
+ autocmd! FileType python call xolox#pyref#enable()
augroup END
-function! s:DefineMappings() " {{{1
- let command = '%s <silent> <buffer> %s %s:call <Sid>PyRef()<CR>'
- " Always define the normal mode mapping.
- execute printf(command, 'nmap', g:pyref_mapping, '')
- " Don't create the insert mode mapping when "g:pyref_mapping" has been
- " changed to something like K because it'll conflict with regular input.
- if g:pyref_mapping =~ '^<[^>]\+>'
- execute printf(command, 'imap', g:pyref_mapping, '<C-O>')
- endif
-endfunction
-
-function! s:PyRef() " {{{1
-
- " Get the identifier under the cursor including any dots to match
- " identifiers like `os.path.join' instead of single words like `join'.
- try
- let isk_save = &isk
- let &isk = '@,48-57,_,192-255,.'
- let ident = expand('<cword>')
- finally
- let &isk = isk_save
- endtry
-
- " Do something useful when there's nothing at the current position.
- if ident == ''
- call xolox#open#url(g:pyref_mirror . '/contents.html')
- return
- endif
-
- " Escape any dots in the expression so it can be used as a pattern.
- let pattern = substitute(ident, '\.', '\\.', 'g')
-
- " Search for an exact match of a module name or identifier in the index.
- let indexfile = fnamemodify(g:pyref_index, ':p')
- try
- let lines = readfile(indexfile)
- catch
- let lines = []
- echoerr "pyref.vim: Failed to read index file! (" . indexfile . ")"
- endtry
- if s:JumpToEntry(lines, '^\C\(module-\|exceptions\.\)\?' . pattern . '\t')
- return
- endif
-
- " Search for a substring match on word boundaries.
- if s:JumpToEntry(lines, '\C\<' . pattern . '\>.*\t')
- return
- endif
-
- " Try to match a method name of one of the standard Python types: strings,
- " lists, dictionaries and files (not exactly ideal but better than nothing).
- for [url, method_pattern] in s:object_methods
- let method = matchstr(ident, method_pattern)
- if method != ''
- if url =~ '%s'
- let url = printf(url, method)
- endif
- call xolox#open#url(g:pyref_mirror . '/' . url)
- return
- endif
- endfor
-
- " Search for a substring match in the index.
- if s:JumpToEntry(lines, '\C' . pattern . '.*\t')
- return
- endif
-
- " Split the expression on all dots and search for a progressively smaller
- " suffix to resolve object attributes like "self.parser.add_option" to
- " global identifiers like "optparse.OptionParser.add_option". This relies
- " on the uniqueness of the method names in the standard library.
- let parts = split(ident, '\.')
- while len(parts) > 1
- call remove(parts, 0)
- let pattern = '\C\<' . join(parts, '\.') . '$'
- if s:JumpToEntry(lines, pattern)
- return
- endif
- endwhile
-
- " As a last resort, search all of http://docs.python.org/ using Google.
- call xolox#open#url('http://google.com/search?btnI&q=inurl:docs.python.org/+' . ident)
-
-endfunction
-
-" This list of lists contains [url_format, method_pattern] pairs that are used
-" to recognize calls to methods of objects that are one of Python's standard
-" types: strings, lists, dictionaries and file handles.
-let s:object_methods = [
- \ ['library/stdtypes.html#str.%s', '\C\.\@<=\(capitalize\|center\|count\|decode\|encode\|endswith\|expandtabs\|find\|format\|index\|isalnum\|isalpha\|isdigit\|islower\|isspace\|istitle\|isupper\|join\|ljust\|lower\|lstrip\|partition\|replace\|rfind\|rindex\|rjust\|rpartition\|rsplit\|rstrip\|split\|splitlines\|startswith\|strip\|swapcase\|title\|translate\|upper\|zfill\)$'],
- \ ['tutorial/datastructures.html#more-on-lists', '\C\.\@<=\(append\|count\|extend\|index\|insert\|pop\|remove\|reverse\|sort\)$'],
- \ ['library/stdtypes.html#dict.%s', '\C\.\@<=\(clear\|copy\|fromkeys\|get\|has_key\|items\|iteritems\|iterkeys\|itervalues\|keys\|pop\|popitem\|setdefault\|update\|values\)$'],
- \ ['library/stdtypes.html#file.%s', '\C\.\@<=\(close\|closed\|encoding\|errors\|fileno\|flush\|isatty\|mode\|name\|newlines\|next\|read\|readinto\|readline\|readlines\|seek\|softspace\|tell\|truncate\|write\|writelines\|xreadlines\)$']]
-
-function! s:JumpToEntry(lines, pattern) " {{{1
- if &verbose
- echomsg "pyref.vim: Trying to match" string(a:pattern)
- endif
- let index = match(a:lines, a:pattern)
- if index >= 0
- let url = split(a:lines[index], '\t')[1]
- call xolox#open#url(g:pyref_mirror . '/' . url)
- return 1
- endif
- return 0
-endfunction
-
" vim: ts=2 sw=2 et nowrap

0 comments on commit a37a24f

Please sign in to comment.