indent.vim 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184
  1. " PEP8 compatible Python indent file
  2. " Language: Python
  3. " Maintainer: Hynek Schlawack <hs@ox.cx>
  4. " Prev Maintainer: Eric Mc Sween <em@tomcom.de> (address invalid)
  5. " Original Author: David Bustos <bustos@caltech.edu> (address invalid)
  6. " Last Change: 2012-06-21
  7. " License: Public Domainlet
  8. function! pymode#indent#Indent(lnum)
  9. " First line has indent 0
  10. if a:lnum == 1
  11. return 0
  12. endif
  13. " If we can find an open parenthesis/bracket/brace, line up with it.
  14. call cursor(a:lnum, 1)
  15. let parlnum = s:SearchParensPair()
  16. if parlnum > 0
  17. let parcol = col('.')
  18. let closing_paren = match(getline(a:lnum), '^\s*[])}]') != -1
  19. if match(getline(parlnum), '[([{]\s*$', parcol - 1) != -1
  20. if closing_paren
  21. return indent(parlnum)
  22. else
  23. return indent(parlnum) + &shiftwidth
  24. endif
  25. else
  26. return parcol
  27. endif
  28. endif
  29. " Examine this line
  30. let thisline = getline(a:lnum)
  31. let thisindent = indent(a:lnum)
  32. " If the line starts with 'elif' or 'else', line up with 'if' or 'elif'
  33. if thisline =~ '^\s*\(elif\|else\)\>'
  34. let bslnum = s:BlockStarter(a:lnum, '^\s*\(if\|elif\)\>')
  35. if bslnum > 0
  36. return indent(bslnum)
  37. else
  38. return -1
  39. endif
  40. endif
  41. " If the line starts with 'except' or 'finally', line up with 'try'
  42. " or 'except'
  43. if thisline =~ '^\s*\(except\|finally\)\>'
  44. let bslnum = s:BlockStarter(a:lnum, '^\s*\(try\|except\)\>')
  45. if bslnum > 0
  46. return indent(bslnum)
  47. else
  48. return -1
  49. endif
  50. endif
  51. " Examine previous line
  52. let plnum = a:lnum - 1
  53. let pline = getline(plnum)
  54. let sslnum = s:StatementStart(plnum)
  55. " If the previous line is blank, keep the same indentation
  56. if pline =~ '^\s*$'
  57. return -1
  58. endif
  59. " If this line is explicitly joined, try to find an indentation that looks
  60. " good.
  61. if pline =~ '\\$'
  62. let compound_statement = '^\s*\(if\|while\|for\s.*\sin\|except\)\s*'
  63. let maybe_indent = matchend(getline(sslnum), compound_statement)
  64. if maybe_indent != -1
  65. return maybe_indent
  66. else
  67. return indent(sslnum) + &sw * 2
  68. endif
  69. endif
  70. " If the previous line ended with a colon and is not a comment, indent
  71. " relative to statement start.
  72. if pline =~ ':\s*$' && pline !~ '^\s*#'
  73. return indent(sslnum) + &sw
  74. endif
  75. " If the previous line was a stop-execution statement or a pass
  76. if getline(sslnum) =~ '^\s*\(break\|continue\|raise\|return\|pass\)\>'
  77. " See if the user has already dedented
  78. if indent(a:lnum) > indent(sslnum) - &sw
  79. " If not, recommend one dedent
  80. return indent(sslnum) - &sw
  81. endif
  82. " Otherwise, trust the user
  83. return -1
  84. endif
  85. " In all other cases, line up with the start of the previous statement.
  86. return indent(sslnum)
  87. endfunction
  88. " Find backwards the closest open parenthesis/bracket/brace.
  89. function! s:SearchParensPair()
  90. let line = line('.')
  91. let col = col('.')
  92. " Skip strings and comments and don't look too far
  93. let skip = "line('.') < " . (line - 50) . " ? dummy :" .
  94. \ 'synIDattr(synID(line("."), col("."), 0), "name") =~? ' .
  95. \ '"string\\|comment"'
  96. " Search for parentheses
  97. call cursor(line, col)
  98. let parlnum = searchpair('(', '', ')', 'bW', skip)
  99. let parcol = col('.')
  100. " Search for brackets
  101. call cursor(line, col)
  102. let par2lnum = searchpair('\[', '', '\]', 'bW', skip)
  103. let par2col = col('.')
  104. " Search for braces
  105. call cursor(line, col)
  106. let par3lnum = searchpair('{', '', '}', 'bW', skip)
  107. let par3col = col('.')
  108. " Get the closest match
  109. if par2lnum > parlnum || (par2lnum == parlnum && par2col > parcol)
  110. let parlnum = par2lnum
  111. let parcol = par2col
  112. endif
  113. if par3lnum > parlnum || (par3lnum == parlnum && par3col > parcol)
  114. let parlnum = par3lnum
  115. let parcol = par3col
  116. endif
  117. " Put the cursor on the match
  118. if parlnum > 0
  119. call cursor(parlnum, parcol)
  120. endif
  121. return parlnum
  122. endfunction
  123. " Find the start of a multi-line statement
  124. function! s:StatementStart(lnum)
  125. let lnum = a:lnum
  126. while 1
  127. if getline(lnum - 1) =~ '\\$'
  128. let lnum = lnum - 1
  129. else
  130. call cursor(lnum, 1)
  131. let maybe_lnum = s:SearchParensPair()
  132. if maybe_lnum < 1
  133. return lnum
  134. else
  135. let lnum = maybe_lnum
  136. endif
  137. endif
  138. endwhile
  139. endfunction
  140. " Find the block starter that matches the current line
  141. function! s:BlockStarter(lnum, block_start_re)
  142. let lnum = a:lnum
  143. let maxindent = 10000 " whatever
  144. while lnum > 1
  145. let lnum = prevnonblank(lnum - 1)
  146. if indent(lnum) < maxindent
  147. if getline(lnum) =~ a:block_start_re
  148. return lnum
  149. else
  150. let maxindent = indent(lnum)
  151. " It's not worth going further if we reached the top level
  152. if maxindent == 0
  153. return -1
  154. endif
  155. endif
  156. endif
  157. endwhile
  158. return -1
  159. endfunction