@@ -2,44 +2,112 @@ if has_key(g:polyglot_is_disabled, 'fish')
2
2
finish
3
3
endif
4
4
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
+
5
54
function ! 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
8
68
return 0
9
69
endif
70
+ let l: shift = 0
10
71
let l: prevline = getline (l: prevlnum )
11
- let l: line = getline (v: lnum )
12
- let l: shiftwidth = shiftwidth ()
13
72
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
24
83
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
33
85
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
38
86
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
41
107
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
43
111
endfunction
44
112
45
113
function ! fish#Format ()
@@ -49,6 +117,8 @@ function! fish#Format()
49
117
let l: command = v: lnum .' ,' .(v: lnum+ v: count- 1 ).' !fish_indent'
50
118
echo l: command
51
119
execute l: command
120
+ " Fix indentation and replace tabs with spaces if necessary.
121
+ normal ! ' [=' ]
52
122
endif
53
123
endfunction
54
124
0 commit comments