Skip to content

Commit 635aad3

Browse files
committed
perf: optimize buffer operations and add memoization
- Add buffer validation with caching mechanism - Implement buffer operation helpers with error handling - Extract common patterns for reuse across modules - Add automatic cache management with buffer lifecycle events - Fix error handling in mark and bookmark operations - Prevent errors with invalid buffers and positions
1 parent 6cf7da0 commit 635aad3

4 files changed

Lines changed: 245 additions & 109 deletions

File tree

lua/markit.lua

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -241,6 +241,7 @@ function M.setup(opts)
241241
assign_defaults(config_module.config)
242242
add_bookmark_commands(config_module.config.bookmarks)
243243
commands.setup(config_module.config)
244+
utils.setup_cache_handlers()
244245
end
245246

246247
return M

lua/markit/bookmark.lua

Lines changed: 48 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -47,19 +47,16 @@ function Bookmarks:get_bookmarks_dir()
4747
end
4848

4949
function 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()
5856
end
5957

6058
function 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')
6562
end
@@ -94,7 +91,6 @@ end
9491
function 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

153147
function 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

255250
function 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]
348344
end
349345

350346
function 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 })
@@ -424,10 +417,6 @@ end
424417
function 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
452441
end
453442

454-
-- Helper functions
443+
-- Helper function to get all bookmark files
455444
local 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')
573578
end
574579

0 commit comments

Comments
 (0)