diff .vim/ftplugin/python_fn.vim @ 0:c30d68fbd368

Initial import from svn.
author Augie Fackler <durin42@gmail.com>
date Wed, 26 Nov 2008 10:56:09 -0600
parents
children
line wrap: on
line diff
new file mode 100644
--- /dev/null
+++ b/.vim/ftplugin/python_fn.vim
@@ -0,0 +1,446 @@
+" -*- vim -*-
+" FILE: python.vim
+" LAST MODIFICATION: 2008-05-17 6:29pm
+" (C) Copyright 2001-2005 Mikael Berthe <bmikael@lists.lilotux.net>
+" Maintained by Jon Franklin <jvfranklin@gmail.com>
+" Version: 1.12
+
+" 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>
+
+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:
+