@@ -2,17 +2,31 @@ local log = require("nvim-tree.log")
22local utils = require (" nvim-tree.utils" )
33local notify = require (" nvim-tree.notify" )
44
5- --- @class Runner
6- local Runner = {}
7- Runner .__index = Runner
5+ local Class = require (" nvim-tree.class" )
6+
7+ --- @alias GitStatusesXYByPath table<string , string>
8+
9+ --- @class (exact ) RunnerOpts
10+ --- @field toplevel string absolute path
11+ --- @field path string ? absolute path
12+ --- @field list_untracked boolean
13+ --- @field list_ignored boolean
14+ --- @field timeout integer
15+ --- @field callback fun ( statuses : GitStatusesXYByPath )?
16+
17+ --- @class (exact ) Runner : Class
18+ --- @field opts RunnerOpts
19+ --- @field statuses GitStatusesXYByPath
20+ --- @field rc integer ? -- -1 indicates timeout
21+ local Runner = Class :new ()
822
923local timeouts = 0
1024local MAX_TIMEOUTS = 5
1125
1226--- @private
1327--- @param status string
1428--- @param path string | nil
15- function Runner :_parse_status_output (status , path )
29+ function Runner :parse_status_output (status , path )
1630 if not path then
1731 return
1832 end
@@ -22,15 +36,15 @@ function Runner:_parse_status_output(status, path)
2236 path = path :gsub (" /" , " \\ " )
2337 end
2438 if # status > 0 and # path > 0 then
25- self .output [utils .path_remove_trailing (utils .path_join ({ self .toplevel , path }))] = status
39+ self .statuses [utils .path_remove_trailing (utils .path_join ({ self . opts .toplevel , path }))] = status
2640 end
2741end
2842
2943--- @private
3044--- @param prev_output string
3145--- @param incoming string
3246--- @return string
33- function Runner :_handle_incoming_data (prev_output , incoming )
47+ function Runner :handle_incoming_data (prev_output , incoming )
3448 if incoming and utils .str_find (incoming , " \n " ) then
3549 local prev = prev_output .. incoming
3650 local i = 1
@@ -45,7 +59,7 @@ function Runner:_handle_incoming_data(prev_output, incoming)
4559 -- skip next line if it is a rename entry
4660 skip_next_line = true
4761 end
48- self :_parse_status_output (status , path )
62+ self :parse_status_output (status , path )
4963 end
5064 i = i + # line
5165 end
@@ -58,35 +72,38 @@ function Runner:_handle_incoming_data(prev_output, incoming)
5872 end
5973
6074 for line in prev_output :gmatch (" [^\n ]*\n " ) do
61- self :_parse_status_output (line )
75+ self :parse_status_output (line )
6276 end
6377
6478 return " "
6579end
6680
81+ --- @private
6782--- @param stdout_handle uv.uv_pipe_t
6883--- @param stderr_handle uv.uv_pipe_t
69- --- @return table
70- function Runner :_getopts (stdout_handle , stderr_handle )
71- local untracked = self .list_untracked and " -u" or nil
72- local ignored = (self .list_untracked and self .list_ignored ) and " --ignored=matching" or " --ignored=no"
84+ --- @return uv.spawn.options
85+ function Runner :get_spawn_options (stdout_handle , stderr_handle )
86+ local untracked = self .opts . list_untracked and " -u" or nil
87+ local ignored = (self .opts . list_untracked and self . opts .list_ignored ) and " --ignored=matching" or " --ignored=no"
7388 return {
74- args = { " --no-optional-locks" , " status" , " --porcelain=v1" , " -z" , ignored , untracked , self .path },
75- cwd = self .toplevel ,
89+ args = { " --no-optional-locks" , " status" , " --porcelain=v1" , " -z" , ignored , untracked , self .opts . path },
90+ cwd = self .opts . toplevel ,
7691 stdio = { nil , stdout_handle , stderr_handle },
7792 }
7893end
7994
95+ --- @private
8096--- @param output string
81- function Runner :_log_raw_output (output )
97+ function Runner :log_raw_output (output )
8298 if log .enabled (" git" ) and output and type (output ) == " string" then
8399 log .raw (" git" , " %s" , output )
84100 log .line (" git" , " done" )
85101 end
86102end
87103
104+ --- @private
88105--- @param callback function | nil
89- function Runner :_run_git_job (callback )
106+ function Runner :run_git_job (callback )
90107 local handle , pid
91108 local stdout = vim .loop .new_pipe (false )
92109 local stderr = vim .loop .new_pipe (false )
@@ -123,20 +140,20 @@ function Runner:_run_git_job(callback)
123140 end
124141 end
125142
126- local opts = self :_getopts (stdout , stderr )
127- log .line (" git" , " running job with timeout %dms" , self .timeout )
128- log .line (" git" , " git %s" , table.concat (utils .array_remove_nils (opts .args ), " " ))
143+ local spawn_options = self :get_spawn_options (stdout , stderr )
144+ log .line (" git" , " running job with timeout %dms" , self .opts . timeout )
145+ log .line (" git" , " git %s" , table.concat (utils .array_remove_nils (spawn_options .args ), " " ))
129146
130147 handle , pid = vim .loop .spawn (
131148 " git" ,
132- opts ,
149+ spawn_options ,
133150 vim .schedule_wrap (function (rc )
134151 on_finish (rc )
135152 end )
136153 )
137154
138155 timer :start (
139- self .timeout ,
156+ self .opts . timeout ,
140157 0 ,
141158 vim .schedule_wrap (function ()
142159 on_finish (- 1 )
@@ -151,19 +168,20 @@ function Runner:_run_git_job(callback)
151168 if data then
152169 data = data :gsub (" %z" , " \n " )
153170 end
154- self :_log_raw_output (data )
155- output_leftover = self :_handle_incoming_data (output_leftover , data )
171+ self :log_raw_output (data )
172+ output_leftover = self :handle_incoming_data (output_leftover , data )
156173 end
157174
158175 local function manage_stderr (_ , data )
159- self :_log_raw_output (data )
176+ self :log_raw_output (data )
160177 end
161178
162179 vim .loop .read_start (stdout , vim .schedule_wrap (manage_stdout ))
163180 vim .loop .read_start (stderr , vim .schedule_wrap (manage_stderr ))
164181end
165182
166- function Runner :_wait ()
183+ --- @private
184+ function Runner :wait ()
167185 local function is_done ()
168186 return self .rc ~= nil
169187 end
@@ -172,64 +190,64 @@ function Runner:_wait()
172190 end
173191end
174192
175- --- @param opts table
176- function Runner :_finalise ( opts )
193+ --- @private
194+ function Runner :finalise ( )
177195 if self .rc == - 1 then
178- log .line (" git" , " job timed out %s %s" , opts .toplevel , opts .path )
196+ log .line (" git" , " job timed out %s %s" , self . opts .toplevel , self . opts .path )
179197 timeouts = timeouts + 1
180198 if timeouts == MAX_TIMEOUTS then
181- notify .warn (string.format (" %d git jobs have timed out after git.timeout %dms, disabling git integration." , timeouts , opts .timeout ))
199+ notify .warn (string.format (" %d git jobs have timed out after git.timeout %dms, disabling git integration." , timeouts ,
200+ self .opts .timeout ))
182201 require (" nvim-tree.git" ).disable_git_integration ()
183202 end
184203 elseif self .rc ~= 0 then
185- log .line (" git" , " job fail rc %d %s %s" , self .rc , opts .toplevel , opts .path )
204+ log .line (" git" , " job fail rc %d %s %s" , self .rc , self . opts .toplevel , self . opts .path )
186205 else
187- log .line (" git" , " job success %s %s" , opts .toplevel , opts .path )
206+ log .line (" git" , " job success %s %s" , self . opts .toplevel , self . opts .path )
188207 end
189208end
190209
191- --- Runs a git process, which will be killed if it takes more than timeout which defaults to 400ms
192- --- @param opts table
193- --- @param callback function | nil executed passing return when complete
194- --- @return table | nil status by absolute path , nil if callback present
195- function Runner .run (opts , callback )
196- local self = setmetatable ({
197- toplevel = opts .toplevel ,
198- path = opts .path ,
199- list_untracked = opts .list_untracked ,
200- list_ignored = opts .list_ignored ,
201- timeout = opts .timeout or 400 ,
202- output = {},
203- rc = nil , -- -1 indicates timeout
204- }, Runner )
205-
206- local async = callback ~= nil
207- local profile = log .profile_start (" git %s job %s %s" , async and " async" or " sync" , opts .toplevel , opts .path )
208-
209- if async and callback then
210+ --- @return GitStatusesXYByPath ? statuses nil if callback present
211+ function Runner :run ()
212+ local async = self .opts .callback ~= nil
213+ local profile = log .profile_start (" git %s job %s %s" , async and " async" or " sync" , self .opts .toplevel , self .opts .path )
214+
215+ if async and self .opts .callback then
210216 -- async, always call back
211- self :_run_git_job (function ()
217+ self :run_git_job (function ()
212218 log .profile_end (profile )
213219
214- self :_finalise ( opts )
220+ self :finalise ( )
215221
216- callback (self .output )
222+ self . opts . callback (self .statuses )
217223 end )
218224 else
219225 -- sync, maybe call back
220- self :_run_git_job ()
221- self :_wait ()
226+ self :run_git_job ()
227+ self :wait ()
222228
223229 log .profile_end (profile )
224230
225- self :_finalise ( opts )
231+ self :finalise ( )
226232
227- if callback then
228- callback (self .output )
233+ if self . opts . callback then
234+ self . opts . callback (self .statuses )
229235 else
230- return self .output
236+ return self .statuses
231237 end
232238 end
233239end
234240
235- return Runner
241+ --- Runs a git process, which will be killed if it takes more than timeout which defaults to 400ms
242+ --- @param opts RunnerOpts
243+ --- @return GitStatusesXYByPath ? statuses nil if callback present
244+ return function (opts )
245+ --- @type Runner
246+ local runner = {
247+ opts = opts ,
248+ statuses = {},
249+ }
250+ runner = Runner :new (runner ) --[[ @as Runner]]
251+
252+ return runner :run ()
253+ end
0 commit comments