xref: /vim-8.2.3635/runtime/indent/python.vim (revision 071d4279)
1*071d4279SBram Moolenaar" Vim indent file
2*071d4279SBram Moolenaar" Language:	Python
3*071d4279SBram Moolenaar" Maintainer:	Bram Moolenaar <[email protected]>
4*071d4279SBram Moolenaar" Original Author:	David Bustos <[email protected]>
5*071d4279SBram Moolenaar" Last Change:	2003 Sep 08
6*071d4279SBram Moolenaar
7*071d4279SBram Moolenaar" Only load this indent file when no other was loaded.
8*071d4279SBram Moolenaarif exists("b:did_indent")
9*071d4279SBram Moolenaar  finish
10*071d4279SBram Moolenaarendif
11*071d4279SBram Moolenaarlet b:did_indent = 1
12*071d4279SBram Moolenaar
13*071d4279SBram Moolenaar" Some preliminary settings
14*071d4279SBram Moolenaarsetlocal nolisp		" Make sure lisp indenting doesn't supersede us
15*071d4279SBram Moolenaarsetlocal autoindent	" indentexpr isn't much help otherwise
16*071d4279SBram Moolenaar
17*071d4279SBram Moolenaarsetlocal indentexpr=GetPythonIndent(v:lnum)
18*071d4279SBram Moolenaarsetlocal indentkeys+=<:>,=elif,=except
19*071d4279SBram Moolenaar
20*071d4279SBram Moolenaar" Only define the function once.
21*071d4279SBram Moolenaarif exists("*GetPythonIndent")
22*071d4279SBram Moolenaar  finish
23*071d4279SBram Moolenaarendif
24*071d4279SBram Moolenaar
25*071d4279SBram Moolenaarlet s:maxoff = 50	" maximum number of lines to look backwards for ()
26*071d4279SBram Moolenaar
27*071d4279SBram Moolenaarfunction GetPythonIndent(lnum)
28*071d4279SBram Moolenaar  " If this line is explicitly joined: If the previous line was also joined,
29*071d4279SBram Moolenaar  " line it up with that one, otherwise add two 'shiftwidth'
30*071d4279SBram Moolenaar  if getline(a:lnum - 1) =~ '\\$'
31*071d4279SBram Moolenaar    if a:lnum > 1 && getline(a:lnum - 2) =~ '\\$'
32*071d4279SBram Moolenaar      return indent(a:lnum - 1)
33*071d4279SBram Moolenaar    endif
34*071d4279SBram Moolenaar    return indent(a:lnum - 1) + (&sw * 2)
35*071d4279SBram Moolenaar  endif
36*071d4279SBram Moolenaar
37*071d4279SBram Moolenaar  " If the start of the line is in a string don't change the indent.
38*071d4279SBram Moolenaar  if has('syntax_items')
39*071d4279SBram Moolenaar	\ && synIDattr(synID(a:lnum, 1, 1), "name") == "pythonString"
40*071d4279SBram Moolenaar    return -1
41*071d4279SBram Moolenaar  endif
42*071d4279SBram Moolenaar
43*071d4279SBram Moolenaar  " Search backwards for the previous non-empty line.
44*071d4279SBram Moolenaar  let plnum = prevnonblank(v:lnum - 1)
45*071d4279SBram Moolenaar
46*071d4279SBram Moolenaar  if plnum == 0
47*071d4279SBram Moolenaar    " This is the first non-empty line, use zero indent.
48*071d4279SBram Moolenaar    return 0
49*071d4279SBram Moolenaar  endif
50*071d4279SBram Moolenaar
51*071d4279SBram Moolenaar  " If the previous line is inside parenthesis, use the indent of the starting
52*071d4279SBram Moolenaar  " line.
53*071d4279SBram Moolenaar  " Trick: use the non-existing "dummy" variable to break out of the loop when
54*071d4279SBram Moolenaar  " going too far back.
55*071d4279SBram Moolenaar  call cursor(plnum, 1)
56*071d4279SBram Moolenaar  let parlnum = searchpair('(', '', ')', 'nbW',
57*071d4279SBram Moolenaar	  \ "line('.') < " . (plnum - s:maxoff) . " ? dummy :"
58*071d4279SBram Moolenaar	  \ . " synIDattr(synID(line('.'), col('.'), 1), 'name')"
59*071d4279SBram Moolenaar	  \ . " =~ 'python\\(Comment\\|String\\)'")
60*071d4279SBram Moolenaar  if parlnum > 0
61*071d4279SBram Moolenaar    let plindent = indent(parlnum)
62*071d4279SBram Moolenaar    let plnumstart = parlnum
63*071d4279SBram Moolenaar  else
64*071d4279SBram Moolenaar    let plindent = indent(plnum)
65*071d4279SBram Moolenaar    let plnumstart = plnum
66*071d4279SBram Moolenaar  endif
67*071d4279SBram Moolenaar
68*071d4279SBram Moolenaar
69*071d4279SBram Moolenaar  " When inside parenthesis: If at the first line below the parenthesis add
70*071d4279SBram Moolenaar  " two 'shiftwidth', otherwise same as previous line.
71*071d4279SBram Moolenaar  " i = (a
72*071d4279SBram Moolenaar  "       + b
73*071d4279SBram Moolenaar  "       + c)
74*071d4279SBram Moolenaar  call cursor(a:lnum, 1)
75*071d4279SBram Moolenaar  let p = searchpair('(', '', ')', 'bW',
76*071d4279SBram Moolenaar	  \ "line('.') < " . (a:lnum - s:maxoff) . " ? dummy :"
77*071d4279SBram Moolenaar	  \ . " synIDattr(synID(line('.'), col('.'), 1), 'name')"
78*071d4279SBram Moolenaar	  \ . " =~ 'python\\(Comment\\|String\\)'")
79*071d4279SBram Moolenaar  if p > 0
80*071d4279SBram Moolenaar    if p == plnum
81*071d4279SBram Moolenaar      " When the start is inside parenthesis, only indent one 'shiftwidth'.
82*071d4279SBram Moolenaar      let pp = searchpair('(', '', ')', 'bW',
83*071d4279SBram Moolenaar	  \ "line('.') < " . (a:lnum - s:maxoff) . " ? dummy :"
84*071d4279SBram Moolenaar	  \ . " synIDattr(synID(line('.'), col('.'), 1), 'name')"
85*071d4279SBram Moolenaar	  \ . " =~ 'python\\(Comment\\|String\\)'")
86*071d4279SBram Moolenaar      if pp > 0
87*071d4279SBram Moolenaar	return indent(plnum) + &sw
88*071d4279SBram Moolenaar      endif
89*071d4279SBram Moolenaar      return indent(plnum) + (&sw * 2)
90*071d4279SBram Moolenaar    endif
91*071d4279SBram Moolenaar    if plnumstart == p
92*071d4279SBram Moolenaar      return indent(plnum)
93*071d4279SBram Moolenaar    endif
94*071d4279SBram Moolenaar    return plindent
95*071d4279SBram Moolenaar  endif
96*071d4279SBram Moolenaar
97*071d4279SBram Moolenaar
98*071d4279SBram Moolenaar  " Get the line and remove a trailing comment.
99*071d4279SBram Moolenaar  " Use syntax highlighting attributes when possible.
100*071d4279SBram Moolenaar  let pline = getline(plnum)
101*071d4279SBram Moolenaar  let pline_len = strlen(pline)
102*071d4279SBram Moolenaar  let col = 0
103*071d4279SBram Moolenaar  while col < pline_len
104*071d4279SBram Moolenaar    if pline[col] == '#' && (!has('syntax_items')
105*071d4279SBram Moolenaar	    \ || synIDattr(synID(plnum, col + 1, 1), "name") == "pythonComment")
106*071d4279SBram Moolenaar      let pline = strpart(pline, 0, col)
107*071d4279SBram Moolenaar      break
108*071d4279SBram Moolenaar    endif
109*071d4279SBram Moolenaar    let col = col + 1
110*071d4279SBram Moolenaar  endwhile
111*071d4279SBram Moolenaar
112*071d4279SBram Moolenaar  " If the previous line ended with a colon, indent this line
113*071d4279SBram Moolenaar  if pline =~ ':\s*$'
114*071d4279SBram Moolenaar    return plindent + &sw
115*071d4279SBram Moolenaar  endif
116*071d4279SBram Moolenaar
117*071d4279SBram Moolenaar  " If the previous line was a stop-execution statement...
118*071d4279SBram Moolenaar  if getline(plnum) =~ '^\s*\(break\|continue\|raise\|return\)\>'
119*071d4279SBram Moolenaar    " See if the user has already dedented
120*071d4279SBram Moolenaar    if indent(a:lnum) > indent(plnum) - &sw
121*071d4279SBram Moolenaar      " If not, recommend one dedent
122*071d4279SBram Moolenaar      return indent(plnum) - &sw
123*071d4279SBram Moolenaar    endif
124*071d4279SBram Moolenaar    " Otherwise, trust the user
125*071d4279SBram Moolenaar    return -1
126*071d4279SBram Moolenaar  endif
127*071d4279SBram Moolenaar
128*071d4279SBram Moolenaar  " If the current line begins with a keyword that lines up with "try"
129*071d4279SBram Moolenaar  if getline(a:lnum) =~ '^\s*\(except\|finally\)\>'
130*071d4279SBram Moolenaar    let lnum = a:lnum - 1
131*071d4279SBram Moolenaar    while lnum >= 1
132*071d4279SBram Moolenaar      echomsg 'got here'
133*071d4279SBram Moolenaar      if getline(lnum) =~ '^\s*\(try\|except\)\>'
134*071d4279SBram Moolenaar	let ind = indent(lnum)
135*071d4279SBram Moolenaar	echomsg 'got here, indent is ' . ind
136*071d4279SBram Moolenaar	if ind >= indent(a:lnum)
137*071d4279SBram Moolenaar	  return -1	" indent is already less than this
138*071d4279SBram Moolenaar	endif
139*071d4279SBram Moolenaar	return ind	" line up with previous try or except
140*071d4279SBram Moolenaar      endif
141*071d4279SBram Moolenaar      let lnum = lnum - 1
142*071d4279SBram Moolenaar    endwhile
143*071d4279SBram Moolenaar    echomsg 'got to the end'
144*071d4279SBram Moolenaar    return -1		" no matching "try"!
145*071d4279SBram Moolenaar  endif
146*071d4279SBram Moolenaar
147*071d4279SBram Moolenaar  " If the current line begins with a header keyword, dedent
148*071d4279SBram Moolenaar  if getline(a:lnum) =~ '^\s*\(elif\|else\)\>'
149*071d4279SBram Moolenaar
150*071d4279SBram Moolenaar    " Unless the previous line was a one-liner
151*071d4279SBram Moolenaar    if getline(plnumstart) =~ '^\s*\(for\|if\|try\)\>'
152*071d4279SBram Moolenaar      return plindent
153*071d4279SBram Moolenaar    endif
154*071d4279SBram Moolenaar
155*071d4279SBram Moolenaar    " Or the user has already dedented
156*071d4279SBram Moolenaar    if indent(a:lnum) <= plindent - &sw
157*071d4279SBram Moolenaar      return -1
158*071d4279SBram Moolenaar    endif
159*071d4279SBram Moolenaar
160*071d4279SBram Moolenaar    return plindent - &sw
161*071d4279SBram Moolenaar  endif
162*071d4279SBram Moolenaar
163*071d4279SBram Moolenaar  " When after a () construct we probably want to go back to the start line.
164*071d4279SBram Moolenaar  " a = (b
165*071d4279SBram Moolenaar  "       + c)
166*071d4279SBram Moolenaar  " here
167*071d4279SBram Moolenaar  if parlnum > 0
168*071d4279SBram Moolenaar    return plindent
169*071d4279SBram Moolenaar  endif
170*071d4279SBram Moolenaar
171*071d4279SBram Moolenaar  return -1
172*071d4279SBram Moolenaar
173*071d4279SBram Moolenaarendfunction
174*071d4279SBram Moolenaar
175*071d4279SBram Moolenaar" vim:sw=2
176