@@ -47,19 +47,16 @@ function Bookmarks:get_bookmarks_dir()
4747end
4848
4949function Bookmarks :get_root_dir ()
50- -- Try to get git root first
5150 local git_dir = vim .fn .system (' git rev-parse --show-toplevel 2>/dev/null' ):gsub (' \n ' , ' ' )
5251 if vim .v .shell_error == 0 and git_dir ~= ' ' then
5352 return git_dir
5453 end
5554
56- -- Fallback to current working directory
5755 return vim .fn .getcwd ()
5856end
5957
6058function Bookmarks :get_bookmark_file ()
6159 local root = self :get_root_dir ()
62- -- Create a valid filename from the root path
6360 local filename = root :gsub (' [^%w_%-]' , ' _' )
6461 return Path :new (self :get_bookmarks_dir ()):joinpath (filename .. ' .json' )
6562end
9491function Bookmarks :serialize ()
9592 local data = {}
9693 for group_nr , group in pairs (self .groups ) do
97- -- Convert numeric keys to strings to avoid sparse array issues
9894 local group_key = tostring (group_nr )
9995 data [group_key ] = {
10096 marks = {},
@@ -103,10 +99,8 @@ function Bookmarks:serialize()
10399 }
104100 for bufnr , buffer_marks in pairs (group .marks ) do
105101 local filename = vim .api .nvim_buf_get_name (bufnr )
106- -- Only save marks from named buffers
107102 if filename and filename ~= ' ' then
108103 data [group_key ].marks [filename ] = {}
109- -- Convert the marks table to an array
110104 for _ , mark in pairs (buffer_marks ) do
111105 table.insert (data [group_key ].marks [filename ], {
112106 line = mark .line ,
@@ -152,15 +146,18 @@ end
152146
153147function Bookmarks :place_mark (group_nr , bufnr , pos )
154148 bufnr = bufnr or a .nvim_get_current_buf ()
155- local group = self .groups [group_nr ]
156149
150+ if not utils .is_valid_buffer (bufnr ) then
151+ return
152+ end
153+
154+ local group = self .groups [group_nr ]
157155 if not group then
158156 self :init (group_nr )
159157 group = self .groups [group_nr ]
160158 end
161159
162- pos = pos or a .nvim_win_get_cursor (0 )
163-
160+ pos = pos or utils .safe_get_current_cursor ()
164161 local data = { buf = bufnr , line = pos [1 ], col = pos [2 ], sign_id = - 1 }
165162
166163 local display_signs = utils .option_nil (self .opt .buf_signs [bufnr ], self .opt .signs )
@@ -192,7 +189,6 @@ function Bookmarks:place_mark(group_nr, bufnr, pos)
192189 group .marks [bufnr ] = {}
193190 end
194191
195- -- Generate a unique key for this mark
196192 local mark_key = string.format (' %d_%d' , pos [1 ], # group .marks [bufnr ] + 1 )
197193 group .marks [bufnr ][mark_key ] = data
198194
@@ -212,7 +208,6 @@ function Bookmarks:toggle_mark(group_nr, bufnr)
212208
213209 local pos = a .nvim_win_get_cursor (0 )
214210
215- -- Check if there's a mark at current line
216211 local found_mark = nil
217212 if group .marks [bufnr ] then
218213 for key , mark in pairs (group .marks [bufnr ]) do
@@ -254,14 +249,18 @@ end
254249
255250function Bookmarks :delete_mark_cursor ()
256251 local bufnr = a .nvim_get_current_buf ()
257- local pos = a .nvim_win_get_cursor (0 )
252+
253+ if not utils .is_valid_buffer (bufnr ) then
254+ return
255+ end
256+
257+ local pos = utils .safe_get_current_cursor ()
258258
259259 local group_nr = group_under_cursor (self .groups , bufnr , pos )
260260 if not group_nr then
261261 return
262262 end
263263
264- -- Find the mark key for the current line
265264 local found_mark = nil
266265 if self .groups [group_nr ].marks [bufnr ] then
267266 for key , mark in pairs (self .groups [group_nr ].marks [bufnr ]) do
@@ -311,7 +310,6 @@ local function find_mark(items, bufnr, pos, next_mode)
311310 return nil
312311 end
313312
314- -- Sort by buffer and line number
315313 table.sort (items , function (a , b )
316314 if a .bufnr == b .bufnr then
317315 if next_mode then
@@ -327,7 +325,6 @@ local function find_mark(items, bufnr, pos, next_mode)
327325 end
328326 end )
329327
330- -- Find the next/prev mark
331328 local found_mark = nil
332329 for _ , mark in ipairs (items ) do
333330 if next_mode then
@@ -343,20 +340,17 @@ local function find_mark(items, bufnr, pos, next_mode)
343340 end
344341 end
345342
346- -- Wrap around if no mark found
347343 return found_mark or items [1 ]
348344end
349345
350346function Bookmarks :navigate (group_nr , next_mode )
351347 local bufnr = a .nvim_get_current_buf ()
352348 local pos = a .nvim_win_get_cursor (0 )
353349
354- -- If no group specified and not on a mark, use the first available group
355350 if not group_nr then
356351 group_nr = get_group_nr_or_first (self , bufnr , pos )
357352 end
358353
359- -- Get all marks for this group from all bookmark files
360354 local items = self :get_list ({ group = group_nr })
361355 local target_mark = find_mark (items , bufnr , pos , next_mode )
362356
@@ -366,7 +360,6 @@ function Bookmarks:navigate(group_nr, next_mode)
366360
367361 if target_mark .bufnr ~= bufnr then
368362 vim .cmd (' silent b' .. target_mark .bufnr )
369- -- Ensure marks are loaded in the new buffer
370363 self :load ()
371364 end
372365 a .nvim_win_set_cursor (0 , { target_mark .lnum , target_mark .col - 1 })
424417function Bookmarks :refresh ()
425418 local bufnr = a .nvim_get_current_buf ()
426419
427- -- if we delete and undo really quickly, the extmark's position will be
428- -- the same, but the sign will no longer be there. so clear and restore all
429- -- signs.
430-
431420 local buf_marks
432421 local display_signs
433422 utils .remove_buf_signs (bufnr , ' BookmarkSigns' )
@@ -451,7 +440,7 @@ function Bookmarks:refresh()
451440 end
452441end
453442
454- -- Helper functions
443+ -- Helper function to get all bookmark files
455444local function get_bookmark_files (self , project_only )
456445 local bookmarks_dir = self :get_bookmarks_dir ()
457446 if project_only then
@@ -501,20 +490,17 @@ function Bookmarks:get_list(opts)
501490 opts = opts or {}
502491 local items = {}
503492
504- -- Get bookmark files based on project_only flag
505493 local files = get_bookmark_files (self , opts .project_only )
506494
507495 for _ , file in ipairs (files ) do
508496 local data = read_bookmark_file (file )
509497 if data then
510498 if opts .group then
511- -- Get specific group
512499 if data [tostring (opts .group )] then
513500 local group_data = data [tostring (opts .group )]
514501 items = vim .list_extend (items , process_group_marks (group_data , opts .group ))
515502 end
516503 else
517- -- Get all groups
518504 for group_key , group_data in pairs (data ) do
519505 local group_nr = tonumber (group_key )
520506 items = vim .list_extend (items , process_group_marks (group_data , group_nr ))
@@ -536,14 +522,18 @@ function Bookmarks:to_list(list_type, group_nr)
536522
537523 local items = {}
538524 for bufnr , buffer_marks in pairs (self .groups [group_nr ].marks ) do
539- for mark_key , mark in pairs (buffer_marks ) do
540- local text = a .nvim_buf_get_lines (bufnr , mark .line - 1 , mark .line , true )[1 ]
541- table.insert (items , {
542- bufnr = bufnr ,
543- lnum = mark .line ,
544- col = mark .col + 1 ,
545- text = text ,
546- })
525+ if utils .is_valid_buffer (bufnr ) then
526+ for mark_key , mark in pairs (buffer_marks ) do
527+ local text = utils .safe_get_line (bufnr , mark .line - 1 )
528+ table.insert (items , {
529+ bufnr = bufnr ,
530+ lnum = mark .line ,
531+ col = mark .col + 1 ,
532+ text = text ,
533+ })
534+ end
535+ else
536+ self .groups [group_nr ].marks [bufnr ] = nil
547537 end
548538 end
549539
@@ -555,20 +545,35 @@ function Bookmarks:all_to_list(list_type)
555545 local list_fn = utils .choose_list (list_type )
556546
557547 local items = {}
548+ local invalid_buffers = {}
549+
558550 for group_nr , group in pairs (self .groups ) do
559551 for bufnr , buffer_marks in pairs (group .marks ) do
560- for mark_key , mark in pairs (buffer_marks ) do
561- local text = a .nvim_buf_get_lines (bufnr , mark .line - 1 , mark .line , true )[1 ]
562- table.insert (items , {
563- bufnr = bufnr ,
564- lnum = mark .line ,
565- col = mark .col + 1 ,
566- text = ' bookmark group ' .. group_nr .. ' : ' .. text ,
567- })
552+ if utils .is_valid_buffer (bufnr ) then
553+ for mark_key , mark in pairs (buffer_marks ) do
554+ local text = utils .safe_get_line (bufnr , mark .line - 1 )
555+ table.insert (items , {
556+ bufnr = bufnr ,
557+ lnum = mark .line ,
558+ col = mark .col + 1 ,
559+ text = ' bookmark group ' .. group_nr .. ' : ' .. text ,
560+ })
561+ end
562+ else
563+ if not invalid_buffers [group_nr ] then
564+ invalid_buffers [group_nr ] = {}
565+ end
566+ table.insert (invalid_buffers [group_nr ], bufnr )
568567 end
569568 end
570569 end
571570
571+ for group_nr , bufnrs in pairs (invalid_buffers ) do
572+ for _ , bufnr in ipairs (bufnrs ) do
573+ self .groups [group_nr ].marks [bufnr ] = nil
574+ end
575+ end
576+
572577 list_fn (items , ' r' )
573578end
574579
0 commit comments