Skip to content

Commit 8a301f9

Browse files
committed
fix(scroll): set cursor using api instead of cursor movements
1 parent b0cfdd0 commit 8a301f9

File tree

1 file changed

+68
-56
lines changed

1 file changed

+68
-56
lines changed

lua/cinnamon/scroll.lua

+68-56
Original file line numberDiff line numberDiff line change
@@ -33,23 +33,23 @@ H.scroller = {
3333
self.window_only = (self.options.mode ~= "cursor")
3434
self.step_delay = math.max(math.floor(self.options.delay), 1)
3535

36-
local original_view = vim.fn.winsaveview()
37-
local original_position = H.get_position()
38-
local original_buffer_id = vim.api.nvim_get_current_buf()
3936
local original_window_id = vim.api.nvim_get_current_win()
37+
local original_buffer_id = vim.api.nvim_get_current_buf()
38+
local original_view = vim.fn.winsaveview()
39+
self.original_position = H.get_position()
4040

4141
H.execute_command(command)
4242

43+
self.window_id = vim.api.nvim_get_current_win()
44+
self.buffer_id = vim.api.nvim_get_current_buf()
4345
self.target_view = vim.fn.winsaveview()
4446
self.target_position = H.get_position()
45-
self.buffer_id = vim.api.nvim_get_current_buf()
46-
self.window_id = vim.api.nvim_get_current_win()
4747

4848
self.error = {
49-
line = H.get_line_error(original_position, self.target_position),
50-
col = self.target_position.col - original_position.col,
51-
winline = self.target_position.winline - original_position.winline,
52-
wincol = self.target_position.wincol - original_position.wincol,
49+
line = H.get_line_error(self.original_position, self.target_position),
50+
col = self.target_position.col - self.original_position.col,
51+
winline = self.target_position.winline - self.original_position.winline,
52+
wincol = self.target_position.wincol - self.original_position.wincol,
5353
}
5454

5555
local step_count = math.max(
@@ -104,6 +104,7 @@ H.scroller = {
104104
self.saved_scrolloff = vim.wo.scrolloff
105105
vim.wo.scrolloff = 0 -- Don't scroll the view when the cursor is near the edge
106106

107+
self.current_position = self.original_position
107108
self.initial_changedtick = vim.b.changedtick
108109
self.interrupted = false
109110
self.previous_step_position = nil
@@ -169,8 +170,8 @@ H.scroller = {
169170
local winline_before = vim.fn.winline()
170171
local wincol_before = vim.fn.wincol()
171172

172-
local line_step = H.move_step("line", self.step_queue.line)
173-
local col_step = H.move_step("col", self.step_queue.col)
173+
local line_step = self:move_cursor("line", self.step_queue.line)
174+
local col_step = self:move_cursor("col", self.step_queue.col)
174175

175176
local winline_step = vim.fn.winline() - winline_before
176177
local wincol_step = vim.fn.wincol() - wincol_before
@@ -187,9 +188,9 @@ H.scroller = {
187188

188189
-- When wrap is enabled, the winline change is not equal to the step size
189190
winline_before = vim.fn.winline()
190-
H.move_step("winline", self.step_queue.winline)
191+
self:move_window("winline", self.step_queue.winline)
191192
winline_step = vim.fn.winline() - winline_before
192-
wincol_step = H.move_step("wincol", self.step_queue.wincol)
193+
wincol_step = self:move_window("wincol", self.step_queue.wincol)
193194

194195
self.step_queue.winline = self.step_queue.winline - winline_step
195196
self.step_queue.wincol = self.step_queue.wincol - wincol_step
@@ -212,23 +213,65 @@ H.scroller = {
212213
end
213214
end,
214215

216+
---@param component "line" | "col"
217+
---@param distance number
218+
move_cursor = function(self, component, distance)
219+
if distance > 0 then
220+
distance = math.floor(distance)
221+
else
222+
distance = math.ceil(distance)
223+
end
224+
225+
if distance == 0 then
226+
return 0
227+
end
228+
229+
self.current_position[component] = self.current_position[component] + distance
230+
vim.api.nvim_win_set_cursor(0, { self.current_position.line, self.current_position.col })
231+
232+
return distance
233+
end,
234+
235+
---@param component "winline" | "wincol"
236+
---@param distance number
237+
---@return number
238+
move_window = function(self, component, distance)
239+
if distance > 0 then
240+
distance = math.floor(distance)
241+
else
242+
distance = math.ceil(distance)
243+
end
244+
local count = math.abs(distance)
245+
246+
if count == 0 then
247+
return 0
248+
end
249+
250+
local command = "normal! "
251+
if count > 1 then
252+
command = command .. count
253+
end
254+
255+
if component == "winline" then
256+
command = command .. (distance > 0 and "\25" or "\5")
257+
else
258+
command = command .. (distance > 0 and "zh" or "zl")
259+
end
260+
261+
vim.cmd(command)
262+
263+
return distance
264+
end,
265+
215266
move_to_target = function(self)
216267
if self.target_view == nil then
217268
error("Target view has not been set")
218269
end
219270

220-
-- The 'curswant' value has to be set with cursor() for the '$' movement.
221-
-- Setting it with winrestview() causes issues when within 'scrolloff'.
222271
vim.api.nvim_win_call(self.window_id, function()
223-
vim.fn.cursor({
224-
self.target_view.lnum,
225-
self.target_view.col + 1,
226-
self.target_view.coladd,
227-
self.target_view.curswant + 1,
228-
})
272+
vim.fn.winrestview(self.target_view)
229273
end)
230274

231-
-- Cursor isn't redrawn if the window was exited
232275
vim.cmd.redraw()
233276
end,
234277

@@ -293,43 +336,12 @@ H.execute_command = function(command)
293336
vim.api.nvim_exec_autocmds("User", { pattern = "CinnamonCmdPost" })
294337
end
295338

296-
---@param component "line" | "col" | "winline" | "wincol"
297-
---@param distance number
298-
---@return number
299-
H.move_step = function(component, distance)
300-
local command = "normal! "
301-
local movement = ""
302-
distance = (distance > 0) and math.floor(distance) or math.ceil(distance)
303-
local count = math.abs(distance)
304-
305-
if count == 0 then
306-
return 0
307-
elseif count > 1 then
308-
command = command .. count
309-
end
310-
311-
if component == "line" then
312-
movement = distance > 0 and "j" or "k"
313-
elseif component == "col" then
314-
movement = distance > 0 and "l" or "h"
315-
elseif component == "winline" then
316-
movement = distance > 0 and "\25" or "\5"
317-
elseif component == "wincol" then
318-
movement = distance > 0 and "zh" or "zl"
319-
else
320-
error("Invalid component: " .. component)
321-
end
322-
323-
vim.cmd(command .. movement)
324-
325-
return distance
326-
end
327-
328339
---@return Position
329340
H.get_position = function()
341+
local cursor = vim.api.nvim_win_get_cursor(0)
330342
return {
331-
line = vim.fn.line("."),
332-
col = vim.fn.virtcol("."),
343+
line = cursor[1],
344+
col = cursor[2],
333345
winline = vim.fn.winline(),
334346
wincol = vim.fn.wincol(),
335347
}

0 commit comments

Comments
 (0)