|
1 | 1 | local M = {}
|
2 | 2 |
|
| 3 | +---@param callback function|nil Function to call with the merged ranges |
3 | 4 | ---@return nil
|
4 | 5 | function M.handle_text_change_animation(callback)
|
5 |
| - local detach_listener = false |
6 | 6 | local ranges = {}
|
7 |
| - local iter = 0 |
8 |
| - |
9 |
| - ---Callback function for buffer changes |
10 |
| - ---@param event any Event type |
11 |
| - ---@param bufnr number Buffer number |
12 |
| - ---@param changedtick number Changed tick |
13 |
| - ---@param start_row number Starting row of change |
14 |
| - ---@param start_col number Starting column of change |
15 |
| - ---@param byte_offset number Byte offset |
16 |
| - ---@param old_end_row number Old end row |
17 |
| - ---@param old_end_col number Old end column |
18 |
| - ---@param old_byte_end number Old end byte |
19 |
| - ---@param new_end_row number New end row |
20 |
| - ---@param new_end_col number New end column |
21 |
| - ---@param new_byte_end number New end byte |
22 |
| - function M.on_bytes( |
23 |
| - event, |
24 |
| - bufnr, |
25 |
| - changedtick, |
| 7 | + local final_ranges = {} |
| 8 | + |
| 9 | + local insert = table.insert |
| 10 | + local max = math.max |
| 11 | + |
| 12 | + -- Flag to detach buffer listener |
| 13 | + local detach_listener = false |
| 14 | + |
| 15 | + local function on_bytes( |
| 16 | + _, -- event |
| 17 | + _, -- bufnr |
| 18 | + _, -- changedtick |
26 | 19 | start_row,
|
27 | 20 | start_col,
|
28 |
| - byte_offset, |
29 |
| - old_end_row, |
30 |
| - old_end_col, |
31 |
| - old_byte_end, |
| 21 | + _, -- byte_offset |
| 22 | + _, -- old_end_row |
| 23 | + _, -- old_end_col |
| 24 | + _, -- old_byte_end |
32 | 25 | new_end_row,
|
33 | 26 | new_end_col,
|
34 |
| - new_byte_end |
| 27 | + _ -- new_byte_end |
35 | 28 | )
|
36 | 29 | if detach_listener then
|
37 | 30 | return true
|
38 | 31 | end
|
39 | 32 |
|
40 | 33 | -- Calculate the affected text range
|
41 |
| - local buffer_line_count = vim.api.nvim_buf_line_count(0) |
42 | 34 | local end_row = start_row + new_end_row
|
43 | 35 | local end_col = start_col + new_end_col
|
44 | 36 |
|
45 |
| - -- Adjust end column for changes at buffer end |
46 |
| - if end_row >= buffer_line_count then |
| 37 | + if end_row >= vim.api.nvim_buf_line_count(0) then |
47 | 38 | local last_line = vim.api.nvim_buf_get_lines(0, -2, -1, false)[1]
|
48 |
| - end_col = #last_line |
| 39 | + if last_line then |
| 40 | + end_col = #last_line |
| 41 | + end |
49 | 42 | end
|
50 | 43 |
|
51 |
| - local range = { |
| 44 | + insert(ranges, { |
52 | 45 | start_line = start_row,
|
53 | 46 | start_col = start_col,
|
54 | 47 | end_line = end_row,
|
55 | 48 | end_col = end_col,
|
56 |
| - } |
57 |
| - |
58 |
| - table.insert(ranges, range) |
59 |
| - |
60 |
| - iter = iter + 1 |
| 49 | + }) |
61 | 50 | end
|
62 | 51 |
|
63 |
| - -- Attach buffer listener |
64 | 52 | vim.api.nvim_buf_attach(0, false, {
|
65 |
| - on_bytes = M.on_bytes, |
| 53 | + on_bytes = on_bytes, |
66 | 54 | })
|
67 | 55 |
|
68 | 56 | vim.schedule(function()
|
69 | 57 | detach_listener = true
|
70 | 58 |
|
71 |
| - local final_ranges = {} |
72 |
| - |
73 |
| - -- Sort ranges by start line and then by start column |
74 |
| - table.sort(ranges, function(a, b) |
75 |
| - if a.start_line == b.start_line then |
76 |
| - return a.start_col < b.start_col |
77 |
| - end |
78 |
| - return a.start_line < b.start_line |
79 |
| - end) |
| 59 | + local range_count = #ranges |
| 60 | + if range_count > 0 then |
| 61 | + table.sort(ranges, function(a, b) |
| 62 | + if a.start_line == b.start_line then |
| 63 | + return a.start_col < b.start_col |
| 64 | + end |
| 65 | + return a.start_line < b.start_line |
| 66 | + end) |
80 | 67 |
|
81 |
| - if #ranges > 0 then |
82 | 68 | local current = ranges[1]
|
83 | 69 |
|
84 |
| - for i = 2, #ranges do |
| 70 | + local is_empty_range = function(r) |
| 71 | + return r.start_line == r.end_line and r.start_col == r.end_col |
| 72 | + end |
| 73 | + |
| 74 | + for i = 2, range_count do |
85 | 75 | local next_range = ranges[i]
|
86 | 76 |
|
87 | 77 | -- Check if ranges overlap or are adjacent
|
88 | 78 | if
|
89 | 79 | current.end_line < next_range.start_line
|
90 | 80 | or (current.end_line == next_range.start_line and current.end_col < next_range.start_col)
|
91 | 81 | then
|
92 |
| - -- No overlap, add current range and start new one |
93 |
| - if current.start_line ~= current.end_line or current.start_col ~= current.end_col then |
94 |
| - table.insert(final_ranges, current) |
| 82 | + -- No overlap, add current range if not empty |
| 83 | + if not is_empty_range(current) then |
| 84 | + insert(final_ranges, current) |
95 | 85 | end
|
96 | 86 | current = next_range
|
97 | 87 | else
|
98 |
| - -- Merge overlapping ranges |
99 |
| - current.end_line = math.max(current.end_line, next_range.end_line) |
| 88 | + -- Merge overlapping ranges (optimize the conditional) |
| 89 | + current.end_line = max(current.end_line, next_range.end_line) |
100 | 90 | if current.end_line == next_range.end_line then
|
101 |
| - current.end_col = math.max(current.end_col, next_range.end_col) |
| 91 | + current.end_col = max(current.end_col, next_range.end_col) |
102 | 92 | end
|
103 | 93 | end
|
104 | 94 | end
|
105 | 95 |
|
106 |
| - if current.start_line ~= current.end_line or current.start_col ~= current.end_col then |
107 |
| - table.insert(final_ranges, current) |
| 96 | + -- Add the last range if not empty |
| 97 | + if not is_empty_range(current) then |
| 98 | + insert(final_ranges, current) |
108 | 99 | end
|
109 | 100 | end
|
110 | 101 |
|
111 |
| - vim.schedule(function() |
112 |
| - if callback then |
113 |
| - callback(final_ranges) |
114 |
| - end |
115 |
| - end) |
| 102 | + if callback then |
| 103 | + callback(final_ranges) |
| 104 | + end |
116 | 105 | end)
|
117 | 106 | end
|
118 | 107 |
|
|
0 commit comments