Mercurial > dotfiles
comparison .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 |
comparison
equal
deleted
inserted
replaced
| -1:000000000000 | 0:c30d68fbd368 |
|---|---|
| 1 " -*- vim -*- | |
| 2 " FILE: python.vim | |
| 3 " LAST MODIFICATION: 2008-05-17 6:29pm | |
| 4 " (C) Copyright 2001-2005 Mikael Berthe <bmikael@lists.lilotux.net> | |
| 5 " Maintained by Jon Franklin <jvfranklin@gmail.com> | |
| 6 " Version: 1.12 | |
| 7 | |
| 8 " USAGE: | |
| 9 " | |
| 10 " Save this file to $VIMFILES/ftplugin/python.vim. You can have multiple | |
| 11 " python ftplugins by creating $VIMFILES/ftplugin/python and saving your | |
| 12 " ftplugins in that directory. If saving this to the global ftplugin | |
| 13 " directory, this is the recommended method, since vim ships with an | |
| 14 " ftplugin/python.vim file already. | |
| 15 " You can set the global variable "g:py_select_leading_comments" to 0 | |
| 16 " if you don't want to select comments preceding a declaration (these | |
| 17 " are usually the description of the function/class). | |
| 18 " You can set the global variable "g:py_select_trailing_comments" to 0 | |
| 19 " if you don't want to select comments at the end of a function/class. | |
| 20 " If these variables are not defined, both leading and trailing comments | |
| 21 " are selected. | |
| 22 " Example: (in your .vimrc) "let g:py_select_leading_comments = 0" | |
| 23 " You may want to take a look at the 'shiftwidth' option for the | |
| 24 " shift commands... | |
| 25 " | |
| 26 " REQUIREMENTS: | |
| 27 " vim (>= 7) | |
| 28 " | |
| 29 " Shortcuts: | |
| 30 " ]t -- Jump to beginning of block | |
| 31 " ]e -- Jump to end of block | |
| 32 " ]v -- Select (Visual Line Mode) block | |
| 33 " ]< -- Shift block to left | |
| 34 " ]> -- Shift block to right | |
| 35 " ]# -- Comment selection | |
| 36 " ]u -- Uncomment selection | |
| 37 " ]c -- Select current/previous class | |
| 38 " ]d -- Select current/previous function | |
| 39 " ]<up> -- Jump to previous line with the same/lower indentation | |
| 40 " ]<down> -- Jump to next line with the same/lower indentation | |
| 41 | |
| 42 " Only do this when not done yet for this buffer | |
| 43 if exists("b:loaded_py_ftplugin") | |
| 44 finish | |
| 45 endif | |
| 46 let b:loaded_py_ftplugin = 1 | |
| 47 | |
| 48 map ]t :PBoB<CR> | |
| 49 vmap ]t :<C-U>PBOB<CR>m'gv`` | |
| 50 map ]e :PEoB<CR> | |
| 51 vmap ]e :<C-U>PEoB<CR>m'gv`` | |
| 52 | |
| 53 map ]v ]tV]e | |
| 54 map ]< ]tV]e< | |
| 55 vmap ]< < | |
| 56 map ]> ]tV]e> | |
| 57 vmap ]> > | |
| 58 | |
| 59 map ]# :call PythonCommentSelection()<CR> | |
| 60 vmap ]# :call PythonCommentSelection()<CR> | |
| 61 map ]u :call PythonUncommentSelection()<CR> | |
| 62 vmap ]u :call PythonUncommentSelection()<CR> | |
| 63 | |
| 64 map ]c :call PythonSelectObject("class")<CR> | |
| 65 map ]d :call PythonSelectObject("function")<CR> | |
| 66 | |
| 67 map ]<up> :call PythonNextLine(-1)<CR> | |
| 68 map ]<down> :call PythonNextLine(1)<CR> | |
| 69 " You may prefer use <s-up> and <s-down>... :-) | |
| 70 | |
| 71 " jump to previous class | |
| 72 map ]J :call PythonDec("class", -1)<CR> | |
| 73 vmap ]J :call PythonDec("class", -1)<CR> | |
| 74 | |
| 75 " jump to next class | |
| 76 map ]j :call PythonDec("class", 1)<CR> | |
| 77 vmap ]j :call PythonDec("class", 1)<CR> | |
| 78 | |
| 79 " jump to previous function | |
| 80 map ]F :call PythonDec("function", -1)<CR> | |
| 81 vmap ]F :call PythonDec("function", -1)<CR> | |
| 82 | |
| 83 " jump to next function | |
| 84 map ]f :call PythonDec("function", 1)<CR> | |
| 85 vmap ]f :call PythonDec("function", 1)<CR> | |
| 86 | |
| 87 | |
| 88 | |
| 89 " Menu entries | |
| 90 nmenu <silent> &Python.Update\ IM-Python\ Menu | |
| 91 \:call UpdateMenu()<CR> | |
| 92 nmenu &Python.-Sep1- : | |
| 93 nmenu <silent> &Python.Beginning\ of\ Block<Tab>[t | |
| 94 \]t | |
| 95 nmenu <silent> &Python.End\ of\ Block<Tab>]e | |
| 96 \]e | |
| 97 nmenu &Python.-Sep2- : | |
| 98 nmenu <silent> &Python.Shift\ Block\ Left<Tab>]< | |
| 99 \]< | |
| 100 vmenu <silent> &Python.Shift\ Block\ Left<Tab>]< | |
| 101 \]< | |
| 102 nmenu <silent> &Python.Shift\ Block\ Right<Tab>]> | |
| 103 \]> | |
| 104 vmenu <silent> &Python.Shift\ Block\ Right<Tab>]> | |
| 105 \]> | |
| 106 nmenu &Python.-Sep3- : | |
| 107 vmenu <silent> &Python.Comment\ Selection<Tab>]# | |
| 108 \]# | |
| 109 nmenu <silent> &Python.Comment\ Selection<Tab>]# | |
| 110 \]# | |
| 111 vmenu <silent> &Python.Uncomment\ Selection<Tab>]u | |
| 112 \]u | |
| 113 nmenu <silent> &Python.Uncomment\ Selection<Tab>]u | |
| 114 \]u | |
| 115 nmenu &Python.-Sep4- : | |
| 116 nmenu <silent> &Python.Previous\ Class<Tab>]J | |
| 117 \]J | |
| 118 nmenu <silent> &Python.Next\ Class<Tab>]j | |
| 119 \]j | |
| 120 nmenu <silent> &Python.Previous\ Function<Tab>]F | |
| 121 \]F | |
| 122 nmenu <silent> &Python.Next\ Function<Tab>]f | |
| 123 \]f | |
| 124 nmenu &Python.-Sep5- : | |
| 125 nmenu <silent> &Python.Select\ Block<Tab>]v | |
| 126 \]v | |
| 127 nmenu <silent> &Python.Select\ Function<Tab>]d | |
| 128 \]d | |
| 129 nmenu <silent> &Python.Select\ Class<Tab>]c | |
| 130 \]c | |
| 131 nmenu &Python.-Sep6- : | |
| 132 nmenu <silent> &Python.Previous\ Line\ wrt\ indent<Tab>]<up> | |
| 133 \]<up> | |
| 134 nmenu <silent> &Python.Next\ Line\ wrt\ indent<Tab>]<down> | |
| 135 \]<down> | |
| 136 | |
| 137 :com! PBoB execute "normal ".PythonBoB(line('.'), -1, 1)."G" | |
| 138 :com! PEoB execute "normal ".PythonBoB(line('.'), 1, 1)."G" | |
| 139 :com! UpdateMenu call UpdateMenu() | |
| 140 | |
| 141 | |
| 142 " Go to a block boundary (-1: previous, 1: next) | |
| 143 " If force_sel_comments is true, 'g:py_select_trailing_comments' is ignored | |
| 144 function! PythonBoB(line, direction, force_sel_comments) | |
| 145 let ln = a:line | |
| 146 let ind = indent(ln) | |
| 147 let mark = ln | |
| 148 let indent_valid = strlen(getline(ln)) | |
| 149 let ln = ln + a:direction | |
| 150 if (a:direction == 1) && (!a:force_sel_comments) && | |
| 151 \ exists("g:py_select_trailing_comments") && | |
| 152 \ (!g:py_select_trailing_comments) | |
| 153 let sel_comments = 0 | |
| 154 else | |
| 155 let sel_comments = 1 | |
| 156 endif | |
| 157 | |
| 158 while((ln >= 1) && (ln <= line('$'))) | |
| 159 if (sel_comments) || (match(getline(ln), "^\\s*#") == -1) | |
| 160 if (!indent_valid) | |
| 161 let indent_valid = strlen(getline(ln)) | |
| 162 let ind = indent(ln) | |
| 163 let mark = ln | |
| 164 else | |
| 165 if (strlen(getline(ln))) | |
| 166 if (indent(ln) < ind) | |
| 167 break | |
| 168 endif | |
| 169 let mark = ln | |
| 170 endif | |
| 171 endif | |
| 172 endif | |
| 173 let ln = ln + a:direction | |
| 174 endwhile | |
| 175 | |
| 176 return mark | |
| 177 endfunction | |
| 178 | |
| 179 | |
| 180 " Go to previous (-1) or next (1) class/function definition | |
| 181 function! PythonDec(obj, direction) | |
| 182 if (a:obj == "class") | |
| 183 let objregexp = "^\\s*class\\s\\+[a-zA-Z0-9_]\\+" | |
| 184 \ . "\\s*\\((\\([a-zA-Z0-9_,. \\t\\n]\\)*)\\)\\=\\s*:" | |
| 185 else | |
| 186 let objregexp = "^\\s*def\\s\\+[a-zA-Z0-9_]\\+\\s*(\\_[^:#]*)\\s*:" | |
| 187 endif | |
| 188 let flag = "W" | |
| 189 if (a:direction == -1) | |
| 190 let flag = flag."b" | |
| 191 endif | |
| 192 let res = search(objregexp, flag) | |
| 193 endfunction | |
| 194 | |
| 195 | |
| 196 " Comment out selected lines | |
| 197 " commentString is inserted in non-empty lines, and should be aligned with | |
| 198 " the block | |
| 199 function! PythonCommentSelection() range | |
| 200 let commentString = "#" | |
| 201 let cl = a:firstline | |
| 202 let ind = 1000 " I hope nobody use so long lines! :) | |
| 203 | |
| 204 " Look for smallest indent | |
| 205 while (cl <= a:lastline) | |
| 206 if strlen(getline(cl)) | |
| 207 let cind = indent(cl) | |
| 208 let ind = ((ind < cind) ? ind : cind) | |
| 209 endif | |
| 210 let cl = cl + 1 | |
| 211 endwhile | |
| 212 if (ind == 1000) | |
| 213 let ind = 1 | |
| 214 else | |
| 215 let ind = ind + 1 | |
| 216 endif | |
| 217 | |
| 218 let cl = a:firstline | |
| 219 execute ":".cl | |
| 220 " Insert commentString in each non-empty line, in column ind | |
| 221 while (cl <= a:lastline) | |
| 222 if strlen(getline(cl)) | |
| 223 execute "normal ".ind."|i".commentString | |
| 224 endif | |
| 225 execute "normal \<Down>" | |
| 226 let cl = cl + 1 | |
| 227 endwhile | |
| 228 endfunction | |
| 229 | |
| 230 " Uncomment selected lines | |
| 231 function! PythonUncommentSelection() range | |
| 232 " commentString could be different than the one from CommentSelection() | |
| 233 " For example, this could be "# \\=" | |
| 234 let commentString = "#" | |
| 235 let cl = a:firstline | |
| 236 while (cl <= a:lastline) | |
| 237 let ul = substitute(getline(cl), | |
| 238 \"\\(\\s*\\)".commentString."\\(.*\\)$", "\\1\\2", "") | |
| 239 call setline(cl, ul) | |
| 240 let cl = cl + 1 | |
| 241 endwhile | |
| 242 endfunction | |
| 243 | |
| 244 | |
| 245 " Select an object ("class"/"function") | |
| 246 function! PythonSelectObject(obj) | |
| 247 " Go to the object declaration | |
| 248 normal $ | |
| 249 call PythonDec(a:obj, -1) | |
| 250 let beg = line('.') | |
| 251 | |
| 252 if !exists("g:py_select_leading_comments") || (g:py_select_leading_comments) | |
| 253 let decind = indent(beg) | |
| 254 let cl = beg | |
| 255 while (cl>1) | |
| 256 let cl = cl - 1 | |
| 257 if (indent(cl) == decind) && (getline(cl)[decind] == "#") | |
| 258 let beg = cl | |
| 259 else | |
| 260 break | |
| 261 endif | |
| 262 endwhile | |
| 263 endif | |
| 264 | |
| 265 if (a:obj == "class") | |
| 266 let eod = "\\(^\\s*class\\s\\+[a-zA-Z0-9_]\\+\\s*" | |
| 267 \ . "\\((\\([a-zA-Z0-9_,. \\t\\n]\\)*)\\)\\=\\s*\\)\\@<=:" | |
| 268 else | |
| 269 let eod = "\\(^\\s*def\\s\\+[a-zA-Z0-9_]\\+\\s*(\\_[^:#]*)\\s*\\)\\@<=:" | |
| 270 endif | |
| 271 " Look for the end of the declaration (not always the same line!) | |
| 272 call search(eod, "") | |
| 273 | |
| 274 " Is it a one-line definition? | |
| 275 if match(getline('.'), "^\\s*\\(#.*\\)\\=$", col('.')) == -1 | |
| 276 let cl = line('.') | |
| 277 execute ":".beg | |
| 278 execute "normal V".cl."G" | |
| 279 else | |
| 280 " Select the whole block | |
| 281 execute "normal \<Down>" | |
| 282 let cl = line('.') | |
| 283 execute ":".beg | |
| 284 execute "normal V".PythonBoB(cl, 1, 0)."G" | |
| 285 endif | |
| 286 endfunction | |
| 287 | |
| 288 | |
| 289 " Jump to the next line with the same (or lower) indentation | |
| 290 " Useful for moving between "if" and "else", for example. | |
| 291 function! PythonNextLine(direction) | |
| 292 let ln = line('.') | |
| 293 let ind = indent(ln) | |
| 294 let indent_valid = strlen(getline(ln)) | |
| 295 let ln = ln + a:direction | |
| 296 | |
| 297 while((ln >= 1) && (ln <= line('$'))) | |
| 298 if (!indent_valid) && strlen(getline(ln)) | |
| 299 break | |
| 300 else | |
| 301 if (strlen(getline(ln))) | |
| 302 if (indent(ln) <= ind) | |
| 303 break | |
| 304 endif | |
| 305 endif | |
| 306 endif | |
| 307 let ln = ln + a:direction | |
| 308 endwhile | |
| 309 | |
| 310 execute "normal ".ln."G" | |
| 311 endfunction | |
| 312 | |
| 313 function! UpdateMenu() | |
| 314 " delete menu if it already exists, then rebuild it. | |
| 315 " this is necessary in case you've got multiple buffers open | |
| 316 " a future enhancement to this would be to make the menu aware of | |
| 317 " all buffers currently open, and group classes and functions by buffer | |
| 318 if exists("g:menuran") | |
| 319 aunmenu IM-Python | |
| 320 endif | |
| 321 let restore_fe = &foldenable | |
| 322 set nofoldenable | |
| 323 " preserve disposition of window and cursor | |
| 324 let cline=line('.') | |
| 325 let ccol=col('.') - 1 | |
| 326 norm H | |
| 327 let hline=line('.') | |
| 328 " create the menu | |
| 329 call MenuBuilder() | |
| 330 " restore disposition of window and cursor | |
| 331 exe "norm ".hline."Gzt" | |
| 332 let dnscroll=cline-hline | |
| 333 exe "norm ".dnscroll."j".ccol."l" | |
| 334 let &foldenable = restore_fe | |
| 335 endfunction | |
| 336 | |
| 337 function! MenuBuilder() | |
| 338 norm gg0 | |
| 339 let currentclass = -1 | |
| 340 let classlist = [] | |
| 341 let parentclass = "" | |
| 342 while line(".") < line("$") | |
| 343 " search for a class or function | |
| 344 if match ( getline("."), '^\s*class\s\+[_a-zA-Z].*:\|^\s*def\s\+[_a-zA-Z].*:' ) != -1 | |
| 345 norm ^ | |
| 346 let linenum = line('.') | |
| 347 let indentcol = col('.') | |
| 348 norm "nye | |
| 349 let classordef=@n | |
| 350 norm w"nywge | |
| 351 let objname=@n | |
| 352 let parentclass = FindParentClass(classlist, indentcol) | |
| 353 if classordef == "class" | |
| 354 call AddClass(objname, linenum, parentclass) | |
| 355 else " this is a function | |
| 356 call AddFunction(objname, linenum, parentclass) | |
| 357 endif | |
| 358 " We actually created a menu, so lets set the global variable | |
| 359 let g:menuran=1 | |
| 360 call RebuildClassList(classlist, [objname, indentcol], classordef) | |
| 361 endif " line matched | |
| 362 norm j | |
| 363 endwhile | |
| 364 endfunction | |
| 365 | |
| 366 " classlist contains the list of nested classes we are in. | |
| 367 " in most cases it will be empty or contain a single class | |
| 368 " but where a class is nested within another, it will contain 2 or more | |
| 369 " this function adds or removes classes from the list based on indentation | |
| 370 function! RebuildClassList(classlist, newclass, classordef) | |
| 371 let i = len(a:classlist) - 1 | |
| 372 while i > -1 | |
| 373 if a:newclass[1] <= a:classlist[i][1] | |
| 374 call remove(a:classlist, i) | |
| 375 endif | |
| 376 let i = i - 1 | |
| 377 endwhile | |
| 378 if a:classordef == "class" | |
| 379 call add(a:classlist, a:newclass) | |
| 380 endif | |
| 381 endfunction | |
| 382 | |
| 383 " we found a class or function, determine its parent class based on | |
| 384 " indentation and what's contained in classlist | |
| 385 function! FindParentClass(classlist, indentcol) | |
| 386 let i = 0 | |
| 387 let parentclass = "" | |
| 388 while i < len(a:classlist) | |
| 389 if a:indentcol <= a:classlist[i][1] | |
| 390 break | |
| 391 else | |
| 392 if len(parentclass) == 0 | |
| 393 let parentclass = a:classlist[i][0] | |
| 394 else | |
| 395 let parentclass = parentclass.'\.'.a:classlist[i][0] | |
| 396 endif | |
| 397 endif | |
| 398 let i = i + 1 | |
| 399 endwhile | |
| 400 return parentclass | |
| 401 endfunction | |
| 402 | |
| 403 " add a class to the menu | |
| 404 function! AddClass(classname, lineno, parentclass) | |
| 405 if len(a:parentclass) > 0 | |
| 406 let classstring = a:parentclass.'\.'.a:classname | |
| 407 else | |
| 408 let classstring = a:classname | |
| 409 endif | |
| 410 exe 'menu IM-Python.classes.'.classstring.' :call <SID>JumpToAndUnfold('.a:lineno.')<CR>' | |
| 411 endfunction | |
| 412 | |
| 413 " add a function to the menu, grouped by member class | |
| 414 function! AddFunction(functionname, lineno, parentclass) | |
| 415 if len(a:parentclass) > 0 | |
| 416 let funcstring = a:parentclass.'.'.a:functionname | |
| 417 else | |
| 418 let funcstring = a:functionname | |
| 419 endif | |
| 420 exe 'menu IM-Python.functions.'.funcstring.' :call <SID>JumpToAndUnfold('.a:lineno.')<CR>' | |
| 421 endfunction | |
| 422 | |
| 423 | |
| 424 function! s:JumpToAndUnfold(line) | |
| 425 " Go to the right line | |
| 426 execute 'normal '.a:line.'gg' | |
| 427 " Check to see if we are in a fold | |
| 428 let lvl = foldlevel(a:line) | |
| 429 if lvl != 0 | |
| 430 " and if so, then expand the fold out, other wise, ignore this part. | |
| 431 execute 'normal 15zo' | |
| 432 endif | |
| 433 endfunction | |
| 434 | |
| 435 "" This one will work only on vim 6.2 because of the try/catch expressions. | |
| 436 " function! s:JumpToAndUnfoldWithExceptions(line) | |
| 437 " try | |
| 438 " execute 'normal '.a:line.'gg15zo' | |
| 439 " catch /^Vim\((\a\+)\)\=:E490:/ | |
| 440 " " Do nothing, just consume the error | |
| 441 " endtry | |
| 442 "endfunction | |
| 443 | |
| 444 | |
| 445 " vim:set et sts=2 sw=2: | |
| 446 |
