1" Vim indent file
2" Language:         Makefile
3" Maintainer:       Nikolai Weibull <now@bitwi.se>
4" Latest Revision:  2007-05-07
5
6if exists("b:did_indent")
7  finish
8endif
9let b:did_indent = 1
10
11setlocal indentexpr=GetMakeIndent()
12setlocal indentkeys=!^F,o,O,<:>,=else,=endif
13setlocal nosmartindent
14
15if exists("*GetMakeIndent")
16  finish
17endif
18
19let s:comment_rx = '^\s*#'
20let s:rule_rx = '^[^ \t#:][^#:]*:\{1,2}\%([^=:]\|$\)'
21let s:continued_rule_rx = '^[^#:]*:\{1,2}\%([^=:]\|$\)'
22let s:continuation_rx = '\\$'
23let s:assignment_rx = '^\s*\h\w*\s*[+?]\==\s*\zs.*\\$'
24let s:folded_assignment_rx = '^\s*\h\w*\s*[+?]\=='
25" TODO: This needs to be a lot more restrictive in what it matches.
26let s:just_inserted_rule_rx = '^\s*[^#:]\+:\{1,2}$'
27let s:conditional_directive_rx = '^ *\%(ifn\=\%(eq\|def\)\|else\)\>'
28let s:end_conditional_directive_rx = '^\s*\%(else\|endif\)\>'
29
30function s:remove_continuation(line)
31  return substitute(a:line, s:continuation_rx, "", "")
32endfunction
33
34function GetMakeIndent()
35  " TODO: Should this perhaps be v:lnum -1?
36"  let prev_lnum = prevnonblank(v:lnum - 1)
37  let prev_lnum = v:lnum - 1
38  if prev_lnum == 0
39    return 0
40  endif
41  let prev_line = getline(prev_lnum)
42
43  let prev_prev_lnum = prev_lnum - 1
44  let prev_prev_line = prev_prev_lnum != 0 ? getline(prev_prev_lnum) : ""
45
46  " TODO: Deal with comments.  In comments, continuations aren't interesting.
47  if prev_line =~ s:continuation_rx
48    if prev_prev_line =~ s:continuation_rx
49      return indent(prev_lnum)
50    elseif prev_line =~ s:rule_rx
51      return &sw
52    elseif prev_line =~ s:assignment_rx
53      call cursor(prev_lnum, 1)
54      if search(s:assignment_rx, 'W') != 0
55        return virtcol('.') - 1
56      else
57        " TODO: ?
58        return &sw
59      endif
60    else
61      " TODO: OK, this might be a continued shell command, so perhaps indent
62      " properly here?  Leave this out for now, but in the next release this
63      " should be using indent/sh.vim somehow.
64      "if prev_line =~ '^\t' " s:rule_command_rx
65      "  if prev_line =~ '^\s\+[@-]\%(if\)\>'
66      "    return indent(prev_lnum) + 2
67      "  endif
68      "endif
69      return indent(prev_lnum) + &sw
70    endif
71  elseif prev_prev_line =~ s:continuation_rx
72    let folded_line = s:remove_continuation(prev_prev_line) . ' ' . s:remove_continuation(prev_line)
73    let lnum = prev_prev_lnum - 1
74    let line = getline(lnum)
75    while line =~ s:continuation_rx
76      let folded_line = s:remove_continuation(line) . ' ' . folded_line
77      let lnum -= 1
78      let line = getline(lnum)
79    endwhile
80    let folded_lnum = lnum + 1
81    if folded_line =~ s:rule_rx
82      if getline(v:lnum) =~ s:rule_rx
83        return 0
84      else
85        return &ts
86      endif
87    else
88"    elseif folded_line =~ s:folded_assignment_rx
89      if getline(v:lnum) =~ s:rule_rx
90        return 0
91      else
92        return indent(folded_lnum)
93      endif
94"    else
95"      " TODO: ?
96"      return indent(prev_lnum)
97    endif
98  elseif prev_line =~ s:rule_rx
99    if getline(v:lnum) =~ s:rule_rx
100      return 0
101    else
102      return &ts
103    endif
104  elseif prev_line =~ s:conditional_directive_rx
105    return &sw
106  else
107    let line = getline(v:lnum)
108    if line =~ s:just_inserted_rule_rx
109      return 0
110    elseif line =~ s:end_conditional_directive_rx
111      return v:lnum - 1 == 0 ? 0 : indent(v:lnum - 1) - &sw
112    else
113      return v:lnum - 1 == 0 ? 0 : indent(v:lnum - 1)
114    endif
115  endif
116endfunction
117