This repository has been archived by the owner on Oct 1, 2020. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 52
/
flow.vim
205 lines (172 loc) · 5.18 KB
/
flow.vim
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
" flow.vim - Flow typechecker integration for vim
if exists("g:loaded_flow")
finish
endif
let g:loaded_flow = 1
" Configuration switches:
" - enable: Typechecking is done on :w.
" - autoclose: Quickfix window closes automatically when there are no errors.
" - errjmp: Jump to errors after typechecking; default off.
" - qfsize: Let the plugin control the quickfix window size.
" - flowpath: Path to the flow executable - default is flow in path
" - showquickfix Show the quickfix window
if !exists("g:flow#enable")
let g:flow#enable = 1
endif
if !exists("g:flow#autoclose")
let g:flow#autoclose = 0
endif
if !exists("g:flow#errjmp")
let g:flow#errjmp = 0
endif
if !exists("g:flow#qfsize")
let g:flow#qfsize = 1
endif
if !exists("g:flow#flowpath")
let g:flow#flowpath = "flow"
endif
if !exists("g:flow#timeout")
let g:flow#timeout = 2
endif
if !exists("g:flow#showquickfix")
let g:flow#showquickfix = 1
endif
" Require the flow executable.
if !executable(g:flow#flowpath)
finish
endif
" flow error format.
let s:flow_errorformat = '%EFile "%f"\, line %l\, characters %c-%.%#,%Z%m,'
" flow from editor.
let s:flow_from = '--from vim'
" Call wrapper for flow.
function! <SID>FlowClientCall(cmd, suffix, ...)
" Invoke typechecker.
" We also concatenate with the empty string because otherwise
" cgetexpr complains about not having a String argument, even though
" type(flow_result) == 1.
let command = g:flow#flowpath.' '.a:cmd.' '.s:flow_from.' '.a:suffix
let flow_result = a:0 > 0 ? system(command, a:1) : system(command)
" Handle the server still initializing
if v:shell_error == 1
echohl WarningMsg
echomsg 'Flow server is still initializing...'
echohl None
cclose
return 0
endif
" Handle timeout
if v:shell_error == 3
echohl WarningMsg
echomsg 'Flow timed out, please try again!'
echohl None
cclose
return 0
endif
return flow_result
endfunction
" Main interface functions.
function! flow#typecheck()
" Flow current outputs errors to stderr and gets fancy with single character
" files
let flow_result = <SID>FlowClientCall('--timeout '.g:flow#timeout.' --retry-if-init false "'.expand('%:p').'"', '2> /dev/null')
let old_fmt = &errorformat
let &errorformat = s:flow_errorformat
if g:flow#errjmp
cexpr flow_result
else
cgetexpr flow_result
endif
if g:flow#showquickfix
if g:flow#autoclose
botright cwindow
else
botright copen
endif
endif
let &errorformat = old_fmt
endfunction
" Get the Flow type at the current cursor position.
function! flow#get_type()
let pos = line('.').' '.col('.')
let path = ' --path '.fnameescape(expand('%'))
let cmd = g:flow#flowpath.' type-at-pos '.pos.path
let stdin = join(getline(1,'$'), "\n")
let output = 'FlowType: '.system(cmd, stdin)
let output = substitute(output, '\n$', '', '')
echo output
endfunction
" Toggle auto-typecheck.
function! flow#toggle()
if g:flow#enable
let g:flow#enable = 0
else
let g:flow#enable = 1
endif
endfunction
" Jump to Flow definition for the current cursor position
function! flow#jump_to_def()
let pos = line('.').' '.col('.')
let path = ' --path '.fnameescape(expand('%'))
let stdin = join(getline(1,'$'), "\n")
let flow_result = <SID>FlowClientCall('get-def --quiet '.pos.path, '', stdin)
" Output format is:
" File: "/path/to/file", line 1, characters 1-11
" Flow returns a single line-feed if no result
if strlen(flow_result) == 1
echo 'No definition found'
return 1
endif
let parts = split(flow_result, ",")
if len(parts) < 2
echo 'cannot find definition'
return 1
endif
" File: "/path/to/file" => /path/to/file
let file = substitute(substitute(parts[0], '"', '', 'g'), 'File ', '', '')
" line 1 => 1
let row = split(parts[1], " ")[1]
" characters 1-11 => 1
let col = 0
if len(parts) == 3
let col = split(split(parts[2], " ")[1], "-")[0]
endif
" File - means current file
if filereadable(file) || file == '-'
if file != '-'
execute 'edit' file
endif
call cursor(row, col)
end
endfunction
" Open importers of current file in quickfix window
function! flow#get_importers()
let flow_result = <SID>FlowClientCall('get-importers "'.expand('%').'" --strip-root', '')
let importers = split(flow_result, '\n')[1:1000]
let l:flow_errorformat = '%f'
let old_fmt = &errorformat
let &errorformat = l:flow_errorformat
if g:flow#errjmp
cexpr importers
else
cgetexpr importers
endif
if g:flow#autoclose
botright cwindow
else
botright copen
endif
let &errorformat = old_fmt
endfunction
" Commands and auto-typecheck.
command! FlowToggle call flow#toggle()
command! FlowMake call flow#typecheck()
command! FlowType call flow#get_type()
command! FlowJumpToDef call flow#jump_to_def()
command! FlowGetImporters call flow#get_importers()
au BufWritePost *.js,*.jsx if g:flow#enable | call flow#typecheck() | endif
" Keep quickfix window at an adjusted height.
function! <SID>AdjustWindowHeight(minheight, maxheight)
exe max([min([line("$"), a:maxheight]), a:minheight]) . "wincmd _"
endfunction
au FileType qf if g:flow#qfsize | call <SID>AdjustWindowHeight(3, 10) | endif