@@ -2,44 +2,112 @@ if has_key(g:polyglot_is_disabled, 'fish')
22 finish
33endif
44
5+ function ! s: IsString (lnum, col )
6+ " Returns "true" if syntax item at the given position is part of fishString.
7+ let l: stack = map (synstack (a: lnum , a: col ), ' synIDattr(v:val, "name")' )
8+ return len (filter (l: stack , ' v:val ==# "fishString"' ))
9+ endfunction
10+
11+ function ! s: IsContinuedLine (lnum)
12+ " Returns "true" if the given line is a continued line.
13+ return getline (a: lnum - 1 ) = ~ ' \v\\$'
14+ endfunction
15+
16+ function ! s: FindPrevLnum (lnum)
17+ " Starting on the given line, search backwards for a line that is not
18+ " empty, not part of a string and not a continued line.
19+ if a: lnum < 1 || a: lnum > line (' $' )
20+ " First line or wrong value, follow prevnonblank() behaviour and
21+ " return zero.
22+ return 0
23+ endif
24+ let l: lnum = prevnonblank (a: lnum )
25+ while l: lnum > 0 && ( s: IsContinuedLine (l: lnum ) || s: IsString (l: lnum , 1 ) )
26+ let l: lnum = prevnonblank (l: lnum - 1 )
27+ endwhile
28+ return l: lnum
29+ endfunction
30+
31+ function ! s: IsSwitch (lnum)
32+ " Returns "true" if the given line is part of a switch block.
33+ let l: lnum = a: lnum
34+ let l: line = getline (l: lnum )
35+ let l: in_block = 0
36+ let l: stop_pat = ' \v^\s*%(if|else|while|for|begin)>'
37+ let l: block_start_pat = ' \v^\s*%(if|while|for|switch|begin)>'
38+ while l: lnum > 0
39+ let l: lnum = prevnonblank (l: lnum - 1 )
40+ let l: line = getline (l: lnum )
41+ if l: line = ~# ' \v^\s*end>'
42+ let l: in_block += 1
43+ elseif l: in_block && l: line = ~# l: block_start_pat
44+ let l: in_block -= 1
45+ elseif ! l: in_block && l: line = ~# l: stop_pat
46+ return 0
47+ elseif ! l: in_block && l: line = ~# ' \v^\s*switch>'
48+ return 1
49+ endif
50+ endwhile
51+ return 0
52+ endfunction
53+
554function ! fish#Indent ()
6- let l: prevlnum = prevnonblank (v: lnum - 1 )
7- if l: prevlnum == # 0
55+ let l: line = getline (v: lnum )
56+ if s: IsString (v: lnum , 1 )
57+ return indent (v: lnum )
58+ endif
59+ " shiftwidth can be misleading in recent versions, use shiftwidth() if
60+ " it is available.
61+ if exists (' *shiftwidth' )
62+ let l: shiftwidth = shiftwidth ()
63+ else
64+ let l: shiftwidth = &shiftwidth
65+ endif
66+ let l: prevlnum = s: FindPrevLnum (v: lnum - 1 )
67+ if l: prevlnum == 0
868 return 0
969 endif
70+ let l: shift = 0
1071 let l: prevline = getline (l: prevlnum )
11- let l: line = getline (v: lnum )
12- let l: shiftwidth = shiftwidth ()
1372 let l: previndent = indent (l: prevlnum )
14- let l: indent = l: previndent
15- if l: prevline = ~# ' \v^\s*%(begin|if|else|while|for|function|switch|case)> '
16- let l: indent += l: shiftwidth
17- endif
18- if l: line = ~# ' \v^\s*end> '
19- let l: indent -= l: shiftwidth
20- " If we're inside a case, dedent twice because it ends the switch.
21- if l: prevline = ~# ' \v^\s*case> '
22- " Previous line starts the case.
23- let l: indent -= l: shiftwidth
73+ if s: IsContinuedLine ( v: lnum )
74+ " It is customary to increment indentation of continued lines by three
75+ " or a custom value defined by the user if available.
76+ let l: previndent = indent ( v: lnum - 1 )
77+ if s: IsContinuedLine ( v: lnum - 1 )
78+ return l: previndent
79+ elseif exists ( ' g:fish_indent_cont ' )
80+ return l: previndent + g: fish_indent_cont
81+ elseif exists ( ' g:indent_cont ' )
82+ return l: previndent + g: indent_cont
2483 else
25- " Scan back to a dedented line to find whether we're in a case.
26- let l: i = l: prevlnum
27- while l: i >= 1 && indent (l: i ) >= l: previndent
28- let l: i = prevnonblank (l: i - 1 )
29- endwhile
30- if indent (l: i ) < l: previndent && getline (l: i ) = ~# ' \v^\s*case>'
31- let l: indent -= l: shiftwidth
32- endif
84+ return l: previndent + 3
3385 endif
34- elseif l: line = ~# ' \v^\s*else>'
35- let l: indent -= l: shiftwidth
36- elseif l: prevline !~# ' \v^\s*switch>' && l: line = ~# ' \v^\s*case>'
37- let l: indent -= l: shiftwidth
3886 endif
39- if l: indent < 0
40- return 0
87+ if l: prevline = ~# ' \v^\s*%(begin|if|else|while|for|function|case|switch)>'
88+ " First line inside a block, increase by one.
89+ let l: shift += 1
90+ endif
91+ if l: line = ~# ' \v^\s*%(end|case|else)>'
92+ " "end", "case" or "else", decrease by one.
93+ let l: shift -= 1
94+ endif
95+ if l: line = ~# ' \v^\s*<case>' && l: prevline = ~# ' \v<switch>'
96+ " "case" following "switch", increase by one.
97+ let l: shift += 1
98+ endif
99+ if l: line = ~# ' \v\s*end>' && s: IsSwitch (v: lnum )
100+ " "end" ends switch block, decrease by one more so it matches
101+ " the indentation of "switch".
102+ let l: shift -= 1
103+ endif
104+ if l: prevline = ~# ' \v^\s*%(if|while|for|else|switch|end)>.*<begin>'
105+ " "begin" after start of block, increase by one.
106+ let l: shift += 1
41107 endif
42- return l: indent
108+ let l: indent = l: previndent + l: shift * l: shiftwidth
109+ " Only return zero or positive numbers.
110+ return l: indent < 0 ? 0 : l: indent
43111endfunction
44112
45113function ! fish#Format ()
@@ -49,6 +117,8 @@ function! fish#Format()
49117 let l: command = v: lnum .' ,' .(v: lnum+ v: count- 1 ).' !fish_indent'
50118 echo l: command
51119 execute l: command
120+ " Fix indentation and replace tabs with spaces if necessary.
121+ normal ! ' [=' ]
52122 endif
53123endfunction
54124
0 commit comments