" -*- vim -*- " FILE: python.vim " LAST MODIFICATION: 2001/09/05 " (C) Copyright 2001 Mikael Berthe " Version: 1.4 " USAGE: " " Juste source this script when editing Python files. " Example: au FileType python source ~me/.vim/scripts/python.vim " 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 (>= 600) " " Shortcuts: " [[ -- Jump to beginning of block " ]] -- Jump to end of block " ]v -- Select (Visual Line Mode) block " ]< -- Shift block to left " ]> -- Shift block to right " ]c -- Select current/previous class " ]f -- Select current/previous function " ] -- Jump to previous line with the same/lower indentation " ] -- Jump to next line with the same/lower indentation map [[ :PBoB vmap [[ :PBoBm'gv`` map ]] :PEoB vmap ]] :PEoBm'gv`` map ]v [[V]] map ]< [[V]]< vmap ]< < map ]> [[V]]> vmap ]> > map ]c :call PythonSelectObject("class") map ]f :call PythonSelectObject("function") map ] :call PythonNextLine(-1) map ] :call PythonNextLine(1) " You may prefer use and ... :-) " Menu entries nmenu &Python.Update\ IM-Python\ Menu \:call UpdateMenu() nmenu &Python.-Sep1- : nmenu &Python.Beginning\ of\ Block[[ \[[ nmenu &Python.End\ of\ Block]] \]] nmenu &Python.-Sep2- : nmenu &Python.Shift\ Block\ Left]< \]< vmenu &Python.Shift\ Block\ Left]< \]< nmenu &Python.Shift\ Block\ Right]> \]> vmenu &Python.Shift\ Block\ Right]> \]> nmenu &Python.-Sep3- : vmenu &Python.Comment\ Selection \:call PythonCommentSelection() nmenu &Python.Comment\ Selection \:call PythonCommentSelection() vmenu &Python.Uncomment\ Selection \:call PythonUncommentSelection() nmenu &Python.Uncomment\ Selection \:call PythonUncommentSelection() nmenu &Python.-Sep4- : nmenu &Python.Previous\ Class \:call PythonDec("class", -1) nmenu &Python.Next\ Class \:call PythonDec("class", 1) nmenu &Python.Previous\ Function \:call PythonDec("function", -1) nmenu &Python.Next\ Function \:call PythonDec("function", 1) nmenu &Python.-Sep5- : nmenu &Python.Select\ Block]v \]v nmenu &Python.Select\ Function]f \]f nmenu &Python.Select\ Class]c \]c nmenu &Python.-Sep6- : nmenu &Python.Previous\ Line\ wrt\ indent] \] nmenu &Python.Next\ Line\ wrt\ indent] \] :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 j" 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 normal j 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 " update the IM-Python menu, that holds Classes and Functions function! UpdateMenu() let cline=line('.') call MakeClassStructure () call MakeFuncStructure () execute "normal ".cline."Gzz" endfunction " make a menu that holds all of the classes function! MakeClassStructure () norm mpgg0 while line(".") <= line("$") if match ( getline("."), '^\s*class\s\+' ) != -1 norm ^w"nyw let name=@n exe 'menu IM-Python.classes.'.name.' '.line(".").'gg' endif if line(".") == line("$") return endif norm j endwhile norm 'p endfunction " make a menu that holds all of the function definitions function! MakeFuncStructure () norm mpgg0 while line(".") <= line("$") if match ( getline("."), '^\s*def\s\+' ) != -1 norm ^w"nyw let name=@n exe 'menu IM-Python.functions.'.name.' '.line(".").'gg' endif if line(".") == line("$") return endif norm j endwhile norm 'p endfunction " vim:set et sts=2 sw=2: