@@ -78,6 +78,15 @@ local default_config = {
7878
7979local log_maker = {}
8080
81+ --- @param x number
82+ --- @param increment number
83+ --- @return number rounded
84+ local round = function (x , increment )
85+ increment = increment or 1
86+ x = x / increment
87+ return (x > 0 and math.floor (x + 0.5 ) or math.ceil (x - 0.5 )) * increment
88+ end
89+
8190--- @class (partial ) neotree.Logger.PartialConfig : neotree.Logger.Config
8291--- @param config neotree.Logger.PartialConfig | neotree.Logger.Config
8392--- @return neotree.Logger
@@ -113,12 +122,6 @@ log_maker.new = function(config)
113122 log .use_file (initial_filepath )
114123 end
115124
116- local round = function (x , increment )
117- increment = increment or 1
118- x = x / increment
119- return (x > 0 and math.floor (x + 0.5 ) or math.ceil (x - 0.5 )) * increment
120- end
121-
122125 local last_logfile_check_time = 0
123126 local current_logfile_inode = - 1
124127 local logfile_check_interval = 20 -- TODO: probably use filesystem events rather than this
@@ -127,36 +130,34 @@ log_maker.new = function(config)
127130 --- @param log_type string
128131 --- @param msg string
129132 local log_to_file = function (log_type , msg )
133+ if not log .file then
134+ vim .schedule (function ()
135+ vim .notify_once (" [neo-tree] Could not open log file: " .. log .outfile )
136+ end )
137+ return
138+ end
130139 local info = debug.getinfo (3 , " Sl" )
131140 local lineinfo = info .short_src .. " :" .. info .currentline
132- local str =
133- string.format (" [%-6s%s] %s%s: %s\n " , log_type , os.date (" %F-%T" ), prefix , lineinfo , msg )
134- if log .file and assert (log .file :write (str )) then
135- local curtime = os.time ()
136- -- make sure the file is valid every so often
137- if os.difftime (curtime , last_logfile_check_time ) >= logfile_check_interval then
138- last_logfile_check_time = curtime
139- log .use_file (log .outfile , true )
140- end
141- return
141+ local str = (" [%-6s%s] %s%s: %s\n " ):format (log_type , os.date (" %F-%T" ), prefix , lineinfo , msg )
142+ local _ , writeerr = log .file :write (str )
143+ if writeerr then
144+ -- Assume that subsequent writes will fail too, so stop logging to file.
145+ log .use_file (false , true )
146+ log .error (" Error writing to log:" , writeerr )
147+ log .file :close ()
142148 end
143149
144- vim .schedule (function ()
145- vim .notify_once (" [neo-tree] Could not open log file: " .. log .outfile )
146- end )
150+ local curtime = os.time ()
151+ -- make sure the file is valid every so often
152+ if os.difftime (curtime , last_logfile_check_time ) >= logfile_check_interval then
153+ last_logfile_check_time = curtime
154+ log .use_file (log .outfile , true )
155+ end
147156 end
148157
149158 --- @type { file : vim.log.levels , console : vim.log.levels }
150159 log .minimum_level = nil
151160
152- vim .api .nvim_create_autocmd (" VimLeavePre" , {
153- callback = function ()
154- if log .file then
155- log .file :close ()
156- end
157- end ,
158- })
159-
160161 local make_string = function (...)
161162 local tbl = {}
162163 for i = 1 , select (" #" , ... ) do
@@ -186,27 +187,33 @@ log_maker.new = function(config)
186187 --- @param log_level vim.log.levels
187188 --- @param message_maker fun ( ... ): string
188189 local logfunc = function (log_level , message_maker )
189- if log_level < log .minimum_level .file and log_level < log .minimum_level .console then
190+ local can_log_to_file = log_level >= log .minimum_level .file
191+ local can_log_to_console = log_level >= log .minimum_level .console
192+ if not can_log_to_file and not can_log_to_console then
190193 return function () end
191194 end
195+
192196 local level_config = config .level_configs [log_level ]
193197 local name_upper = level_config .name :upper ()
194198 return function (...)
195199 -- Return early if we're below the config.level
196200 -- Ignore this if vim is exiting
197201 if vim .v .dying > 0 or vim .v .exiting ~= vim .NIL then
198- return
202+ if log .file then
203+ config .use_file = false
204+ log .file :close ()
205+ end
199206 end
200207
201208 local msg = message_maker (... )
202209
203210 -- Output to log file
204- if config .use_file and log_level >= log . minimum_level . file then
211+ if config .use_file and can_log_to_file then
205212 log_to_file (name_upper , msg )
206213 end
207214
208215 -- Output to console
209- if config .use_console and log_level >= log . minimum_level . console then
216+ if config .use_console and can_log_to_console then
210217 vim .schedule (function ()
211218 notify (msg , log_level )
212219 end )
@@ -252,30 +259,47 @@ log_maker.new = function(config)
252259 --- @field name string
253260 --- @field hl string
254261
262+ --- Log trace-level information.
255263 log .trace = logfunc (Levels .TRACE , make_string )
264+ --- Log debug information.
256265 log .debug = logfunc (Levels .DEBUG , make_string )
266+ --- Log useful information/UI feedback.
257267 log .info = logfunc (Levels .INFO , make_string )
268+ --- Log a warning.
258269 log .warn = logfunc (Levels .WARN , make_string )
270+ --- Log at an "error" level. Doesn't actually raise an error.
259271 log .error = logfunc (Levels .ERROR , make_string )
272+ --- Unused, kept around for compatibility at the moment. Remove in v4.0.
260273 log .fatal = logfunc (Levels .FATAL , make_string )
261274 -- tree-sitter queries recognize any .format and highlight it w/ string.format highlights
275+ --- @type table<string , { format : fun ( fmt : string ?, ... : any ) } >
262276 log .at = {
263277 trace = {
278+ --- Log trace-level information, but like string.format.
279+ --- @see string.format
264280 format = logfunc (Levels .TRACE , string.format ),
265281 },
266282 debug = {
283+ --- Log debug information, but like string.format.
284+ --- @see string.format
267285 format = logfunc (Levels .DEBUG , string.format ),
268286 },
269287 info = {
288+ --- Log useful information/UI feedback, but like string.format.
289+ --- @see string.format
270290 format = logfunc (Levels .INFO , string.format ),
271291 },
272292 warn = {
293+ --- Log a warning, but like string.format.
294+ --- @see string.format
273295 format = logfunc (Levels .WARN , string.format ),
274296 },
275297 error = {
298+ --- Log an error, but like string.format.
276299 format = logfunc (Levels .ERROR , string.format ),
277300 },
278301 fatal = {
302+ --- Unused, kept around for compatibility at the moment. Remove in v4.0.
279303 format = logfunc (Levels .FATAL , string.format ),
280304 },
281305 }
@@ -295,6 +319,8 @@ log_maker.new = function(config)
295319 return config .use_file
296320 end
297321 log .outfile = type (file ) == " string" and file or initial_filepath
322+ log .outfile = vim .fn .expand (log .outfile )
323+ log .outfile = vim .fn .fnamemodify (log .outfile , " :p" )
298324 local fp , err = io.open (log .outfile , " a+" )
299325
300326 if not fp then
@@ -307,10 +333,14 @@ log_maker.new = function(config)
307333 if not stat then
308334 config .use_file = false
309335 log .warn (" Could not stat log file:" , log .outfile , stat_err )
336+ fp :close ()
310337 return config .use_file
311338 end
312339
313340 if stat .ino ~= current_logfile_inode then
341+ if log .file then
342+ log .file :close ()
343+ end
314344 -- the fp is pointing to a different file
315345 log .file = fp
316346 log .file :setvbuf (" line" )
0 commit comments