]> git.madduck.net Git - etc/vim.git/blob - autoload/ale/events.vim

madduck's git repository

Every one of the projects in this repository is available at the canonical URL git://git.madduck.net/madduck/pub/<projectpath> — see each project's metadata for the exact URL.

All patches and comments are welcome. Please squash your changes to logical commits before using git-format-patch and git-send-email to patches@git.madduck.net. If you'd read over the Git project's submission guidelines and adhered to them, I'd be especially grateful.

SSH access, as well as push access can be individually arranged.

If you use my repositories frequently, consider adding the following snippet to ~/.gitconfig and using the third clone URL listed for each project:

[url "git://git.madduck.net/madduck/"]
  insteadOf = madduck:

Squashed '.vim/bundle/ale/' content from commit 22185c4c
[etc/vim.git] / autoload / ale / events.vim
1 " Author: w0rp <devw0rp@gmail.com>
2 " Description: ALE functions for autocmd events.
3
4 " Get the number of milliseconds since some vague, but consistent, point in
5 " the past.
6 "
7 " This function can be used for timing execution, etc.
8 "
9 " The time will be returned as a Number.
10 function! ale#events#ClockMilliseconds() abort
11     return float2nr(reltimefloat(reltime()) * 1000)
12 endfunction
13
14 function! ale#events#QuitEvent(buffer) abort
15     " Remember when ALE is quitting for BufWrite, etc.
16     call setbufvar(a:buffer, 'ale_quitting', ale#events#ClockMilliseconds())
17 endfunction
18
19 function! ale#events#QuitRecently(buffer) abort
20     let l:time = getbufvar(a:buffer, 'ale_quitting', 0)
21
22     return l:time && ale#events#ClockMilliseconds() - l:time < 1000
23 endfunction
24
25 function! ale#events#SaveEvent(buffer) abort
26     let l:should_lint = ale#Var(a:buffer, 'enabled') && g:ale_lint_on_save
27
28     if l:should_lint
29         call setbufvar(a:buffer, 'ale_save_event_fired', 1)
30     endif
31
32     if ale#Var(a:buffer, 'fix_on_save') && !ale#events#QuitRecently(a:buffer)
33         let l:will_fix = ale#fix#Fix(a:buffer, 'save_file')
34         let l:should_lint = l:should_lint && !l:will_fix
35     endif
36
37     if l:should_lint && !ale#events#QuitRecently(a:buffer)
38         call ale#Queue(0, 'lint_file', a:buffer)
39     endif
40 endfunction
41
42 function! ale#events#LintOnEnter(buffer) abort
43     " Unmark a file as being changed outside of Vim after we try to check it.
44     call setbufvar(a:buffer, 'ale_file_changed', 0)
45
46     if ale#Var(a:buffer, 'enabled') && g:ale_lint_on_enter
47         call ale#Queue(0, 'lint_file', a:buffer)
48     endif
49 endfunction
50
51 function! ale#events#ReadOrEnterEvent(buffer) abort
52     " Apply pattern options if the variable is set.
53     if get(g:, 'ale_pattern_options_enabled', 1)
54     \&& !empty(get(g:, 'ale_pattern_options'))
55         call ale#pattern_options#SetOptions(a:buffer)
56     endif
57
58     " When entering a buffer, we are no longer quitting it.
59     call setbufvar(a:buffer, 'ale_quitting', 0)
60     let l:filetype = getbufvar(a:buffer, '&filetype')
61     call setbufvar(a:buffer, 'ale_original_filetype', l:filetype)
62
63     " If the file changed outside of Vim, check it on BufEnter,BufRead
64     if getbufvar(a:buffer, 'ale_file_changed')
65         call ale#events#LintOnEnter(a:buffer)
66     endif
67 endfunction
68
69 function! ale#events#FileTypeEvent(buffer, new_filetype) abort
70     " The old filetype will be set to an empty string by the BuFEnter event,
71     " and not linting when the old filetype hasn't been set yet prevents
72     " buffers being checked when you enter them when linting on enter is off.
73     let l:old_filetype = getbufvar(a:buffer, 'ale_original_filetype', v:null)
74
75     if l:old_filetype isnot v:null
76     \&& !empty(a:new_filetype)
77     \&& a:new_filetype isnot# l:old_filetype
78         " Remember what the new filetype is.
79         call setbufvar(a:buffer, 'ale_original_filetype', a:new_filetype)
80
81         if g:ale_lint_on_filetype_changed
82             call ale#Queue(300, 'lint_file', a:buffer)
83         endif
84     endif
85 endfunction
86
87 function! ale#events#FileChangedEvent(buffer) abort
88     call setbufvar(a:buffer, 'ale_file_changed', 1)
89
90     if bufnr('') == a:buffer
91         call ale#events#LintOnEnter(a:buffer)
92     endif
93 endfunction
94
95 " A timer for emulating InsertLeave.
96 "
97 " We only need a single timer, and we'll lint the last buffer we entered
98 " insert mode on.
99 if !exists('s:insert_leave_timer')
100     let s:insert_leave_timer = -1
101 endif
102
103 " True if the ModeChanged event exists.
104 " In this case, ModeChanged will be used instead of InsertLeave emulation.
105 let s:mode_changed_exists = exists('##ModeChanged')
106
107 function! ale#events#EmulateInsertLeave(buffer) abort
108     if mode() is# 'n'
109         call timer_stop(s:insert_leave_timer)
110         call ale#Queue(0, '', a:buffer)
111     endif
112 endfunction
113
114 function! ale#events#InsertEnterEvent(buffer) abort
115     if g:ale_close_preview_on_insert && exists('*ale#preview#CloseIfTypeMatches')
116         call ale#preview#CloseIfTypeMatches('ale-preview')
117     endif
118
119     " Start a repeating timer if the use might not trigger InsertLeave, so we
120     " can emulate its behavior.
121     " If the ModeChanged autocmd exists, it will be used instead of this
122     " timer; as ModeChanged will be sent regardless of how the insert mode is
123     " exited, including <Esc>, <C-c> and <C-]>.
124     if ale#Var(a:buffer, 'lint_on_insert_leave')
125     \&& maparg("\<C-c>", 'i') isnot# '<Esc>'
126     \&& !s:mode_changed_exists
127         call timer_stop(s:insert_leave_timer)
128         let s:insert_leave_timer = timer_start(
129         \   100,
130         \   {-> ale#events#EmulateInsertLeave(a:buffer) },
131         \   {'repeat': -1}
132         \)
133     endif
134 endfunction
135
136 function! ale#events#InsertLeaveEvent(buffer) abort
137     " Kill the InsertLeave emulation if the event fired.
138     " If the ModeChanged event is available, it will be used instead of
139     " a timer.
140     if !s:mode_changed_exists
141         call timer_stop(s:insert_leave_timer)
142     endif
143
144     if ale#Var(a:buffer, 'lint_on_insert_leave')
145         call ale#Queue(0, '', a:buffer)
146     endif
147
148     " Look for a warning to echo as soon as we leave Insert mode.
149     " The script's position variable used when moving the cursor will
150     " not be changed here.
151     "
152     " We don't echo this message in emulated insert leave mode, as the user
153     " may want less work to happen on pressing <C-c> versus <Esc>
154     if exists('*ale#engine#Cleanup')
155         call ale#cursor#EchoCursorWarning()
156
157         if g:ale_virtualtext_cursor is# 'current' || g:ale_virtualtext_cursor is# 1 || g:ale_virtualtext_cursor is# '1'
158             " Show a virtualtext message if enabled.
159             call ale#virtualtext#ShowCursorWarning()
160         endif
161     endif
162 endfunction
163
164 function! ale#events#Init() abort
165     " This value used to be a Boolean as a Number, and is now a String.
166     let l:text_changed = '' . g:ale_lint_on_text_changed
167
168     augroup ALEEvents
169         autocmd!
170
171         " These events always need to be set up.
172         autocmd BufEnter,BufRead * call ale#events#ReadOrEnterEvent(str2nr(expand('<abuf>')))
173         autocmd BufWritePost * call ale#events#SaveEvent(str2nr(expand('<abuf>')))
174
175         if g:ale_enabled
176             if l:text_changed is? 'always'
177             \|| l:text_changed is# '1'
178             \|| g:ale_lint_on_text_changed is v:true
179                 autocmd TextChanged,TextChangedI * call ale#Queue(ale#Var(str2nr(expand('<abuf>')), 'lint_delay'))
180             elseif l:text_changed is? 'normal'
181                 autocmd TextChanged * call ale#Queue(ale#Var(str2nr(expand('<abuf>')), 'lint_delay'))
182             elseif l:text_changed is? 'insert'
183                 autocmd TextChangedI * call ale#Queue(ale#Var(str2nr(expand('<abuf>')), 'lint_delay'))
184             endif
185
186             if g:ale_lint_on_enter
187                 autocmd BufWinEnter * call ale#events#LintOnEnter(str2nr(expand('<abuf>')))
188                 " Track when the file is changed outside of Vim.
189                 autocmd FileChangedShellPost * call ale#events#FileChangedEvent(str2nr(expand('<abuf>')))
190             endif
191
192             if g:ale_lint_on_filetype_changed
193                 " Only start linting if the FileType actually changes after
194                 " opening a buffer. The FileType will fire when buffers are opened.
195                 autocmd FileType * call ale#events#FileTypeEvent(
196                 \   str2nr(expand('<abuf>')),
197                 \   expand('<amatch>')
198                 \)
199             endif
200
201             " Add an InsertEnter event if we need to close the preview window
202             " on entering insert mode, or if we want to run ALE on leaving
203             " insert mode and <C-c> is not the same as <Esc>.
204             "
205             " We will emulate leaving insert mode for users that might not
206             " trigger InsertLeave.
207             "
208             " If the ModeChanged event is available, this timer will not
209             " be used.
210             if g:ale_close_preview_on_insert
211             \|| (g:ale_lint_on_insert_leave && maparg("\<C-c>", 'i') isnot# '<Esc>' && !s:mode_changed_exists)
212                 autocmd InsertEnter * call ale#events#InsertEnterEvent(str2nr(expand('<abuf>')))
213             endif
214
215             let l:add_insert_leave_event = g:ale_lint_on_insert_leave
216
217             if g:ale_echo_cursor || g:ale_cursor_detail
218                 " We need to make the message display on InsertLeave
219                 let l:add_insert_leave_event = 1
220
221                 autocmd CursorMoved,CursorHold * if exists('*ale#engine#Cleanup') | call ale#cursor#EchoCursorWarningWithDelay() | endif
222             endif
223
224             if g:ale_virtualtext_cursor is# 'current' || g:ale_virtualtext_cursor is# 1 || g:ale_virtualtext_cursor is# '1'
225                 " We need to make the message display on InsertLeave
226                 let l:add_insert_leave_event = 1
227
228                 autocmd CursorMoved,CursorHold * if exists('*ale#engine#Cleanup') | call ale#virtualtext#ShowCursorWarningWithDelay() | endif
229             endif
230
231             if l:add_insert_leave_event
232                 if s:mode_changed_exists
233                     " If the ModeChanged event is available, handle any
234                     " transition from the Insert mode to any other mode.
235                     autocmd ModeChanged i*:* call ale#events#InsertLeaveEvent(str2nr(expand('<abuf>')))
236                 else
237                     " If ModeChanged is not available, handle InsertLeave events.
238                     autocmd InsertLeave * call ale#events#InsertLeaveEvent(str2nr(expand('<abuf>')))
239                 endif
240             endif
241
242             if g:ale_hover_cursor
243                 autocmd CursorHold * if exists('*ale#lsp#Send') | call ale#hover#ShowTruncatedMessageAtCursor() | endif
244             endif
245         endif
246     augroup END
247
248     augroup AleURISchemes
249         autocmd!
250
251         autocmd BufNewFile,BufReadPre jdt://** call ale#uri#jdt#ReadJDTLink(expand('<amatch>'))
252     augroup END
253 endfunction