11local api , uv = vim .api , vim .uv
2- local async = require (' guard._async' )
32local util = require (' guard.util' )
43local getopt = util .getopt
54local report_error = util .report_error
@@ -11,31 +10,22 @@ M.group = api.nvim_create_augroup('Guard', { clear = true })
1110M .user_fmt_autocmds = {}
1211M .user_lint_autocmds = {}
1312
14- -- Fix: per-buffer debounce timers
15- local debounce_timers = {}
16-
13+ local debounce_timer = nil
1714local function debounced_lint (opt )
18- local buf = opt .buf
19-
20- if debounce_timers [buf ] then
21- debounce_timers [buf ]:stop ()
22- debounce_timers [buf ]:close ()
23- debounce_timers [buf ] = nil
15+ if debounce_timer then
16+ debounce_timer :stop ()
17+ debounce_timer = nil
2418 end
25-
26- debounce_timers [buf ] = assert (uv .new_timer ())
19+ --- @diagnostic disable-next-line : undefined-field
20+ debounce_timer = assert (uv .new_timer ()) --[[ uv_timer_t]]
21+ --- @type integer
2722 local interval = assert (tonumber (util .getopt (' lint_interval' )))
28-
29- debounce_timers [buf ]:start (interval , 0 , function ()
30- if debounce_timers [buf ] then
31- debounce_timers [buf ]:stop ()
32- debounce_timers [buf ]:close ()
33- debounce_timers [buf ] = nil
34- end
23+ debounce_timer :start (interval , 0 , function ()
24+ debounce_timer :stop ()
25+ debounce_timer :close ()
26+ debounce_timer = nil
3527 vim .schedule (function ()
36- if api .nvim_buf_is_valid (buf ) then
37- require (' guard.lint' ).do_lint (buf )
38- end
28+ require (' guard.lint' ).do_lint (opt .buf )
3929 end )
4030 end )
4131end
@@ -84,16 +74,11 @@ function M.get_lint_autocmds(bufnr)
8474 if not api .nvim_buf_is_valid (bufnr ) then
8575 return {}
8676 end
87-
88- -- Get buffer-specific autocmds
8977 local aus = api .nvim_get_autocmds ({
9078 group = M .group ,
9179 event = { ' BufWritePost' , ' BufEnter' , ' TextChanged' , ' InsertLeave' },
9280 buffer = bufnr ,
9381 })
94-
95- -- Note: User GuardFmt autocmds are global, we include them for compatibility
96- -- but they should be filtered by buffer in their callbacks
9782 return vim .list_extend (
9883 aus ,
9984 api .nvim_get_autocmds ({
10691
10792--- @param buf number
10893--- @return boolean
94+ --- We don't check ignore patterns here because users might expect
95+ --- other formatters in the same group to run even if another
96+ --- might ignore this file
10997function M .check_fmt_should_attach (buf )
110- return # M .get_format_autocmds (buf ) == 0 and vim .bo [buf ].buftype ~= ' nofile'
98+ -- check if it's not attached already
99+ return # M .get_format_autocmds (buf ) == 0
100+ -- and has an underlying file
101+ and vim .bo [buf ].buftype ~= ' nofile'
111102end
112103
113104--- @param buf number
@@ -120,13 +111,13 @@ function M.check_lint_should_attach(buf, ft)
120111
121112 local aus = M .get_lint_autocmds (buf )
122113
123- -- For '*' filetype, check if there's already a '*' pattern autocmd
124- -- For specific filetype, check if there's already a non-' *' pattern autocmd
125- local has_conflicting = iter ( aus ): any ( function ( au )
126- return ft == ' * ' and au . pattern == ' * ' or au . pattern ~= ' * '
127- end )
128-
129- return not has_conflicting
114+ return # iter ( aus )
115+ : filter ( ft == ' *' and function ( it )
116+ return it . pattern == ' * '
117+ end or function ( it )
118+ return it . pattern ~= ' * ' and it . pattern ~= ' GuardFmt '
119+ end )
120+ : totable () == 0
130121end
131122
132123--- @param buf number
@@ -141,10 +132,6 @@ function M.try_attach_fmt_to_buf(buf)
141132 })
142133end
143134
144- -- Track which buffers want User GuardFmt autocmd for lint
145- local lint_on_fmt_buffers = {}
146- local user_guardfmt_autocmd_id = nil
147-
148135--- @param buf number
149136--- @param events string[]
150137--- @param ft string
@@ -155,21 +142,15 @@ function M.try_attach_lint_to_buf(buf, events, ft)
155142
156143 for _ , ev in ipairs (events ) do
157144 if ev == ' User GuardFmt' then
158- -- Register this buffer for lint-on-format
159- lint_on_fmt_buffers [buf ] = true
160-
161- -- Create global User GuardFmt autocmd only once
162- if not user_guardfmt_autocmd_id then
163- user_guardfmt_autocmd_id = au (' User' , {
164- group = M .group ,
165- pattern = ' GuardFmt' ,
166- callback = function (opt )
167- if lint_on_fmt_buffers [opt .buf ] and opt .data .status == ' done' then
168- lazy_debounced_lint (opt )
169- end
170- end ,
171- })
172- end
145+ au (' User' , {
146+ group = M .group ,
147+ pattern = ' GuardFmt' ,
148+ callback = function (opt )
149+ if opt .buf == buf and opt .data .status == ' done' then
150+ lazy_debounced_lint (opt )
151+ end
152+ end ,
153+ })
173154 else
174155 au (ev , {
175156 group = M .group ,
@@ -201,11 +182,13 @@ end
201182--- @param ft string
202183--- @param formatters FmtConfig[]
203184function M .fmt_on_filetype (ft , formatters )
204- -- Check executability and report errors
205- iter (formatters ):each (function (config )
185+ -- check if all cmds executable before registering formatter
186+ iter (formatters ):any (function (config )
206187 if type (config ) == ' table' and config .cmd and vim .fn .executable (config .cmd ) ~= 1 then
207188 report_error (config .cmd .. ' not executable' )
189+ return false
208190 end
191+ return true
209192 end )
210193
211194 au (' FileType' , {
@@ -261,11 +244,11 @@ end
261244--- @param ft string
262245--- @param events string[]
263246function M .lint_on_filetype (ft , events )
264- -- Check executability and report errors
265- iter (require (' guard.filetype' )[ft ].linter ):each (function (config )
247+ iter (require (' guard.filetype' )[ft ].linter ):any (function (config )
266248 if config .cmd and vim .fn .executable (config .cmd ) ~= 1 then
267249 report_error (config .cmd .. ' not executable' )
268250 end
251+ return true
269252 end )
270253
271254 au (' FileType' , {
281264--- @param ft string
282265function M .fmt_attach_custom (ft , events )
283266 M .user_fmt_autocmds [ft ] = {}
267+ -- we don't know what autocmds are passed in, so these are attached asap
284268 iter (events ):each (function (event )
285269 table.insert (
286270 M .user_fmt_autocmds [ft ],
@@ -298,15 +282,16 @@ end
298282--- @param ft string
299283function M .lint_attach_custom (ft , config )
300284 M .user_lint_autocmds [ft ] = {}
285+ -- we don't know what autocmds are passed in, so these are attached asap
301286 iter (config .events ):each (function (event )
302287 table.insert (
303288 M .user_lint_autocmds [ft ],
304289 api .nvim_create_autocmd (
305290 event .name ,
306291 maybe_fill_auoption (event .opt or {}, function (opt )
307- async . run (function ()
292+ coroutine.resume ( coroutine.create (function ()
308293 require (' guard.lint' ).do_lint_single (opt .buf , config )
309- end )
294+ end ))
310295 end )
311296 )
312297 )
0 commit comments