| 
									
										
										
										
											2004-06-13 20:20:40 +00:00
										 |  |  | " Vim indent file | 
					
						
							| 
									
										
										
										
											2005-02-12 14:29:27 +00:00
										 |  |  | " Language:		Python | 
					
						
							|  |  |  | " Maintainer:		Bram Moolenaar <Bram@vim.org> | 
					
						
							| 
									
										
										
										
											2004-06-13 20:20:40 +00:00
										 |  |  | " Original Author:	David Bustos <bustos@caltech.edu> | 
					
						
							| 
									
										
										
										
											2007-05-05 17:54:07 +00:00
										 |  |  | " Last Change:		2006 Jun 18 | 
					
						
							| 
									
										
										
										
											2004-06-13 20:20:40 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | " Only load this indent file when no other was loaded. | 
					
						
							|  |  |  | if exists("b:did_indent") | 
					
						
							|  |  |  |   finish | 
					
						
							|  |  |  | endif | 
					
						
							|  |  |  | let b:did_indent = 1 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | " Some preliminary settings | 
					
						
							|  |  |  | setlocal nolisp		" Make sure lisp indenting doesn't supersede us | 
					
						
							|  |  |  | setlocal autoindent	" indentexpr isn't much help otherwise | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | setlocal indentexpr=GetPythonIndent(v:lnum) | 
					
						
							|  |  |  | setlocal indentkeys+=<:>,=elif,=except | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | " Only define the function once. | 
					
						
							|  |  |  | if exists("*GetPythonIndent") | 
					
						
							|  |  |  |   finish | 
					
						
							|  |  |  | endif | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2005-02-26 23:04:13 +00:00
										 |  |  | " Come here when loading the script the first time. | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2004-06-13 20:20:40 +00:00
										 |  |  | let s:maxoff = 50	" maximum number of lines to look backwards for () | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | function GetPythonIndent(lnum) | 
					
						
							| 
									
										
										
										
											2006-04-30 18:54:39 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2004-06-13 20:20:40 +00:00
										 |  |  |   " If this line is explicitly joined: If the previous line was also joined, | 
					
						
							|  |  |  |   " line it up with that one, otherwise add two 'shiftwidth' | 
					
						
							|  |  |  |   if getline(a:lnum - 1) =~ '\\$' | 
					
						
							|  |  |  |     if a:lnum > 1 && getline(a:lnum - 2) =~ '\\$' | 
					
						
							|  |  |  |       return indent(a:lnum - 1) | 
					
						
							|  |  |  |     endif | 
					
						
							| 
									
										
										
										
											2005-02-26 23:04:13 +00:00
										 |  |  |     return indent(a:lnum - 1) + (exists("g:pyindent_continue") ? eval(g:pyindent_continue) : (&sw * 2)) | 
					
						
							| 
									
										
										
										
											2004-06-13 20:20:40 +00:00
										 |  |  |   endif | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   " If the start of the line is in a string don't change the indent. | 
					
						
							|  |  |  |   if has('syntax_items') | 
					
						
							| 
									
										
										
										
											2004-06-16 11:19:22 +00:00
										 |  |  | 	\ && synIDattr(synID(a:lnum, 1, 1), "name") =~ "String$" | 
					
						
							| 
									
										
										
										
											2004-06-13 20:20:40 +00:00
										 |  |  |     return -1 | 
					
						
							|  |  |  |   endif | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   " Search backwards for the previous non-empty line. | 
					
						
							|  |  |  |   let plnum = prevnonblank(v:lnum - 1) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   if plnum == 0 | 
					
						
							|  |  |  |     " This is the first non-empty line, use zero indent. | 
					
						
							|  |  |  |     return 0 | 
					
						
							|  |  |  |   endif | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   " If the previous line is inside parenthesis, use the indent of the starting | 
					
						
							|  |  |  |   " line. | 
					
						
							|  |  |  |   " Trick: use the non-existing "dummy" variable to break out of the loop when | 
					
						
							|  |  |  |   " going too far back. | 
					
						
							|  |  |  |   call cursor(plnum, 1) | 
					
						
							| 
									
										
										
										
											2006-04-05 20:41:53 +00:00
										 |  |  |   let parlnum = searchpair('(\|{\|\[', '', ')\|}\|\]', 'nbW', | 
					
						
							| 
									
										
										
										
											2004-06-13 20:20:40 +00:00
										 |  |  | 	  \ "line('.') < " . (plnum - s:maxoff) . " ? dummy :" | 
					
						
							|  |  |  | 	  \ . " synIDattr(synID(line('.'), col('.'), 1), 'name')" | 
					
						
							| 
									
										
										
										
											2004-06-16 11:19:22 +00:00
										 |  |  | 	  \ . " =~ '\\(Comment\\|String\\)$'") | 
					
						
							| 
									
										
										
										
											2004-06-13 20:20:40 +00:00
										 |  |  |   if parlnum > 0 | 
					
						
							|  |  |  |     let plindent = indent(parlnum) | 
					
						
							|  |  |  |     let plnumstart = parlnum | 
					
						
							|  |  |  |   else | 
					
						
							|  |  |  |     let plindent = indent(plnum) | 
					
						
							|  |  |  |     let plnumstart = plnum | 
					
						
							|  |  |  |   endif | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   " When inside parenthesis: If at the first line below the parenthesis add | 
					
						
							|  |  |  |   " two 'shiftwidth', otherwise same as previous line. | 
					
						
							|  |  |  |   " i = (a | 
					
						
							|  |  |  |   "       + b | 
					
						
							|  |  |  |   "       + c) | 
					
						
							|  |  |  |   call cursor(a:lnum, 1) | 
					
						
							| 
									
										
										
										
											2006-04-05 20:41:53 +00:00
										 |  |  |   let p = searchpair('(\|{\|\[', '', ')\|}\|\]', 'bW', | 
					
						
							| 
									
										
										
										
											2004-06-13 20:20:40 +00:00
										 |  |  | 	  \ "line('.') < " . (a:lnum - s:maxoff) . " ? dummy :" | 
					
						
							|  |  |  | 	  \ . " synIDattr(synID(line('.'), col('.'), 1), 'name')" | 
					
						
							| 
									
										
										
										
											2004-06-16 11:19:22 +00:00
										 |  |  | 	  \ . " =~ '\\(Comment\\|String\\)$'") | 
					
						
							| 
									
										
										
										
											2004-06-13 20:20:40 +00:00
										 |  |  |   if p > 0 | 
					
						
							|  |  |  |     if p == plnum | 
					
						
							|  |  |  |       " When the start is inside parenthesis, only indent one 'shiftwidth'. | 
					
						
							| 
									
										
										
										
											2006-04-05 20:41:53 +00:00
										 |  |  |       let pp = searchpair('(\|{\|\[', '', ')\|}\|\]', 'bW', | 
					
						
							| 
									
										
										
										
											2004-06-13 20:20:40 +00:00
										 |  |  | 	  \ "line('.') < " . (a:lnum - s:maxoff) . " ? dummy :" | 
					
						
							|  |  |  | 	  \ . " synIDattr(synID(line('.'), col('.'), 1), 'name')" | 
					
						
							| 
									
										
										
										
											2004-06-16 11:19:22 +00:00
										 |  |  | 	  \ . " =~ '\\(Comment\\|String\\)$'") | 
					
						
							| 
									
										
										
										
											2004-06-13 20:20:40 +00:00
										 |  |  |       if pp > 0 | 
					
						
							| 
									
										
										
										
											2005-02-26 23:04:13 +00:00
										 |  |  | 	return indent(plnum) + (exists("g:pyindent_nested_paren") ? eval(g:pyindent_nested_paren) : &sw) | 
					
						
							| 
									
										
										
										
											2004-06-13 20:20:40 +00:00
										 |  |  |       endif | 
					
						
							| 
									
										
										
										
											2005-02-26 23:04:13 +00:00
										 |  |  |       return indent(plnum) + (exists("g:pyindent_open_paren") ? eval(g:pyindent_open_paren) : (&sw * 2)) | 
					
						
							| 
									
										
										
										
											2004-06-13 20:20:40 +00:00
										 |  |  |     endif | 
					
						
							|  |  |  |     if plnumstart == p | 
					
						
							|  |  |  |       return indent(plnum) | 
					
						
							|  |  |  |     endif | 
					
						
							|  |  |  |     return plindent | 
					
						
							|  |  |  |   endif | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   " Get the line and remove a trailing comment. | 
					
						
							|  |  |  |   " Use syntax highlighting attributes when possible. | 
					
						
							|  |  |  |   let pline = getline(plnum) | 
					
						
							|  |  |  |   let pline_len = strlen(pline) | 
					
						
							| 
									
										
										
										
											2004-07-26 12:53:41 +00:00
										 |  |  |   if has('syntax_items') | 
					
						
							|  |  |  |     " If the last character in the line is a comment, do a binary search for | 
					
						
							|  |  |  |     " the start of the comment.  synID() is slow, a linear search would take | 
					
						
							|  |  |  |     " too long on a long line. | 
					
						
							|  |  |  |     if synIDattr(synID(plnum, pline_len, 1), "name") =~ "Comment$" | 
					
						
							|  |  |  |       let min = 1 | 
					
						
							|  |  |  |       let max = pline_len | 
					
						
							|  |  |  |       while min < max | 
					
						
							|  |  |  | 	let col = (min + max) / 2 | 
					
						
							|  |  |  | 	if synIDattr(synID(plnum, col, 1), "name") =~ "Comment$" | 
					
						
							|  |  |  | 	  let max = col | 
					
						
							|  |  |  | 	else | 
					
						
							|  |  |  | 	  let min = col + 1 | 
					
						
							|  |  |  | 	endif | 
					
						
							|  |  |  |       endwhile | 
					
						
							|  |  |  |       let pline = strpart(pline, 0, min - 1) | 
					
						
							| 
									
										
										
										
											2004-06-13 20:20:40 +00:00
										 |  |  |     endif | 
					
						
							| 
									
										
										
										
											2004-07-26 12:53:41 +00:00
										 |  |  |   else | 
					
						
							|  |  |  |     let col = 0 | 
					
						
							|  |  |  |     while col < pline_len | 
					
						
							|  |  |  |       if pline[col] == '#' | 
					
						
							|  |  |  | 	let pline = strpart(pline, 0, col) | 
					
						
							|  |  |  | 	break | 
					
						
							|  |  |  |       endif | 
					
						
							|  |  |  |       let col = col + 1 | 
					
						
							|  |  |  |     endwhile | 
					
						
							|  |  |  |   endif | 
					
						
							| 
									
										
										
										
											2004-06-13 20:20:40 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |   " If the previous line ended with a colon, indent this line | 
					
						
							|  |  |  |   if pline =~ ':\s*$' | 
					
						
							|  |  |  |     return plindent + &sw | 
					
						
							|  |  |  |   endif | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   " If the previous line was a stop-execution statement... | 
					
						
							| 
									
										
										
										
											2007-05-05 17:54:07 +00:00
										 |  |  |   if getline(plnum) =~ '^\s*\(break\|continue\|raise\|return\|pass\)\>' | 
					
						
							| 
									
										
										
										
											2004-06-13 20:20:40 +00:00
										 |  |  |     " See if the user has already dedented | 
					
						
							|  |  |  |     if indent(a:lnum) > indent(plnum) - &sw | 
					
						
							|  |  |  |       " If not, recommend one dedent | 
					
						
							|  |  |  |       return indent(plnum) - &sw | 
					
						
							|  |  |  |     endif | 
					
						
							|  |  |  |     " Otherwise, trust the user | 
					
						
							|  |  |  |     return -1 | 
					
						
							|  |  |  |   endif | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   " If the current line begins with a keyword that lines up with "try" | 
					
						
							|  |  |  |   if getline(a:lnum) =~ '^\s*\(except\|finally\)\>' | 
					
						
							|  |  |  |     let lnum = a:lnum - 1 | 
					
						
							|  |  |  |     while lnum >= 1 | 
					
						
							|  |  |  |       if getline(lnum) =~ '^\s*\(try\|except\)\>' | 
					
						
							|  |  |  | 	let ind = indent(lnum) | 
					
						
							|  |  |  | 	if ind >= indent(a:lnum) | 
					
						
							|  |  |  | 	  return -1	" indent is already less than this | 
					
						
							|  |  |  | 	endif | 
					
						
							|  |  |  | 	return ind	" line up with previous try or except | 
					
						
							|  |  |  |       endif | 
					
						
							|  |  |  |       let lnum = lnum - 1 | 
					
						
							|  |  |  |     endwhile | 
					
						
							|  |  |  |     return -1		" no matching "try"! | 
					
						
							|  |  |  |   endif | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   " If the current line begins with a header keyword, dedent | 
					
						
							|  |  |  |   if getline(a:lnum) =~ '^\s*\(elif\|else\)\>' | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     " Unless the previous line was a one-liner | 
					
						
							|  |  |  |     if getline(plnumstart) =~ '^\s*\(for\|if\|try\)\>' | 
					
						
							|  |  |  |       return plindent | 
					
						
							|  |  |  |     endif | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     " Or the user has already dedented | 
					
						
							|  |  |  |     if indent(a:lnum) <= plindent - &sw | 
					
						
							|  |  |  |       return -1 | 
					
						
							|  |  |  |     endif | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     return plindent - &sw | 
					
						
							|  |  |  |   endif | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   " When after a () construct we probably want to go back to the start line. | 
					
						
							|  |  |  |   " a = (b | 
					
						
							|  |  |  |   "       + c) | 
					
						
							|  |  |  |   " here | 
					
						
							|  |  |  |   if parlnum > 0 | 
					
						
							|  |  |  |     return plindent | 
					
						
							|  |  |  |   endif | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   return -1 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | endfunction | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | " vim:sw=2 |