@@ -172,6 +172,21 @@ function M.find_node_line(node)
172172 return - 1
173173end
174174
175+ --- @param extmarks vim.api.keyset.get_extmark_item[] as per vim.api.nvim_buf_get_extmarks
176+ --- @return number
177+ function M .extmarks_length (extmarks )
178+ local length = 0
179+ for _ , extmark in ipairs (extmarks ) do
180+ local details = extmark [4 ]
181+ if details and details .virt_text then
182+ for _ , text in ipairs (details .virt_text ) do
183+ length = length + vim .fn .strchars (text [1 ])
184+ end
185+ end
186+ end
187+ return length
188+ end
189+
175190-- get the node in the tree state depending on the absolute path of the node
176191-- (grouped or hidden too)
177192--- @param path string
@@ -288,11 +303,51 @@ function M.rename_loaded_buffers(old_path, new_path)
288303 end
289304end
290305
306+ local is_windows_drive = function (path )
307+ return (M .is_windows ) and (path :match (" ^%a:\\ $" ) ~= nil )
308+ end
309+
291310--- @param path string path to file or directory
292311--- @return boolean
293312function M .file_exists (path )
294- local _ , error = vim .loop .fs_stat (path )
295- return error == nil
313+ if not (M .is_windows or M .is_wsl ) then
314+ local _ , error = vim .loop .fs_stat (path )
315+ return error == nil
316+ end
317+
318+ -- Windows is case-insensetive, but case-preserving
319+ -- If a file's name is being changed into itself
320+ -- with different casing, windows will falsely
321+ -- report that file is already existing, so a hand-rolled
322+ -- implementation of checking for existance is needed.
323+ -- Same holds for WSL, since it can sometimes
324+ -- access Windows files directly.
325+ -- For more details see (#3117).
326+
327+ if is_windows_drive (path ) then
328+ return vim .fn .isdirectory (path ) == 1
329+ end
330+
331+ local parent = vim .fn .fnamemodify (path , " :h" )
332+ local filename = vim .fn .fnamemodify (path , " :t" )
333+
334+ local handle = vim .loop .fs_scandir (parent )
335+ if not handle then
336+ -- File can not exist if its parent directory does not exist
337+ return false
338+ end
339+
340+ while true do
341+ local name , _ = vim .loop .fs_scandir_next (handle )
342+ if not name then
343+ break
344+ end
345+ if name == filename then
346+ return true
347+ end
348+ end
349+
350+ return false
296351end
297352
298353--- @param path string
0 commit comments